# Packet Station: the web app (uvicorn on port 8000, the API and the built frontend). # Installed by deploy/vm/install.sh into /etc/systemd/system. See docs/DEPLOY.md, "Native VM install". # NPM on docker-1 is the only client allowed on port 8000 (packetstation-firewall.service). [Unit] Description=Packet Station web app Documentation=file:///opt/packetstation/current/docs/DEPLOY.md Requires=packetstation-migrate.service # Wants, not Requires: a restart of nftables.service must not restart the app. ExecStartPre checks the table. Wants=packetstation-firewall.service After=packetstation-migrate.service packetstation-firewall.service postgresql@16-main.service network-online.target Wants=postgresql@16-main.service network-online.target StartLimitIntervalSec=300 StartLimitBurst=5 [Service] Type=exec User=packetstation Group=packetstation EnvironmentFile=/etc/packetstation/packetstation.env # The app's secrets only. It never gets the VISUAL or M-Files password. LoadCredential=postgres_app_password:/etc/packetstation/secrets/postgres_app_password LoadCredential=ldap_bind_password:/etc/packetstation/secrets/ldap_bind_password LoadCredential=session_key:/etc/packetstation/secrets/session_key LoadCredential=seal_key:/etc/packetstation/secrets/seal_key # The app never listens without the firewall table in place ("+": this check runs as root). ExecStartPre=+/usr/sbin/nft list table inet packetstation ExecStart=/opt/packetstation/current/deploy/vm/ps-launch.sh app SyslogIdentifier=packetstation-app Restart=on-failure RestartSec=5s TimeoutStopSec=30s WorkingDirectory=/ UMask=0027 MemoryMax=1G LimitNOFILE=16384 # Sandbox. Read-only file system except the assets and the archive mount. # The leading "-" lets the app start while the archive is not mounted (ARCHIVE_ROOT unset). ReadWritePaths=/var/lib/packetstation/assets ReadWritePaths=-/mnt/packetstation-archive InaccessiblePaths=/etc/packetstation/secrets NoNewPrivileges=yes ProtectSystem=strict ProtectHome=yes PrivateTmp=yes PrivateDevices=yes ProtectKernelTunables=yes ProtectKernelModules=yes ProtectKernelLogs=yes ProtectControlGroups=yes ProtectClock=yes ProtectHostname=yes ProtectProc=invisible # AF_NETLINK: glibc's getaddrinfo asks the kernel for the local addresses through it. RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6 AF_NETLINK RestrictNamespaces=yes RestrictRealtime=yes RestrictSUIDSGID=yes LockPersonality=yes RemoveIPC=yes CapabilityBoundingSet= AmbientCapabilities= SystemCallArchitectures=native SystemCallFilter=@system-service SystemCallErrorNumber=EPERM # Not set: MemoryDenyWriteExecute. pypdfium2 goes through ctypes, whose callbacks may need # writable and executable memory. Turn it on only after a filing and a print pass on the test VM. [Install] WantedBy=multi-user.target