Plain Linux Docker install
Requirements
- Docker 24+, Docker Compose v2
- An external reverse proxy (nginx, Caddy, Traefik) for TLS termination
Quick start
# 1. Prepare a directory
mkdir -p /opt/stacks/bebe-moment && cd /opt/stacks/bebe-moment
# 2. Download compose + env
curl -fLO https://raw.githubusercontent.com/svrforum/bebe-moment/main/compose/docker-compose.yml
curl -fL https://raw.githubusercontent.com/svrforum/bebe-moment/main/compose/.env.example -o .env
# 3. Edit .env
nano .env
# SECRET_KEY, POSTGRES_PASSWORD, PUBLIC_URL, ADMIN_USER_EMAIL are required
# MEDIA_SERVICE_TOKEN, MEDIA_JWT_SECRET (32+ bytes each) are also required —
# media-service auth/signing keys. Generate: openssl rand -hex 32
# 4. Start
docker compose up -d
# 5. First login
# Open PUBLIC_URL → sign up as the first user → onboarding (family + baby)
# The first user becomes the admin (owner) → /admin is accessible
Generating SECRET_KEY
openssl rand -hex 32
Generate MEDIA_SERVICE_TOKEN and MEDIA_JWT_SECRET the same way, each separately.
First login
Open PUBLIC_URL and you'll see the first-user sign-up screen. After signing up and finishing onboarding (family + baby setup), that first user is the admin (owner). Everyone after joins by invite link only, and the admin area lives at /admin (or Settings → Admin).
Reverse proxy example (Caddy)
bebe.example.com {
reverse_proxy localhost:3000
}
Give the proxy a generous timeout (≥ 600s) and allow WebSocket so large tus uploads and SSE aren't cut off. Set PUBLIC_URL to the public domain (https://…). Switching to https flips the session cookie to the __Secure- prefix, so a one-time re-login may be required.
Upgrading
docker compose pull
docker compose up -d
On startup prisma migrate deploy runs automatically to bring the schema up to date.
Backups
./data— uploaded originals + derivatives (back up regularly)./pg— Postgres data (pg_dumpor a NAS backup tool, etc.)./redis— transient queue (no restore needed)
The built-in app backup (Settings → Admin → Backup, with full/incremental/remote S3) is recommended alongside this.
Troubleshooting
Page returns 500 / log shows MEDIA_SERVICE_TOKEN env required
If media-backed pages (timeline, detail) return 500 and the log shows MEDIA_SERVICE_TOKEN env required, the container is missing MEDIA_SERVICE_TOKEN / MEDIA_JWT_SECRET.
- The root
.envis both gitignored and dockerignored, so it is not baked into the image. These values must be passed as runtime env (composeenvironment:). /api/healthdoes not touch media and stays 200, so a health check won't catch this — verify with a real photo page.
Page loads but photos don't (broken thumbnails)
The signed URL points at a port that isn't exposed (e.g. :3001).
- This deployment exposes only port 3000; the browser reaches the internal media (
:3001) via the/media/*Next rewrite. - Do not set
MEDIA_PUBLIC_BASE_URL/NEXT_PUBLIC_MEDIA_BASE_URL(unset falls back toPUBLIC_URL, serving/media/...same-origin). Setting:3001makes the browser unable to reach it and images break.
See Troubleshooting for more cases.