GET STARTED / DOCKER

Deploy with Docker.

Run the published image with SQLite or PostgreSQL, on a plain Docker host or on any deploy platform that takes a compose file and puts its own proxy in front.

01

The image

RevFox is published to GitHub's container registry for linux/amd64 and linux/arm64. One container runs the whole server, with the panel built in.

ghcr.io/revfox-dev/revfox
TagWhat it is
latestThe newest release.
0.3The newest patch release of 0.3.
0.3.1Exactly that release. Never changes.
edgeThe newest unreleased commit. For testing, not production.
sha-<commit>One unreleased commit, by its short hash.

The container listens on two ports:

PortServesWho calls it
8080The panel and its /api/... endpointsYou and your team, in a browser
8081/sdk-events, /v1/... and /app-store-server-notifications/...Your apps, your backend, and the App Store

Both answer GET /api/health with 204. The image's built-in health check uses it, and so can your platform.

02

Run with SQLite

The simplest setup: one container, with the database file in a volume at /app/data. Use this docker-compose.yml, also in the repository.

services:
  revfox:
    image: ghcr.io/revfox-dev/revfox:${REVFOX_IMAGE_TAG:-latest}
    restart: unless-stopped
    environment:
      REVFOX_API_URL: ${REVFOX_API_URL:-}
      REVFOX_ADMIN_PASSWORD: ${REVFOX_ADMIN_PASSWORD:-}
    expose:
      - "8080"
      - "8081"
    volumes:
      - revfox-data:/app/data

volumes:
  revfox-data:

On a deploy platform, create a compose-based service and paste the file in. The platform starts it and keeps the volume across deploys.

Leave the ${...} values as they are

They are variables, not text to replace. ${REVFOX_API_URL:-} takes REVFOX_API_URL from the environment, or stays empty when it is not set. Most platforms list these variables in the service's environment settings, where you fill them in. See Configure.

On a plain Docker host

Without a platform in front, publish the ports yourself by replacing expose with:

    ports:
      - "8080:8080"
      - "8081:8081"
docker compose up -d

Put a reverse proxy with TLS in front of both ports before exposing them to the internet, as in the Nginx example.

Bind mounts

The server runs as user 10001. A named volume works as is. If you mount a host folder at /app/data instead, give that user ownership first: sudo chown -R 10001:10001 /path/to/folder.

03

Run with PostgreSQL

For a database you can back up, inspect and move separately, run PostgreSQL next to RevFox. Use docker-compose.postgres.yml:

services:
  revfox:
    image: ghcr.io/revfox-dev/revfox:${REVFOX_IMAGE_TAG:-latest}
    restart: unless-stopped
    depends_on:
      postgres:
        condition: service_healthy
    environment:
      REVFOX_API_URL: ${REVFOX_API_URL:-}
      REVFOX_ADMIN_PASSWORD: ${REVFOX_ADMIN_PASSWORD:-}
      REVFOX_DATABASE_TYPE: postgres
      REVFOX_DATABASE_HOST: postgres
      REVFOX_DATABASE_NAME: revfox
      REVFOX_DATABASE_USER: revfox
      REVFOX_DATABASE_PASSWORD: ${POSTGRES_PASSWORD:?set POSTGRES_PASSWORD}
    expose:
      - "8080"
      - "8081"

  postgres:
    image: postgres:16-alpine
    restart: unless-stopped
    environment:
      POSTGRES_DB: revfox
      POSTGRES_USER: revfox
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?set POSTGRES_PASSWORD}
    volumes:
      - postgres-data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U revfox -d revfox"]
      interval: 5s
      timeout: 5s
      retries: 10

volumes:
  postgres-data:

Set POSTGRES_PASSWORD to a long random value; the file refuses to start without it. The database is only reachable from inside the compose network.

An existing database

To use a PostgreSQL server you already run, drop the postgres service and give RevFox a connection URL instead:

services:
  revfox:
    image: ghcr.io/revfox-dev/revfox:${REVFOX_IMAGE_TAG:-latest}
    restart: unless-stopped
    environment:
      REVFOX_API_URL: ${REVFOX_API_URL:-}
      REVFOX_ADMIN_PASSWORD: ${REVFOX_ADMIN_PASSWORD:-}
      REVFOX_DATABASE_TYPE: postgres
      REVFOX_DATABASE_URL: ${REVFOX_DATABASE_URL:?set REVFOX_DATABASE_URL}
    expose:
      - "8080"
      - "8081"

Give RevFox its own database and user rather than sharing the default postgres database. As a superuser on that server:

CREATE USER revfox WITH PASSWORD 'long-random-password';
CREATE DATABASE revfox OWNER revfox;

RevFox creates its tables in the empty database on its first start.

A database on another server

For a managed database or one on another machine, use its public host and require TLS:

