Dockerfile.PocketBase.s3 is the PocketBase all-in-one image with S3 turned on: media goes to an existing bucket on WARP_PB_S3_ENDPOINT (AWS, MinIO, or a SeaweedFS elsewhere), and the database stays in /data/pb_data. The compose files require the endpoint and key pair, default the bucket to warp, the region to us-east-1 and path style to true, and add host.docker.internal so the endpoint can be on the Docker host. Modelled on DriverVault's external-S3 compose files. The entrypoint now waits up to 30 seconds for an external S3 endpoint to answer and stops if it doesn't, instead of starting a homeserver that would fail on its first upload. WARP_PB_S3_FORCE_PATH_STYLE is left empty in .env.example so the S3 file's default applies. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Docker-AIO: everything in one image
The homeserver, the admin panel and the web client in one image, one image
per database. entrypoint.sh starts them in one
container; if one exits, the rest are stopped and the container's restart
policy brings the set back.
| Dockerfile | Image | Database |
|---|---|---|
Dockerfile |
warp-aio |
SQLite, /data/warp.db |
Dockerfile.PocketBase |
warp-aio-pocketbase |
PocketBase (embedded driver), /data/pb_data |
Dockerfile.PostgreSQL |
warp-aio-postgresql |
PostgreSQL 17 in the container, /data/postgres |
Dockerfile.PocketBase.s3 |
warp-aio-pocketbase-s3 |
PocketBase, media in an existing S3 bucket elsewhere |
Dockerfile.PocketBase.SeaweedFS |
warp-aio-pocketbase-seaweedfs |
PocketBase, media in SeaweedFS (weed server -s3) in the container |
Dockerfile.PocketBase.SeaweedFS.split |
warp-aio-pocketbase-seaweedfs-split |
PocketBase, media in SeaweedFS split into its roles, with its admin UI |
| Compose file | Image |
|---|---|
docker-compose.sqlite.yml |
warp-aio, built here |
docker-compose.pocketbase.yml |
warp-aio-pocketbase, built here |
docker-compose.postgresql.yml |
warp-aio-postgresql, built here |
docker-compose.pocketbase.s3.yml |
warp-aio-pocketbase-s3, built here |
docker-compose.pocketbase.seaweedfs.yml |
warp-aio-pocketbase-seaweedfs, built here |
docker-compose.pocketbase.seaweedfs.split.yml |
warp-aio-pocketbase-seaweedfs-split, built here |
docker-compose.*.prod.yml |
the same images, pulled, never built |
Everything lives in the warp-data volume, mounted on /data; the
SeaweedFS images add seaweed-data on /seaweed/data (and the split one
seaweed-admin on /seaweed/admin).
cd Docker-AIO
cp .env.example .env # then edit it
docker compose -f docker-compose.sqlite.yml up -d --build
docker compose -f docker-compose.sqlite.yml exec warp warp create-account --username admin --admin
Homeserver on :8008, admin panel on :8009, web client on :8080.
The PostgreSQL in warp-aio-postgresql listens only on a Unix socket
inside the container, so it needs no password and is not reachable from
outside. To point that image at a PostgreSQL elsewhere instead, set
WARP_AIO_EMBEDDED_POSTGRES=false and WARP_DB_CONNECTION_STRING.
The Dockerfiles share their build stages line for line; only the header, the SeaweedFS stage and the final stage differ. Keep the build stages in step when changing one.
S3 elsewhere
Dockerfile.PocketBase.s3 keeps the PocketBase database in
/data/pb_data and puts media in a bucket on an S3 endpoint that already
exists: AWS, MinIO, or a SeaweedFS on another host. Nothing in the
container runs a gateway or creates the bucket.
cp .env.example .env # set WARP_PB_S3_ENDPOINT, WARP_PB_S3_ACCESS_KEY,
# WARP_PB_S3_SECRET (and WARP_PB_S3_BUCKET)
docker compose -f docker-compose.pocketbase.s3.yml up -d --build
Path-style addressing is on by default, which SeaweedFS and MinIO need;
set WARP_PB_S3_FORCE_PATH_STYLE=false for AWS S3. For a gateway on the
Docker host, use http://host.docker.internal:8333: the compose files add
that host entry. The container waits up to 30 seconds for the endpoint to
answer and stops if it does not, rather than starting a homeserver that
would fail on its first upload.
SeaweedFS
The two SeaweedFS images keep the PocketBase database in /data/pb_data
and put media in an S3 bucket (WARP_PB_S3_BUCKET, default warp) on a
SeaweedFS inside the same container. The compose files point the
homeserver at it; .env only has to give it credentials:
cp .env.example .env # set WARP_PB_S3_ACCESS_KEY, WARP_PB_S3_SECRET
# (and SEAWEED_ADMIN_PASSWORD for split)
docker compose -f docker-compose.pocketbase.seaweedfs.yml up -d --build
Dockerfile.PocketBase.SeaweedFSrunsweed server -s3: master, volume, filer and S3 gateway in one process. The gateway has exactly one identity, the homeserver's key pair.Dockerfile.PocketBase.SeaweedFS.splitruns each role as its own process, plus SeaweedFS's admin UI on port 23646, where further S3 identities are created and revoked under Object Store → Users. The homeserver's identity is written into the filer's IAM store on every boot (the store the admin UI writes too), so a key added there never displaces it, and a rotatedWARP_PB_S3_SECRETlands on the next start.
Both refuse to start without the key pair, and the split one without
SEAWEED_ADMIN_PASSWORD: either would otherwise serve an open gateway or
an open panel that can mint credentials. The S3 gateway and the admin UI
are published on 127.0.0.1 only; the volume server, which serves content
by id with no authentication, is never published. Inside, it is on 8081,
since 8080 is the web client.
Both write /seaweed/data in the layout weed server -dir uses, and their
compose files share a project and volumes, so switching between them
needs no migration.
Media already stored on the filesystem is not moved into the bucket when
S3 is turned on, so start these on a fresh warp-data or copy the files
across first. The SeaweedFS release is pinned in the Dockerfiles
(SEAWEED_VERSION, 4.45); upgrading it means a rebuild.
Settings
Every setting is in .env, copied from .env.example,
which lists them all with their defaults; an empty value means the
default. .env is not committed. On top of the settings of
Docker/, it has:
| Variable | Default | |
|---|---|---|
WARP_AIO_ADMIN |
true |
false runs no admin panel |
WARP_AIO_WEB |
true |
false runs no web client |
The database driver and connection string come from the image.
Prod files
The .prod.yml files pull $WARP_REGISTRY/<image>:$WARP_VERSION
(defaults ghcr.io/dariuszjaniak and latest). Push the images first,
from the repository root:
docker build -t $WARP_REGISTRY/warp-aio:$WARP_VERSION -f Docker-AIO/Dockerfile .
docker build -t $WARP_REGISTRY/warp-aio-pocketbase:$WARP_VERSION -f Docker-AIO/Dockerfile.PocketBase .
docker build -t $WARP_REGISTRY/warp-aio-postgresql:$WARP_VERSION -f Docker-AIO/Dockerfile.PostgreSQL .
docker build -t $WARP_REGISTRY/warp-aio-pocketbase-s3:$WARP_VERSION -f Docker-AIO/Dockerfile.PocketBase.s3 .
docker build -t $WARP_REGISTRY/warp-aio-pocketbase-seaweedfs:$WARP_VERSION -f Docker-AIO/Dockerfile.PocketBase.SeaweedFS .
docker build -t $WARP_REGISTRY/warp-aio-pocketbase-seaweedfs-split:$WARP_VERSION -f Docker-AIO/Dockerfile.PocketBase.SeaweedFS.split .
for i in warp-aio warp-aio-pocketbase warp-aio-postgresql warp-aio-pocketbase-s3 \
warp-aio-pocketbase-seaweedfs warp-aio-pocketbase-seaweedfs-split; do
docker push $WARP_REGISTRY/$i:$WARP_VERSION
done