Skip to main content

max / makenotwork

Delete the stale server unit file; the bootstrap script is the real one server/deploy/makenotwork.service described the pre-Sando single-directory layout: /opt/makenotwork paths that no longer exist and no EnvironmentFile, with Restart=always/RestartSec=5, so installing it on a rebuilt node produced a crash loop with no DATABASE_URL. Prod's unit has always come from sando/deploy/bootstrap-node.sh, and nothing in the tree referenced the copy. Folded the half of its content a node still needs into that template: the scan-spool StateDirectory (mirrored in constants::SCAN_SPOOL_DIR, which bootstrap never created), and the LimitNOFILE and MemoryMax ceilings docs/troubleshooting.md states as facts. The systemd sandbox did not go with it. The server writes bare repositories under GIT_REPOS_PATH, so ProtectSystem=strict with the deleted file's ReadWritePaths breaks repository creation; that needs a measured write set and a prod restart, filed as mnw-server ad427fb3. Prod's live values are recorded under the troubleshooting table so neither number reads as true today.
Author: Max Johnson <me@maxj.phd> · 2026-08-23 01:48 UTC
Signed with PGP, not checked
Commit: 16887a2fd2a7647202b681a1c0cc6cd59890b5e3
Parent: 7fb12e0
4 files changed, +31 insertions, -64 deletions
@@ -525,5 +525,12 @@
525 525 `env!("CARGO_PKG_VERSION")` for Sentry release strings. Bump the version in
526 526 `Cargo.toml` before every production deploy.
527 527
528 + The systemd unit is not in this repo. `sando/deploy/bootstrap-node.sh` writes
529 + `/etc/systemd/system/makenotwork.service` when a node is bootstrapped, so that
530 + script is the only description of how the server runs. A second copy here went
531 + stale against the release-symlink layout and was deleted 2026-08-22; installing
532 + it would have pointed a node at a binary path that does not exist and started
533 + the process with no `EnvironmentFile`.
534 +
528 535 `server/deploy/archive/deploy.sh.legacy` is a retained cutover reference, not a
529 536 supported path.
@@ -141,6 +141,7 @@
141 141 cat > "/etc/systemd/system/$SERVICE_NAME" <<EOF
142 142 [Unit]
143 143 Description=Makenotwork
144 + Documentation=https://makenot.work/docs
144 145 After=network.target
145 146
146 147 [Service]
@@ -160,6 +161,16 @@
160 161 # Exit 2 = migration failure (MNW server convention). Don't restart;
161 162 # operator must intervene before the next deploy.
162 163 RestartPreventExitStatus=2
164 + # Scan-spool tempfiles for streaming large uploads through the malware
165 + # pipeline. systemd creates the directory, chowns it to the service user and
166 + # adds it to ReadWritePaths. The path is mirrored in
167 + # \`makenotwork::constants::SCAN_SPOOL_DIR\`, so it is /var/lib/makenotwork
168 + # rather than \$STATE_DIR and the two names are not interchangeable.
169 + StateDirectory=makenotwork/scan-spool
170 + StateDirectoryMode=0700
171 + # The ceilings server/docs/troubleshooting.md documents.
172 + LimitNOFILE=65535
173 + MemoryMax=512M
163 174 StandardOutput=journal
164 175 StandardError=journal
165 176 SyslogIdentifier=$BIN_NAME
@@ -167,6 +178,12 @@
167 178 [Install]
168 179 WantedBy=multi-user.target
169 180 EOF
181 + # Deliberately absent: the systemd sandbox (ProtectSystem, NoNewPrivileges,
182 + # ProtectHome, the Restrict* set). Turning it on needs a measured
183 + # ReadWritePaths, because the server writes bare git repositories under
184 + # GIT_REPOS_PATH (/opt/git by default) as well as STATE_DIR and the scan
185 + # spool. A sandbox that lists only STATE_DIR breaks repository creation.
186 + # GoingsOn mnw-server task ad427fb3.
170 187 systemctl daemon-reload
171 188 systemctl enable "$SERVICE_NAME" >/dev/null 2>&1 || true
172 189
@@ -176,3 +176,10 @@
176 176 | Login rate limit | 2/sec, burst 5 | 429 Too Many Requests |
177 177 | API rate limit | 2/sec, burst 10 | 429 Too Many Requests |
178 178 | SyncKit rate limit | 10/sec, burst 30 | 429 Too Many Requests |
179 +
180 + The two systemd ceilings are what `sando/deploy/bootstrap-node.sh` writes into
181 + the unit. Prod was bootstrapped before they were in the template and reports
182 + `MemoryMax=infinity` and `LimitNOFILE=524288` as of 2026-08-22, so read the
183 + running unit with `systemctl show makenotwork -p MemoryMax -p LimitNOFILE`
184 + before treating either number as the reason for a symptom. GoingsOn mnw-server
185 + task `ad427fb3` closes the gap.
@@ -1,64 +1,0 @@
1 - # Makenotwork systemd service
2 - # Place in /etc/systemd/system/makenotwork.service
3 - #
4 - # Commands:
5 - # sudo systemctl daemon-reload
6 - # sudo systemctl enable makenotwork
7 - # sudo systemctl start makenotwork
8 - # sudo systemctl status makenotwork
9 - # journalctl -u makenotwork -f
10 -
11 - [Unit]
12 - Description=Makenotwork - Fair creator platform
13 - Documentation=https://makenot.work/docs
14 - After=network.target postgresql.service
15 - Requires=postgresql.service
16 -
17 - [Service]
18 - Type=simple
19 - User=makenotwork
20 - Group=makenotwork
21 - WorkingDirectory=/opt/makenotwork
22 - ExecStart=/opt/makenotwork/makenotwork
23 - Restart=always
24 - RestartSec=5
25 - # Exit code 2 = migration failure. Don't restart; the operator must intervene.
26 - RestartPreventExitStatus=2
27 -
28 - # Environment file with secrets
29 - EnvironmentFile=/opt/makenotwork/.env
30 - Environment=HOME=/opt/makenotwork
31 -
32 - # Security hardening
33 - NoNewPrivileges=true
34 - ProtectSystem=strict
35 - ProtectHome=true
36 - PrivateTmp=true
37 - ReadWritePaths=/opt/makenotwork
38 - # Scan-spool tempfiles for streaming large uploads through the malware
39 - # pipeline. systemd creates /var/lib/makenotwork/scan-spool, chowns to
40 - # the service user, and adds it to ReadWritePaths automatically. Path
41 - # is mirrored in `constants::SCAN_SPOOL_DIR`.
42 - StateDirectory=makenotwork/scan-spool
43 - StateDirectoryMode=0700
44 - RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6
45 - RestrictNamespaces=true
46 - RestrictRealtime=true
47 - RestrictSUIDSGID=true
48 - LockPersonality=true
49 - ProtectKernelTunables=true
50 - ProtectKernelModules=true
51 - ProtectControlGroups=true
52 - SystemCallArchitectures=native
53 -
54 - # Resource limits
55 - LimitNOFILE=65535
56 - MemoryMax=512M
57 -
58 - # Logging (goes to journald)
59 - StandardOutput=journal
60 - StandardError=journal
61 - SyslogIdentifier=makenotwork
62 -
63 - [Install]
64 - WantedBy=multi-user.target