Files
Megalodon/README.md
T
VeillaxandClaude Sonnet 5.5 88487d9744
CI / test (push) Successful in 2m15s
Release / release (push) Successful in 2m51s
Restyle the dashboard to the Lightwell design language
Same tokens, sidebar shell, components and voice as Hammerhead: teal accent,
warm neutrals, status badges with text, dialogs with focus trapping that name
what they affect, empty states, skeleton loading, outline icons, 44px touch
targets and a slide-in drawer on phones. The strict CSP stays: no inline
styles or scripts, so icons and sizes use classes.

Adds docs/design.md and scripts/lint-design.mjs (run in CI), capitalizes
server error messages in one place, and rewrites interface copy to the voice
rules (sentence case, buttons that name the result, no dashes).

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-31 00:30:30 -06:00

9.5 KiB

Megalodon

Remote management for ARK: Survival Evolved servers over RCON. One small binary (no database, no dependencies) that watches your servers, gives you a web dashboard to run them from, and does the boring parts on a schedule.

It talks to the server the way the game's own admin console does, so it works with any ARK:SE server that has RCON switched on, whether it runs in Docker, on TrueNAS, or on a plain machine.

What it does

Watch

  • Live status of every server: online or not, players, map, version, RCON latency, uptime, and a 24-hour player-count graph. No RCON password needed for the map/version/player cap: it also asks the game's query port, like the Steam server browser does.
  • Join/leave events, chat log, and an audit trail of everything anyone does from the dashboard.
  • A player database across all servers: first and last seen, total play time, number of visits, notes.
  • A watch list: get an event the moment a particular player joins.
  • Prometheus metrics at /metrics.

Control

  • Save the world, broadcast, chat as SERVER, whisper to one player, kick, set the time of day, set the message of the day, wipe wild creatures.
  • Bans that behave: with a reason, optionally for a set time, applied to every server in a cluster at once, and enforced again whenever the player turns up (even on a server that was offline when you banned them). Expired bans lift themselves.
  • Restarts that warn people: a countdown with announcements at 30, 15, 10, 5, 2 and 1 minute and 30 and 10 seconds, a world save first, cancellable at any time. Optionally Megalodon starts the server again itself (see start_command), and can start it automatically if it stays down.
  • A raw console with history and suggestions, plus saved macros (named lists of commands).
  • Cluster actions: broadcast or save on every server in one click.

Automate

  • Schedules: a save every 30 minutes, a daily restart at 04:30 on weekdays, a broadcast every hour, any console command on a timer.
  • Notifications to Discord, ntfy or any webhook for the events you choose.
  • Welcome message whispered to each player who joins.
  • Chat filter: warn, then kick or temporarily ban, for words you list.

Share it safely

  • Three roles: viewer (look), moderator (talk to players, kick, ban, save), admin (everything, including the raw console, restarts, schedules and settings).
  • API tokens with the same roles, for scripts and monitoring.

Setting up the server side

RCON is off by default. In GameUserSettings.ini under [ServerSettings]:

RCONEnabled=True
RCONPort=27020
ServerAdminPassword=choose-something-long

(or add ?RCONEnabled=True?RCONPort=27020?ServerAdminPassword=... to the launch command). The password you set there is the RCON password.

Do not expose the RCON port to the internet. RCON is unencrypted and its password is the whole admin password. Keep it on your LAN or a VPN; only Megalodon needs to reach it. If Megalodon and the server are on the same machine or Docker network, nothing needs to be opened at all.

Installing on Linux (systemd)

curl -fsSL https://git.veillax.com/Veillax/megalodon/raw/branch/main/deploy/install.sh | sudo sh

This downloads the latest release (checking its SHA-256), installs /usr/local/bin/megalodon, creates a megalodon user, /etc/megalodon/ (settings) and /var/lib/megalodon/ (data), opens /etc/megalodon/megalodon.env in your editor, then starts the service and prints the first-run admin password. Run it again to upgrade; your settings are kept.

Options: --version v0.1.0, --listen 0.0.0.0:8480, --source (build from the repository with Go instead), --no-edit, --no-start, and --uninstall (add --purge to delete settings and data). Download the script and read it first if you prefer: it is deploy/install.sh.

Running it by hand

# download a release, or: go build ./cmd/megalodon
./megalodon serve

On first run it writes megalodon.json, creates a user called admin and prints its password once in the log. Open http://127.0.0.1:8480, sign in, and use Add server. Or copy megalodon.example.json and edit it.

