Files
Warp/Docker-AIO/Dockerfile.PocketBase.SeaweedFS.split
T
tajniak81andClaude Opus 5.5 36d83551aa Docker-AIO: PocketBase images with SeaweedFS for media
Dockerfile.PocketBase.SeaweedFS bakes SeaweedFS into the PocketBase
all-in-one image as one `weed server -s3` process;
Dockerfile.PocketBase.SeaweedFS.split runs master, volume, filer, S3
gateway and the admin UI as separate processes, with the homeserver's
S3 identity seeded into the filer's IAM store on every boot. Media goes
to the bucket, the database stays in /data/pb_data, and both layouts
share /seaweed/data, so switching between them needs no migration.

The entrypoint now tracks every process in one list and stops them in
reverse start order, and it refuses to start an open S3 gateway or
admin UI. Each image gets a build and a prod compose file, and
.env.example and the README cover the new settings. Modelled on
DriverVault's Docker-AIO SeaweedFS images.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-22 20:33:21 +02:00

160 lines
6.7 KiB
Docker

# warp-aio-pocketbase-seaweedfs-split — the homeserver, the admin panel and
# the web client on PocketBase, with SeaweedFS in the same image as the
# media store, split into its roles: master, volume, filer, S3 gateway and
# admin UI, one process each. Over Dockerfile.PocketBase.SeaweedFS that buys
# per-role restart, per-role metrics ports and the admin UI, where S3
# identities are minted and revoked under Object Store → Users.
#
# The homeserver's identity lives in the filer's IAM store, seeded on every
# boot, the same store the admin UI writes; so a key added there never
# displaces the homeserver's. /seaweed/data has the layout `weed server -dir`
# writes, so it moves between the two SeaweedFS images unchanged.
#
# Build from the repository root:
#
# docker build -t warp-aio-pocketbase-seaweedfs-split -f Docker-AIO/Dockerfile.PocketBase.SeaweedFS.split .
# docker run -p 8008:8008 -p 8009:8009 -p 8080:8080 \
# -p 127.0.0.1:8333:8333 -p 127.0.0.1:23646:23646 \
# -v warp-data:/data -v seaweed-data:/seaweed/data -v seaweed-admin:/seaweed/admin \
# -e WARP_SERVER_NAME=warp.example \
# -e WARP_PB_S3_ACCESS_KEY=warp -e WARP_PB_S3_SECRET=change-me \
# -e WEED_ADMIN_PASSWORD=change-me \
# warp-aio-pocketbase-seaweedfs-split
#
# WARP_PB_S3_ACCESS_KEY, WARP_PB_S3_SECRET and WEED_ADMIN_PASSWORD are
# required; the container refuses to start an open gateway or admin UI.
#
# Ports inside the container (publish 8333 and 23646 on loopback at most;
# master, volume and filer listen on loopback only):
#
# 8008 homeserver 8333 SeaweedFS S3 gateway
# 8009 admin panel 8888 SeaweedFS filer
# 8080 web client 9333 SeaweedFS master
# 8081 SeaweedFS volume 23646 SeaweedFS admin UI
# 9324-9328 SeaweedFS metrics: master, volume, filer, S3, admin
# SeaweedFS release to bake in, pinned so a rebuild later brings up the same
# one; --build-arg SEAWEED_VERSION=... to upgrade. Global, because a FROM uses
# it.
ARG SEAWEED_VERSION="4.45"
FROM node:22-alpine AS web
WORKDIR /src
RUN corepack enable
# Lockfile and manifests first, so the package store survives source changes.
COPY package.json pnpm-workspace.yaml pnpm-lock.yaml ./
COPY apps/ui/package.json ./apps/ui/
COPY apps/admin/package.json ./apps/admin/
COPY apps/web/package.json ./apps/web/
RUN pnpm install --frozen-lockfile --filter @warp/admin... --filter @warp/web...
COPY apps/ui ./apps/ui
COPY apps/admin ./apps/admin
COPY apps/web ./apps/web
RUN pnpm --filter @warp/admin build && pnpm --filter @warp/web build
FROM golang:1.26-alpine AS build
ARG VERSION=0.0.0-dev
ARG COMMIT=unknown
ARG BUILD_DATE=unknown
ENV CGO_ENABLED=0
WORKDIR /src
# The homeserver. Dependencies first, so the module cache survives source
# changes.
COPY server/go.mod server/go.sum ./server/
RUN cd server && go mod download
COPY server ./server
RUN cd server && go build -trimpath \
-ldflags "-s -w \
-X github.com/dariuszjaniak/warp/server/internal/buildinfo.Version=${VERSION} \
-X github.com/dariuszjaniak/warp/server/internal/buildinfo.Commit=${COMMIT} \
-X github.com/dariuszjaniak/warp/server/internal/buildinfo.BuildDate=${BUILD_DATE}" \
-o /out/warp ./cmd/warp
# The admin panel and the web client, each with its frontend embedded.
COPY apps/admin/go.mod ./apps/admin/
COPY apps/admin/cmd ./apps/admin/cmd
COPY apps/admin/internal ./apps/admin/internal
COPY --from=web /src/apps/admin/internal/panel/build/dist ./apps/admin/internal/panel/build/dist
RUN cd apps/admin && GOWORK=off go build -trimpath -ldflags "-s -w -X main.version=${VERSION}" \
-o /out/warp-admin ./cmd/warp-admin
COPY apps/web/go.mod ./apps/web/
COPY apps/web/cmd ./apps/web/cmd
COPY apps/web/host ./apps/web/host
COPY apps/web/client/client.go ./apps/web/client/
COPY --from=web /src/apps/web/client/build/dist ./apps/web/client/build/dist
RUN cd apps/web && GOWORK=off go build -trimpath -ldflags "-s -w -X main.version=${VERSION}" \
-o /out/warp-web ./cmd/warp-web
# The one static weed binary from the official image.
FROM chrislusf/seaweedfs:${SEAWEED_VERSION} AS seaweed
FROM alpine:3.21
# tini is PID 1 so signals reach the entrypoint and zombies are reaped.
RUN apk add --no-cache ca-certificates tzdata curl tini && \
adduser -D -u 10001 -h /data warp
COPY --from=build /out/warp /out/warp-admin /out/warp-web /usr/local/bin/
COPY --from=seaweed /usr/bin/weed /usr/local/bin/weed
COPY warp.yaml.example /etc/warp/warp.yaml.example
COPY --chmod=755 Docker-AIO/entrypoint.sh /usr/local/bin/warp-aio
# /data: the database, signing key and anything stored before S3 was on.
# /seaweed/data: master, volume and filer, sharing it.
# /seaweed/admin: the admin UI's session key and maintenance state.
# Mount a volume on each; a fresh named volume inherits the ownership.
RUN mkdir -p /data /seaweed/data /seaweed/admin && chown -R warp:warp /data /seaweed
WORKDIR /data
USER warp
# Media goes to the bucket on the gateway inside this image: a fixed
# loopback address, path style because a self-hosted gateway has no
# per-bucket DNS, and a region SeaweedFS ignores. Media stored on the
# filesystem before S3 was on is not moved into the bucket.
ENV WARP_LISTEN_ADDRESS=":8008" \
WARP_PRIVATE_KEY="/data/signing.key" \
WARP_DB_DRIVER="pocketbase" \
WARP_DB_CONNECTION_STRING="/data/pb_data" \
WARP_PB_S3_ENABLED="true" \
WARP_PB_S3_ENDPOINT="http://127.0.0.1:8333" \
WARP_PB_S3_BUCKET="warp" \
WARP_PB_S3_REGION="us-east-1" \
WARP_PB_S3_FORCE_PATH_STYLE="true" \
WARP_LOG_FORMAT="json" \
WARP_ADMIN_LISTEN=":8009" \
WARP_ADMIN_HOMESERVER="http://127.0.0.1:8008" \
WARP_ADMIN_LOG_FORMAT="json" \
WARP_WEB_LISTEN=":8080" \
WARP_WEB_HOMESERVER="http://127.0.0.1:8008" \
WARP_WEB_LOG_FORMAT="json" \
WARP_AIO_ADMIN="true" \
WARP_AIO_WEB="true" \
WARP_AIO_EMBEDDED_POSTGRES="false" \
WARP_AIO_SEAWEEDFS="split" \
WEED_ADMIN_USER="admin"
EXPOSE 8008 8009 8080 8333 23646
# Every process must answer, so a wedged one shows in `docker ps`.
HEALTHCHECK --interval=30s --timeout=10s --start-period=60s --retries=3 \
CMD curl -fsS -o /dev/null http://127.0.0.1:9333/cluster/status && \
curl -fsS -o /dev/null http://127.0.0.1:8081/healthz && \
curl -fsS -o /dev/null http://127.0.0.1:8888/healthz && \
curl -fsS -o /dev/null http://127.0.0.1:8333/healthz && \
curl -fsS -o /dev/null http://127.0.0.1:23646/health && \
curl -fsS -o /dev/null http://127.0.0.1:8008/healthz && \
{ [ "$WARP_AIO_ADMIN" != true ] || curl -fsS -o /dev/null http://127.0.0.1:8009/healthz; } && \
{ [ "$WARP_AIO_WEB" != true ] || curl -fsS -o /dev/null http://127.0.0.1:8080/healthz; } || exit 1
ENTRYPOINT ["/sbin/tini", "--", "warp-aio"]