When to use
- You're shipping an open-source product with a "self-host in 5 minutes" story.
- Users should get a working local stack with one command, and
.envshould be safe-by-default.
Steps
- Create
docker-compose.selfhost.ymlwith three services and a healthcheck-gated backend:name: myapp services: postgres: image: pgvector/pgvector:pg17 environment: POSTGRES_DB: ${POSTGRES_DB:-myapp} POSTGRES_USER: ${POSTGRES_USER:-myapp} POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-myapp} volumes: [pgdata:/var/lib/postgresql/data] healthcheck: test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-myapp}"] interval: 5s retries: 5 backend: build: { context: ., dockerfile: Dockerfile } depends_on: { postgres: { condition: service_healthy } } ports: ["${PORT:-8080}:8080"] environment: DATABASE_URL: postgres://${POSTGRES_USER:-myapp}:${POSTGRES_PASSWORD:-myapp}@postgres:5432/${POSTGRES_DB:-myapp} JWT_SECRET: ${JWT_SECRET:-change-me-in-production} APP_ENV: ${APP_ENV:-production} # safe default frontend: build: context: . dockerfile: Dockerfile.web args: REMOTE_API_URL: http://backend:8080 depends_on: [backend] ports: ["${FRONTEND_PORT:-3000}:3000"] volumes: pgdata: - Add a
make selfhosttarget that auto-creates.envand generates a random JWT secret on first run:selfhost: @if [ ! -f .env ]; then \ cp .env.example .env; \ JWT=$$(openssl rand -hex 32); \ sed -i "s/^JWT_SECRET=.*/JWT_SECRET=$$JWT/" .env; \ fi docker compose -f docker-compose.selfhost.yml up -d --build @for i in $$(seq 1 30); do \ curl -sf http://localhost:$${PORT:-8080}/health > /dev/null && break; \ sleep 2; \ done @curl -sf http://localhost:$${PORT:-8080}/health && echo "✓ Stack is running!" .env.examplelists every knob (ports, email provider, OAuth) with safe defaults and comments for secrets.
Example
User journey:
git clone https://github.com/org/app.git
cd app
make selfhost
# ✓ Stack is running!
# Frontend: http://localhost:3000
# Backend: http://localhost:8080
Caveats
JWT_SECRETdefaulting tochange-me-in-productionis intentional: users who skip the.envstep get a loud, searchable string in logs. Auto-generate viaopenssl rand -hex 32to silently make the default safe.- Default
APP_ENV=productionso any "dev master password" feature is off unless explicitly enabled. - The 30-attempt health poll covers slow first-run Docker image pulls.
Source: kjuhwa/skills-hub — distributed by TomeVault.