By default the dashboard only listens on 127.0.0.1. To reach it from elsewhere, put it behind an HTTPS reverse proxy, or expose it through Hammerhead, and set "cookie_secure": true and "trust_proxy": true. Don't put the dashboard on the open internet over plain HTTP.

Docker: see Dockerfile and deploy/docker-compose.yml. Set TZ so scheduled times use your clock.

Commands

megalodon serve [-config megalodon.json] [-listen addr]
megalodon user NAME [ROLE]       add a user, or change a password (reads MEGALODON_PASSWORD or stdin)
megalodon token NAME [ROLE]      create an API token (printed once)
megalodon rcon -addr host:27020 -password PW [COMMAND...]
                                 one-off console command, or an interactive prompt without a command

Configuration

Everything is in one JSON file, and everything except listen, data_dir, poll_seconds, chat_seconds, trust_proxy and cookie_secure can be edited from the dashboard (changes are written back to the file). See megalodon.example.json.

Setting Meaning
servers[].host, rcon_port, password where to reach the console
servers[].query_port game query port (UDP, usually 27015); 0 turns it off
servers[].start_command shell command that starts the server (docker start ark-island, systemctl start ark, a script). Runs on the machine Megalodon is on; it must return promptly
servers[].auto_start run start_command when the server has been down for auto_start_after seconds (default 120), at most every 5 minutes. A server you Stop from the dashboard stays stopped
jobs[] action is save, broadcast, restart, command, destroy_wild_dinos or motd; use every ("30m") or at (["04:30"], optionally with days)
notify[] kind is discord, ntfy or json. No events list means joins, leaves, up/down, restarts, bans and errors
poll_seconds how often each server is asked who is online (default 10)

Files in data_dir: events.jsonl (event log, rotated at 20 MB), players.json, bans.json, samples-<server>.jsonl (the graph).

API

Everything the dashboard does goes through a JSON API. Sign in with POST /api/login, or send an API token as Authorization: Bearer mgl_….

curl -H "Authorization: Bearer $TOKEN" http://127.0.0.1:8480/api/servers
curl -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
     -d '{"action":"broadcast","message":"Restart in 10 minutes"}' \
     http://127.0.0.1:8480/api/servers/island/action

action is one of save, broadcast, say, whisper, kick, ban, unban, allow, disallow, destroy_wild_dinos, set_time, motd, exec, restart, stop, cancel_restart and start. POST /api/actions does the same on several (or all) servers. GET /api/events, GET /api/players, GET /api/stream (live events, server-sent) and GET /metrics round it out.

Prometheus: megalodon_server_up, megalodon_players, megalodon_players_max, megalodon_rcon_rtt_ms, megalodon_uptime_seconds, megalodon_restart_pending, all labelled by server.

Security notes

  • Passwords are stored as PBKDF2-SHA256 hashes; API tokens as SHA-256 hashes. RCON passwords sit in megalodon.json in plain text (they have to), so the file is written 0600: keep it that way.
  • Sessions are HttpOnly, SameSite=Strict cookies, and every change needs a custom header a web page on another site can't send. Failed sign-ins are rate-limited per address.
  • The dashboard has a strict Content-Security-Policy and never renders game text as HTML.
  • Values that go into console commands (Steam IDs, messages) are validated and stripped of quotes and line breaks, so a player name or message can't inject a second command. The raw console is admin-only and recorded in the event log.
  • Moderators can see audit entries; viewers cannot.

Honest limits

  • It has been tested against a simulated ARK server and unit tests, not yet against a real ARK:SE server. The console's reply formats (ListPlayers, GetChat) are parsed leniently, but if one differs on your version, open an issue with the raw reply (megalodon rcon … ListPlayers).
  • RCON can't read or write GameUserSettings.ini, install mods or update the game; restarting and updating are left to whatever runs the server (Docker, systemd, SteamCMD).
  • Commands that take an in-game player ID rather than a Steam ID (GiveItemToPlayer, GiveExpToPlayer) are available from the console but have no buttons, because RCON doesn't report that ID.
  • ARK:SE only (it is untested on ASA, which uses the same protocol but may differ in detail).

Design

The dashboard follows the Lightwell design language, the same one Hammerhead uses: teal accent, warm neutrals, a sidebar, status badges with text, and dialogs that name what they affect. See docs/design.md. node scripts/lint-design.mjs checks the rules a machine can check.

Development

go test ./...
go run ./cmd/fakeark &              # a pretend server on :27020 (password "secret") with players and chat
go run ./cmd/megalodon serve

Releases are built by the Gitea workflow when a v* tag is pushed.

Licensed under the AGPL-3.0 (see LICENSE).