├── .gitignore ├── data └── initdb.d │ └── init.sql ├── example.env ├── docker-compose.yaml ├── app ├── Dockerfile └── entrypoint.sh ├── README.md └── .github └── workflows └── docker-publish.yml /.gitignore: -------------------------------------------------------------------------------- 1 | .env 2 | data/config/* 3 | -------------------------------------------------------------------------------- /data/initdb.d/init.sql: -------------------------------------------------------------------------------- 1 | CREATE DATABASE IF NOT EXISTS syncstorage_rs; 2 | CREATE DATABASE IF NOT EXISTS tokenserver_rs; 3 | 4 | GRANT ALL PRIVILEGES 5 | ON syncstorage_rs.* 6 | TO sync; 7 | 8 | GRANT ALL PRIVILEGES 9 | ON tokenserver_rs.* 10 | TO sync; 11 | -------------------------------------------------------------------------------- /example.env: -------------------------------------------------------------------------------- 1 | ########################################## 2 | ## Firefox SyncStorage RS Configuration ## 3 | ########################################## 4 | 5 | # URL clients will use to connect to the sync server (ttps://hostname:8000) 6 | # If you use a reverse proxy, that URL should be used here (https://sync.example.com) 7 | SYNC_URL= 8 | 9 | # MySQL passwords (should be random) 10 | MYSQL_ROOT_PASSWORD= 11 | MYSQL_PASSWORD= 12 | 13 | # Master sync key (must be 64 characters long) 14 | # Use: `cat /dev/urandom | base32 | head -c64` to generate a random value 15 | SYNC_MASTER_SECRET= 16 | 17 | # Hashing secret (must be 64 characters long) 18 | # Use: `cat /dev/urandom | base32 | head -c64` to generate a random value 19 | METRICS_HASH_SECRET= 20 | -------------------------------------------------------------------------------- /docker-compose.yaml: -------------------------------------------------------------------------------- 1 | services: 2 | mariadb: 3 | container_name: firefox_mariadb 4 | image: linuxserver/mariadb:10.6.13 5 | volumes: 6 | - ./data/config:/config 7 | - ./data/initdb.d/init.sql:/config/initdb.d/init.sql 8 | restart: unless-stopped 9 | environment: 10 | MYSQL_DATABASE: syncstorage 11 | MYSQL_USER: sync 12 | MYSQL_PASSWORD: ${MYSQL_PASSWORD} 13 | MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD} 14 | 15 | syncserver: 16 | container_name: firefox_syncserver 17 | build: ./app/ 18 | restart: unless-stopped 19 | ports: 20 | - "8000:8000" 21 | depends_on: 22 | - mariadb 23 | environment: 24 | LOGLEVEL: info 25 | SYNC_URL: ${SYNC_URL} 26 | SYNC_CAPACITY: 10 # Max number of users that will be accepted 27 | SYNC_MASTER_SECRET: ${SYNC_MASTER_SECRET} 28 | METRICS_HASH_SECRET: ${METRICS_HASH_SECRET} 29 | SYNC_SYNCSTORAGE_DATABASE_URL: mysql://sync:${MYSQL_PASSWORD}@mariadb:3306/syncstorage_rs 30 | SYNC_TOKENSERVER_DATABASE_URL: mysql://sync:${MYSQL_PASSWORD}@mariadb:3306/tokenserver_rs 31 | -------------------------------------------------------------------------------- /app/Dockerfile: -------------------------------------------------------------------------------- 1 | from rust:latest 2 | 3 | ARG GIT_COMMIT=1dc421474df2a4ee973d529534cd0eb7189d58ce 4 | 5 | # Create needed directories 6 | RUN mkdir /app /config 7 | WORKDIR /app 8 | 9 | # Install needed packages 10 | RUN apt-get update && apt-get install -y --no-install-recommends \ 11 | python3-virtualenv \ 12 | python3-pip \ 13 | python3-dev \ 14 | default-mysql-client \ 15 | && rm -rf /var/lib/apt/lists/* 16 | 17 | # Clone syncstorage-rs and build it 18 | RUN git clone https://github.com/mozilla-services/syncstorage-rs ./ \ 19 | && git checkout ${GIT_COMMIT} \ 20 | && cargo install --path ./syncserver --no-default-features --features=syncstorage-db/mysql --locked \ 21 | && cargo install diesel_cli --no-default-features --features 'mysql' \ 22 | && cargo clean 23 | 24 | # Setup the Python venv 25 | RUN virtualenv venv \ 26 | && /app/venv/bin/pip install -r requirements.txt \ 27 | && /app/venv/bin/pip install -r tools/tokenserver/requirements.txt \ 28 | && /app/venv/bin/pip install pyopenssl==22.1.0 29 | 30 | # Cleanup 31 | RUN rm -rf \ 32 | /var/cache \ 33 | /var/log \ 34 | /var/lib/apt \ 35 | /var/lib/dpkg 36 | 37 | # Copy entrypoint script and set it 38 | COPY --chmod=755 entrypoint.sh / 39 | ENTRYPOINT /entrypoint.sh 40 | -------------------------------------------------------------------------------- /app/entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | sleep 5 4 | 5 | # First run all migrations 6 | /usr/local/cargo/bin/diesel --database-url "${SYNC_SYNCSTORAGE_DATABASE_URL}" migration --migration-dir syncstorage-mysql/migrations run 7 | /usr/local/cargo/bin/diesel --database-url "${SYNC_TOKENSERVER_DATABASE_URL}" migration --migration-dir tokenserver-db/migrations run 8 | 9 | # Parse token server database URL 10 | proto="$(echo $SYNC_TOKENSERVER_DATABASE_URL | grep :// | sed -e's,^\(.*://\).*,\1,g')" 11 | url="$(echo ${SYNC_TOKENSERVER_DATABASE_URL/$proto/})" 12 | userpass="$(echo $url | grep @ | cut -d@ -f1)" 13 | pass="$(echo $userpass | grep : | cut -d: -f2)" 14 | user="$(echo $userpass | grep : | cut -d: -f1)" 15 | host="$(echo ${url/$user:$pass@/} | cut -d/ -f1)" 16 | port="$(echo $host | sed -e 's,^.*:,:,g' -e 's,.*:\([0-9]*\).*,\1,g' -e 's,[^0-9],,g')" 17 | host="$(echo ${host/:$port/} | cut -d/ -f1)" 18 | db="$(echo $url | grep / | cut -d/ -f2-)" 19 | 20 | # Create service and node if they doesnt exist 21 | mysql $db -h $host -P $port -u $user -p"$pass" < /config/local.toml <Example: http://sync.example.com:8000/1.0/sync/1.5 57 | 58 | To confirm the sync is working you can enable success logs in `about:config` also. Set `services.sync.log.appender.file.logOnSuccess` to true. Now you should see sync logs in `about:sync-log` 59 | 60 | Syncing is usually very quick, and when a sync occurs you can see logs in `docker compose logs -f` also. 61 | -------------------------------------------------------------------------------- /.github/workflows/docker-publish.yml: -------------------------------------------------------------------------------- 1 | name: Docker 2 | 3 | # This workflow uses actions that are not certified by GitHub. 4 | # They are provided by a third-party and are governed by 5 | # separate terms of service, privacy policy, and support 6 | # documentation. 7 | 8 | on: 9 | push: 10 | branches: [ "main" ] 11 | # Publish semver tags as releases. 12 | tags: [ 'v*.*.*' ] 13 | pull_request: 14 | branches: [ "main" ] 15 | 16 | env: 17 | # Use docker.io for Docker Hub if empty 18 | REGISTRY: ghcr.io 19 | # github.repository as / 20 | IMAGE_NAME: ${{ github.repository }} 21 | 22 | 23 | jobs: 24 | build: 25 | 26 | runs-on: ubuntu-latest 27 | permissions: 28 | contents: read 29 | packages: write 30 | # This is used to complete the identity challenge 31 | # with sigstore/fulcio when running outside of PRs. 32 | id-token: write 33 | 34 | steps: 35 | - name: Checkout repository 36 | uses: actions/checkout@v4 37 | 38 | # Install the cosign tool except on PR 39 | # https://github.com/sigstore/cosign-installer 40 | - name: Install cosign 41 | if: github.event_name != 'pull_request' 42 | uses: sigstore/cosign-installer@59acb6260d9c0ba8f4a2f9d9b48431a222b68e20 #v3.5.0 43 | with: 44 | cosign-release: 'v2.2.4' 45 | 46 | # Set up BuildKit Docker container builder to be able to build 47 | # multi-platform images and export cache 48 | # https://github.com/docker/setup-buildx-action 49 | - name: Set up Docker Buildx 50 | uses: docker/setup-buildx-action@f95db51fddba0c2d1ec667646a06c2ce06100226 # v3.0.0 51 | 52 | # Login against a Docker registry except on PR 53 | # https://github.com/docker/login-action 54 | - name: Log into registry ${{ env.REGISTRY }} 55 | if: github.event_name != 'pull_request' 56 | uses: docker/login-action@343f7c4344506bcbf9b4de18042ae17996df046d # v3.0.0 57 | with: 58 | registry: ${{ env.REGISTRY }} 59 | username: ${{ github.actor }} 60 | password: ${{ secrets.GITHUB_TOKEN }} 61 | 62 | # Extract metadata (tags, labels) for Docker 63 | # https://github.com/docker/metadata-action 64 | - name: Extract Docker metadata 65 | id: meta 66 | uses: docker/metadata-action@96383f45573cb7f253c731d3b3ab81c87ef81934 # v5.0.0 67 | with: 68 | images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} 69 | 70 | # Build and push Docker image with Buildx (don't push on PR) 71 | # https://github.com/docker/build-push-action 72 | - name: Build and push Docker image 73 | id: build-and-push 74 | uses: docker/build-push-action@0565240e2d4ab88bba5387d719585280857ece09 # v5.0.0 75 | with: 76 | context: app 77 | push: ${{ github.event_name != 'pull_request' }} 78 | tags: ${{ steps.meta.outputs.tags }} 79 | labels: ${{ steps.meta.outputs.labels }} 80 | cache-from: type=gha 81 | cache-to: type=gha,mode=max 82 | 83 | # Sign the resulting Docker image digest except on PRs. 84 | # This will only write to the public Rekor transparency log when the Docker 85 | # repository is public to avoid leaking data. If you would like to publish 86 | # transparency data even for private images, pass --force to cosign below. 87 | # https://github.com/sigstore/cosign 88 | - name: Sign the published Docker image 89 | if: ${{ github.event_name != 'pull_request' }} 90 | env: 91 | # https://docs.github.com/en/actions/security-guides/security-hardening-for-github-actions#using-an-intermediate-environment-variable 92 | TAGS: ${{ steps.meta.outputs.tags }} 93 | DIGEST: ${{ steps.build-and-push.outputs.digest }} 94 | # This step uses the identity token to provision an ephemeral certificate 95 | # against the sigstore community Fulcio instance. 96 | run: echo "${TAGS}" | xargs -I {} cosign sign --yes {}@${DIGEST} 97 | --------------------------------------------------------------------------------