Bebe MomentBebe Moment

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_dump or 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 .env is both gitignored and dockerignored, so it is not baked into the image. These values must be passed as runtime env (compose environment:).
  • /api/health does 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 to PUBLIC_URL, serving /media/... same-origin). Setting :3001 makes the browser unable to reach it and images break.

See Troubleshooting for more cases.