Skip to content

IT Installation Linux

IT-Master Heizmann edited this page Sep 18, 2026 · 1 revision

Installation unter Linux

Caution

Diese Seite richtet sich ausschliesslich an Informatikerinnen und Informatiker. Nicht für Laien geeignet: Die Befehle laufen mit Root-Rechten; Fehler bei Benutzern, Rechten oder systemd-Units können den Server gefährden oder Daten unzugänglich machen. Ohne Fachkenntnisse bitte Installation Schritt für Schritt verwenden.

Für wen ist diese Seite? Für Informatikerinnen und Informatiker, die SmallTime 2027 auf einem Linux-Server (Debian/Ubuntu, RHEL-Familie) als systemd-Dienst betreiben. Beispiele für Debian/Ubuntu.

Inhalt

  1. Node.js installieren
  2. Dienstbenutzer und Verzeichnisse
  3. Paket installieren
  4. Berechtigungen
  5. systemd-Unit
  6. Logs
  7. Firewall und Reverse-Proxy
  8. Update

Node.js installieren

Benötigt: Node.js >= 26.9.0 < 27, npm >= 11.19.1 < 12.

Variante A – NodeSource (systemweit, empfohlen für Dienste):

sudo apt-get update && sudo apt-get install -y ca-certificates curl
curl -fsSL https://deb.nodesource.com/setup_26.x -o /tmp/nodesource_setup.sh
sudo bash /tmp/nodesource_setup.sh
sudo apt-get install -y nodejs
node -v   # v26.x, mindestens v26.9.0
npm -v

Paket auf Major 26 festhalten, damit ein apt upgrade nicht auf 27 springt (NodeSource-Repositories sind pro Major getrennt; trotzdem prüfen).

Variante B – nvm (Benutzerinstallation):

sudo -iu smalltime
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.3/install.sh | bash
source ~/.nvm/nvm.sh
nvm install 26.9.0
which node   # z. B. /home/smalltime/.nvm/versions/node/v26.9.0/bin/node

Mit nvm in der systemd-Unit den absoluten Pfad zu node verwenden. Eine Home-Installation verträgt sich nicht mit ProtectHome=true.

Variante C – offizielles Tarball von https://nodejs.org/dist/v26.9.0/ nach /opt/node-v26.9.0 entpacken und /usr/local/bin/node verlinken.

Build-Werkzeuge für die nativen Module sqlite3 und bcrypt, falls keine vorgebauten Binärdateien verfügbar sind:

sudo apt-get install -y build-essential python3

Dienstbenutzer und Verzeichnisse

sudo useradd --system --home-dir /opt/smalltime --shell /usr/sbin/nologin smalltime
sudo mkdir -p /opt/smalltime
Pfad Inhalt Besitzer Modus
/opt/smalltime Programm (app.cjs, dist/, public/, node_modules/, package*.json) root:smalltime 750 / Dateien 640
/opt/smalltime/.env Secrets root:smalltime 640
/opt/smalltime/config backend.json, security.json (wird geschrieben) smalltime:smalltime 750
/opt/smalltime/data SQLite, Backups, Dokumente, custom.css smalltime:smalltime 700
/opt/smalltime/uploads Uploads smalltime:smalltime 700
/opt/smalltime/convert nur für den Import aus SmallTime PHP smalltime:smalltime 700

Die Daten können auch unter /var/lib/smalltime liegen und per Symlink (data -> /var/lib/smalltime/data) eingebunden werden. Die App löst die Pfade relativ zum Paketordner auf; konfigurierbar sind sie nicht.


Paket installieren

# Paket (Inhalt von dist/ aus prod.cmd bzw. Release-ZIP) nach /opt/smalltime kopieren
sudo unzip smalltime-1.0.0.zip -d /opt/smalltime      # Beispiel
cd /opt/smalltime
sudo npm install --omit=dev
sudo nano .env      # FRONTEND_ORIGIN, SESSION_SECRET, SECURE_COOKIE, TRUST_PROXY

Neues SESSION_SECRET erzeugen, falls nötig:

node -e "console.log(require('crypto').randomBytes(48).toString('base64'))"

Werte: Konfiguration. .env wird aus dem Arbeitsverzeichnis geladen (WorkingDirectory in der Unit). Umgebungsvariablen aus der Unit (Environment=/EnvironmentFile=) haben Vorrang vor .env.


Berechtigungen

cd /opt/smalltime
sudo mkdir -p config data uploads convert
sudo chown -R root:smalltime /opt/smalltime
sudo find /opt/smalltime -type d -exec chmod 750 {} +
sudo find /opt/smalltime -type f -exec chmod 640 {} +
sudo chown -R smalltime:smalltime config data uploads convert
sudo chmod 700 data uploads convert
sudo chmod 640 .env

