How to Self-Host Firefox Sync Using syncstorage-rs

This article provides a step-by-step guide for privacy-conscious users on how to self-host Mozilla's syncstorage-rs server and configure the Firefox Web Browser to use this private infrastructure. By deploying your own sync server using Docker and MariaDB, and updating a single configuration setting within Firefox, you can maintain complete control over your browsing history, bookmarks, passwords, and open tabs without storing your encrypted data on Mozilla's cloud servers.

Prerequisites

Before deploying the server, ensure you have the following ready:

  • A Linux server with Docker and Docker Compose installed.
  • A registered domain name (or subdomain) pointing to your server.
  • A reverse proxy (such as Nginx, Caddy, or Traefik) configured to handle HTTPS/TLS termination for your domain.
  • A Mozilla Account (formerly Firefox Account). Note that this setup self-hosts the data storage, while still using Mozilla's public authentication servers to verify your identity.

Step 1: Prepare the Database

The syncstorage-rs server requires a MySQL or MariaDB instance with two separate databases: one for storing the actual sync data (syncstorage) and one for managing authentication tokens (tokenserver).

Create a project directory on your server:

mkdir firefox-sync && cd firefox-sync

Create an initialization SQL script named init.sql to automatically build the required databases and permissions when the database container starts:

CREATE DATABASE IF NOT EXISTS syncstorage_rs;
CREATE DATABASE IF NOT EXISTS tokenserver_rs;

GRANT ALL PRIVILEGES ON syncstorage_rs.* TO 'syncuser'@'%';
GRANT ALL PRIVILEGES ON tokenserver_rs.* TO 'syncuser'@'%';
FLUSH PRIVILEGES;

Step 2: Configure Docker Compose

Next, generate two random secrets that the server will use for security. Run the following command twice and save the outputs:

head -c 32 /dev/urandom | base64

Create a docker-compose.yml file in your firefox-sync directory. Replace your_db_password, your_root_password, secret_1, secret_2, and https://sync.yourdomain.com with your actual values.

version: '3.8'

services:
  mariadb:
    image: mariadb:10.11
    container_name: sync-db
    restart: unless-stopped
    environment:
      MYSQL_ROOT_PASSWORD: your_root_password
      MYSQL_USER: syncuser
      MYSQL_PASSWORD: your_db_password
    volumes:
      - ./db_data:/var/lib/mysql
      - ./init.sql:/docker-entrypoint-initdb.d/init.sql:ro
    healthcheck:
      test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"]
      interval: 10s
      timeout: 5s
      retries: 3

  syncstorage:
    image: mozilla/syncstorage-rs:latest
    container_name: sync-server
    restart: unless-stopped
    depends_on:
      mariadb:
        condition: service_healthy
    ports:
      - "127.0.0.1:8000:8000"
    environment:
      SYNC_HOST: 0.0.0.0
      SYNC_PORT: 8000
      SYNC_HUMAN_LOGS: 1
      SYNC_MASTER_SECRET: "secret_1"
      SYNC_HASH_SECRET: "secret_2"
      SYNC_SYNCSTORAGE__DATABASE_URL: "mysql://syncuser:your_db_password@mariadb:3306/syncstorage_rs"
      SYNC_TOKENSERVER__DATABASE_URL: "mysql://syncuser:your_db_password@mariadb:3306/tokenserver_rs"
      SYNC_TOKENSERVER__ENABLED: "true"
      SYNC_TOKENSERVER__RUN_MIGRATIONS: "true"
      SYNC_TOKENSERVER__FXA_EMAIL_DOMAIN: "api.accounts.firefox.com"
      SYNC_TOKENSERVER__FXA_OAUTH_SERVER_URL: "https://oauth.accounts.firefox.com"
      SYNC_TOKENSERVER__FXA_METRICS_HASH_SECRET: "secret_2"
      SYNC_TOKENSERVER__ADDITIONAL_BLOCKING_THREADS_FOR_FXA_REQUESTS: 2

Start the containers to initialize the databases and run the migrations:

docker compose up -d

Step 3: Register the Node in the Token Server

Even though the server is running, it will reject sync attempts until you register your domain as an available storage node inside the tokenserver_rs database.

Run the following command to access the MariaDB container (enter your MYSQL_ROOT_PASSWORD when prompted):

docker exec -it sync-db mariadb -u root -p tokenserver_rs

Once inside the MariaDB shell, run these two SQL queries. Replace https://sync.yourdomain.com with your actual HTTPS domain URL, and set capacity to the maximum number of users you want this server to support:

INSERT INTO services (id, service, pattern) VALUES (1, 'sync-1.5', '{node}/1.5/{uid}');

INSERT INTO nodes (id, service, node, available, current_load, capacity, downed, backoff) 
VALUES (1, 1, 'https://sync.yourdomain.com', 1, 0, 10, 0, 0);

EXIT;

Step 4: Configure the Reverse Proxy

The syncstorage-rs container is now listening on 127.0.0.1:8000. Configure your chosen reverse proxy to route traffic from https://sync.yourdomain.com to http://127.0.0.1:8000.

Ensure your reverse proxy passes the standard X-Forwarded-For and X-Forwarded-Proto headers, and that a valid SSL/TLS certificate (such as one from Let's Encrypt) is active. Firefox will refuse to sync over an unencrypted HTTP connection.

You can verify the server is reachable by navigating to https://sync.yourdomain.com/__heartbeat__ in your browser. It should return a JSON response indicating the database and server are healthy.

Step 5: Point Firefox to Your Private Server

With the server operational, you must instruct Firefox to use your private infrastructure instead of Mozilla's default storage servers.

  1. Open the Firefox Web Browser.
  2. If you are currently logged into a Mozilla Account in Firefox, sign out first.
  3. In the address bar, type about:config and press Enter.
  4. Click Accept the Risk and Continue.
  5. In the search bar, type identity.sync.tokenserver.uri.
  6. Click the Edit (pencil) icon next to the preference.
  7. Replace the default URL with your custom domain, appending /1.0/sync/1.5 to the end. It must look like this: https://sync.yourdomain.com/1.0/sync/1.5
  8. Click the Save (checkmark) icon.
  9. Log back into your Mozilla Account in Firefox.

Verification

To confirm that Firefox is utilizing your self-hosted server, type about:sync-log into the Firefox address bar. If a sync has occurred, you will see log files listed. Open the most recent log file and verify that the requests are being sent to https://sync.yourdomain.com. You can also check the syncstorage_rs database on your server; the bso (Basic Storage Object) table will now be populated with your encrypted browser data. You can repeat Step 5 on any other desktop or mobile Firefox browser to sync data across all your devices using your private server.