Date: 2026-05-11
Time: 15:54
This is a Terraria dedicated server provisioning script for the ftl2-servercraft project. It automates the full lifecycle of a Terraria game server on Linode infrastructure running Fedora — from cloud instance creation through software installation, security hardening, DNS setup, and ongoing operations like starting/stopping the server, backing up worlds, and monitoring player counts. It uses FTL2's automation API (ftl) to execute remote commands and manage state.
The module exposes several top-level async functions, all taking an ftl automation handle, a ServerConfig, and a log callback:
# Full provisioning (infra + software + security + DNS)
await provision(ftl, config, log)
# Server lifecycle
await start_server(ftl, config, log)
alive = await verify_server(ftl, config, log)
await save_and_stop(ftl, config)
# World management
await restore_world(ftl, config, backup_path, log)
local_path = await backup_world(ftl, config, log)
# Monitoring
count = await get_player_count(ftl, config) # Returns int or None if server down
# Teardown
await destroy(ftl, config, log)
The provision() function orchestrates seven sequential steps: infrastructure, Terraria install, utilities, security, swap, ownership, and DDNS. Each step is idempotent — it checks state before acting.
All configuration comes from a ServerConfig object (from ..config). Key attributes used:
| Attribute | Purpose |
|-----------|---------|
| config.name | Server label / Linode instance name |
| config.admin_user | Non-root admin username created on the server |
| config.linode_type | Linode plan type |
| config.linode_region | Linode datacenter region |
| config.linode_image | OS image (Fedora) |
| config.server_url | Terraria server download URL (defaults to v1455) |
| config.world_name | World .wld filename |
| config.configdirpath | Local directory with serverconfig.txt, run.sh, jail.local |
| config.ddns_hostname | Cloudflare DNS hostname (optional) |
| config.slack_channel | Slack channel for status notifications |
| config.get_ip() | Returns the server's IP address |
Constants: TMUX_SESSION = "terraria", default server URL points to Terraria v1455.
ftl.state to persist Linode instance metadata. Provision checks state before creating — won't duplicate servers. Destroy removes from state.root, creates an admin user with SSH key auth, hardens SSH (disables password auth, IPv4 only), then reconnects as the admin user.save, exit, playing) are sent via tmux send-keys. Player count is read by capturing the tmux pane output and regex-matching N players? connected.backup_world() sends save to the Terraria console and waits 5 seconds before fetching the .wld file. Backups are timestamped and stored in ~/data/terraria/backups/.provision() catches exceptions and posts failure messages to Slack before re-raising. Success also posts to Slack.resultdict() helper: Normalizes FTL2 action results (which can be dicts, lists, or objects with .output) into plain dicts — used throughout for extracting stdout.ServerConfig from ..config, updatednsrecord from ..cloudflare (lazy import in stepddns)shell, copy, file, geturl, unarchive, hostname, user, service, lineinfile, pip, waitforssh, fetch, swap, community.general.linodev4, community.general.slack, ansible.posix.authorized_key, ansible.posix.firewalldftl.state (persistent state file), ftl.add_host() (dynamic inventory), host group terraria