Linux team service

Reading time 3 min

This is a systemd template for a fresh, separately reviewed Linux installation. It is not an overlay script for an existing host and does not provision DNS/TLS/firewall. The operator needs Git, npm, supported Node 24+, systemd and approved sudo access. Names and paths are illustrative.

Read-only preflight

command -v node
node --version
npm --version
git --version
systemctl --version
getent passwd fg-editor
getent group fg-editor
ls -ld /srv/field-guide /srv/field-guide/app /srv/field-guide/data

Expected missing identity/paths are findings, not permission to overwrite. Stop if names already belong to unrelated work. Confirm intended source access, install location, read/write model, public reader account and rollback before creating anything. Do not paste credentials into a clone URL.

Path Access
App, source Editor reads and writes authorized content
Private data Service, operator only
Output parent Service creates staging siblings and renames
Reader output Web server reads, traverses intended artifact
Engine, dependencies Selected executable, readable packages
Backup storage Restricted outside public root

Prepare a fresh service identity

Run only after preflight confirms this new installation plan. Inspect each result; do not execute blindly against an existing server.

sudo useradd --system --create-home --home-dir /srv/field-guide \
  --shell /usr/sbin/nologin fg-editor
sudo install -d -o fg-editor -g fg-editor -m 0750 /srv/field-guide/data
sudo -u fg-editor git clone \
  https://github.com/KineticEnforcer/MarkStackV2.git /srv/field-guide/app
cd /srv/field-guide/app
git rev-parse HEAD
git status --short

Select/inspect the approved exact engine revision before installing, not changing branch head blindly. A private repo needs an authorized authenticated install route controlled by the operator. Repository access is separate from editor login accounts.

sudo -u fg-editor npm ci
sudo -u fg-editor npm test
sudo -u fg-editor npm run build
sudo -u fg-editor env MARKSTACK_USERS_FILE=/srv/field-guide/data/users.json \
  npm run editor:create-admin -- --user admin

Stop on a failed step. Create-admin uses the hidden prompt, not a password argument. Keep the selected users path consistent with service. Initial build consumes available safe runtime/default inputs; after runtime branding/links changes, use a new build/publication with correct selection.

Review reader read/traverse permissions separately. The service home/source may be restrictive. Add only intended output access through your OS model; do not grant web server access to data just because an ancestor blocks traversal. A successful service-user build does not prove nginx can read output.

systemd unit template

Save through your approved host-config process as /etc/systemd/system/field-guide-editor.service. Replace executable after checking command -v node as service identity, actual hostname and paths.

[Unit]
Description=Field Guide MarkStack V2 editor
After=network.target

[Service]
Type=simple
User=fg-editor
Group=fg-editor
WorkingDirectory=/srv/field-guide/app
ExecStart=/usr/bin/node /srv/field-guide/app/editor-server.js
Environment=MARKSTACK_EDITOR_HOST=127.0.0.1
Environment=MARKSTACK_EDITOR_PORT=3001
Environment=MARKSTACK_USERS_FILE=/srv/field-guide/data/users.json
Environment=MARKSTACK_EDITOR_ALLOWED_HOSTS=editor.example.com
Environment=MARKSTACK_EDITOR_COOKIE_SECURE=1
Environment=MARKSTACK_TRUSTED_PROXIES=loopback
Restart=on-failure
NoNewPrivileges=true
ProtectSystem=strict
ReadWritePaths=/srv/field-guide
UMask=0027

[Install]
WantedBy=multi-user.target
Directive Meaning, limit
User, Group Dedicated identity; not root
Workdir, ExecStart Exact installation and supported Node
Restart Restart on process failure; not application health proof
NoNewPrivileges Prevent privilege gain; not a network gate
ProtectSystem Read-only filesystem policy with reviewed exceptions
ReadWritePaths Writable namespace exception; does not grant Unix permissions
UMask Creation mask; existing files, ACLs still matter

The write exception is deliberately whole illustrative installation because source saves and publication siblings require it. It is broader than immutable engine isolation. Narrow only after mapping real write requirements and testing save/publish/runtime rotation; do not block required output-parent operations accidentally.

A shell-managed/version-manager Node path might not exist in a non-login service environment. Use an accessible absolute executable and verify its supported version. Do not assume operator node is the same binary systemd runs. After=network.target is ordering, not a guarantee every external endpoint is ready.

Validate before enable

sudo systemd-analyze verify /etc/systemd/system/field-guide-editor.service

Fix errors before reloading/enabling. Syntax verification is not startup, filesystem access, TLS or reader acceptance. Only after review, stage acceptance and intended maintenance window:

sudo systemctl daemon-reload
sudo systemctl enable --now field-guide-editor.service
sudo systemctl status field-guide-editor.service
sudo journalctl -u field-guide-editor.service --since '10 minutes ago'

Logs may contain private operational paths. Inspect locally and sanitize before support sharing. A retrying restart loop needs root-cause diagnosis, not repeated enable commands or world-writable data.

HTTPS and acceptance

Check Required evidence
Listener Intended loopback 3001 only
Proxy Exact allowed Host, trusted peer and safe forwarding
Cookie Secure mode through actual HTTPS
Files Private accounts, history inaccessible to reader
Writes Save plus staged publish, backup rotation on staging
Reader Current static artifact independent of editor
Recovery Service stop, start, return and protected backup tested

Configure the HTTPS proxy before browser sign-in because Secure cookies require HTTPS. The unit does not issue certificates or restrict external proxy access. Readers requiring privacy need a separate gate. Private team editor covers perimeter/account checks.

Restart signs writers out and loses current in-memory job/log/limiter state. It does not stop a separate static host or erase saved accounts. Coordinate running publication before stopping the service. Preserve actual failed/live paths before rollback.

Verification scope and source

The illustrative unit previously passed local systemd-analyze verify; that proves syntax only. Service-user creation, ownership, sandbox access, production startup and availability were not exercised on your host. Re-verify your final adapted unit and staging behavior.

Checked 12 October 2026: systemd execution/user/permissions/sandbox guidance. Engine/account local checks and their limits are in Validation limits.