A podman-compose setup to run AppFlowy with Postgres, Caddy (for SSL), and automated backups to S3.
- Overview
- Requirements
- Repository Structure
- Getting Started
- Automated Database Backups
- Caddy for SSL/TLS
- Advanced Tips
- Updating AppFlowy Source
- Contributing
- License
This repository provides a Podman-based deployment for AppFlowy, a customizable productivity suite. It includes:
- Postgres for database storage.
- AppFlowy (Rust backend + Flutter web) built from source or from an existing Docker/Podman image.
- Caddy for automated HTTPS certificates (via Let’s Encrypt).
- A backup service that dumps the Postgres DB to
.sql
, then uploads it to Amazon S3, and removes older backups automatically.
This setup is ideal for self-hosted scenarios where you want a secure, SSL-enabled AppFlowy instance with a daily backup routine.
- Podman (or Docker) and podman-compose installed.
- Git.
- A domain pointing to the server’s public IP (for Caddy SSL).
- AWS account and an S3 bucket (for backups).
- (Optional) Rust + Flutter if you plan to build AppFlowy from source directly on the host or within Docker/Podman.
appflowy-podman-deployment
├─ appflowy/ # (Submodule or cloned source of AppFlowy)
├─ backup/
│ ├─ Dockerfile # Alpine image with PostgreSQL client & AWS CLI
│ ├─ backup-cron.sh # Cron job setup script
│ └─ backup.sh # Main backup script (pg_dump & S3 upload)
├─ .gitignore # Ignore secrets, build artifacts, etc.
├─ .env.example # Example environment variables
├─ build_appflowy.sh # (Optional) Script to clone/build AppFlowy from source
├─ Caddyfile # Caddy reverse proxy config
├─ podman-compose.yml # Podman Compose file defining all containers
└─ README.md # This readme
git clone https://github.com/your-username/appflowy-podman-deployment.git
cd appflowy-podman-deployment
# (If you're using git submodules instead of a direct clone approach)
git submodule update --init --recursive
If you’re not using submodules, you can remove the
appflowy/
folder and letbuild_appflowy.sh
clone AppFlowy on-the-fly.
- Copy
.env.example
to.env
:cp .env.example .env
- Edit
.env
with real values:- Postgres credentials:
APPFLOWY_DB_USER
,APPFLOWY_DB_PASS
,APPFLOWY_DB_NAME
. - AppFlowy secrets (like
APPFLOWY_BACKEND__SECRET_KEY
). - Caddy domain (
CADDY_DOMAIN
) and email (CADDY_EMAIL
) for Let’s Encrypt. - AWS credentials & bucket info:
AWS_ACCESS_KEY_ID
,AWS_SECRET_ACCESS_KEY
,AWS_DEFAULT_REGION
,S3_BUCKET_NAME
.
- Postgres credentials:
Important: Keep
.env
out of version control since it contains secrets.
If you want to build from source locally (instead of using a prebuilt image or Dockerfile that does it for you):
./build_appflowy.sh
This script (by default) will:
- Clone the AppFlowy repo to
appflowy/
(if not already existing). - Build the Rust backend (
cargo build --release
). - Build the Flutter web client (
flutter build web
).
Adjust the script as needed for your environment.
From the root of this repo:
podman-compose up -d
Containers launched:
- postgres: Stores AppFlowy data.
- appflowy: The AppFlowy backend + web. By default, it’s built from the Dockerfile in
docker/
or simply references the compiled artifacts if you prefer. - caddy: Listens on port 80/443, obtains a TLS cert for
CADDY_DOMAIN
via Let’s Encrypt, and reverse proxies requests toappflowy:8080
. - db_backup: A daily cron job at 2 AM that runs
pg_dump
, uploads to S3, and removes backups older than 7 days.
Check logs:
podman-compose logs -f
- Caddy: watch for successful SSL certificate issuance.
- db_backup: the actual backup job logs appear after the daily cron runs (or you can manually trigger it inside the container).
Once up, visit https://your-domain
(the CADDY_DOMAIN
) to access AppFlowy. You should see a valid TLS certificate and the AppFlowy interface.
- The db_backup container is built from
backup/Dockerfile
(Alpine + Postgres client + AWS CLI). backup-cron.sh
sets a cron job for 2:00 AM daily, callingbackup.sh
.backup.sh
:- Runs
pg_dump
on your Postgres database. - Uploads the dump (
.sql
) tos3://<S3_BUCKET_NAME>/backups/
. - Lists objects under
backups/
, compares timestamps, and deletes anything older than 7 days.
- Runs
For large setups or production, many prefer to handle old file deletion with an S3 Lifecycle Policy (see below).
By default, the script parses aws s3 ls
output, looking for backups older than 7 days, then deletes them. If you want to let S3 handle cleanup automatically:
- Remove the “delete older than 7 days” logic in
backup.sh
. - Set up an S3 Lifecycle Policy to expire objects under
/backups/
after 7 days.
- Download the desired
.sql
file from S3:aws s3 cp s3://your-s3-bucket-name/backups/appflowy_YYYY-MM-DD_HH-MM-SS.sql .
- Use
psql
to restore it into your Postgres DB:psql -U appflowy -d appflowy -h <postgres_host> -f appflowy_YYYY-MM-DD_HH-MM-SS.sql
Caddy automatically manages certificates via Let’s Encrypt. It listens on ports 80 and 443, so ensure:
- Your domain (
CADDY_DOMAIN
) has a valid DNS record pointing to the server. - Ports 80 and 443 are open on your firewall.
The Caddyfile
does a simple reverse_proxy appflowy:8080
. If you need advanced configuration or custom headers, add them in Caddyfile
.
Instead of manually deleting older backups, you can:
- Remove the relevant lines in
backup.sh
that parse and delete older objects. - Create an S3 Lifecycle Configuration to automatically expire objects after N days.
- Edit
backup-cron.sh
to change0 2 * * *
(which is 2 AM daily). - For instance,
0 */6 * * *
would run every 6 hours,30 1 * * *
runs at 1:30 AM daily, etc.
If you’re using Git submodules:
cd appflowy/
git checkout main
git pull origin main
cd ..
git add appflowy
git commit -m "Update AppFlowy submodule to latest"
Then rebuild as needed (e.g., ./build_appflowy.sh
).
If you’re cloning in build_appflowy.sh
with --depth=1
, update that script to fetch the latest main branch.
- Issues/PRs: If you encounter issues or have improvements, feel free to open a PR or issue in this repo.
- AppFlowy Core: For bugs or feature requests in the core AppFlowy code, contribute directly to the official AppFlowy-IO/AppFlowy repo.
- This repository’s scripts/configuration are provided under your preferred open-source license (e.g., MIT).
- AppFlowy itself is licensed under AGPLv3.
- The Docker/Podman images for Postgres and Caddy each have their own licenses.
Use at your own risk. Always keep backups, secure your
.env
secrets, and test thoroughly before production deployment.