Files
Warp/Docker-AIO
tajniak81andClaude Opus 5.5 a47e15cc1c
CI / Test (ubuntu-latest) (push) Canceled after 0s
CI / Test (windows-latest) (push) Canceled after 0s
CI / Storage tests on PostgreSQL (push) Canceled after 0s
CI / Complement (federation off) (push) Canceled after 0s
CI / golangci-lint (push) Canceled after 0s
CI / Smoke test the binary (push) Canceled after 0s
CI / Admin panel (push) Canceled after 0s
CI / Web client (push) Canceled after 0s
CI / Desktop client (ubuntu-24.04) (push) Canceled after 0s
CI / Desktop client (windows-latest) (push) Canceled after 0s
PocketBase as a standalone database server
The pocketbase driver no longer embeds PocketBase: Warp keeps its data as
PocketBase collections on a server of its own and reaches it only through
the REST API, the way the postgres driver reaches PostgreSQL.
database.connection_string is the server's URL, and Warp signs in as the
superuser in WARP_PB_SUPERUSER_EMAIL / WARP_PB_SUPERUSER_PASSWORD (or a
WARP_PB_SUPERUSER_FILE of the two).

Every SQL table is a superuser-only collection of the same name and
columns, created by warp migrate. Reads go through PocketBase's SQL
endpoint with the SQL drivers' queries, via a read-only database/sql
driver that inlines arguments, moves long ones into warp_params and pages
past 1000 rows. Writes are record operations in batch requests under one
write lock in the Warp process. Media is a protected file field in
warp_media, local or in the S3 bucket Warp writes into PocketBase's
settings. Search matches word prefixes with LIKE. The storage tests run
against an in-process PocketBase and pass as on SQLite.

Docker: the PocketBase stacks get a pocketbase service running
tajniak81/pocketbase-docker-root (WARP_PB_IMAGE), with a pb-data volume
and its admin UI on loopback; the AIO images run that PocketBase binary
as a process beside the homeserver, making up a superuser when none is
set. The .env examples, READMEs, docs and warp.yaml.example follow.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 16:31:08 +01:00
..
2026-10-22 20:22:24 +02:00

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, a process in the container, /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.sqlite.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 four PocketBase images run PocketBase as a process of its own beside the homeserver, the binary taken from tajniak81/pocketbase-docker-root (the PB_IMAGE build argument picks another, PocketBase 0.40 or later). Its pb_data is /data/pb_data, and its admin UI is on :8070, published on loopback. The homeserver signs in as the superuser in WARP_PB_SUPERUSER_EMAIL and WARP_PB_SUPERUSER_PASSWORD, whose password is set again on every start; without them, the first start makes one up and keeps it in /data/pocketbase-superuser.env, where the admin UI's login can be read back. To point an image at a PocketBase elsewhere, set WARP_AIO_POCKETBASE=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.pocketbase.s3.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.pocketbase.seaweedfs.example .env      # set WARP_PB_S3_ACCESS_KEY, WARP_PB_S3_SECRET
docker compose -f docker-compose.pocketbase.seaweedfs.yml up -d --build
  • Dockerfile.PocketBase.SeaweedFS runs weed 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.split runs 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 rotated WARP_PB_S3_SECRET lands 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 compose file has its own settings file, named after it: docker-compose.<name>.yml takes .env.<name>.example, so docker-compose.pocketbase.seaweedfs.split.yml takes .env.pocketbase.seaweedfs.split.example. Each lists only the settings its compose file uses, with their defaults, and names the ones that are required; an empty value means the default. Copy the one you need to .env. .env is not committed. On top of the settings of Docker/, they have:

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 10.2.1.10:5500/admin 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