feat(deploy): add self-hosted homelab deploy toolkit
- deploy/deploy.sh: idempotent deploy script with dynamic port
allocation (3011..30200), flock-based concurrency, atomic
.postgrest-port/.nextjs-port writes, port cleanup of the previous
deploy + dev stack, nginx config rendering+reload, healthchecks
with rollback, optional image pruning
- deploy/docker-compose.yml + Dockerfile.nextjs: example stack
consuming ${POSTGREST_HOST_PORT} / ${NEXTJS_HOST_PORT} (kept as
reference; the repo's root docker-compose.yml is the source of
truth for the actual production stack)
- deploy/nginx.conf.template: /api/* -> PostgREST, /* -> Next.js
- deploy/.env.production.example: managed port block + preserved secrets
- deploy/healthcheck.sh: standalone health probe (cron-friendly)
- deploy/Makefile: deploy/status/health/logs/down/rollback targets
- deploy/GITEA_SETUP.md: webhook vs Actions runner instructions
- deploy/README.md + deploy/.gitignore
Note: .gitea/workflows/deploy.yml was deliberately not added — the
existing workflow at that path on Gitea main is the source of truth
and is left untouched.
This commit is contained in:
@@ -0,0 +1,70 @@
|
||||
# =============================================================================
|
||||
# docker-compose.yml — production stack consumed by deploy.sh
|
||||
# =============================================================================
|
||||
#
|
||||
# The host-side ports (POSTGREST_HOST_PORT, NEXTJS_HOST_PORT) are written by
|
||||
# deploy.sh into .env.production. We interpolate from there with ${VAR:-3011}
|
||||
# so a manual `docker compose up` without the deploy script still works.
|
||||
#
|
||||
# Note on networking: the Next.js container calls PostgREST on
|
||||
# `host.docker.internal:POSTGREST_HOST_PORT` so the inlined
|
||||
# NEXT_PUBLIC_API_URL (a localhost URL, per the deploy contract) resolves
|
||||
# correctly. On Linux you may need to add
|
||||
# extra_hosts:
|
||||
# - "host.docker.internal:host-gateway"
|
||||
# which is included below for that reason.
|
||||
# =============================================================================
|
||||
|
||||
name: prod-app # default project name; deploy.sh overrides with -p
|
||||
|
||||
services:
|
||||
postgrest:
|
||||
image: postgrest/postgrest:latest
|
||||
container_name: prod-app-postgrest
|
||||
restart: unless-stopped
|
||||
# The host port is dynamic. The container always listens on 3000.
|
||||
ports:
|
||||
- "${POSTGREST_HOST_PORT:-3011}:3000"
|
||||
environment:
|
||||
PGRST_DB_URI: ${PGRST_DB_URI}
|
||||
PGRST_DB_ANON_ROLE: ${PGRST_DB_ANON_ROLE:-anon}
|
||||
PGRST_DB_SCHEMA: ${PGRST_DB_SCHEMA:-public}
|
||||
PGRST_SERVER_PORT: 3000
|
||||
# Optional: tighten CORS for your real domain
|
||||
PGRST_DB_TXN_END: "commit-allow-overwrite"
|
||||
# Healthcheck lets `docker compose ps` show healthy state.
|
||||
healthcheck:
|
||||
test: ["CMD", "wget", "-qO-", "http://127.0.0.1:3000/"]
|
||||
interval: 10s
|
||||
timeout: 3s
|
||||
retries: 6
|
||||
|
||||
nextjs:
|
||||
# Build context is the workspace root (one level up from this file).
|
||||
build:
|
||||
context: ..
|
||||
dockerfile: deploy/Dockerfile.nextjs
|
||||
container_name: prod-app-nextjs
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "${NEXTJS_HOST_PORT:-3012}:3000"
|
||||
environment:
|
||||
# Runtime vars — these can change without rebuilding. NEXT_PUBLIC_*
|
||||
# is also exported here for completeness, but the BROWSER's view of
|
||||
# NEXT_PUBLIC_API_URL is baked in at build time (see Dockerfile).
|
||||
NODE_ENV: production
|
||||
PORT: 3000
|
||||
NEXT_PUBLIC_API_URL: ${NEXT_PUBLIC_API_URL}
|
||||
env_file:
|
||||
- ../.env.production # server-side secrets read at runtime
|
||||
extra_hosts:
|
||||
# Lets the container reach the host on the dynamically allocated port.
|
||||
- "host.docker.internal:host-gateway"
|
||||
depends_on:
|
||||
postgrest:
|
||||
condition: service_healthy
|
||||
healthcheck:
|
||||
test: ["CMD", "wget", "-qO-", "http://127.0.0.1:3000/api/health"]
|
||||
interval: 10s
|
||||
timeout: 3s
|
||||
retries: 6
|
||||
Reference in New Issue
Block a user