REVFOX_DATABASE_URL=postgres://revfox:[email protected]:5432/revfox?sslmode=require

A database on the same server

A database your platform already runs on the same server is reachable by its container name, over a Docker network the two containers share. Two things to set:

  1. The host. Use the database's container name, not localhost. Platforms show it in the database's internal connection URL, such as postgres://postgres:…@k4d9x2:5432/postgres; the host is k4d9x2.
  2. The network. A compose stack gets its own network, so it cannot see other containers by default. Turn on your platform's setting that connects the stack to its shared or predefined network.
REVFOX_DATABASE_URL=postgres://revfox:long-random-password@k4d9x2:5432/revfox?sslmode=disable

sslmode=disable is fine here: the traffic stays on the server's internal Docker network. Use require if the database has TLS turned on.

On a plain Docker host, attach RevFox to the database's network yourself. docker inspect <container> lists the networks a container is on:

services:
  revfox:
    # ...as above
    networks:
      - default
      - database

networks:
  database:
    external: true
    name: the-database-network
"no such host" on startup

RevFox cannot resolve the database's container name, so the two containers are not on a shared network. Check the network step above.

04

Add the domains

Give each port its own domain. In your platform's domain settings for the revfox service, route:

DomainContainer port
https://app.example.com8080
https://api.example.com8081

Some platforms take both in one field, with the container port after the domain: https://app.example.com:8080,https://api.example.com:8081. The port there picks the container port; visitors still use 443.

Then set REVFOX_API_URL to the API domain and redeploy. The panel shows this URL wherever you copy an API address, such as the App Store server notification URL.

REVFOX_API_URL=https://api.example.com

The proxy needs no extra configuration. RevFox reads the standard Host, X-Forwarded-Proto, X-Forwarded-Host and X-Forwarded-For headers that platform proxies send by default, to mark the session cookie secure, check where panel requests come from, and record client IPs.

Lock down the panel, not the API

Your apps, your backend and Apple must reach the API domain from anywhere. The panel domain is only for your team, so you can put an IP allowlist or an access proxy in front of it.

05

Configure

The compose files read their settings from variables written as ${...}. Leave the file as it is and set the values outside it:

  • On a deploy platform, in the service's environment settings. Most platforms read the compose file and list its variables there for you.
  • On a plain Docker host, in a .env file next to the compose file. docker compose reads it by itself.
REVFOX_IMAGE_TAG=0.3.1
REVFOX_API_URL=https://api.example.com
REVFOX_ADMIN_PASSWORD=a-long-random-password

Each variable is written in one of three ways:

In the fileWhen the variable is not set
${REVFOX_API_URL:-}Empty. RevFox then uses its own default.
${REVFOX_IMAGE_TAG:-latest}The value after :-, here latest.
${POSTGRES_PASSWORD:?set POSTGRES_PASSWORD}Required: the deploy stops with that message.
VariablePurpose
REVFOX_IMAGE_TAGThe image tag to run. Defaults to latest; pin a version such as 0.3.1 in production.
REVFOX_API_URLThe public URL of the API domain. Empty, the panel derives it from the address in your browser.
REVFOX_ADMIN_PASSWORDThe first admin's password, read only when the database is new. Empty, a random one is printed in the log.
POSTGRES_PASSWORDThe PostgreSQL password, in the PostgreSQL setup.
REVFOX_DATABASE_URLThe connection URL, when you use an existing database.
REVFOX_LOG_LEVELdebug, info, warn or error. Defaults to info.

Every other setting, such as the database connection and the Play notification polling, has an environment variable too. See Configuration.

06

First login

A fresh database creates a bootstrap account, [email protected]. Unless you set REVFOX_ADMIN_PASSWORD, its password is random and printed once in the container log. Open your platform's log view, or run:

docker compose logs revfox | grep "first admin account"
Required before launch

Sign in and change the bootstrap password before exposing the panel publicly. If you set REVFOX_ADMIN_PASSWORD, you can remove it after the first start.

07

Upgrade

Change REVFOX_IMAGE_TAG to the new version and redeploy. On a plain Docker host:

docker compose pull
docker compose up -d

RevFox updates its database schema when it starts. Back up first, and read the release notes for anything to do by hand.

08

Back up

Many platforms can back up volumes and databases on a schedule; turn that on for the volume at /app/data or for the PostgreSQL service. To back up by hand:

SQLite

Stop RevFox so the database file is not mid-write, archive the volume, then start it again.

docker compose stop revfox
docker run --rm --volumes-from "$(docker compose ps -aq revfox)" -v "$PWD":/backup alpine \
  tar czf /backup/revfox-data.tgz -C /app/data .
docker compose start revfox

PostgreSQL

docker compose -f docker-compose.postgres.yml exec postgres \
  pg_dump -U revfox revfox > revfox.sql

RevFox is running

Configure your first project.

Dashboard setup