byeCloud: Firefox Sync Server

published on on byeCloud, Caddy, Docker, Selfhosted

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 and none of those seemed to satisfy my needs but Firefox Sync almost does. 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. It consists of two parts: First is the account server, which is not that good documented so I chose to use their hosted one, but with a own sync server so that I use their hosted stuff 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.

There were multiple Docker containers available for Firefox Sync but none of them really worked, so I decided to build one by my own and I will share it with you now :-)

I've created a project on GitHub that contains a fully working Firefox Sync Server setup with my favorite webserver Caddy as a reverse proxy. This is managed using docker-compose:

Simply customize ffsync/syncserver.ini and then put the domain for your sync server into entry/Caddyfile or just remove the whole entry service (which is the reverse proxy) from docker-compose.yml and use your own proxy like nginx.

This following excerpt is part of my docker-compose.yml file:

version: "3"

    build: ffsync/
    restart: always
      - ./data/ffsync:/data
      - ./ffsync/syncserver.ini:/tmp/syncserver.ini

    image: abiosoft/caddy:0.10.4
    restart: always
      - ffsync
      - "80:80"
      - "443:443"
      - ./entry/Caddyfile:/etc/Caddyfile
      - ./data"entry:/root/.caddy

Then just run docker-compose up -d and Caddy 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 and log in to "Firefox Sync" and start synchronization. Have a look at the size of the database at data/ffsync/dbsync.db to see if your data gets saved.

Client side: macOS (also Windows, Linux)

Obviously, the client here is Firefox. I use version 54 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):


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.

Be sure to set allow_new_users to false in syncserver.ini after registering your user and restart the docker container.

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. There's already a GitHub issue, but it does not seem to have much traction... Still I hope that this will be implemented soon...