Podman Deployment¶
Bifolk supports deployment with Podman using Quadlets — systemd unit files that let systemd manage Podman containers natively. This is the recommended production deployment method when using Podman.
Target Audience: System administrators deploying Bifolk with Podman on Linux
Prerequisites¶
- Podman 4.4 or higher
- systemd (standard on most Linux distributions)
- Git for cloning the repository
- At least 1 GB of disk space
Enable Lingering¶
Rootless Podman services run inside your user session. To keep them running after you log out, enable lingering for your user:
Quadlet Files¶
Quadlets are located in docker/quadlets/ in the repository:
| Variant | Directory | Database |
|---|---|---|
| SQLite | docker/quadlets/sqlite/ |
SQLite (simpler, single-file) |
| PostgreSQL | docker/quadlets/postgres/ |
PostgreSQL (recommended for production) |
Installation¶
1. Clone the Repository¶
2. Create Podman Secrets¶
Secrets are stored in Podman's secret store and mounted as read-only files into the container. The entrypoint reads them via the *_FILE environment variables.
SQLite variant (2 secrets):
# Generate and store the Django secret key
python3 -c "import secrets; print(secrets.token_urlsafe(50))" > /tmp/secret_key.txt
podman secret create bifolk_secret_key /tmp/secret_key.txt
rm /tmp/secret_key.txt
# Store the email password (leave empty if email is not configured)
echo "" > /tmp/email_password.txt
podman secret create bifolk_email_password /tmp/email_password.txt
rm /tmp/email_password.txt
PostgreSQL variant (3 secrets):
# Generate and store the Django secret key
python3 -c "import secrets; print(secrets.token_urlsafe(50))" > /tmp/secret_key.txt
podman secret create bifolk_secret_key /tmp/secret_key.txt
rm /tmp/secret_key.txt
# Generate and store the database password
python3 -c "import secrets; print(secrets.token_urlsafe(32))" > /tmp/db_password.txt
podman secret create bifolk_db_password /tmp/db_password.txt
rm /tmp/db_password.txt
# Store the email password (leave empty if email is not configured)
echo "" > /tmp/email_password.txt
podman secret create bifolk_email_password /tmp/email_password.txt
rm /tmp/email_password.txt
3. Create the Environment File¶
Copy the example environment file for your chosen variant:
# SQLite
cp docker/quadlets/sqlite/bifolk.env ~/.config/containers/systemd/bifolk.env
# PostgreSQL
cp docker/quadlets/postgres/bifolk.env ~/.config/containers/systemd/bifolk.env
Edit the file and configure your domain, timezone, and email settings:
Key settings to update:
DJANGO_DEBUG=False
DJANGO_ALLOWED_HOSTS=yourdomain.com,www.yourdomain.com
DJANGO_CSRF_TRUSTED_ORIGINS=https://yourdomain.com
TIME_ZONE=Europe/Berlin
4. Install Quadlet Files¶
Copy the quadlet files for your chosen variant to the systemd quadlet directory:
# SQLite
cp docker/quadlets/sqlite/*.container \
docker/quadlets/sqlite/*.network \
docker/quadlets/sqlite/*.volume \
~/.config/containers/systemd/
# PostgreSQL
cp docker/quadlets/postgres/*.container \
docker/quadlets/postgres/*.network \
docker/quadlets/postgres/*.volume \
~/.config/containers/systemd/
5. Reload systemd and Start Services¶
Verify the quadlets were detected:
Start the services:
# SQLite
systemctl --user start bifolk-app.service bifolk-docs.service
# PostgreSQL (start the database first, then the app)
systemctl --user start bifolk-db.service bifolk-app.service bifolk-docs.service
6. Create the Superuser¶
7. Verify¶
# Check service status
systemctl --user status bifolk-app.service
# Check application health
curl http://localhost:8000/health/
# View recent logs
journalctl --user -u bifolk-app --since "10 minutes ago"
Common Operations¶
View Logs¶
Restart a Service¶
Stop All Services¶
systemctl --user stop bifolk-app.service bifolk-docs.service
# PostgreSQL only
systemctl --user stop bifolk-db.service
Upgrade Bifolk¶
# Pull the latest image
podman pull ghcr.io/mwtechnican/bifolk:latest
# Restart to apply the update
systemctl --user restart bifolk-app.service
Rootful Deployment (System-wide)¶
To run Bifolk as a system-level service (rootful, accessible to all users), copy the quadlets to the system directory and use systemctl without --user:
sudo cp docker/quadlets/sqlite/*.container \
docker/quadlets/sqlite/*.network \
docker/quadlets/sqlite/*.volume \
/etc/containers/systemd/
sudo cp docker/quadlets/sqlite/bifolk.env /etc/containers/systemd/bifolk.env
sudo systemctl daemon-reload
sudo systemctl start bifolk-app.service bifolk-docs.service
Warning
Rootful Podman runs containers as root on the host. Prefer rootless deployment unless your infrastructure specifically requires system-level services.
Troubleshooting¶
Service Fails to Start¶
Check the journal for error details:
Quadlets Not Detected After daemon-reload¶
Verify the files are in the correct directory and have the right extensions:
Check for syntax errors in the quadlet files:
Secret Not Found¶
List available secrets to verify they were created:
Re-create any missing secrets using the commands in Step 2.
Permission Denied on Volume¶
The :Z flag on volume mounts applies SELinux relabeling. If you see permission errors unrelated to SELinux, verify that the container starts as root (UID 0) so the entrypoint can run chown before dropping privileges to the bifolk user.
Next Steps¶
- Reverse Proxy & Security Headers — configure HTTPS in front of Bifolk
- Initial Setup — create the superuser and configure the application
- Configuration — complete environment variable reference