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:
podman machine init
podman machine startOn Linux, podman compose talks to the Podman API socket, so start it for your user:
systemctl --user start podman.socketpodman 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:
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:
podman compose run --rm drfed drfed-account create \
--email alice@example.com --name "Alice"
podman compose up -d drfedReplace 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:
podman compose logs -f drfedFollow 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:
podman compose stop drfed
podman compose run --rm drfed drfed-account create \
--email bob@example.com --name "Bob"
podman compose up -d drfedPostgreSQL
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:
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:
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:
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:
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-stoppedpodman compose -f compose.yaml -f compose.web.yaml up -dThe 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:
# 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.tgzTo restore it into a new, empty volume:
podman compose run --rm -T drfed \
tar xzf - -C /var/lib/drfed < drfed-data.tgz
podman compose up -d drfedFor 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:
podman compose pull drfed
podman compose up -d drfedWith 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.