Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Use Docker to Deploy Your Own Sync Server

Mozilla publishes Docker images of its syncstorage-rs builds on ghcr.io. This guide provides a simple docker compose setup that can act as a starting point to self-host Sync.

Images are available for both MySQL and PostgreSQL as the database. Differences in configuration or deployment steps will be noted.

Note: At the time of writing, there are no tagged release builds available on ghcr.io. This guide will use a build from the main development branch.

Prerequisites and Presumptions

  • The reader is familiar with the command line interface and docker.
  • The reader is going to use Mozilla accounts for authentication and authorization.
  • The service will be deployed at http://localhost:8000/.

Docker Compose, Sync Services Only

With a MySQL or PostgreSQL database is already up and running, save the yaml below into a file, e.g. docker-compose.yaml, and ensure the image field is using the correct MySQL or PostgreSQL build for the database.

services:
  syncserver:
    image: ghcr.io/mozilla-services/syncstorage-rs/syncstorage-rs-mysql:${SYNCSERVER_VERSION:-b16ef5064b}
    platform: linux/amd64
    container_name: syncserver
    ports:
      - "8000:8000"
    environment:
      SYNC_HOST: "0.0.0.0"
      SYNC_PORT: "8000"
      SYNC_MASTER_SECRET: "${SYNC_MASTER_SECRET}"
      SYNC_SYNCSTORAGE__DATABASE_URL: "${SYNC_SYNCSTORAGE__DATABASE_URL}"
      SYNC_TOKENSERVER__DATABASE_URL: "${SYNC_TOKENSERVER__DATABASE_URL}"
      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"
    restart: unless-stopped
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8000/__heartbeat__"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 60s

Note that multiple values will be read from the environment:

  • SYNC_MASTER_SECRET: a secret used in cryptographic operationsk a passphrase or random character string, e.g. use_your_own_secret_4d3d3d3d
  • SYNC_SYNCSTORAGE__DATABASE_URL: database URL for syncstorage, e.g. mysql://sync:test@example.io/syncstorage or postgres://testo:@localhost/syncdb
  • SYNC_TOKENSERVER__DATABASE_URL: database URL for tokenserver, e.g. mysql://sync:test@example.io/tokenserver or postgres://testo:@localhost/syncdb

The values can be directly written into the yaml as well.

Next, start the service with docker compose:

SYNC_MASTER_SECRET=use_your_own_secret_4d3d3d3d \
SYNC_SYNCSTORAGE__DATABASE_URL="mysql://sync:test@example.io/syncstorage" \
SYNC_TOKENSERVER__DATABASE_URL="mysql://sync:test@example.io/tokenserver" \
docker compose -f docker-compose.yaml up -d

Database Bootstrapping

After starting the service on a clean, uninitialized database, some bootstrapping records need to be inserted.

For MySQL, run

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

INSERT INTO tokenserver.nodes (service, node, available, current_load, capacity, downed, backoff)
VALUES (
  (SELECT id FROM services WHERE service = 'sync-1.5'),
  'http://localhost:8000',
  1, 0, 1000, 0, 0
);

For PostgreSQL, run

INSERT INTO nodes (service, node, available, current_load, capacity, downed, backoff)
VALUES (
  (SELECT id FROM services WHERE service = 'sync-1.5'),
  'http://localhost:8000',
  1, 0, 1000, 0, 0
);

Note that http://localhost:8000 above needs to be replaced with the actual service URL.

Restart the service with

docker compose -f docker-compose.yaml restart

Docker Compose, One-Shot with PostgreSQL

Alternatively, the database can be started through docker compose as well. The real service URL can be set with the NODE_URL environment variable.

Save the yaml below into a file, e.g. docker-compose.one-shot.yaml.

services:
  syncserver:
    image: ghcr.io/mozilla-services/syncstorage-rs/syncstorage-rs-postgres:${SYNCSERVER_VERSION:-11659d98f9}
    platform: linux/amd64
    container_name: syncserver
    ports:
      - "8000:8000"
    environment:
      SYNC_HOST: "0.0.0.0"
      SYNC_PORT: "8000"
      SYNC_MASTER_SECRET: "${SYNC_MASTER_SECRET:-changeme_secret_key}"
      SYNC_SYNCSTORAGE__DATABASE_URL: "postgres://sync:sync@postgres:5432/syncserver"
      SYNC_TOKENSERVER__DATABASE_URL: "postgres://sync:sync@postgres:5432/syncserver"
      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_HUMAN_LOGS: "${SYNC_HUMAN_LOGS:-false}"
      RUST_LOG: "${RUST_LOG:-info}"
    depends_on:
      postgres:
        condition: service_healthy
    restart: unless-stopped
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8000/__heartbeat__"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 60s

  postgres:
    image: postgres:18
    container_name: syncserver-postgres
    environment:
      POSTGRES_USER: sync
      POSTGRES_PASSWORD: sync
      POSTGRES_DB: syncserver
    volumes:
      - postgres_data:/var/lib/postgresql
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U sync -d syncserver"]
      interval: 10s
      timeout: 5s
      retries: 5
      start_period: 30s
    restart: unless-stopped

  # insert record for the storage node
  bootstrap:
    image: postgres:18
    container_name: syncserver-bootstrap
    environment:
      PGHOST: postgres
      PGPORT: 5432
      PGUSER: sync
      PGPASSWORD: sync
      PGDATABASE: syncserver
      NODE_URL: "${NODE_URL:-http://localhost:8000}"
    depends_on:
      syncserver:
        condition: service_healthy
    command: >
      sh -c "
      echo 'Waiting for migrations to complete...';
      sleep 5;
      echo 'Inserting storage node record...';
      psql -c \"INSERT INTO nodes (service, node, available, current_load, capacity, downed, backoff)
               VALUES ((SELECT id FROM services WHERE service = 'sync-1.5'), '\$\${NODE_URL}', 1, 0, 1000, 0, 0)
               ON CONFLICT (service, node) DO NOTHING;\";
      echo 'DB bootstrap complete';
      "
    restart: "no"

volumes:
  postgres_data:
    driver: local

Next, start the service with docker compose:

SYNC_MASTER_SECRET=use_your_own_secret_4d3d3d3d \
NODE_URL=http://localhost:8000 \
docker compose -f docker-compose.one-shot.yaml up -d

Configuring Firefox

Firefox itself needs to be configured to use the self-hosted Sync server.

  1. Go to about:config in Firefox.
  2. Find the identity.sync.tokenserver.uri configuration.
  3. Change the value to http://localhost:8000/1.0/sync/1.5.
  4. Restart Firefox.

Firefox should be using the self-hosted Sync server at this point. That can be verified by checking the logs in about:sync-log.