Factorio Field guide

Install mods on a Factorio headless server via Mod Portal API

Automate mod installations and updates on headless Factorio servers: authenticate via the Mod Portal API, download dependencies, and manage mod-list.json.

Install mods on a Factorio headless server via Mod Portal API

Managing modifications on a dedicated Factorio server without a desktop user interface (headless Linux) often presents logistical challenges for server administrators. Manually downloading dozens of zip archives in a desktop browser and uploading them via SFTP is tedious, introduces version mismatches, and frequently breaks inter-mod dependencies.

The official Wube Mod Portal exposes a public REST API that allows operators to query metadata, inspect compatibility, and fetch releases directly from the Linux command line using curl and jq. This guide explains how to authenticate with your service token, query mod dependencies, download archives, and configure mod-list.json.

Locating your service token in player-data.json#

Downloading mod archives from official Wube endpoints requires authentication; anonymous archive retrieval is rejected.

Authentication utilizes your Factorio service token. If the game client or server has run previously on your host, credentials are saved inside player-data.json:

bash
cat /opt/factorio/player-data.json | grep -E "(service-username|service-token)"

Set these credentials as environment variables for scripting:

bash
FACTORIO_USER="your_username"
FACTORIO_TOKEN="your_token_from_player_data"

Querying mod metadata via the Mod Portal API#

Before downloading an archive, retrieve the release manifest to verify compatibility with your Factorio server branch (e.g. Factorio 2.0 or 1.1) and inspect dependency requirements.

Issue a public GET query against the API (using the widely deployed flib library as an example):

bash
curl -s "https://mods.factorio.com/api/mods/flib" | jq '.releases[-1] | {version, factorio_version, file_name, download_url, sha1}'

The response outputs JSON containing the latest release version, compatible Factorio runtime releases, the sha1 checksum, and the target download_url.

Downloading mod packages with curl#

Using the extracted download path and user credentials, stream the zip package directly into your server's mods directory:

bash
MOD_URL="/api/downloads/data/flib_0.15.0.zip"
OUTPUT_FILE="/opt/factorio/mods/flib_0.15.0.zip"

curl -L -f -o "$OUTPUT_FILE" \
  "https://mods.factorio.com${MOD_URL}?username=${FACTORIO_USER}&token=${FACTORIO_TOKEN}"

Verify archive integrity against the expected checksum:

bash
sha1sum "$OUTPUT_FILE"

The -L flag is essential because the portal API issues an HTTP 302 redirect toward cloud storage CDN endpoints.

Activating installed packages in mod-list.json#

The Factorio dedicated engine evaluates which packages to load from the mods folder by parsing mod-list.json.

Construct or update your active mod manifest using jq:

bash
cat << 'EOF' | sudo tee /opt/factorio/mods/mod-list.json
{
  "mods": [
    {
      "name": "base",
      "enabled": true
    },
    {
      "name": "flib",
      "enabled": true
    }
  ]
}
EOF

Validate JSON syntax:

bash
jq . /opt/factorio/mods/mod-list.json > /dev/null && echo "mod-list.json is valid"

Execute a configuration verification dry-run without starting a live game loop:

bash
/opt/factorio/bin/x64/factorio --check-config

When the command reports Configuration check successful, all mod dependencies are resolved and the dedicated server is ready for multiplayer sessions.

For large overhaul modpacks (Space Age, Krastorio 2, Space Exploration) containing 50+ packages, server operators manage dependencies through an integrated server management platform, where mod catalogue synchronization and dependency validation are handled automatically.

Sources#