eratic / deploy / server / docker-compose.yml
343 words
 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
# The edge web server for this box.
#
# One Caddy, owning ports 80 and 443, serving every site on the machine
# straight from disk. No second proxy hop, no per-project container: a static
# file server has no runtime to isolate, so adding one would be complexity
# bought with nothing.
#
#   docker compose -f /opt/web/caddy/docker-compose.yml up -d
#   docker compose -f /opt/web/caddy/docker-compose.yml logs -f

services:
  caddy:
    image: caddy:2-alpine
    container_name: web-caddy
    restart: unless-stopped

    ports:
      - '80:80'
      - '443:443'
      - '443:443/udp' # HTTP/3

    volumes:
      # All sites, read-only. Each project deploys into a subdirectory and
      # points its conf.d file at /srv/<project>/current/<site>.
      #
      # The parent directory is mounted rather than each release, because
      # `current` is a RELATIVE symlink into releases/ — mounting the whole
      # tree is what lets a deploy flip that symlink and have it take effect
      # immediately, with no restart.
      - /opt/web/sites:/srv:ro

      # The config DIRECTORY, never an individual file.
      #
      # Docker pins a single-file bind mount to that file's inode. rsync (and
      # most editors) write a temporary file and rename it over the original,
      # which creates a NEW inode — so the container keeps serving the old
      # contents forever while the host file plainly shows the new ones. That
      # failure is completely silent: the reload succeeds, reports no error,
      # and applies nothing. Mounting the directory makes replacements visible.
      - /opt/web/caddy/etc:/etc/caddy:ro

      # Certificates and ACME account keys. Losing this volume means
      # re-issuing every certificate, so it is the one thing here worth
      # backing up.
      - caddy-data:/data
      - caddy-config:/config

    security_opt:
      - no-new-privileges:true

    # No healthcheck on purpose. Any meaningful probe has to name a hostname,
    # which would tie this server-wide file to one particular site, and a probe
    # that does not would report "unhealthy" on a box whose sites are all
    # simply fine. `restart: unless-stopped` covers a crash; deploy.sh verifies
    # the sites over real HTTPS afterwards, which is the check that matters.

    logging:
      driver: json-file
      options:
        max-size: '10m'
        max-file: '3'

volumes:
  caddy-data:
  caddy-config:

static mirror of HEAD · about · clone: git clone https://git.makefuture.ro/eratic.git