rescriptum
Deployment
Guide
Deployment
Deployment
The binary is self-contained: copy it somewhere, give it an answers directory, and start it. Everything below is about doing that repeatably.
For Synology DSM 7 — which has no systemd — see its own page.
An environment file
Keep configuration in one root-readable file rather than in a unit or a command line.
Anything on a command line is visible to every user on the machine through ps,
which matters as soon as a token is involved:
# /etc/rescriptum.env (chmod 600, owned by root)
RESCRIPTUM_ANSWERS_DIR=/srv/answers
RESCRIPTUM_LISTEN_ADDR=0.0.0.0:8000
RESCRIPTUM_TIMEOUT_SECS=10
# RESCRIPTUM_ANSWER_TOKEN=…
Under systemd, EnvironmentFile= below reads it and you need nothing else. Elsewhere —
and on DSM 7, which has no systemd — point
RESCRIPTUM_ENV_FILE at the same file and
the binary reads it itself, refusing to start if it cannot.
A systemd unit
# /etc/systemd/system/rescriptum.service
[Unit]
Description=rescriptum — per-machine answer files for unattended installs
After=network-online.target
Wants=network-online.target
[Service]
ExecStart=/usr/local/bin/rescriptum
EnvironmentFile=/etc/rescriptum.env
Restart=on-failure
RestartSec=2
# It needs to read one directory and bind one port. Nothing else.
DynamicUser=yes
ReadOnlyPaths=/srv/answers
NoNewPrivileges=yes
PrivateTmp=yes
PrivateDevices=yes
ProtectSystem=strict
ProtectHome=yes
ProtectKernelTunables=yes
ProtectControlGroups=yes
RestrictAddressFamilies=AF_INET AF_INET6
SystemCallFilter=@system-service
[Install]
WantedBy=multi-user.target
$ sudo systemctl enable --now rescriptum
$ curl -s http://localhost:8000/health
OK
Adjust for what you actually enable:
- SQLite store — the database needs to be writable, so
ReadWritePaths=/srvand dropReadOnlyPaths. - Request capture —
ReadWritePaths=the capture directory. - A port below 1024 — add
AmbientCapabilities=CAP_NET_BIND_SERVICE.
Logs go to stderr, so journalctl -u rescriptum -f is the live view.
In a container
There is nothing to install, so the image is the binary:
FROM scratch
COPY rescriptum /rescriptum
ENV RESCRIPTUM_ANSWERS_DIR=/answers RESCRIPTUM_LISTEN_ADDR=0.0.0.0:8000
EXPOSE 8000
ENTRYPOINT ["/rescriptum"]
Use the build for the right architecture — the musl ones are statically linked, which is what
makes FROM scratch work. Mount the answers directory read-only.
Sizing it
The defaults are already right for both ends of the range this was built for.
| Setting | Default | Change it when |
|---|---|---|
RESCRIPTUM_WORKERS | CPU count | you are sharing a small box and want to cap runtime threads |
RESCRIPTUM_MAX_CONNECTIONS | 2048 | you are seeing 503s during a burst — or want to shed earlier |
RESCRIPTUM_TIMEOUT_SECS | 10 | clients are on a slow link, or you want to cut off slowloris sooner |
MAX_CONNECTIONS is not a throughput limit. Over the cap the server writes a prompt 503
and closes rather than queueing — a client that is told to retry is better off than one
parked in a queue that turns a burst into an out-of-memory.
A 2,000-machine rollout completes in under two seconds at the measured throughput, so sizing is rarely the interesting problem. Troubleshooting usually is.
Replacing a running instance
$ ./deploy.sh admin@nas
$ ./deploy.sh admin@nas /volume1/netboot # a different remote directory
What it does, in order:
- Builds for the target (
TARGET, defaultarmv7-unknown-linux-gnueabihf). - Checks the local answers with
rescriptum checkand refuses to continue if anything fails — shipping a broken answer set is worse than not deploying. - Copies the binary under a temporary name, then renames it into place. Replacing a running binary in place is how a half-copied file gets executed.
- Stops the running instance, starts the new one detached, and confirms it stayed up.
- Confirms
/healthanswers over the network, so a firewall problem is reported as one rather than as a mysterious silence.
| Environment | Default |
|---|---|
TARGET | armv7-unknown-linux-gnueabihf |
ANSWERS | <remote-dir>/answers |
PORT | 8000 |
It replaces what is running; it does not install autostart. On DSM that is a
Task Scheduler entry; with systemd it is systemctl enable.
Upgrading
Answers are data, not state: nothing is migrated, and a new binary reads the same directory. Replace it and restart.
The exception is the SQLite store, which carries a schema version. There is one so far, so there is nothing to migrate; what the version buys is the other direction, an older binary refusing to open a database written by a newer one rather than guessing at it. See the SQLite store.