Schreibrecht braucht der Dienst nur auf config/ (security.json beim ersten Start und über Administration → Sicherheit), data/, uploads/ und convert/ (Mapping-Vorschlag, Bericht).

Note

Wird npm install als root ausgeführt, gehören node_modules root; das ist gewollt (der Dienst liest nur). Die find … chmod 640 darf keine ausführbaren Binärdateien in node_modules/.bin betreffen, die zur Laufzeit gebraucht werden; SmallTime benötigt zur Laufzeit keine.


systemd-Unit

/etc/systemd/system/smalltime.service:

[Unit]
Description=SmallTime 2027 Zeiterfassung
Documentation=https://github.com/<organisation>/<repo>/wiki/IT-Installation-Linux
After=network-online.target
Wants=network-online.target
# Optional mit lokalem Redis:
# After=redis-server.service

[Service]
Type=simple
User=smalltime
Group=smalltime
WorkingDirectory=/opt/smalltime
ExecStart=/usr/bin/node app.cjs
# .env wird von der App selbst geladen. Alternativ hier setzen (hat Vorrang):
# Environment=NODE_ENV=production
# EnvironmentFile=/etc/smalltime/smalltime.env
Restart=on-failure
RestartSec=5
KillSignal=SIGTERM
TimeoutStopSec=20

# Härtung
NoNewPrivileges=true
PrivateTmp=true
PrivateDevices=true
ProtectSystem=strict
ProtectHome=true
ProtectKernelTunables=true
ProtectKernelModules=true
ProtectControlGroups=true
RestrictSUIDSGID=true
LockPersonality=true
RestrictAddressFamilies=AF_INET AF_INET6 AF_UNIX
ReadWritePaths=/opt/smalltime/config /opt/smalltime/data /opt/smalltime/uploads /opt/smalltime/convert
UMask=0027

[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable --now smalltime
systemctl status smalltime
curl -s http://127.0.0.1:55000/api/health

Hinweise:

  • ExecStart an den Node-Pfad anpassen (which node).
  • MemoryDenyWriteExecute=true nicht setzen; V8 braucht JIT-Speicher.
  • Mit ProtectSystem=strict sind nur die ReadWritePaths beschreibbar. Liegt data/ per Symlink woanders, den Zielpfad eintragen.
  • SIGTERM schliesst HTTP-Server, Redis und SQLite geordnet.

Logs

Die App schreibt nur auf stdout/stderr (HTTP-Zugriffe im combined-Format, Anwendungsereignisse als JSON-Zeilen), siehe Logs. Unter systemd landet alles im Journal:

journalctl -u smalltime -f                    # live
journalctl -u smalltime --since today -p warning
journalctl -u smalltime -o cat | grep '^{' | jq 'select(.level=="error")'   # nur App-Fehler

Aufbewahrung über /etc/systemd/journald.conf (SystemMaxUse=, MaxRetentionSec=). Die Zugriffslogs enthalten IP-Adressen; Aufbewahrungsdauer datenschutzkonform begrenzen. Separate Dateien sind möglich mit StandardOutput=append:/var/log/smalltime/smalltime.log und StandardError=append:/var/log/smalltime/error.log (Verzeichnis anlegen, in ReadWritePaths aufnehmen, logrotate mit copytruncate).


Firewall und Reverse-Proxy

Node.js lauscht auf allen Schnittstellen auf Port 55000; eine Bindung an 127.0.0.1 ist nicht konfigurierbar. Deshalb 55000 in der Firewall sperren und nur den Proxy öffnen:

sudo ufw default deny incoming
sudo ufw allow OpenSSH
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable

Proxy-Konfiguration (nginx, Caddy): Reverse-Proxy und HTTPS. In .env dann TRUST_PROXY=true, SECURE_COOKIE=true; in config/security.json "allowLocalhost": false.


Update

sudo systemctl stop smalltime
sudo sqlite3 /opt/smalltime/data/app.sqlite ".backup '/root/smalltime-before-update.sqlite'"
cd /opt/smalltime
sudo rm -rf dist public
sudo cp -r /tmp/smalltime-neu/{app.cjs,dist,public,package.json,package-lock.json} .
sudo npm install --omit=dev
sudo chown -R root:smalltime app.cjs dist public package.json package-lock.json node_modules
sudo systemctl start smalltime
journalctl -u smalltime -n 50 --no-pager

.env, config/, data/, uploads/, convert/ nicht ersetzen. Migrationen laufen beim Start automatisch. Weitere Hinweise: Sicherheit und Betrieb.


Weiter mit: Reverse-Proxy und HTTPS · Docker · Sicherheit und Betrieb

Clone this wiki locally