In this article I will show you how to set up a Firefox Sync Server as a Docker container. In my case this will replace iCloud Bookmark / Tab synchronization. This article is part of the byeCloud series in which I try to replace iCloud with self-hosted services.
I’ve evaluated different solutions to synchronize tabs and bookmarks, but none of them seemed to satisfy my needs. Firefox Sync almost does. Originally, I wanted to use Chromium with some plugin that would allow me to self-host a bookmark sync service. While there is a working solution called Unmark which also has a Chrome extension that works in general, the open source version lacks HTML bookmark import functionality and seems not to be the best possible software quality after a quick review (in fact I implemented a HTML bookmark to Unmark JSON converter to import my bookmarks but even their JSON import code drove me crazy).
Luckily, Mozilla makes the good stuff and provides all of the infrastructure for their hosted Firefox Sync service as open source on GitHub (thanks!). It consists of two parts: First is the account server, which is not that extensively documented so I chose to use their hosted one, but with a own sync server so that I use their hosted service for authentication but my server for saving the data.
System setup
As the Firefox Sync server is a integral part of my daily workflow when switching machines (e.g. at home and then at work), I chose to set it up on my VPS rather than on my NAS at home to have it accessible from everywhere. I used Traefik as a reverse proxy that also cares for certificates via Let’s Encrypt.
Luckily, by now Mozilla provides an offical image for their syncserver on DockerHub. This makes it extremely easy to set up.
Here’s how my docker-compose.yml
looks like:
version: '3'
services:
traefik:
image: traefik:latest
restart: unless-stopped
command: --docker --logLevel="INFO"
ports:
- "80:80"
- "443:443"
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- ./traefik.toml:/etc/traefik/traefik.toml
- ./acme.json:/acme.json
firefox-syncserver:
image: mozilla/syncserver:latest
restart: unless-stopped
volumes:
- firefox-syncserver-data:/tmp
- /etc/localtime:/etc/localtime:ro
environment:
- TZ=Europe/Berlin
- SYNCSERVER_PUBLIC_URL=https://your-sync-server.example.com
- SYNCSERVER_SECRET=ADD_SOME_SECRET_HERE
- SYNCSERVER_SQLURI=sqlite:////tmp/syncserver.db
- SYNCSERVER_BATCH_UPLOAD_ENABLED=true
- SYNCSERVER_FORCE_WSGI_ENVIRON=true
- SYNCSERVER_ALLOW_NEW_USER=true
- PORT=4500
labels:
- traefik.enable=true
- traefik.frontend.rule=Host:your-sync-server.example.com
- traefik.port=4500
volumes:
firefox-syncserver-data:
Just exchange ADD_SOME_SECRET_HERE
with some real secret and provide proper URLs for your sync service.
Here’s my Traefik configuration, traefik.toml
:
# Show Docker events for now
logLevel = "INFO"
defaultEntryPoints = ["https", "http"]
# Force HTTPS
[entryPoints]
[entryPoints.http]
address = ":80"
[entryPoints.http.redirect]
entryPoint = "https"
[entryPoints.https]
address = ":443"
[entryPoints.https.tls]
[acme]
email = "webmaster@example.com"
# Store certificates in /acme.json
storage = "acme.json"
acmeLogging = true
onHostRule = true
onDemand = false
# Use HTTP challenge as my DNS provider does not support DNS challenge
entryPoint = "https"
[acme.httpChallenge]
entryPoint = "http"
[docker]
endpoint = "unix:///var/run/docker.sock"
watch = true
# Only expose services that are enabled explicitly
exposedbydefault = false
Then run docker-compose up -d
and Traefik will obtain SSL certificates from Let’s Encrypt and start serving Firefox Sync Server.
Afterwards set up Firefox on your machine, configure the URL to your server, log in to “Firefox Sync” and start synchronization. Have a look at the size of the database at /tmp/syncserver.db
to see if your data gets saved.
Client side: macOS (also Windows, Linux)
Obviously, the client here is Firefox. I use version 63 at the time of writing this. Open the advanced preferences at about:config
and set the property identity.sync.tokenserver.uri
to match the sync endpoint of your server, like this (please! have a closer look at the URL as this format differs from the preset value):
https://your-sync-server.example.com/token/1.0/sync/1.5
Then save, open the normal preferences window and click “Sync”. You will be prompted for your username and password for Firefox Sync. If you don’t have any, it’s a good time to register now. After logging in and starting the sync, everything should work.
After registering your user, be sure to set the SYNCSERVER_ALLOW_NEW_USER
environment variable to false
in docker-compose.yml
and run docker-compose up -d
again to recreate the container.
If things don’t work for any reason, chances are good to find traces of the problem at about:sync-log
.
Data migration
Migrating the data from Safari or any other browser is easy. In Safari, click “File” -> “Export bookmarks”. This will save your bookmarks as a HTML file. This can be imported from the Firefox bookmark manager (“Bookmarks” -> “Manage Bookmarks” -> click the little sync-star icon -> “Import Bookmarks from HTML”).
Client side: iOS
Although there’s a Firefox version for iOS, this sadly does not support providing a custom sync server right now. With this GitHub issue, Firefox for iOS now supports custom FxA servers, but this involves much more than provided here and it’s not trivial to set this up… Still I hope that this will be implemented soon, a new GitHub issue has been filed for the follow-up problem to only use a custom sync server.