Add systemd unit, nginx config and a README

The nginx block is plain http; certbot adds the TLS server block and the
redirect itself. It sets X-Forwarded-Proto, which is load-bearing: the
app compares the browser's Origin against the URL it believes it is
serving, and without that header it thinks it is on http while the
browser says https, decides every save is cross-site and drops the
session.

Upstream's README is kept as README.nullboard.md.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UU1vyTHj3uE9PJYSxRxwkU
This commit is contained in:
Tom Flux
2026-08-14 22:41:11 +01:00
co-authored by Claude Opus 5
parent d94984cd97
commit 00d3cb0e61
3 changed files with 229 additions and 0 deletions
+50
View File
@@ -0,0 +1,50 @@
# ValidBoard — systemd unit
#
# sudo cp deploy/validboard.service /etc/systemd/system/
# sudo systemctl daemon-reload
# sudo systemctl enable --now validboard
# systemctl status validboard
#
# Set the password before the first start, as the same user this runs as:
# bin/validboard-passwd
[Unit]
Description=ValidBoard - kanban boards stored in SQLite
Documentation=https://git.tomflux.xyz/tom/ValidBoard
After=network.target
[Service]
Type=simple
User=susan
Group=www-data
WorkingDirectory=/disks/git-repos/ValidBoard
# The database holds the boards, the password hash and the session secret.
# Point it elsewhere (e.g. /var/lib/validboard/validboard.db) if you'd rather
# keep data off the repo disk — just create the directory and chown it first.
Environment=VALIDBOARD_DB=/disks/git-repos/ValidBoard/data/validboard.db
# nginx terminates TLS, so the session cookie should never go out over plain
# http. Drop this line if you ever run the service without a certificate.
Environment=VALIDBOARD_SECURE_COOKIE=1
Environment=RACK_ENV=production
Environment=APP_ENV=production
ExecStart=/usr/bin/puma --bind tcp://127.0.0.1:8047 --threads 0:8 --environment production config.ru
Restart=on-failure
RestartSec=5s
# Boards are small and the process is a single Ruby app; none of this is
# load-bearing, it just limits the blast radius.
NoNewPrivileges=yes
PrivateTmp=yes
ProtectSystem=full
ProtectHome=read-only
ProtectKernelTunables=yes
ProtectControlGroups=yes
RestrictSUIDSGID=yes
[Install]
WantedBy=multi-user.target