[
  {
    "path": ".dockerignore",
    "content": "/.dev\n/.idea\n/*.iml\n\n/.git\n/.github\n/examples\n/.editorconfig\n/.gitattributes\n/.gitignore\n/CHANGELOG.md\n/LICENSE\n/README.md\n"
  },
  {
    "path": ".editorconfig",
    "content": "# editorconfig.org\nroot = true\n\n[*]\nindent_style = space\nindent_size = 2\nend_of_line = lf\ncharset = utf-8\ntrim_trailing_whitespace = true\ninsert_final_newline = true\n\n[*.md]\ntrim_trailing_whitespace = false\n"
  },
  {
    "path": ".gitattributes",
    "content": "/*.sh linguist-detectable=false\n"
  },
  {
    "path": ".github/CODEOWNERS",
    "content": "*\t@crazy-max\n"
  },
  {
    "path": ".github/FUNDING.yml",
    "content": "github: crazy-max\ncustom: https://www.paypal.me/crazyws\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.md",
    "content": "---\nname: Bug report\nabout: Create a report to help us improve\n---\n\n### Behaviour\n\n#### Steps to reproduce this issue\n\n1.\n2.\n3.\n\n#### Expected behaviour\n\n> Tell me what should happen\n\n#### Actual behaviour\n\n> Tell me what happens instead\n\n### Configuration\n\n* Docker version (type `docker --version`) :\n* Docker compose version if applicable (type `docker-compose --version`) : \n* Platform (Debian 9, Ubuntu 18.04, ...) : \n* System info (type `uname -a`) : \n* Include all necessary configuration files : `docker-compose.yml`, `.env`, ...\n\n### Docker info\n\n```\n> Output of command `docker info`\n```\n\n### Logs\n\n```\n> Container logs (set FF_SYNCSERVER_LOGLEVEL to debug if applicable)\n```\n"
  },
  {
    "path": ".github/SUPPORT.md",
    "content": "# Support [![](https://isitmaintained.com/badge/resolution/crazy-max/docker-firefox-syncserver.svg)](https://isitmaintained.com/project/crazy-max/docker-firefox-syncserver)\n\n## Reporting an issue\n\nPlease do a search in [open issues](https://github.com/crazy-max/docker-firefox-syncserver/issues?utf8=%E2%9C%93&q=) to see if the issue or feature request has already been filed.\n\nIf you find your issue already exists, make relevant comments and add your [reaction](https://github.com/blog/2119-add-reactions-to-pull-requests-issues-and-comments). Use a reaction in place of a \"+1\" comment.\n\n:+1: - upvote\n\n:-1: - downvote\n\nIf you cannot find an existing issue that describes your bug or feature, submit an issue using the guidelines below.\n\n## Writing good bug reports and feature requests\n\nFile a single issue per problem and feature request.\n\n* Do not enumerate multiple bugs or feature requests in the same issue.\n* Do not add your issue as a comment to an existing issue unless it's for the identical input. Many issues look similar, but have different causes.\n\nThe more information you can provide, the more likely someone will be successful reproducing the issue and finding a fix.\n\nYou are now ready to [create a new issue](https://github.com/crazy-max/docker-firefox-syncserver/issues/new/choose)!\n\n## Closure policy\n\n* Support directly related to Firefox Syncserver will not be provided if your problem is not related to the operation of this image.\n* Issues that don't have the information requested above (when applicable) will be closed immediately and the poster directed to the support guidelines.\n* Issues that go a week without a response from original poster are subject to closure at my discretion.\n"
  },
  {
    "path": ".github/dependabot.yml",
    "content": "version: 2\nupdates:\n  - package-ecosystem: \"github-actions\"\n    directory: \"/\"\n    schedule:\n      interval: \"daily\"\n      time: \"08:00\"\n      timezone: \"Europe/Paris\"\n    labels:\n      - \":game_die: dependencies\"\n      - \":robot: bot\"\n"
  },
  {
    "path": ".github/labels.yml",
    "content": "## more info https://github.com/crazy-max/ghaction-github-labeler\n- # automerge\n  name: \":bell: automerge\"\n  color: \"8f4fbc\"\n  description: \"\"\n- # bot\n  name: \":robot: bot\"\n  color: \"69cde9\"\n  description: \"\"\n- # bug\n  name: \":bug: bug\"\n  color: \"b60205\"\n  description: \"\"\n- # dependencies\n  name: \":game_die: dependencies\"\n  color: \"0366d6\"\n  description: \"\"\n- # documentation\n  name: \":memo: documentation\"\n  color: \"c5def5\"\n  description: \"\"\n- # duplicate\n  name: \":busts_in_silhouette: duplicate\"\n  color: \"cccccc\"\n  description: \"\"\n- # enhancement\n  name: \":sparkles: enhancement\"\n  color: \"0054ca\"\n  description: \"\"\n- # feature request\n  name: \":bulb: feature request\"\n  color: \"0e8a16\"\n  description: \"\"\n- # feedback\n  name: \":mega: feedback\"\n  color: \"03a9f4\"\n  description: \"\"\n- # future maybe\n  name: \":rocket: future maybe\"\n  color: \"fef2c0\"\n  description: \"\"\n- # good first issue\n  name: \":hatching_chick: good first issue\"\n  color: \"7057ff\"\n  description: \"\"\n- # help wanted\n  name: \":pray: help wanted\"\n  color: \"4caf50\"\n  description: \"\"\n- # invalid\n  name: \":no_entry_sign: invalid\"\n  color: \"e6e6e6\"\n  description: \"\"\n- # investigate\n  name: \":mag: investigate\"\n  color: \"e6625b\"\n  description: \"\"\n- # needs more info\n  name: \":thinking: needs more info\"\n  color: \"795548\"\n  description: \"\"\n- # pinned\n  name: \":pushpin: pinned\"\n  color: \"28008e\"\n  description: \"\"\n- # question\n  name: \":question: question\"\n  color: \"3f51b5\"\n  description: \"\"\n- # sponsor\n  name: \":sparkling_heart: sponsor\"\n  color: \"fedbf0\"\n  description: \"\"\n- # stale\n  name: \":skull: stale\"\n  color: \"237da0\"\n  description: \"\"\n- # upstream\n  name: \":eyes: upstream\"\n  color: \"fbca04\"\n  description: \"\"\n- # wontfix\n  name: \":coffin: wontfix\"\n  color: \"ffffff\"\n  description: \"\"\n"
  },
  {
    "path": ".github/workflows/build.yml",
    "content": "name: build\n\nconcurrency:\n  group: build-${{ github.ref }}\n  cancel-in-progress: true\n\non:\n  push:\n    branches:\n      - 'master'\n    tags:\n      - '*'\n    paths-ignore:\n      - '**.md'\n  pull_request:\n    branches:\n      - 'master'\n    paths-ignore:\n      - '**.md'\n\nenv:\n  DOCKERHUB_SLUG: crazymax/firefox-syncserver\n  GHCR_SLUG: ghcr.io/crazy-max/firefox-syncserver\n\njobs:\n  build:\n    runs-on: ubuntu-latest\n    steps:\n      -\n        name: Checkout\n        uses: actions/checkout@v3\n      -\n        name: Docker meta\n        id: meta\n        uses: docker/metadata-action@v4\n        with:\n          images: |\n            ${{ env.DOCKERHUB_SLUG }}\n            ${{ env.GHCR_SLUG }}\n          tags: |\n            type=match,pattern=(.*)-r,group=1\n            type=ref,event=pr\n            type=edge\n          labels: |\n            org.opencontainers.image.title=Firefox Sync Server\n            org.opencontainers.image.description=Firefox Sync Server\n            org.opencontainers.image.vendor=CrazyMax\n      -\n        name: Set up QEMU\n        uses: docker/setup-qemu-action@v2\n      -\n        name: Set up Docker Buildx\n        uses: docker/setup-buildx-action@v2\n      -\n        name: Login to DockerHub\n        if: github.event_name != 'pull_request'\n        uses: docker/login-action@v2\n        with:\n          username: ${{ secrets.DOCKER_USERNAME }}\n          password: ${{ secrets.DOCKER_PASSWORD }}\n      -\n        name: Login to GHCR\n        if: github.event_name != 'pull_request'\n        uses: docker/login-action@v2\n        with:\n          registry: ghcr.io\n          username: ${{ github.repository_owner }}\n          password: ${{ secrets.GITHUB_TOKEN }}\n      -\n        name: Build\n        uses: docker/bake-action@v3\n        with:\n          files: |\n            ./docker-bake.hcl\n            ${{ steps.meta.outputs.bake-file }}\n          targets: image-all\n          push: ${{ github.event_name != 'pull_request' }}\n      -\n        name: Check manifest\n        if: github.event_name != 'pull_request'\n        run: |\n          docker buildx imagetools inspect ${{ env.DOCKERHUB_SLUG }}:${{ steps.meta.outputs.version }}\n          docker buildx imagetools inspect ${{ env.GHCR_SLUG }}:${{ steps.meta.outputs.version }}\n      -\n        name: Inspect image\n        if: github.event_name != 'pull_request'\n        run: |\n          docker pull ${{ env.DOCKERHUB_SLUG }}:${{ steps.meta.outputs.version }}\n          docker image inspect ${{ env.DOCKERHUB_SLUG }}:${{ steps.meta.outputs.version }}\n          docker pull ${{ env.GHCR_SLUG }}:${{ steps.meta.outputs.version }}\n          docker image inspect ${{ env.GHCR_SLUG }}:${{ steps.meta.outputs.version }}\n"
  },
  {
    "path": ".github/workflows/labels.yml",
    "content": "name: labels\n\non:\n  push:\n    branches:\n      - 'master'\n    paths:\n      - '.github/labels.yml'\n      - '.github/workflows/labels.yml'\n\njobs:\n  labeler:\n    runs-on: ubuntu-latest\n    steps:\n      -\n        name: Checkout\n        uses: actions/checkout@v3\n      -\n        name: Run Labeler\n        uses: crazy-max/ghaction-github-labeler@v4\n"
  },
  {
    "path": ".github/workflows/test.yml",
    "content": "name: test\n\non:\n  push:\n    branches:\n      - 'master'\n    paths-ignore:\n      - '**.md'\n  pull_request:\n    branches:\n      - 'master'\n    paths-ignore:\n      - '**.md'\n\njobs:\n  test:\n    runs-on: ubuntu-latest\n    steps:\n      -\n        name: Checkout\n        uses: actions/checkout@v3\n      -\n        name: Prepare\n        id: prep\n        run: |\n          echo ::set-output name=build_tag::test\n          echo ::set-output name=container_name::firefox-syncserver\n          echo ::set-output name=running_timeout::120\n          echo ::set-output name=running_log_check::Listening at\n      -\n        name: Set up QEMU\n        uses: docker/setup-qemu-action@v2\n      -\n        name: Set up Docker Buildx\n        uses: docker/setup-buildx-action@v2\n      -\n        name: Build\n        uses: docker/bake-action@v3\n        with:\n          targets: image-local\n        env:\n          DEFAULT_TAG: ${{ steps.prep.outputs.build_tag }}\n      -\n        name: Start container\n        run: |\n          docker rm -f ${{ steps.prep.outputs.container_name }} > /dev/null 2>&1 || true\n          docker run -d --name ${{ steps.prep.outputs.container_name }} \\\n            -e \"FF_SYNCSERVER_SECRET=5up3rS3kr1t\" \\\n            ${{ steps.prep.outputs.build_tag }}\n      -\n        name: Test run\n        run: |\n          TIMEOUT=$((SECONDS + ${{ steps.prep.outputs.running_timeout }}))\n          while read LOGLINE; do\n            echo ${LOGLINE}\n            if [[ ${LOGLINE} == *\"${{ steps.prep.outputs.running_log_check }}\"* ]]; then\n              echo \"🎉 Container up!\"\n              break\n            fi\n            if [[ $SECONDS -gt ${TIMEOUT} ]]; then\n              >&2 echo \"❌ Failed to run ${{ steps.prep.outputs.container_name }} container\"\n              docker rm -f ${{ steps.prep.outputs.container_name }} > /dev/null 2>&1 || true\n              exit 1\n            fi\n          done < <(docker logs -f ${{ steps.prep.outputs.container_name }} 2>&1)\n\n          CONTAINER_STATUS=$(docker container inspect --format \"{{.State.Status}}\" ${{ steps.prep.outputs.container_name }})\n          if [[ ${CONTAINER_STATUS} != \"running\" ]]; then\n            >&2 echo \"❌ Container ${{ steps.prep.outputs.container_name }} returned status '$CONTAINER_STATUS'\"\n            docker rm -f ${{ steps.prep.outputs.container_name }} > /dev/null 2>&1 || true\n            exit 1\n          fi\n          docker rm -f ${{ steps.prep.outputs.container_name }} > /dev/null 2>&1 || true\n          echo\n"
  },
  {
    "path": ".gitignore",
    "content": "/.dev\n\n# JetBrains\n/.idea\n/*.iml\n"
  },
  {
    "path": "CHANGELOG.md",
    "content": "# Changelog\n\n## 1.8.0-r15 (2021/03/04)\n\n* Renamed `yasu` (more info https://github.com/crazy-max/yasu#yet-another)\n\n## 1.8.0-r14 (2021/03/02)\n\n* Switch to `gosu`\n\n## 1.8.0-RC13 (2020/12/12)\n\n* Add postgres support (#42)\n\n## 1.8.0-RC12 (2019/12/07)\n\n* Fix timezone\n\n## 1.8.0-RC11 (2019/11/17)\n\n* Allow to set custom `PUID`/`PGID`\n* Allow to use Docker secrets for `FF_SYNCSERVER_SECRET`\n* mozilla-services/syncserver@5932c46\n\n## 1.8.0-RC10 (2019/09/26)\n\n* Switch to GitHub Actions\n* :warning: Stop publishing Docker image on Quay\n* Multi-platform Docker image\n* mozilla-services/syncserver@e9b63a0\n* :warning: Run as non-root user\n* Fix access log issue if not defined\n* Implicit timezone through tzdata package\n\n> :warning: **UPGRADE NOTES**\n> As the Docker container now runs as a non-root user, you have to first stop the container and change permissions to `data` volume:\n> ```\n> docker-compose stop\n> chown -R 1000:1000 data/\n> docker-compose pull\n> docker-compose up -d\n> ```\n\n## 1.8.0-RC9 (2019/08/05)\n\n* Option to enable access log (`FF_SYNCSERVER_ACCESSLOG`)\n* Option to tune log level (`FF_SYNCSERVER_LOGLEVEL`)\n* Issue with healthcheck, remove for now (#10)\n\n## 1.8.0-RC8 (2019/08/04)\n\n* Add healthcheck\n* Alpine Linux 3.10\n\n## 1.8.0-RC7 (2019/06/23)\n\n* mozilla-services/syncserver@ac7b29c\n\n## 1.8.0-RC6 (2019/03/21)\n\n* Option to allow forwarded IPs (PR #7)\n\n## 1.8.0-RC5 (2019/03/20)\n\n* Switch to Alpine 3.9 based image\n\n## 1.8.0-RC4 (2019/02/04)\n\n* Fix build (pypa/pip#6158)\n\n## 1.8.0-RC3 (2019/01/22)\n\n* Add `FF_SYNCSERVER_SQLURI` env var (#5)\n* No need to put `syncserver.ini` in data folder\n\n## 1.8.0-RC2 (2018/07/27)\n\n* Switch to Alpine 3.8 based image\n\n## 1.8.0-RC1 (2018/05/25)\n\n* Firefox Sync Server 1.8.0\n\n## 1.7.0-RC2 (2018/05/25)\n\n* Come back to Firefox Sync Server 1.7.0\n\n## 1.6.0-RC3 (2018/05/25)\n\n* Wrong tag pushed (1.7.0)\n* No need of Supervisor\n\n## 1.7.0-RC1 (2018/02/17)\n\n* Firefox Sync Server 1.7.0\n* No need of Supervisor\n\n## 1.6.0-RC2 (2018/01/10)\n\n* Python image updated\n\n## 1.6.0-RC1 (2017/12/25)\n\n* Initial version based on Firefox Sync Server 1.6.0\n"
  },
  {
    "path": "Dockerfile",
    "content": "ARG SYNCSERVER_VERSION=1.8.0\nARG SHA1_COMMIT=5932c464d70ec9cf0344b1d3e970b3711de6a98e\n\nFROM crazymax/yasu:latest AS yasu\nFROM python:2.7-alpine3.10\n\nARG SYNCSERVER_VERSION\nARG SHA1_COMMIT\nRUN apk --update --no-cache add \\\n    bash \\\n    curl \\\n    libffi \\\n    libressl \\\n    libstdc++ \\\n    mariadb-client \\\n    postgresql-client \\\n    shadow \\\n    tzdata \\\n  && apk --update --no-cache add -t build-dependencies \\\n    build-base \\\n    gcc \\\n    git \\\n    libffi-dev \\\n    libressl-dev \\\n    mariadb-dev \\\n    musl-dev \\\n    postgresql-dev \\\n    python-dev \\\n  && git clone https://github.com/mozilla-services/syncserver app \\\n  && cd app \\\n  && git reset --hard $SHA1_COMMIT \\\n  && pip install --upgrade --no-cache-dir -r requirements.txt \\\n  && pip install --upgrade --no-cache-dir -r dev-requirements.txt \\\n  && pip install psycopg2 pymysql \\\n  && apk del build-dependencies \\\n  && rm -rf /tmp/* /var/cache/apk/* \\\n  && python ./setup.py develop\n\nENV TZ=\"UTC\" \\\n  PUID=\"1000\" \\\n  PGID=\"1000\"\n\nCOPY --from=yasu / /\nCOPY entrypoint.sh /entrypoint.sh\n\nRUN chmod a+x /entrypoint.sh \\\n  && mkdir -p /data /opt/syncserver \\\n  && addgroup -g ${PGID} syncserver \\\n  && adduser -u ${PUID} -G syncserver -h /data -s /bin/sh -D syncserver \\\n  && chown -R syncserver. /data /opt/syncserver\n\nEXPOSE 5000\nVOLUME [ \"/data\" ]\n\nENTRYPOINT [ \"/entrypoint.sh\" ]\nCMD [ \"/usr/local/bin/gunicorn\", \"--paste\", \"/opt/syncserver/syncserver.ini\" ]\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2017-2023 CrazyMax\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "<p align=\"center\"><a href=\"https://github.com/crazy-max/docker-firefox-syncserver\" target=\"_blank\"><img height=\"128\" src=\"https://raw.githubusercontent.com/crazy-max/docker-firefox-syncserver/master/.github/docker-firefox-syncserver.jpg\"></a></p>\n\n<p align=\"center\">\n  <a href=\"https://hub.docker.com/r/crazymax/firefox-syncserver/tags?page=1&ordering=last_updated\"><img src=\"https://img.shields.io/github/v/tag/crazy-max/docker-firefox-syncserver?label=version&style=flat-square\" alt=\"Latest Version\"></a>\n  <a href=\"https://github.com/crazy-max/docker-firefox-syncserver/actions?workflow=build\"><img src=\"https://img.shields.io/github/actions/workflow/status/crazy-max/docker-firefox-syncserver/build.yml?branch=master&label=build&logo=github&style=flat-square\" alt=\"Build Status\"></a>\n  <a href=\"https://hub.docker.com/r/crazymax/firefox-syncserver/\"><img src=\"https://img.shields.io/docker/stars/crazymax/firefox-syncserver.svg?style=flat-square&logo=docker\" alt=\"Docker Stars\"></a>\n  <a href=\"https://hub.docker.com/r/crazymax/firefox-syncserver/\"><img src=\"https://img.shields.io/docker/pulls/crazymax/firefox-syncserver.svg?style=flat-square&logo=docker\" alt=\"Docker Pulls\"></a>\n  <br /><a href=\"https://github.com/sponsors/crazy-max\"><img src=\"https://img.shields.io/badge/sponsor-crazy--max-181717.svg?logo=github&style=flat-square\" alt=\"Become a sponsor\"></a>\n  <a href=\"https://www.paypal.me/crazyws\"><img src=\"https://img.shields.io/badge/donate-paypal-00457c.svg?logo=paypal&style=flat-square\" alt=\"Donate Paypal\"></a>\n</p>\n\n## ⚠️ Abandoned project\n\nThis project is not maintained anymore and is abandoned. Feel free to fork and\nmake your own changes if needed.\n\n## About\n\n[Firefox Sync Server](http://moz-services-docs.readthedocs.io/en/latest/howtos/run-sync-1.5.html)\nDocker image.\n\n> **Note**\n> \n> Want to be notified of new releases? Check out 🔔 [Diun (Docker Image Update Notifier)](https://github.com/crazy-max/diun)\n> project!\n\n___\n\n* [Features](#features)\n* [Build locally](#build-locally)\n* [Image](#image)\n* [Environment variables](#environment-variables)\n* [Volumes](#volumes)\n* [Ports](#ports)\n* [Usage](#usage)\n  * [Docker Compose](#docker-compose)\n  * [Command line](#command-line)\n* [Notes](#notes)\n  * [Use with MySQL database](#use-with-mysql-database)\n  * [Use with PostgreSQL database](#use-with-postgresql-database)\n* [Upgrade](#upgrade)\n* [Contributing](#contributing)\n* [License](#license)\n\n## Features\n\n* Run as non-root user\n* Multi-platform image\n* [Traefik](https://github.com/containous/traefik-library-image) as reverse proxy and creation/renewal of Let's Encrypt certificates (see [this template](examples/traefik))\n\n## Build locally\n\n```shell\ngit clone https://github.com/crazy-max/docker-firefox-syncserver.git\ncd docker-firefox-syncserver\n\n# Build image and output to docker (default)\ndocker buildx bake\n\n# Build multi-platform image\ndocker buildx bake image-all\n```\n\n## Image\n\n| Registry                                                                                         | Image                           |\n|--------------------------------------------------------------------------------------------------|---------------------------------|\n| [Docker Hub](https://hub.docker.com/r/crazymax/firefox-syncserver/)                                            | `crazymax/firefox-syncserver`                 |\n| [GitHub Container Registry](https://github.com/users/crazy-max/packages/container/package/firefox-syncserver)  | `ghcr.io/crazy-max/firefox-syncserver`        |\n\nFollowing platforms for this image are available:\n\n```\n$ docker run --rm mplatform/mquery crazymax/firefox-syncserver:latest\nImage: crazymax/firefox-syncserver:latest\n * Manifest List: Yes\n * Supported platforms:\n   - linux/amd64\n   - linux/arm/v6\n   - linux/arm/v7\n   - linux/arm64\n   - linux/386\n   - linux/ppc64le\n   - linux/s390x\n```\n\n## Environment variables\n\n* `TZ`: The timezone assigned to the container (default `UTC`)\n* `PUID`: Process UID (default `1000`)\n* `PGID`: Process GID (default `1000`)\n* `FF_SYNCSERVER_ACCESSLOG`: Display access log (default `false`)\n* `FF_SYNCSERVER_LOGLEVEL`: Log level output (default `info`)\n* `FF_SYNCSERVER_PUBLIC_URL`: Must be edited to point to the public URL of your server (default `http://localhost:5000`).\n* `FF_SYNCSERVER_SECRET`: This is a secret key used for signing authentication tokens. It should be long and randomly-generated.\n* `FF_SYNCSERVER_ALLOW_NEW_USERS`: Set this to `false` to disable new-user signups on the server. Only request by existing accounts will be honoured (default `true`).\n* `FF_SYNCSERVER_FORCE_WSGI_ENVIRON`: Set this to `true` to work around a mismatch between public_url and the application URL as seen by python, which can happen in certain reverse-proxy hosting setups (default `false`).\n* `FF_SYNCSERVER_SQLURI`: Defines the database in which to store all server data (default `sqlite:///data/syncserver.db`).\n* `FF_SYNCSERVER_FORWARDED_ALLOW_IPS`: Set this to `*` or an IP range if you use an Nginx reverse proxy (optional). \n\n> 💡 `FF_SYNCSERVER_SECRET_FILE` can be used to fill in the value from a file, especially for Docker's secrets feature.\n\n## Volumes\n\n* `/data`: Contains SQLite database if `FF_SYNCSERVER_SQLURI` is untouched\n\n> :warning: Note that the volumes should be owned by the user/group with the specified `PUID` and `PGID`. If you don't give the volume correct permissions, the container may not start.\n\n## Ports\n\n* `5000`: Gunicorn port\n\n## Usage\n\n### Docker Compose\n\nDocker compose is the recommended way to run this image. You can use the following [docker compose template](examples/compose/docker-compose.yml), then run the container:\n\n```bash\ndocker-compose up -d\ndocker-compose logs -f\n```\n\n### Command line\n\nYou can also use the following minimal command:\n\n```bash\n$ docker run -d -p 5000:5000 --name firefox_syncserver \\\n  -e TZ=\"Europe/Paris\" \\\n  -e FF_SYNCSERVER_SECRET=\"5up3rS3kr1t\" \\\n  -v $(pwd)/data:/data \\\n  crazymax/firefox-syncserver:latest\n```\n\n## Notes\n\n### Use with MySQL database\n\nSet `FF_SYNCSERVER_SQLURI=pymysql://user:password@mysql_server_ip/db_name`\n\n### Use with PostgreSQL database\n\nSet `FF_SYNCSERVER_SQLURI=postgresql://user:password@postgresql_server_ip/db_name`\n\n## Upgrade\n\nRecreate the container whenever I push an update:\n\n```bash\ndocker-compose pull\ndocker-compose up -d\n```\n\n## Contributing\n\nWant to contribute? Awesome! The most basic way to show your support is to star the project, or to raise issues. You\ncan also support this project by [**becoming a sponsor on GitHub**](https://github.com/sponsors/crazy-max) or by making\na [Paypal donation](https://www.paypal.me/crazyws) to ensure this journey continues indefinitely!\n\nThanks again for your support, it is much appreciated! :pray:\n\n## License\n\nMIT. See `LICENSE` for more details.\n"
  },
  {
    "path": "docker-bake.hcl",
    "content": "variable \"DEFAULT_TAG\" {\n  default = \"msmtpd:local\"\n}\n\n// Special target: https://github.com/docker/metadata-action#bake-definition\ntarget \"docker-metadata-action\" {\n  tags = [\"${DEFAULT_TAG}\"]\n}\n\n// Default target if none specified\ngroup \"default\" {\n  targets = [\"image-local\"]\n}\n\ntarget \"image\" {\n  inherits = [\"docker-metadata-action\"]\n}\n\ntarget \"image-local\" {\n  inherits = [\"image\"]\n  output = [\"type=docker\"]\n}\n\ntarget \"image-all\" {\n  inherits = [\"image\"]\n  platforms = [\n    \"linux/amd64\",\n    \"linux/arm/v6\",\n    \"linux/arm/v7\",\n    \"linux/arm64\",\n    \"linux/386\",\n    \"linux/ppc64le\",\n    \"linux/s390x\"\n  ]\n}\n"
  },
  {
    "path": "entrypoint.sh",
    "content": "#!/bin/bash\n\nTZ=${TZ:-UTC}\n\nFF_SYNCSERVER_ACCESSLOG=${FF_SYNCSERVER_ACCESSLOG:-false}\nFF_SYNCSERVER_LOGLEVEL=${FF_SYNCSERVER_LOGLEVEL:-info}\nFF_SYNCSERVER_PUBLIC_URL=${FF_SYNCSERVER_PUBLIC_URL:-http://localhost:5000/}\nFF_SYNCSERVER_ALLOW_NEW_USERS=${FF_SYNCSERVER_ALLOW_NEW_USERS:-true}\nFF_SYNCSERVER_FORCE_WSGI_ENVIRON=${FF_SYNCSERVER_FORCE_WSGI_ENVIRON:-false}\nFF_SYNCSERVER_SQLURI=${FF_SYNCSERVER_SQLURI:-sqlite:///data/syncserver.db}\n\n# From https://github.com/docker-library/mariadb/blob/master/docker-entrypoint.sh#L21-L41\n# usage: file_env VAR [DEFAULT]\n#    ie: file_env 'XYZ_DB_PASSWORD' 'example'\n# (will allow for \"$XYZ_DB_PASSWORD_FILE\" to fill in the value of\n#  \"$XYZ_DB_PASSWORD\" from a file, especially for Docker's secrets feature)\nfile_env() {\n  local var=\"$1\"\n  local fileVar=\"${var}_FILE\"\n  local def=\"${2:-}\"\n  if [ \"${!var:-}\" ] && [ \"${!fileVar:-}\" ]; then\n    echo >&2 \"error: both $var and $fileVar are set (but are exclusive)\"\n    exit 1\n  fi\n  local val=\"$def\"\n  if [ \"${!var:-}\" ]; then\n    val=\"${!var}\"\n  elif [ \"${!fileVar:-}\" ]; then\n    val=\"$(< \"${!fileVar}\")\"\n  fi\n  export \"$var\"=\"$val\"\n  unset \"$fileVar\"\n}\n\nif [ -n \"${PGID}\" ] && [ \"${PGID}\" != \"$(id -g syncserver)\" ]; then\n  echo \"Switching to PGID ${PGID}...\"\n  sed -i -e \"s/^syncserver:\\([^:]*\\):[0-9]*/syncserver:\\1:${PGID}/\" /etc/group\n  sed -i -e \"s/^syncserver:\\([^:]*\\):\\([0-9]*\\):[0-9]*/syncserver:\\1:\\2:${PGID}/\" /etc/passwd\nfi\nif [ -n \"${PUID}\" ] && [ \"${PUID}\" != \"$(id -u syncserver)\" ]; then\n  echo \"Switching to PUID ${PUID}...\"\n  sed -i -e \"s/^syncserver:\\([^:]*\\):[0-9]*:\\([0-9]*\\)/syncserver:\\1:${PUID}:\\2/\" /etc/passwd\nfi\n\n# Timezone\necho \"Setting timezone to ${TZ}...\"\nln -snf /usr/share/zoneinfo/${TZ} /etc/localtime\necho ${TZ} > /etc/timezone\n\n# Check secret\necho \"Checking prerequisites...\"\nfile_env 'FF_SYNCSERVER_SECRET'\nif [ -z \"$FF_SYNCSERVER_SECRET\" ] ; then\n  >&2 echo \"ERROR: Either FF_SYNCSERVER_SECRET or FF_SYNCSERVER_SECRET_FILE must be defined\"\n  exit 1\nfi\n\nSYNCSERVER_INI_PATH=\"/opt/syncserver/syncserver.ini\"\n\nGU_ACCESSLOG=\"accesslog = -\"\nif [ \"$FF_SYNCSERVER_ACCESSLOG\" != true ]; then\n  GU_ACCESSLOG=\nfi\n\n# Config\necho \"Generating configuration...\"\ncat > \"$SYNCSERVER_INI_PATH\" <<EOL\n[server:main]\nuse = egg:gunicorn\nhost = 0.0.0.0\nport = 5000\nworkers = 1\ntimeout = 30\nloglevel = ${FF_SYNCSERVER_LOGLEVEL}\n${GU_ACCESSLOG}\n\n[app:main]\nuse = egg:syncserver\n\n[syncserver]\n# This must be edited to point to the public URL of your server,\n# i.e. the URL as seen by Firefox.\npublic_url = ${FF_SYNCSERVER_PUBLIC_URL}\n\n# This defines the database in which to store all server data.\nsqluri = ${FF_SYNCSERVER_SQLURI}\n\n# This is a secret key used for signing authentication tokens.\n# It should be long and randomly-generated.\n# The following command will give a suitable value on *nix systems:\n#\n#    head -c 20 /dev/urandom | sha1sum\n#\n# If not specified then the server will generate a temporary one at startup.\nsecret = ${FF_SYNCSERVER_SECRET}\n\n# Set this to \"false\" to disable new-user signups on the server.\n# Only request by existing accounts will be honoured.\nallow_new_users = ${FF_SYNCSERVER_ALLOW_NEW_USERS}\n\n# Set this to \"true\" to work around a mismatch between public_url and\n# the application URL as seen by python, which can happen in certain reverse-\n# proxy hosting setups.  It will overwrite the WSGI environ dict with the\n# details from public_url.  This could have security implications if e.g.\n# you tell the app that it's on HTTPS but it's really on HTTP, so it should\n# only be used as a last resort and after careful checking of server config.\nforce_wsgi_environ = ${FF_SYNCSERVER_FORCE_WSGI_ENVIRON}\n\n# Uncomment and edit the following to use a local BrowserID verifier\n# rather than posting assertions to the mozilla-hosted verifier.\n# Audiences should be set to your public_url without a trailing slash.\n#[browserid]\n#backend = tokenserver.verifiers.LocalVerifier\n#audiences = https://localhost:5000\n\nEOL\n\nif [ -n \"$FF_SYNCSERVER_FORWARDED_ALLOW_IPS\" ]; then\n  cat >> \"$SYNCSERVER_INI_PATH\" <<EOL\n# If you are running Nginx on a different host than the ff sync server the ff snyc server have to trust the X-Forwarded-* headers sent by Nginx.\nforwarded_allow_ips = ${FF_SYNCSERVER_FORWARDED_ALLOW_IPS}\nEOL\nfi\n\necho \"Fixing perms...\"\nchown -R syncserver:syncserver /data /opt/syncserver\n\nexec yasu syncserver:syncserver \"$@\"\n"
  },
  {
    "path": "examples/compose/docker-compose.yml",
    "content": "version: \"3.2\"\n\nservices:\n  firefox-syncserver:\n    image: crazymax/firefox-syncserver:latest\n    container_name: firefox_syncserver\n    ports:\n      - target: 5000\n        published: 5000\n        protocol: tcp\n    volumes:\n      - \"firefox-syncserver:/data\"\n    env_file:\n      - \"./firefox-syncserver.env\"\n    restart: always\n\nvolumes:\n  firefox-syncserver:\n"
  },
  {
    "path": "examples/compose/firefox-syncserver.env",
    "content": "TZ=Europe/Paris\nPUID=1000\nPGID=1000\nFF_SYNCSERVER_PUBLIC_URL=http://firefox-syncserver.example.com:5000\nFF_SYNCSERVER_SECRET=5up3rS3kr1t\nFF_SYNCSERVER_ALLOW_NEW_USERS=true\nFF_SYNCSERVER_FORCE_WSGI_ENVIRON=false\n"
  },
  {
    "path": "examples/traefik/README.md",
    "content": "## Usage\n\n```bash\ntouch acme.json\nchmod 600 acme.json\ndocker-compose up -d\ndocker-compose logs -f\n```\n"
  },
  {
    "path": "examples/traefik/docker-compose.yml",
    "content": "version: \"3.2\"\n\nservices:\n  traefik:\n    image: traefik:2.3\n    container_name: traefik\n    command:\n      - \"--global.checknewversion=false\"\n      - \"--global.sendanonymoususage=false\"\n      - \"--log=true\"\n      - \"--log.level=INFO\"\n      - \"--entrypoints.http=true\"\n      - \"--entrypoints.http.address=:80\"\n      - \"--entrypoints.http.http.redirections.entrypoint.to=https\"\n      - \"--entrypoints.http.http.redirections.entrypoint.scheme=https\"\n      - \"--entrypoints.https=true\"\n      - \"--entrypoints.https.address=:443\"\n      - \"--certificatesresolvers.letsencrypt\"\n      - \"--certificatesresolvers.letsencrypt.acme.storage=acme.json\"\n      - \"--certificatesresolvers.letsencrypt.acme.email=webmaster@example.com\"\n      - \"--certificatesresolvers.letsencrypt.acme.httpchallenge\"\n      - \"--certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=http\"\n      - \"--providers.docker\"\n      - \"--providers.docker.watch=true\"\n      - \"--providers.docker.exposedbydefault=false\"\n    ports:\n      - target: 80\n        published: 80\n        protocol: tcp\n      - target: 443\n        published: 443\n        protocol: tcp\n    volumes:\n      - \"./acme.json:/acme.json\"\n      - \"/var/run/docker.sock:/var/run/docker.sock\"\n    restart: always\n\n  firefox-syncserver:\n    image: crazymax/firefox-syncserver:latest\n    container_name: firefox_syncserver\n    volumes:\n      - \"firefox-syncserver:/data\"\n    labels:\n      - \"traefik.enable=true\"\n      - \"traefik.http.routers.firefox-syncserver.entrypoints=https\"\n      - \"traefik.http.routers.firefox-syncserver.rule=Host(`firefox-syncserver.example.com`)\"\n      - \"traefik.http.routers.firefox-syncserver.tls=true\"\n      - \"traefik.http.routers.firefox-syncserver.tls.certresolver=letsencrypt\"\n      - \"traefik.http.routers.firefox-syncserver.tls.domains[0].main=firefox-syncserver.example.com\"\n      - \"traefik.http.services.firefox-syncserver.loadbalancer.server.port=5000\"\n    env_file:\n      - \"./firefox-syncserver.env\"\n    restart: always\n\nvolumes:\n  firefox-syncserver:\n"
  },
  {
    "path": "examples/traefik/firefox-syncserver.env",
    "content": "TZ=Europe/Paris\nPUID=1000\nPGID=1000\nFF_SYNCSERVER_PUBLIC_URL=https://firefox-syncserver.example.com\nFF_SYNCSERVER_SECRET=5up3rS3kr1t\nFF_SYNCSERVER_ALLOW_NEW_USERS=true\nFF_SYNCSERVER_FORCE_WSGI_ENVIRON=false\n"
  }
]