Factorio Headless Server on Linux

Factorio is a factory-building game that supports cooperative multiplayer through dedicated servers. This guide covers downloading Factorio server software, configuring server-settings.json for gameplay parameters, setting up map generation with custom seeds, installing mods, enabling RCON for remote console access, and managing the server with systemd. Factorio servers are lightweight and efficient, making them ideal for long-running multiplayer factories.

Table of Contents

System Requirements

Factorio is lightweight compared to other multiplayer games:

  • Ubuntu 20.04 LTS or later
  • 2GB RAM minimum (4GB recommended for 50+ players)
  • 10GB disk space
  • Single CPU core minimum (dual-core recommended)
  • Stable internet connection
  • Factorio game license (can use trial)

Factorio runs efficiently even on modest hardware, making it excellent for shared hosting.

Downloading Factorio Server

Factorio server is available directly from the publisher. First, register for a player account:

  1. Visit https://www.factorio.com/
  2. Create an account and register your copy
  3. Go to https://www.factorio.com/download and note your download URL

Create dedicated factorio user:

sudo useradd -m -s /bin/bash factorio
sudo -u factorio mkdir -p /home/factorio/factorio-server

Download Factorio server (replace VERSION with current version):

cd /home/factorio/factorio-server

# Download latest version (requires authentication)
sudo -u factorio wget --user your_username --password your_password \
    https://factorio.com/get-download/stable/headless/linux64 \
    -O factorio_headless_x64.tar.xz

# Alternative: use curl with auth
sudo -u factorio curl -L "https://factorio.com/get-download/stable/headless/linux64" \
    --user your_username:your_password \
    -o factorio_headless_x64.tar.xz

Extract the server:

sudo -u factorio tar -xf factorio_headless_x64.tar.xz
ls -la /home/factorio/factorio-server/factorio/bin/x64/

Verify installation:

/home/factorio/factorio-server/factorio/bin/x64/factorio --version

Create data directories:

sudo -u factorio mkdir -p /home/factorio/factorio-data/{saves,mods,scenarios,logs}

Server Configuration

Create the main startup script:

sudo tee /home/factorio/factorio-server/start_server.sh > /dev/null <<'EOF'
#!/bin/bash

FACTORIO_DIR="/home/factorio/factorio-server/factorio"
DATA_DIR="/home/factorio/factorio-data"
SAVE_NAME="${SAVE_NAME:-factorio_saves}"
ADMIN_PASSWORD="${ADMIN_PASSWORD:-changeme}"
GAME_PASSWORD="${GAME_PASSWORD:-}"

cd "$DATA_DIR"

mkdir -p "$DATA_DIR/saves"
mkdir -p "$DATA_DIR/logs"

# Create world if it doesn't exist
if [ ! -f "$DATA_DIR/saves/$SAVE_NAME.zip" ]; then
    echo "Creating new world: $SAVE_NAME"
    "$FACTORIO_DIR/bin/x64/factorio" \
        --create "$DATA_DIR/saves/$SAVE_NAME.zip" \
        --map-gen-seed 12345
fi

# Run the server
exec "$FACTORIO_DIR/bin/x64/factorio" \
    --start-server "$DATA_DIR/saves/$SAVE_NAME.zip" \
    --server-settings "$DATA_DIR/server-settings.json" \
    --server-whitelist "$DATA_DIR/whitelist.json" \
    --console-log "$DATA_DIR/logs/factorio_$(date +%Y%m%d).log" \
    2>&1
EOF

sudo chmod +x /home/factorio/factorio-server/start_server.sh
sudo chown factorio:factorio /home/factorio/factorio-server/start_server.sh

Server Settings JSON

Create comprehensive server configuration:

sudo tee /home/factorio/factorio-data/server-settings.json > /dev/null <<'EOF'
{
  "name": "My Factorio Server",
  "description": "Cooperative factory building server",
  "tags": ["factorio", "coop", "factory"],
  "max_players": 255,
  "visibility": {
    "public": true,
    "lan": false
  },
  "token": "",
  "game_password": "",
  "require_user_verification": true,
  "max_upload_in_kilobytes_per_second": 0,
  "minimum_latency_in_ticks": 0,
  "ignore_player_limit_for_returning_players": false,
  "allow_commands": "admins-only",
  "pause_when_empty": false,
  "only_admins_can_pause_the_game": true,
  "only_admins_can_manage_players": false,
  "autosave_interval": 10,
  "autosave_slots": 5,
  "afk_autokick_interval": 0,
  "auto_pause": true,
  "only_admins_can_trigger_incidents": true,
  "admins": [
    "YOUR_USERNAME"
  ],
  "ban_list_file": "ban-list.json",
  "whitelist_file": "whitelist.json",
  "use_whitelist": false
}
EOF

