MUD Hosting with Linux VPS providers
Legacy MUD codebases (CircleMUD, ROM, Merc) require specific runtime environments that differ from modern web applications. This guide addresses the practical constraints of hosting 1990s-era C code on contemporary systemd-based Linux distributions, covering compilation of 32-bit binaries on 64-bit systems, persistent service management, and backup strategies for flat-file player data. The steps assume a fresh Ubuntu 22.04 LTS or Debian 12 VPS with root access.
Provision VPS and Create mud User
Provision a low-tier VPS (1-2GB RAM suffices for most MUDs). Create a dedicated unprivileged user to run the game—never run MUD code as root due to buffer overflow risks in legacy C code. Disable password authentication and root login in SSH to prevent brute-force attacks.
# Create user
useradd -m -s /bin/bash mud
usermod -aG sudo mud
# Harden SSH (edit /etc/ssh/sshd_config)
PermitRootLogin no
PasswordAuthentication no
PubkeyAuthentication yes
systemctl restart sshd⚠ Common Pitfalls
- •Running the MUD as root allows exploit of buffer overflows to compromise the entire server
- •Forgetting to set a strong password for the mud user before disabling root login can lock you out
Install Legacy Build Dependencies
Install GCC, make, and 32-bit compatibility libraries. Many MUDs from the 1990s assume 32-bit architecture and require libc6-dev-i386 to compile on modern 64-bit systems. Also install git to clone repositories and screen/tmux for initial testing.
dpkg --add-architecture i386
apt update
apt install -y build-essential gcc-multilib libc6-dev-i386 git tmux⚠ Common Pitfalls
- •Missing libc6-dev-i386 causes 'fatal error: bits/libc-header-start.h' during compilation
- •Not installing gcc-multilib prevents linking of 32-bit object files on 64-bit systems
Compile Codebase and Configure Ports
Clone your MUD source (e.g., from https://github.com/jelson/circle). Edit src/config.h to set the game port (commonly 4000, 5000, or 9000). Compile with -DLINUX or -DMERC flags as required by the specific derivative. Test the binary manually before proceeding to systemd setup.
cd /home/mud
git clone https://github.com/jelson/circle.git
cd circle/src
# Edit port in config.h (change #define GAME_PORT)
sed -i 's/#define GAME_PORT.*/#define GAME_PORT 4000/' config.h
make clean && make -DLINUX
cd .. && ./autorun.sh⚠ Common Pitfalls
- •Hardcoded absolute paths in autorun scripts break when moved between directories
- •Port numbers below 1024 require root privileges; choose ports above 1024 for unprivileged execution
Create Systemd Service for Persistence
Create a systemd service file to ensure the MUD restarts automatically after crashes or reboots. Set WorkingDirectory explicitly—legacy MUDs often use relative paths for player files and area files that resolve against the current working directory, not the binary location.
[Unit]
Description=MUD Game Server
After=network.target
[Service]
Type=simple
User=mud
Group=mud
WorkingDirectory=/home/mud/circle
ExecStart=/home/mud/circle/src/circle 4000
ExecStop=/bin/kill -TERM $MAINPID
Restart=always
RestartSec=10
[Install]
WantedBy=multi-user.target⚠ Common Pitfalls
- •Omitting WorkingDirectory causes 'No such file or directory' errors when the MUD tries to open ../lib/player or similar relative paths
- •Using Type=forking instead of Type=simple can confuse systemd if the MUD's daemonization logic is inconsistent
Configure Firewall and Security Hardening
Enable UFW (Uncomplicated Firewall) to block all ports except SSH and your MUD port. Install fail2ban to prevent SSH brute force. Consider rate-limiting connections to the MUD port if you experience denial-of-service attacks from malformed telnet clients.
ufw default deny incoming
ufw allow 22/tcp
ufw allow 4000/tcp
ufw enable
apt install fail2ban
systemctl enable fail2ban⚠ Common Pitfalls
- •Enabling UFW before allowing SSH can disconnect your session—ensure SSH is allowed before enabling
- •Some VPS providers have external firewalls; ensure both UFW and provider firewall allow the MUD port
Implement Automated Backup Strategy
Create a backup script that tarballs player files (usually in ../player, ../save, or ../lib), area files, and configuration. Schedule via systemd timer or cron. Exclude core dumps and log files to save space. Store backups offsite using rclone to S3-compatible storage or similar.
#!/bin/bash
DATE=$(date +%Y%m%d-%H%M%S)
BACKUP_DIR="/home/mud/backups"
MUD_DIR="/home/mud/circle"
tar -czf $BACKUP_DIR/mud-backup-$DATE.tar.gz \
--exclude='*.log' --exclude='core.*' \
-C $MUD_DIR lib/ src/⚠ Common Pitfalls
- •Backing up player files while the MUD is running can corrupt data if saves happen mid-backup; use --exclude or stop the service first
- •Not testing restoration procedures leads to discovering backup corruption only during disaster recovery
Setup Monitoring and Log Rotation
Monitor the MUD process using systemd status checks and log grepping for segmentation faults. Configure logrotate to prevent syslog from filling disk with connection errors from port scanners. Set up a simple port-check cron job to alert if the game becomes unreachable.
# Check if MUD is listening
ss -tlnp | grep :4000
# Logrotate config (/etc/logrotate.d/mud)
/var/log/mud/*.log {
daily
rotate 7
compress
missingok
}⚠ Common Pitfalls
- •Default logrotate settings can leave MUD logs uncompressed and consuming disk space rapidly on busy servers
- •Monitoring only the process PID misses 'zombie' states where the process exists but accepts no connections—always check the port
What you built
With the MUD running under systemd, verify persistence by rebooting the VPS and checking that the service auto-starts. Schedule weekly backup tests by restoring to a temporary directory. Monitor disk usage monthly—player files and logs accumulate over years of operation. For updates, always compile in a staging directory first to verify compatibility with your specific derivative's codebase before replacing the production binary.