Skip to main content

max / makenotwork

6.7 KB · 210 lines History Blame Raw
1 [serve]
2 interval_secs = 300
3 prune_days = 30
4 listen = "0.0.0.0:9100"
5 peer_heartbeat_secs = 60
6 route_check_interval_secs = 300
7 dashboard = false
8 # api_token loaded from POM_API_TOKEN env var
9
10 # The database is at a fixed absolute path, not wherever XDG_DATA_HOME happens
11 # to point. The unit sets XDG_DATA_HOME=/var/lib and an interactive shell does
12 # not, so before this was configured `pom serve` and a hand-run `pom test` on
13 # this host opened two different files and neither said so: the suites ran,
14 # passed, and reported into a database nothing served.
15 [storage]
16 db_path = "/var/lib/pom/pom.db"
17
18 [instance]
19 name = "hetzner"
20
21 [targets.mnw]
22 label = "Makenotwork Production"
23 expected_routes = ["/", "/discover", "/login", "/docs"]
24
25 [[targets.mnw.dns]]
26 name = "makenot.work"
27 record_type = "A"
28 expected = []
29
30 [[targets.mnw.dns]]
31 name = "forums.makenot.work"
32 record_type = "A"
33 expected = []
34
35 [[targets.mnw.dns]]
36 name = "git.makenot.work"
37 record_type = "A"
38 expected = []
39
40 [[targets.mnw.cors]]
41 url = "https://fsn1.your-objectstorage.com/makenotwork-files/cors-probe"
42 origin = "https://makenot.work"
43 method = "PUT"
44
45 [targets.mnw.whois]
46 domain = "makenot.work"
47 warn_days = 30
48
49 [targets.mnw.health]
50 url = "https://makenot.work/api/health"
51 timeout_secs = 10
52
53 [targets.mnw.health.expect]
54 status_code = 200
55 json_fields = { "status" = "operational", "checks.database" = "true" }
56
57 [targets.mnw.health.trending]
58 baseline_window_hours = 168
59 spike_threshold = 2.0
60
61 [targets.mnw.tls]
62 host = "makenot.work"
63
64 [targets.mnw.tests]
65 # Present in prod's live /etc/pom/pom.toml and previously missing here, which
66 # made this file unsafe to deploy: installing it would have silently dropped the
67 # remote CI check from prod. Keep the two in step.
68 ssh = "max@100.106.221.39"
69 command = "/home/max/staging/run-ci.sh"
70 timeout_secs = 600
71 staleness_days = 7
72
73 [targets.mnw.backups]
74 # Where the backups actually are, verified on prod 2026-07-29: the nightly job
75 # writes /var/lib/mnw/backups/makenotwork/makenotwork-<date>.sql.gz. This said
76 # /opt/makenotwork/backups, a path that does not exist on that host, so the
77 # check reported the target degraded for a directory it could not find while the
78 # real backups went unwatched. The app lives at /opt/mnw/current, not
79 # /opt/makenotwork; the old path looks like a pre-rename leftover.
80 #
81 # pom matches files by the "<database>-" or "<database>_" prefix inside this
82 # directory, so the directory is the per-database one, not its parent.
83 directory = "/var/lib/mnw/backups/makenotwork"
84 databases = ["makenotwork"]
85 max_age_hours = 25
86 interval_secs = 3600
87
88 [targets.mnw.scan_pipeline]
89 # Polls /admin/uploads/health.json for queue depth, stuck-scan count,
90 # held backlog, and per-layer error rates. Thresholds per
91 # scan-pipeline-audit.md ยง 6. Localhost on the makenotwork port to
92 # skip the Caddy + Cloudflare path (internal-only signal).
93 base_url = "http://127.0.0.1:3000"
94 interval_secs = 300
95 timeout_secs = 10
96
97 [targets.mnw.synckit_fleet]
98 # Which SyncKit SDK versions are actually syncing. SyncKit is client-side
99 # only, so there is no deployed version to poll; the server aggregates the
100 # version off each sync request's User-Agent and this reads that. Authed
101 # with alerts.alerts_ingest_token, so the check does not spawn without one.
102 # Informational: an old version in the field never degrades the target, only
103 # a readout PoM cannot take does. Localhost for the same reason as above.
104 base_url = "http://127.0.0.1:3000"
105 window_days = 30
106 interval_secs = 3600
107 timeout_secs = 10
108
109 [targets.mnw-cli]
110 label = "MNW CLI SSH Server"
111
112 [[targets.mnw-cli.dns]]
113 name = "cli.makenot.work"
114 record_type = "A"
115 expected = []
116
117 [targets.mnw-cli.ssh_banner]
118 host = "127.0.0.1"
119 port = 22
120 timeout_secs = 5
121
122 [targets.mt]
123 label = "Multithreaded Forum"
124 expected_routes = ["/"]
125
126 [targets.mt.health]
127 url = "http://127.0.0.1:3400/api/health"
128 timeout_secs = 5
129
130 [targets.mt.health.expect]
131 status_code = 200
132 # `tls_trust_anchors` is whether the host CA bundle gave mt any outbound TLS
133 # anchors. mt ships none of its own, so a thin or stale bundle takes out the
134 # OAuth token exchange that logs users in, while the box still boots, serves
135 # pages, and answers 200 here. mt deliberately does not degrade `status` for it
136 # (a bad bundle is a whole-fleet condition, and failing the load-balancer check
137 # would turn a login outage into a total one), so this assertion is the only
138 # thing that makes the condition visible before a user finds it.
139 json_fields = { "status" = "operational", "database" = "true", "tls_trust_anchors" = "true" }
140
141 [targets.mt.tls]
142 host = "forums.makenot.work"
143
144 [targets.mt.tests]
145 ssh = "max@100.106.221.39"
146 command = "cd /home/max/staging/multithreaded && cargo test --workspace 2>&1"
147 timeout_secs = 300
148 staleness_days = 7
149
150 [targets.htpy]
151 label = "htpy.app"
152
153 [[targets.htpy.dns]]
154 name = "htpy.app"
155 record_type = "A"
156 expected = []
157
158 [targets.htpy.whois]
159 domain = "htpy.app"
160 warn_days = 30
161
162 [targets.htpy.health]
163 # htpy-web moved twice and this URL followed neither move: it listens on 3200,
164 # not 8080, and /archive/<name> now 308s to /viewer/<name>. Checking the old
165 # address failed on connect, so the target has been reading "unreachable" with an
166 # open incident since 2026-03-29 while htpy.app itself served fine. Verified
167 # 2026-07-29: this returns 200 with "htpy" in the body from fw13, astra and
168 # hetzner, and 3200 is in the tailnet ACL's inter-server port list.
169 url = "http://100.99.153.68:3200/viewer/S_2"
170 timeout_secs = 10
171
172 [targets.htpy.health.expect]
173 status_code = 200
174 body_contains = "htpy"
175
176 [targets.htpy.tls]
177 host = "htpy.app"
178
179 [peers.astra]
180 address = "100.106.221.39:9100"
181 on_missing = "alert"
182 # token = "<astra's POM_API_TOKEN value>"
183
184 [peers.macbook]
185 address = "100.100.246.136:9100"
186 on_missing = "log"
187 # token = "<macbook's POM_API_TOKEN value>"
188
189 [alerts]
190 # postmark_token loaded from POM_POSTMARK_TOKEN env var
191 to = "pom-alerts@makenot.work"
192
193 # MNW operator-log sink: also pushes alerts to POST {mnw_url}/api/internal/alerts.
194 # The token loads from POM_ALERTS_INGEST_TOKEN and must match ALERTS_INGEST_TOKEN
195 # in /etc/mnw/makenotwork.env; both mnw_url and the token must be present, else
196 # the sink stays disabled.
197 #
198 # Not the public URL. Caddy answers 404 to /api/internal/* by design (see the
199 # @internal matcher in the Caddyfile), so the sink has to address the app port
200 # directly. Measured 2026-08-15: POST https://makenot.work/api/internal/alerts
201 # is 404, POST http://127.0.0.1:3000/api/internal/alerts is 401 without a token.
202 mnw_url = "http://127.0.0.1:3000"
203
204 # WAM ticket sink: failure alerts become tickets instead of email. WAM listens on
205 # this host, and its token loads from POM_WAM_TOKEN, which must match the WAM
206 # node's token. Leave wam_url unset until the deployed WAM actually requires
207 # auth: the binary at /opt/wam/wam is an April build that predates the
208 # require_auth middleware, so it accepts unauthenticated writes.
209 # wam_url = "http://127.0.0.1:7890"
210