sudo chown factorio:factorio /home/factorio/factorio-data/server-settings.json

Configuration explanation:

  • name: Server name displayed in server list
  • max_players: Maximum concurrent players (default 255)
  • visibility.public: Enable to show in server browser
  • pause_when_empty: Pause game when no players are online
  • autosave_interval: Minutes between autosaves
  • autosave_slots: Number of autosave backups to keep
  • allow_commands: "admins-only" restricts commands to admins
  • afk_autokick_interval: Minutes before kicking AFK players (0 = disabled)
  • only_admins_can_trigger_incidents: Controls incident spawning permissions

Map Generation and Presets

Create map generation presets:

sudo tee /home/factorio/factorio-data/map-gen-settings.json > /dev/null <<'EOF'
{
  "terrain_segmentation": "normal",
  "water": "normal",
  "starting_area": "normal",
  "peaceful_mode": false,
  "cliff_settings": {
    "cliff_elevation_0": 10,
    "cliff_elevation_interval": 10,
    "cliff_richness": 0.8
  },
  "autoplace_controls": {
    "coal": {
      "frequency": "normal",
      "size": "normal",
      "richness": "normal"
    },
    "stone": {
      "frequency": "normal",
      "size": "normal",
      "richness": "normal"
    },
    "iron-ore": {
      "frequency": "normal",
      "size": "normal",
      "richness": "normal"
    },
    "copper-ore": {
      "frequency": "normal",
      "size": "normal",
      "richness": "normal"
    },
    "crude-oil": {
      "frequency": "normal",
      "size": "normal",
      "richness": "normal"
    },
    "trees": {
      "frequency": "normal",
      "size": "normal",
      "richness": "normal"
    },
    "enemy-base": {
      "frequency": "normal",
      "size": "normal",
      "richness": "normal"
    }
  },
  "seed": 0
}
EOF

sudo chown factorio:factorio /home/factorio/factorio-data/map-gen-settings.json

Create world with custom map generation:

# Stop server first
sudo systemctl stop factorio.service

# Create new world with specific seed and settings
sudo -u factorio /home/factorio/factorio-server/factorio/bin/x64/factorio \
    --create /home/factorio/factorio-data/saves/new_world.zip \
    --map-gen-settings /home/factorio/factorio-data/map-gen-settings.json

# Restart server with new world
sudo systemctl start factorio.service

RCON Configuration

Enable RCON for remote console access. Add to server startup script:

# RCON port configuration (add to start script)
RCON_PORT=27015
RCON_PASSWORD="SecureRconPassword"

Create RCON client script for remote administration:

sudo tee /home/factorio/factorio-server/rcon_client.py > /dev/null <<'EOF'
#!/usr/bin/env python3

import socket
import json
import sys
import time

class FactorioRCON:
    def __init__(self, host, port, password):
        self.host = host
        self.port = port
        self.password = password
        self.socket = None
        self.command_id = 0
    
    def connect(self):
        self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.socket.connect((self.host, self.port))
        
        # Authenticate
        auth_msg = {
            "jsonrpc": "2.0",
            "method": "Auth",
            "params": {"password": self.password},
            "id": 1
        }
        self.send_command(auth_msg)
        response = self.socket.recv(1024).decode()
        print(f"Auth response: {response}")
    
    def send_command(self, command_dict):
        msg = json.dumps(command_dict) + "\n"
        self.socket.send(msg.encode())
    
    def execute_command(self, command):
        self.command_id += 1
        cmd_msg = {
            "jsonrpc": "2.0",
            "method": "call",
            "params": {"method": command},
            "id": self.command_id
        }
        self.send_command(cmd_msg)
        
        response = self.socket.recv(4096).decode()
        return response
    
    def close(self):
        if self.socket:
            self.socket.close()

if __name__ == "__main__":
    if len(sys.argv) < 2:
        print("Usage: rcon_client.py <command>")
        sys.exit(1)
    
    rcon = FactorioRCON("127.0.0.1", 27015, "SecureRconPassword")
    try:
        rcon.connect()
        result = rcon.execute_command(sys.argv[1])
        print(result)
    finally:
        rcon.close()
EOF

sudo chmod +x /home/factorio/factorio-server/rcon_client.py
sudo chown factorio:factorio /home/factorio/factorio-server/rcon_client.py

Common RCON commands:

# Player management
/promote playername          # Make player admin
/demote playername          # Remove admin status
/kick playername            # Kick a player
/ban playername             # Ban a player
/unban playername           # Unban a player
/ban-by-account playername  # Ban by account

# Server control
/help                       # Show available commands
/save                       # Force save world
/quit                       # Graceful shutdown
/evolution                  # Show evolution factor

# Game control
/cheat                      # Enable cheat mode
/toggle-pause              # Pause/unpause game
/time                      # Show elapsed time
/seed                      # Show map seed

# Messaging
/say message               # Broadcast to all players
/whisper player message    # Send private message

Mod Installation

Download mods from the Factorio mod portal:

cd /home/factorio/factorio-data/mods

# Mods can be downloaded from https://mods.factorio.com/
# Popular mods:
# - Bob's Mods (comprehensive content expansion)
# - Angel's Mods (production extensions)
# - Industrial Revolution 2
# - Space Exploration

# Download and extract mod (example)
sudo -u factorio wget https://github.com/factoriotools/factorio-mirror/releases/download/latest/some-mod.zip
sudo -u factorio unzip -o some-mod.zip

# List installed mods
ls -la /home/factorio/factorio-data/mods/

Create mod configuration file:

sudo tee /home/factorio/factorio-data/saves/mods.json > /dev/null <<'EOF'
{
  "mods": [
    {
      "name": "base",
      "enabled": true
    },
    {
      "name": "example-mod",
      "enabled": true
    }
  ]
}
EOF

sudo chown factorio:factorio /home/factorio/factorio-data/saves/mods.json

Firewall and Ports

Configure firewall for Factorio:

# Default game port (TCP/UDP)
GAME_PORT=34197

# Optional RCON port
RCON_PORT=27015

# Configure UFW
sudo ufw allow 34197/tcp
sudo ufw allow 34197/udp
sudo ufw allow 27015/tcp

# For iptables
sudo iptables -A INPUT -p tcp --dport 34197 -j ACCEPT
sudo iptables -A INPUT -p udp --dport 34197 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 27015 -j ACCEPT

# Verify
sudo ufw status numbered

Running with Systemd

Create systemd service:

sudo tee /etc/systemd/system/factorio.service > /dev/null <<'EOF'
[Unit]
Description=Factorio Headless Server
After=network.target
Wants=network-online.target

[Service]
Type=simple
User=factorio
Group=factorio
WorkingDirectory=/home/factorio/factorio-data
EnvironmentFile=/home/factorio/factorio-server/server.env

ExecStart=/home/factorio/factorio-server/start_server.sh

Restart=on-failure
RestartSec=10
StandardOutput=journal
StandardError=journal

# Resource limits
LimitNOFILE=65536
LimitNPROC=4096

# Security
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ProtectHome=yes
ReadWritePaths=/home/factorio/factorio-data

[Install]
WantedBy=multi-user.target
EOF

Create environment file:

sudo tee /home/factorio/factorio-server/server.env > /dev/null <<'EOF'
SAVE_NAME=factorio_saves
ADMIN_PASSWORD=changeme
GAME_PASSWORD=
EOF

sudo chown factorio:factorio /home/factorio/factorio-server/server.env
sudo chmod 600 /home/factorio/factorio-server/server.env

Enable and start:

sudo systemctl daemon-reload
sudo systemctl enable factorio.service
sudo systemctl start factorio.service
sudo systemctl status factorio.service

Monitor logs:

sudo journalctl -u factorio.service -f
tail -f /home/factorio/factorio-data/logs/factorio_$(date +%Y%m%d).log

Backup and Recovery

Create automated backup script:

sudo tee /home/factorio/backup_factorio.sh > /dev/null <<'EOF'
#!/bin/bash

DATA_DIR="/home/factorio/factorio-data"
BACKUP_DIR="$DATA_DIR/backups"
RETENTION_DAYS=30
TIMESTAMP=$(date +%Y%m%d_%H%M%S)

mkdir -p "$BACKUP_DIR"

# Backup saves and configurations
tar -czf "$BACKUP_DIR/factorio_backup_${TIMESTAMP}.tar.gz" \
    -C "$DATA_DIR" saves/ mods/ \
    2>/dev/null

if [ $? -eq 0 ]; then
    SIZE=$(du -sh "$BACKUP_DIR/factorio_backup_${TIMESTAMP}.tar.gz" | awk '{print $1}')
    echo "[$(date)] Backup created: ${SIZE}"
else
    echo "[$(date)] Backup failed!" >&2
    exit 1
fi

# Cleanup old backups
find "$BACKUP_DIR" -name "factorio_backup_*.tar.gz" -mtime +${RETENTION_DAYS} -delete
EOF

sudo chmod +x /home/factorio/backup_factorio.sh
sudo chown factorio:factorio /home/factorio/backup_factorio.sh

Add to crontab:

sudo tee -a /var/spool/cron/crontabs/factorio > /dev/null <<'EOF'
0 3 * * * /home/factorio/backup_factorio.sh >> /home/factorio/factorio-data/logs/backup.log 2>&1
EOF

Restore backup:

sudo systemctl stop factorio.service
BACKUP="/home/factorio/factorio-data/backups/factorio_backup_20240101_030000.tar.gz"
sudo -u factorio tar -xzf "$BACKUP" -C /home/factorio/factorio-data/
sudo systemctl start factorio.service

Administration

Create admin management script:

sudo tee /home/factorio/manage_admins.sh > /dev/null <<'EOF'
#!/bin/bash

# Add admin to whitelist
add_admin() {
    python3 /home/factorio/factorio-server/rcon_client.py "/promote $1"
}

# Remove admin
remove_admin() {
    python3 /home/factorio/factorio-server/rcon_client.py "/demote $1"
}

case "$1" in
    add)
        add_admin "$2"
        ;;
    remove)
        remove_admin "$2"
        ;;
    *)
        echo "Usage: $0 {add|remove} playername"
        ;;
esac
EOF

sudo chmod +x /home/factorio/manage_admins.sh

Monitoring

Create monitoring script:

sudo tee /home/factorio/monitor_factorio.sh > /dev/null <<'EOF'
#!/bin/bash

echo "=== Factorio Server Status ==="
echo "Timestamp: $(date)"
echo ""

# Service status
if systemctl is-active --quiet factorio.service; then
    echo "✓ Service is running"
else
    echo "✗ Service is NOT running"
    exit 1
fi

# Process info
PID=$(pgrep -f "factorio.*start-server")
if [ ! -z "$PID" ]; then
    MEM=$(ps -p $PID -o rss= | awk '{print $1/1024 " MB"}')
    CPU=$(ps -p $PID -o %cpu= | awk '{print $1 "%"}')
    echo "Memory: $MEM"
    echo "CPU: $CPU"
fi

# Port status
echo ""
if ss -tlnp | grep -q ":34197"; then
    echo "✓ Game port 34197 listening"
else
    echo "✗ Game port not listening"
fi

# Disk usage
echo ""
USAGE=$(df -h /home/factorio/factorio-data | awk 'NR==2 {print $5}')
echo "Disk usage: $USAGE"

# Latest save file
echo ""
LATEST=$(ls -t /home/factorio/factorio-data/saves/*.zip 2>/dev/null | head -1)
if [ ! -z "$LATEST" ]; then
    MODIFIED=$(date -r "$LATEST" '+%Y-%m-%d %H:%M:%S')
    echo "Latest save: $(basename $LATEST) - $MODIFIED"
fi
EOF

sudo chmod +x /home/factorio/monitor_factorio.sh

Conclusion

Your Factorio headless server is now fully operational with RCON support, mod capability, and automated backups. Factorio provides engaging cooperative factory-building experiences with incredible longevity and depth.

Key takeaways:

  • Factorio is lightweight and can run on modest hardware
  • Configure server settings appropriately for your playstyle
  • Use mods to enhance gameplay experiences
  • Implement regular automated backups
  • Monitor server performance, which is generally stable
  • Use admin commands for community management
  • Plan regular maintenance during off-peak hours

A well-maintained Factorio server can support hundreds of hours of collaborative factory building for your community.