Repository navigation
Expand file tree
/
Copy pathdocker-compose.yml
More file actions
123 lines (118 loc) · 3.97 KB
/
Copy pathdocker-compose.yml
File metadata and controls
123 lines (118 loc) · 3.97 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
122
123
# Production stack for meshcore-mqtt-broker.
#
# Usage:
# 1. cp .env.example .env && edit values (SUBSCRIBER_*, AUTH_EXPECTED_AUDIENCE, TUNNEL_TOKEN, ...)
# 2. docker compose -f docker-compose.prod.yml up -d
# 3. In the Cloudflare Zero Trust dashboard, point the tunnel's public hostname
# at the service URL http://broker:8883 (Docker DNS resolves the service name
# on the internal network shared with cloudflared).
services:
broker:
# Replace <owner> with your GHCR namespace, or comment this line and uncomment `build:` for local builds.
image: ghcr.io/dutch-meshcore/collector:latest
# build:
# context: .
# dockerfile: Dockerfile
container_name: meshcore-mqtt-broker
restart: unless-stopped
labels:
autoheal: "true"
autoheal.stop.timeout: "30"
init: true # PID 1 reaper; clean SIGTERM forwarding to node.
env_file: .env # SUBSCRIBER_*, AUTH_*, ABUSE_*, MQTT_*
environment:
ABUSE_PERSISTENCE_PATH: /data/abuse-detection.db # forced — must point at the writable volume
volumes:
- broker_data:/data # SQLite DB + WAL/SHM siblings live here
networks: [internal]
read_only: true # rootfs is immutable
tmpfs:
- /tmp:size=16M,mode=1777 # safety net for any lib that touches os.tmpdir()
cap_drop: [ALL] # port 8883 > 1024, no caps needed
security_opt:
- no-new-privileges:true
ulimits:
nofile:
soft: 4096
hard: 8192
deploy:
resources:
limits:
memory: 256M
cpus: "1.0"
reservations:
memory: 64M
logging:
driver: json-file
options:
max-size: "10m"
max-file: "3"
healthcheck:
test: ["CMD", "/nodejs/bin/node", "-e", "require('net').createConnection(Number(process.env.MQTT_WS_PORT)||8883,'127.0.0.1').on('connect',function(){this.end();process.exit(0)}).on('error',function(){process.exit(1)})"]
interval: 30s
timeout: 5s
retries: 3
start_period: 20s
ports:
- "8883:8883" # Optional: expose MQTT port directly (not needed if using cloudflared tunnel)
autoheal:
# Pinned to the multi-platform digest published for willfarrell/autoheal:latest on 2026-07-28.
image: willfarrell/autoheal:latest@sha256:e513881f029803a9214bed90e88a16fbe945dd4c0876bbdf037f29d12b55f8e5
container_name: meshcore-autoheal
restart: unless-stopped
environment:
AUTOHEAL_CONTAINER_LABEL: autoheal
AUTOHEAL_INTERVAL: "5"
AUTOHEAL_DEFAULT_STOP_TIMEOUT: "30"
volumes:
- /var/run/docker.sock:/var/run/docker.sock
network_mode: none
read_only: true
cap_drop: [ALL]
security_opt:
- no-new-privileges:true
logging:
driver: json-file
options:
max-size: "10m"
max-file: "3"
cloudflared:
# Pin to a specific release in production. See https://github.com/cloudflare/cloudflared/releases
image: cloudflare/cloudflared:latest
container_name: meshcore-cloudflared
restart: unless-stopped
command: tunnel --no-autoupdate run
environment:
TUNNEL_TOKEN: ${TUNNEL_TOKEN:?TUNNEL_TOKEN must be set in .env}
TUNNEL_METRICS: 0.0.0.0:60123
healthcheck:
test: ["CMD", "cloudflared", "tunnel", "ready"]
interval: 30s
timeout: 5s
retries: 3
start_period: 20s
networks: [internal]
depends_on:
broker:
condition: service_healthy
read_only: true
tmpfs:
- /tmp:size=16M,mode=1777
cap_drop: [ALL]
security_opt:
- no-new-privileges:true
deploy:
resources:
limits:
memory: 128M
cpus: "0.5"
logging:
driver: json-file
options:
max-size: "10m"
max-file: "3"
networks:
internal:
driver: bridge
volumes:
broker_data: