-
Notifications
You must be signed in to change notification settings - Fork 22
Expand file tree
/
Copy pathdocker-compose.yml
More file actions
121 lines (117 loc) · 5.27 KB
/
Copy pathdocker-compose.yml
File metadata and controls
121 lines (117 loc) · 5.27 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
# Pad — local production setup with PostgreSQL + Redis
# Usage:
# 1. cp .env.example .env # generates a POSTGRES_PASSWORD if missing
# 2. docker compose up -d
#
# Starts Pad with PostgreSQL for storage and Redis for real-time events,
# notifications, and the shared session-presence registry.
# The web UI binds to 127.0.0.1:7777 on the host by default — LAN/internet
# access requires explicit opt-in (see PAD_BIND_ADDR below or the prod override).
# First-time setup: visit the UI or run `pad auth setup` from a local CLI.
services:
pad:
build:
context: .
dockerfile: Dockerfile
ports:
# Bind to loopback only by default. A fresh install exposes the bootstrap
# endpoint until the first admin is created, so defaulting to 0.0.0.0
# would hand control of the instance to anyone who can route to the host.
# Override by setting PAD_BIND_ADDR=0.0.0.0 (or a specific LAN IP) in .env.
- "${PAD_BIND_ADDR:-127.0.0.1}:7777:7777"
environment:
# Container UID/GID for the pad process. Default to 1000/1000 for
# backward compat with existing compose deploys whose volumes were
# created under the previous USER pad (uid 1000) image. Override to
# match your host volume's ownership if different.
#
# ${VAR-default} (no colon), not ${VAR:-default}. Compose follows
# shell-like semantics — colon form would silently convert PUID=
# or PGID= in .env to 1000, masking operator typos. Colon-less lets
# explicit-empty values reach the entrypoint, which rejects them
# with a clear error (matches docker-entrypoint.sh's own
# ${VAR-99} convention).
PUID: "${PUID-1000}"
PGID: "${PGID-1000}"
PAD_HOST: "0.0.0.0"
PAD_PORT: "7777"
PAD_DB_DRIVER: "postgres"
# POSTGRES_PASSWORD is REQUIRED — docker compose refuses to start when unset.
# Use libpq's keyword=value DSN (not the URI form) so passwords with
# reserved URI characters like '/', '+', ':', '@' — common in
# `openssl rand -base64` output — don't need percent-encoding and
# can't break the connection string by accident.
PAD_DATABASE_URL: "host=postgres port=5432 user=pad password=${POSTGRES_PASSWORD:?POSTGRES_PASSWORD is required — see .env.example} dbname=pad sslmode=disable"
# PAD_ENCRYPTION_KEY is REQUIRED on Postgres — Pad won't auto-generate
# one because a multi-replica deploy would generate a different key
# per replica and fail cross-instance decryption. Generate with
# `openssl rand -hex 32` and keep it stable across restarts.
PAD_ENCRYPTION_KEY: "${PAD_ENCRYPTION_KEY:?PAD_ENCRYPTION_KEY is required — see .env.example}"
PAD_REDIS_URL: "redis://redis:6379"
PAD_DATA_DIR: "/data"
PAD_LOG_LEVEL: "info"
# Cloud-mode wiring — safe to keep enabled on self-host deploys
# because every var defaults to empty and pad treats empty as
# "not in cloud mode". Populate from .env when co-deploying with
# pad-cloud so the reverse sidecar can cascade Stripe cancels on
# account delete (TASK-690).
PAD_CLOUD: "${PAD_CLOUD:-}"
PAD_CLOUD_SECRET: "${PAD_CLOUD_SECRET:-}"
PAD_CLOUD_SIDECAR_URL: "${PAD_CLOUD_SIDECAR_URL:-}"
PAD_CLOUD_OUTBOUND_SECRET: "${PAD_CLOUD_OUTBOUND_SECRET:-}"
volumes:
- pad-data:/data
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_healthy
restart: unless-stopped
healthcheck:
# Conditional: root → su-exec to pad; non-root → direct wget.
# Mirrors the Dockerfile HEALTHCHECK so `docker run --user 1234`
# pass-through still reports healthy.
#
# NOTE: $$(id -u), not $(id -u) — Compose performs $-interpolation
# on YAML strings BEFORE the value reaches the container. Single
# `$` would be parsed as a Compose variable reference; `$$` escapes
# to a literal `$` so the shell inside the container sees `$(id -u)`.
test: ["CMD-SHELL", "if [ \"$$(id -u)\" = \"0\" ]; then exec su-exec pad wget -q --spider http://localhost:7777/api/v1/health; fi; exec wget -q --spider http://localhost:7777/api/v1/health"]
interval: 10s
timeout: 5s
retries: 3
# Bumped 10s → 60s. The always-chown-R policy in the entrypoint
# means a user restoring a backup with a large attachment store
# can spend tens of seconds before pad starts listening — 10s
# would mark the container unhealthy mid-startup.
start_period: 60s
postgres:
image: postgres:17-alpine
environment:
POSTGRES_USER: pad
# Required. Fail-fast with the helpful error below when unset.
POSTGRES_PASSWORD: "${POSTGRES_PASSWORD:?POSTGRES_PASSWORD is required — see .env.example}"
POSTGRES_DB: pad
volumes:
- pg-data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U pad"]
interval: 5s
timeout: 3s
retries: 5
restart: unless-stopped
redis:
image: redis:7-alpine
command: redis-server --maxmemory 64mb --maxmemory-policy allkeys-lru
volumes:
- redis-data:/data
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 5s
timeout: 3s
retries: 5
restart: unless-stopped
volumes:
pad-data:
pg-data:
redis-data: