Firefox Sync logo obtained from Wikimedia Commons
Firefox Sync logo obtained from Wikimedia Commons

As I’m working on multiple machines (two desks at work, one desk at home, laptop, …) I’ve always been looking for a way to sync my browsers… Of course, I knew about Firefox’ sync, but I obviously don’t want to store my private browsing data in Mozilla’s cloud! Every once in a while I stumbled upon articles and posts suggesting to run a private syncserver. However, every time when looking into that project it left an uncomfortable impression: (i) you need to manually compile some 3rd party software, (ii) the whole thing seems very complex/unclean, as it requires an account server and a sync server and may work with Mozilla’s account server (but how?), and (iii) the sync project was once already abandoned (Firefox Weave was discontinued because too complex and unreliable)… Therefore, I never dared to give it a try.

Today, when I’ve again been frustrated with that fragmented situation, I saw that Mozilla’s syncserver sources contain a Dockerfile! It probably has been there for ages, but I never recognised it.. Even if that project may be a mess, in a container environment it’s pretty easy to give it a try (and clean it, if unsatisfied)! That changes everything! :P

So I changed everything, and tooted about it. Various people then convinced me to write this article. And I also learnt that Epiphany can do Firefox’ sync out of the box!

Get the Syncserver Running

Running your own syncserver using Docker is pretty straight forward. This how-to is based on the project’s readme at GitHub:mozilla-services/syncserver, but I’m using docker-compose and I deployed the service behind an Nginx proxy. You can of course skip the proxy settings and have it run locally or something.

Get the Code

Just clone the sources from GitHub:

git clone https://github.com/mozilla-services/syncserver

You should now see a new directory syncserver containing all the sources, including a Dockerfile.

Build a Docker Image

Change into the project’s directory, that contains the Dockerfile and build a new Docker image using:

docker build -t syncserver:latest .

That will take a while, but when it’s finished you’ll find a new image (double check with docker images).

The provided Dockerfile is basically sufficient, but in my scenario I also need to properly declare an exposed port. So I edited that file and added

EXPOSE 5000

See also the diff of my commit. I decided to take port 5000, as the user running the syncserver is unpriviledged (so :80 and :443 are not an option) and :5000 is the example in the project’s readme ;-)

Create a Docker-Compose Configuration

Docker-Compose makes it easier to assemble and handle multiple containers in a medium complex environment.

My compose config looks like this:

firefox-sync:
  restart: always
  image: syncserver:latest
  container_name: firefox-sync
  volumes:
    - /path/to/mozilla-sync/share:/syncshare
  environment:
    - SYNCSERVER_PUBLIC_URL=https://firefox-sync.example.com
    - SYNCSERVER_SECRET=waitis6eexeeda7ifoolitauv2Aehooxie8eim2quaiyiaXeer
    - SYNCSERVER_SQLURI=sqlite:////syncshare/syncserver.db
    - SYNCSERVER_BATCH_UPLOAD_ENABLED=true
    - SYNCSERVER_FORCE_WSGI_ENVIRON=true
    - PORT=5000
    - VIRTUAL_HOST=firefox-sync.example.com
    - VIRTUAL_PORT=5000
    - HTTPS_METHOD=noredirect
  logging:
    driver: syslog
    options:
      tag: docker/web/firefoxsync

This snippet encodes for a container named firefox-sync, which is based on the image syncserver:latest. It mounts the host’s directory /path/to/mozilla-sync/share into the container as /syncshare (I’d like to store my stuff outside of the container). In addition it declares some environment:

  • SYNCSERVER_PUBLIC_URL tells the service the actual URL to your instance.
  • SYNCSERVER_SECRET should be complicated as it is used to generate internal certificates and stuff.
  • SYNCSERVER_SQLURI tell the service which database to use. I point it to the directory (/syncshare) that was mounted into the container, so it will actually store the database on the host.
  • SYNCSERVER_BATCH_UPLOAD_ENABLED is, if I understand correctly, an option to allow for uploading everything immediately…?
  • SYNCSERVER_FORCE_WSGI_ENVIRON must be set to true, if SYNCSERVER_PUBLIC_URL doesn’t match the actual URL seen by the python tool. In my case, I would connect to SYNCSERVER_PUBLIC_URL, which is however the Nginx proxy, which forwards the traffic to the syncserver. However, the syncserver will see a different request (e.g. it’s internally not https anymore) and complain.

The last two variables (VIRTUAL_HOST and VIRTUAL_PORT) just configure the reverse proxy that I’m using. Feel free to drop these lines if you want to expose the service directly to the network, but then you need to add a port forwarding for that container, such as

ports:
  - "80:5000"

which forwards traffic at your machine’s HTTP port (:80, use a different port if you’re already running a web server) to the service’s port in the container (:5000).

If you have a porper Docker-Compose configuration, just run

docker-compose up -d --remove-orphans

to start the service. Et voilà, you should be able to access the service at the configured SYNCSERVER_PUBLIC_URL :)

Configure Firefox to use your Private Sync Server

First make sure you’re signed out in the browser! That means, about:preferences#sync should not show your identity and instead provide a button to sign in.

Then, open about:config and search for identity.sync.tokenserver.uri. By default, it will be set to Mozilla’s sync server https://token.services.mozilla.com/1.0/sync/1.5. Edit that field and point it to your SYNCSERVER_PUBLIC_URL plus /token/1.0/sync/1.5. Thus, in our example above I’d set it to https://firefox-sync.example.com/token/1.0/sync/1.5.

Now go back to about:preferences#sync and sign in with your Mozilla account. Yes, correct. You still need an account at Mozilla! But that is just for authentication… There is an option to also run a private account server (see Run your own Firefox Accounts Server), but that’s even more complicated. And as I need a Mozilla account anyway to develop my AddOns, I skipped that additional hassling..

Open Issues and Troubleshooting

There are still a few issues with different clients. For example, I don’t know how to tell Epiphany to use my private syncserver instead of Mozilla’s public instance.. In addition, there is apparently no Firefox in the F-Droid repository, that properly supports sync…

For general debugging and troubleshooting, search engines are a good start.. In addition, I learnt that there is about:sync-log, which contains very detailed error messages in case of problems.

Eventually…

… I got my sync! #hooray

It’s still crisply and I didn’t test it too much, but so far it’s looking pretty good.


Martin Scharm

stuff. just for the records.

Do you like this page?
You can actively support me!

5 comments

spolix | Permalink |

https://noobs.tech/how-to-create-a-firefox-sync-server/

Matt | Permalink |

I followed your tutorial and got the FF syncserver working. I am however struggling to get SSL up. How did you get this working, since your config files hint to SSL use?

Thanks!

Martin Scharm | Permalink |

As I said, I have an nginx reverse proxy in front of the sync server (https://github.com/nginx-proxy/nginx-proxy), which does the TLS stuff. That should be pretty straight forward..?

solnyshok | Permalink |

Hi, are there any other benefits than privacy to using own sync server? Can you give more storage space to history sync, or increase number of bookmarks/tabs stored?

Tread | Permalink |

What I don’t understand is how Mozilla can take such a simple concept and create these abominations of server-side complexity. It shouldn’t be this hard. On the server you should be able to start a single process that accesses a single database and be done with it.

Leave a comment

There are multiple options to leave a comment: