Skip to content

Docker ​

These steps run the container image with Docker Compose. Check that the Compose plugin is installed with docker compose version.

Quick start ​

Save this file as compose.yaml in an empty directory:

yaml
name: drfed

services:
  drfed:
    image: ghcr.io/fedify-dev/drfed:0.2.0
    environment:
      # The origin browsers and other servers reach DrFed at.  Instances are
      # its subdomains, such as http://alice.drfed.localhost:8888.
      DRFED_ROOT_ORIGIN: http://drfed.localhost:8888
      # Print login links to the container log instead of sending mail.
      DRFED_MAIL_LOG_CONTENT: "true"
    ports:
      - "127.0.0.1:8888:8888"
    volumes:
      - drfed-data:/var/lib/drfed
    # Longer than DrFed's own 10-second shutdown deadline.
    stop_grace_period: 20s
    restart: unless-stopped

volumes:
  drfed-data:

Create your account, then start DrFed:

sh
docker compose run --rm drfed drfed-account create \
  --email alice@example.com --name "Alice"
docker compose up -d drfed

Replace the email address and display name with your own. Open http://drfed.localhost:8888 and sign in with your email address. This local example prints the login link to the container log instead of sending mail:

sh
docker compose logs -f drfed

Follow the open http://drfed.localhost:8888/login/… link in the log to finish signing in.

docker compose run --rm drfed drfed-migrate --check runs drfed-migrate instead of the server; see how the image runs commands. run --rm reuses the drfed service definition, so management commands see the same environment, volumes, and database as the server. Keep database settings in that service.

PGlite maintenance ​

Only one process can open a PGlite data directory; see PGlite: one process at a time. Create the first account before starting the server, as in the quick start. For later maintenance, stop the server first:

sh
docker compose stop drfed
docker compose run --rm drfed drfed-account create \
  --email bob@example.com --name "Bob"
docker compose up -d drfed

PostgreSQL ​

For long-running or shared deployments, use PostgreSQL. It lets you create accounts and check migrations while DrFed is running. This example keeps the database in its own named volume:

yaml
name: drfed

services:
  postgres:
    image: postgres:18
    environment:
      POSTGRES_DB: drfed
      POSTGRES_USER: drfed
      # Replace this password here and in DRFED_POSTGRES_URL below.
      POSTGRES_PASSWORD: change-me
    volumes:
      - postgres-data:/var/lib/postgresql
    healthcheck:
      test: ["CMD", "pg_isready", "--username=drfed", "--dbname=drfed"]
      interval: 5s
      timeout: 5s
      retries: 12
    restart: unless-stopped

  drfed:
    image: ghcr.io/fedify-dev/drfed:0.2.0
    depends_on:
      postgres:
        condition: service_healthy
    environment:
      DRFED_ROOT_ORIGIN: https://drfed.example.com
      DRFED_POSTGRES_URL: postgres://drfed:change-me@postgres/drfed
      # Configure a mail transport for login mail, for example:
      # DRFED_SMTP_URL: smtps://user:password@smtp.example.com
    ports:
      - "127.0.0.1:8888:8888"
    # Longer than DrFed's own 10-second shutdown deadline.
    stop_grace_period: 20s
    restart: unless-stopped

volumes:
  postgres-data:

Replace the password in both places and configure a mail transport for login mail; see Configuration. Start both services, then create an account without stopping DrFed:

sh
docker compose up -d
docker compose run --rm drfed drfed-account create \
  --email alice@example.com --name "Alice"

Run a single DrFed server per database; multiple server replicas are not supported.

Migrations ​

The server applies database migrations when it starts. To inspect or apply them without starting the server, run drfed-migrate through the same service:

sh
docker compose run --rm drfed drfed-migrate --check
docker compose run --rm drfed drfed-migrate

--check exits with 0 only when the database matches the image's migrations, and with 1 when it is uninitialized or has pending migrations. With PGlite, stop the server first.

A separate frontend ​

drfed-server serves the frontend by default. To run the frontend in its own container from the same image, layer this file over your compose.yaml as compose.web.yaml:

yaml
services:
  drfed:
    command: ["drfed-server", "--no-web"]
    environment:
      # The frontend's public origin, where login links point.
      DRFED_LOGIN_ORIGINS: '["http://localhost:3000"]'

  web:
    image: ghcr.io/fedify-dev/drfed:0.2.0
    command: ["drfed-web"]
    depends_on:
      - drfed
    environment:
      DRFED_PUBLIC_ORIGIN: http://localhost:3000
      DRFED_BACKEND_URL: http://drfed:8888
      # The backend is plain HTTP on the Compose network, not loopback.
      DRFED_ALLOW_INSECURE_BACKEND: "true"
    ports:
      - "127.0.0.1:3000:3000"
    stop_grace_period: 20s
    restart: unless-stopped
sh
docker compose -f compose.yaml -f compose.web.yaml up -d

The frontend reaches the backend at http://drfed:8888 on the Compose network. Plain HTTP to a backend other than loopback needs DRFED_ALLOW_INSECURE_BACKEND, which is safe only on a trusted internal network. Set DRFED_LOGIN_ORIGINS and DRFED_PUBLIC_ORIGIN to the frontend's public origin.

Backups and upgrades ​

Data in the volume survives container replacement, including docker compose up -d after an image change. docker compose down --volumes deletes the volume and every account and instance in it.

To back up a PGlite volume to drfed-data.tgz, run this script next to your compose.yaml. It stops the server while it copies the volume and starts it again only if it was running. An earlier drfed-data.tgz is replaced only when the new backup is complete:

sh
# Start the server again afterwards only if it is running now, and replace an
# earlier drfed-data.tgz only with a complete backup.
running=$(docker compose ps --status running --quiet drfed)
finish() {
  if [ -n "$running" ]; then
    docker compose up -d drfed
  fi
  rm -f drfed-data.tgz.partial
}
trap finish EXIT
trap 'exit 1' HUP INT TERM
docker compose stop drfed
docker compose run --rm -T drfed \
  tar czf - -C /var/lib/drfed . > drfed-data.tgz.partial
mv drfed-data.tgz.partial drfed-data.tgz

To restore it into a new, empty volume:

sh
docker compose run --rm -T drfed \
  tar xzf - -C /var/lib/drfed < drfed-data.tgz
docker compose up -d drfed

For PostgreSQL, back up and restore the database with pg_dump and pg_restore.

To upgrade, back up your data, change the image tag in compose.yaml, then pull the new image and recreate the container. The server applies new migrations when it starts:

sh
docker compose pull drfed
docker compose up -d drfed

With PostgreSQL, check the result with docker compose run --rm drfed drfed-migrate --check; with PGlite, stop the server first. To go back to an older version, restore the backup you made before upgrading.

Licensed under the GNU AGPL v3 or later.
hackers.pub icon © 2025 Bak Eunji, CC BY-SA 4.0, recolored.