Skip to content

Podman ​

These steps run the container image with Podman and podman compose. CI runs the Compose examples, and the backup and restore commands exactly as shown here, against every image with Podman.

Before you start ​

On macOS and Windows, Podman runs containers in a virtual machine. Create and start it once:

sh
podman machine init
podman machine start

On Linux, podman compose talks to the Podman API socket, so start it for your user:

sh
systemctl --user start podman.socket

podman compose runs an external Compose provider: docker-compose if it is installed, otherwise podman-compose. CI tests these steps with docker-compose. To choose another provider, set PODMAN_COMPOSE_PROVIDER or compose_providers in containers.conf; set PODMAN_COMPOSE_WARNING_LOGS=false to hide the notice it prints for each command. See podman compose.

If DOCKER_HOST is set, podman compose passes it to the provider, which then uses that engine instead of Podman. Unset it before running these steps.

Rootless Podman gives a new named volume the image's ownership of /var/lib/drfed, just like Docker, so the Compose files need no Podman-specific volume options.

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
podman compose run --rm drfed drfed-account create \
  --email alice@example.com --name "Alice"
podman 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
podman compose logs -f drfed

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

podman 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
podman compose stop drfed
podman compose run --rm drfed drfed-account create \
  --email bob@example.com --name "Bob"
podman 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
podman compose up -d
podman 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
podman compose run --rm drfed drfed-migrate --check
podman 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
podman 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 podman compose up -d after an image change. podman 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=$(podman compose ps --status running --quiet drfed)
finish() {
  if [ -n "$running" ]; then
    podman compose up -d drfed
  fi
  rm -f drfed-data.tgz.partial
}
trap finish EXIT
trap 'exit 1' HUP INT TERM
podman compose stop drfed
podman 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
podman compose run --rm -T drfed \
  tar xzf - -C /var/lib/drfed < drfed-data.tgz
podman 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
podman compose pull drfed
podman compose up -d drfed

With PostgreSQL, check the result with podman 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.