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_4d3d3d3dSYNC_SYNCSTORAGE__DATABASE_URL: database URL for syncstorage, e.g.mysql://sync:test@example.io/syncstorageorpostgres://testo:@localhost/syncdbSYNC_TOKENSERVER__DATABASE_URL: database URL for tokenserver, e.g.mysql://sync:test@example.io/tokenserverorpostgres://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.
- Go to
about:configin Firefox. - Find the
identity.sync.tokenserver.uriconfiguration. - Change the value to
http://localhost:8000/1.0/sync/1.5. - 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.