Repository navigation
Expand file tree
/
Copy pathdocker-compose.coolify.yaml
More file actions
70 lines (68 loc) · 2.82 KB
/
Copy pathdocker-compose.coolify.yaml
File metadata and controls
70 lines (68 loc) · 2.82 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
# Deployed by Coolify as this repo's docker_compose_location. Differs from
# docker-compose.yaml only in the network: joins the pre-existing external `coolify`
# network so Traefik and other tenant apps can reach this container by service name
# (`postgresql`) — see README for why this is a separate file rather than the default.
services:
postgresql:
image: postgres:18-alpine
restart: unless-stopped
environment:
POSTGRES_USER: ${POSTGRES_USER:-postgres}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?POSTGRES_PASSWORD must be set}
volumes:
- postgresql-data-v18:/var/lib/postgresql
networks:
- coolify
# Security hardening (OWASP Docker Security Cheat Sheet). Every value here was verified
# against real throwaway containers first — both a fresh init and a restart on existing
# data (the scenario every redeploy of this live instance actually hits) — not guessed:
# - cap_add: postgres's own entrypoint needs these five specifically to chown/chmod the
# data dir and drop from root to the postgres user on startup. cap_drop: ALL alone
# breaks it (`chmod: /var/run/postgresql: Operation not permitted`).
# - read_only + tmpfs: /var/lib/postgresql (the real data) is already a named volume, so
# it stays writable regardless of read_only. Postgres also needs /tmp and
# /var/run/postgresql (its default Unix socket) writable — confirmed by testing, real
# CREATE TABLE/INSERT/SELECT queries succeed against this exact configuration.
cap_drop:
- ALL
cap_add:
- CHOWN
- FOWNER
- DAC_OVERRIDE
- SETUID
- SETGID
security_opt:
- no-new-privileges:true
read_only: true
tmpfs:
- /tmp
- /var/run/postgresql
mem_limit: 1g
cpus: 1.0
pids_limit: 200
logging:
driver: json-file
options:
max-size: "10m"
max-file: "3"
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-postgres}"]
interval: 30s
timeout: 5s
retries: 3
start_period: 10s
volumes:
# Named distinctly from the old postgresql-data volume (16-alpine's data dir, kept as a
# rollback point) rather than reusing that name — Postgres major versions are not
# in-place upgradeable; a fresh volume + pg_dumpall restore is the migration path.
#
# Mount point is /var/lib/postgresql (not .../data) — the official image changed its
# expected convention starting at 18: it now stores data in a major-version-specific
# subdirectory under this path (supporting pg_ctlcluster-style upgrades) and refuses to
# start if anything is mounted at the old /var/lib/postgresql/data path, even an empty
# volume — found this out by deploying it and reading the crash log, not from the
# release notes.
postgresql-data-v18:
networks:
coolify:
external: true