- Python 48.5%
- CSS 17.8%
- JavaScript 13.7%
- Shell 13.2%
- HTML 6.8%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
|
|
||
| apache | ||
| config | ||
| fail2ban | ||
| nginx | ||
| public | ||
| runtime | ||
| scripts | ||
| sudoers | ||
| systemd | ||
| tests | ||
| .gitignore | ||
| CHANGELOG.md | ||
| README.md | ||
| VERSION | ||
Palworld Operations dashboard
A private dashboard for an existing Palworld dedicated server. It controls only the approved GNU screen session or systemd service owned by the configured service account; the web application cannot execute arbitrary shell commands.
Current release: 1.1.0
The package is preconfigured for:
Dashboard URL: https://palworld.dwaynelowson.co.uk
Game endpoint: palworld.dwaynelowson.co.uk:8211
Screen session: palworld
Install path: /home/palworld/Steam/steamapps/common/PalServer
Steam account: palworld
Steam app: 2394010
Dashboard port: 127.0.0.1:8767
Features
- Online state, uptime, Palworld version, Steam build, player count, FPS, frame time, world day, base count, and player roster.
- Start, restart, stop, update-check, and update buttons.
- Optional systemd supervision of the named GNU screen session, with automatic crash recovery that still respects intentional dashboard stops.
- Optional REST-assisted saves and player shutdown warnings.
- Protected
Pal/Savedbackup before every installed update. - Live Palworld console output and update progress.
- Original archipelago artwork, layered glass panels, and cyan/coral/leaf accents give the operator interface a more distinctive Palworld-inspired identity without changing any controls.
- The update surface now uses the same teal glass treatment as the rest of the dashboard, with coral retained only as a restrained highlight.
- A separate dashboard login with scrypt password hashing, login throttling, signed sessions, CSRF checks, HTTPS-only cookies, and strict browser headers.
- Fail2ban protection for repeated login failures, sourced directly from the dashboard's systemd journal.
- A bounded readiness check lets Fail2ban finish creating its control socket before the installer verifies the Palworld jail.
- Loopback-only dashboard listener behind Apache and the existing wildcard certificate.
What happens to the existing screen session
The default screen control mode does not stop or replace the currently detached
2930696.palworld session. The dashboard finds it by the exact session name
palworld and reports it as online.
The first dashboard stop or restart sends Ctrl-C to that session and waits up
to 120 seconds for a clean exit. It deliberately refuses a forced screen quit.
Subsequent starts launch this fixed command as the palworld account:
cd /home/palworld/Steam/steamapps/common/PalServer
screen -dmS palworld -L -Logfile Pal/Saved/Logs/palworld-screen.log ./PalServer.sh
Screen writes the server's console output to
Pal/Saved/Logs/palworld-screen.log, but it is not involved when the dashboard
reads that file. The root-owned helper drops to the palworld account and runs
tail -F directly against the configured path.
If the server currently uses required launch arguments, pass them once with
--launch-arguments '...'. They are stored only in the root-owned control
configuration and are never accepted from the browser.
Optional crash supervision
Use --control-mode supervised-screen when systemd should own the screen
server and restart Palworld after an unexpected exit. This mode starts GNU
screen with -D -m, which remains in the foreground until its session ends;
systemd can therefore track the real session instead of a launcher that has
already exited.
The supervised unit uses Restart=always with a 20-second delay and stops
retrying after five failures within five minutes. A dashboard Stop action uses
systemctl stop, so an intentional stop remains stopped. The installer does
not enable this unit at boot; boot startup remains a separate choice.
The first switch to supervised mode requires the old screen session to be stopped. This prevents the new unit from racing an unmanaged copy:
# Stop the old bootstrap wrapper if it currently owns the session. Otherwise,
# use Stop in the dashboard before continuing.
sudo systemctl disable --now palworld-screen.service
sudo -u palworld screen -ls
sudo bash ./scripts/install.sh \
--control-mode supervised-screen \
--public-host palworld.dwaynelowson.co.uk \
--public-endpoint palworld.dwaynelowson.co.uk:8211
# Or use Start in the dashboard.
sudo systemctl start palworld-dashboard-screen.service
Do not enable palworld-dashboard-screen.service if the server should remain
off after a host reboot. If boot startup is wanted later, enable it explicitly
with sudo systemctl enable palworld-dashboard-screen.service.
Prerequisites
- Ubuntu/systemd, Python 3.10+,
sudo, GNU screen, SteamCMD, Apache 2, and Fail2ban. PalServer.shat the configured install path.appmanifest_2394010.acffrom the same Steam installation. SteamCMD may put it in the parentsteamappsdirectory or inPalServer/steamapps; the installer detects both layouts.- The DNS CNAME for
palworld.dwaynelowson.co.ukand the wildcard certificate at/etc/letsencrypt/live/dwaynelowson.co.uk/. - Optional: Palworld REST API on port 8212 for live metrics, world saves, and player warnings.
Install
Extract the package on the server, enter its directory, and run:
python3 -m unittest discover -s tests -p 'test_*.py'
bash -n ./scripts/install.sh ./scripts/uninstall.sh
sudo bash ./scripts/install.sh \
--public-host palworld.dwaynelowson.co.uk \
--public-endpoint palworld.dwaynelowson.co.uk:8211
The other defaults already match the supplied server layout. The installer
locates SteamCMD at /usr/games/steamcmd, /usr/bin/steamcmd, or
/usr/local/bin/steamcmd, discovers the matching manifest, verifies app
2394010, and prompts for a new dashboard passphrase. Use --app-manifest
only when SteamCMD stored the manifest outside either detected layout.
It also prompts for the Palworld AdminPassword. Leaving it blank keeps basic
screen controls and updates working, but live players/FPS/world metrics and
REST-assisted saves/warnings are unavailable. For a non-interactive install,
put each secret in a root-readable file and use:
sudo bash ./scripts/install.sh \
--dashboard-password-file /root/palworld-dashboard-password \
--rest-password-file /root/palworld-admin-password
Do not paste either password into shell history or chat. Re-running the
installer upgrades the dashboard and preserves its existing login unless
--reset-auth is passed. A successful install or upgrade restarts the dashboard
service, so newly deployed interface assets are available immediately.
The installer also validates the existing Fail2ban configuration, installs the
palworld-dashboard journal filter and jail, enables Fail2ban at boot, restarts
it, and confirms the jail is active. If the new configuration does not validate,
the previous service-specific files are restored and installation stops.
The jail bans an address after five failed login requests within ten minutes for one hour. Check it with:
sudo fail2ban-client status palworld-dashboard
sudo journalctl -u palworld-dashboard.service -f -o cat
Apache reverse proxy
The ready-to-use vhost is
apache/palworld.dwaynelowson.co.uk.conf. It points at 127.0.0.1:8767 and
uses the existing wildcard certificate paths.
sudo cp ./apache/palworld.dwaynelowson.co.uk.conf \
/etc/apache2/sites-available/palworld.dwaynelowson.co.uk.conf
sudo a2enmod ssl proxy proxy_http headers
sudo a2ensite palworld.dwaynelowson.co.uk.conf
sudo apache2ctl configtest
sudo systemctl reload apache2
Only reload Apache after Syntax OK. The /api/events proxy rule has the long
timeout needed for the live activity stream.
Optional Palworld REST API
For live game metrics and graceful operations, configure these values in the
server's PalWorldSettings.ini and restart Palworld:
RESTAPIEnabled=True
RESTAPIPort=8212
AdminPassword=<strong unique password>
The dashboard calls only http://127.0.0.1:8212/v1/api. Do not publish TCP
8212 through Apache, the router, or a public firewall rule.
All dashboard clients share one REST status sample for ten seconds, so opening
the web dashboard and Nexus does not multiply calls to Palworld. The shared log
event stream removes blank lines and successful dashboard polling entries for
info, metrics, and players; REST failures and administrative operations
remain visible. Palworld still records the reduced set of REST audit entries in
its raw screen log.
Update behavior
The update button compares the local manifest with Steam app 2394010. When a
new build is approved, the root-only updater:
- asks Palworld to save and warn players when REST credentials are available;
- stops only the configured screen session or supervised service;
- copies
Pal/Savedto a timestamped, root-only backup under/home/palworld/backups; - runs SteamCMD as
palworldwith+force_install_dir ... +app_update 2394010 validate; - verifies the installed build ID; and
- starts the server again only if it was running before the update.
While this runs, the dashboard follows the one-shot update service through checking, saving, backup, installation, and restart. It waits for a terminal success or failure report and shows a final refresh button instead of assuming that the first SteamCMD response means the update has finished. Reloading the page during an active update resumes the same progress view.
Without REST credentials, startup health is checked through the approved screen session. Backups are never deleted automatically. A failed update keeps its backup path in the update status; it does not attempt an unsupported Steam build rollback.
Operational checks
systemctl status palworld-dashboard.service --no-pager
systemctl status palworld-dashboard-screen.service --no-pager
sudo journalctl -u palworld-dashboard.service -n 100 --no-pager
sudo /usr/local/libexec/palworld-dashboard-control status
sudo -u palworld screen -ls
curl -H 'Host: palworld.dwaynelowson.co.uk' \
http://127.0.0.1:8767/healthz
In default screen mode, helper status shows "service":"screen:palworld".
In supervised mode it shows
"service":"palworld-dashboard-screen.service" and includes the exact screen
session. A health request with any unexpected Host header is rejected.
Security boundary
The public web process runs as the non-login palworld-dashboard account. Its
sudo policy permits a root-owned helper with only eight fixed arguments. The
helper revalidates the root-owned paths, account, session name, executables,
manifest, log location, and optional fixed launch arguments before every
operation.
The browser never supplies a path, session name, service name, or command-line
argument. Dashboard and REST secrets remain in /etc/palworld-dashboard.env
with mode 0600. Keep the dashboard behind HTTPS and consider the same IP
allow-list or VPN policy used by the other dashboards.
Fail2ban trusts only the validated client address appended by the loopback
reverse proxy. Do not expose port 8767 directly, and preserve the supplied
X-Forwarded-For proxy behaviour if the reverse-proxy configuration changes.
The dashboard systemd service must keep NoNewPrivileges disabled because its
only privileged operation is the fixed sudo helper above. Enabling a systemd
hardening option that implicitly forces NoNewPrivileges will block every
control button before the helper can run.
Files installed
/opt/palworld-dashboard/ dashboard, updater, and web files
/etc/palworld-dashboard.env dashboard and REST secrets (0600)
/etc/palworld-dashboard-control.conf approved screen and paths (0600)
/usr/local/libexec/palworld-dashboard-control
/etc/systemd/system/palworld-dashboard.service
/etc/systemd/system/palworld-dashboard-update.service
/etc/systemd/system/palworld-dashboard-screen.service supervised mode only
/etc/sudoers.d/palworld-dashboard
/etc/fail2ban/filter.d/palworld-dashboard.conf
/etc/fail2ban/jail.d/palworld-dashboard.local
/var/lib/palworld-dashboard/ cached Steam release state
/home/palworld/backups/ protected update backups
Uninstall
sudo bash ./scripts/uninstall.sh
The uninstaller removes the dashboard application, its dashboard systemd units, helper, sudo policy, and service-specific Fail2ban filter and jail. It stops the dashboard-owned supervised screen unit when present, while preserving both configuration files, the Steam release cache, Palworld itself, and all backups.
For an explicit complete dashboard purge, including its configuration, secrets, release cache, and service account:
sudo bash ./scripts/uninstall.sh -a
# --all is equivalent
Even the complete dashboard purge never removes the Palworld installation, world saves, an external screen service, or protected update backups.
Production package layout
The downloadable production archive intentionally contains only the dashboard runtime, static interface, installer, service definitions, fixed sudo policy, reverse-proxy examples, configuration examples, tests, and this guide. Preview site tooling and web-build metadata are excluded because the production service never reads or installs them.
The production dashboard does not run, embed, or call an AI service. It is a local Python application controlling the fixed Palworld helper described above.
To build the same server-only archive from a full source checkout:
bash ./scripts/package-production.sh ./palworld-dashboard-production.tar.gz