Keep pack, loader, Java, and memory together
A CurseForge pack declares its Minecraft version, mod loader, mods, and configuration. AUTO_CURSEFORGE reads that manifest and installs the matching Forge or Fabric loader automatically.
Pin a tested modpack file and use the loader, Java version, and memory requirements specified for that release.
Prerequisites
- a CurseForge pack with server support
- the pack's normal file ID, not its separate server-file download
- enough RAM and disk for the selected pack
- the Java image tag required by its Minecraft version
- the same pack release on test clients
- a complete backup before importing an existing world
Compose baseline with a pinned file
The file ID below is the pinned ATM8 example used by the itzg documentation. It is intentionally an older, concrete example; replace the slug, file ID, Java tag, and memory together for your chosen pack.
services:
mc:
image: itzg/minecraft-server:java17
restart: unless-stopped
ports:
- "25565:25565"
environment:
EULA: "TRUE"
TYPE: AUTO_CURSEFORGE
CF_SLUG: all-the-mods-8
CF_FILE_ID: "4248390"
CF_API_KEY_FILE: /run/secrets/cf_api_key
MEMORY: 6G
mem_limit: 8g
volumes:
- ./data:/data
- ./downloads:/downloads:ro
secrets:
- cf_api_key
secrets:
cf_api_key:
file: ./cf_api_key.secret
Create cf_api_key.secret beside Compose, restrict its host permissions, and keep it out of version control. A personal key is optional while the image ships a key; if you do not supply one, remove both CF_API_KEY_FILE and the secret declarations.
Validate without exposing the secret value:
docker compose config
docker compose pull mc
Why the file ID matters
Without CF_FILE_ID, the image locates the newest pack file again on a later startup. That makes an ordinary restart an implicit pack and loader upgrade.
You can pin with a specific file URL, CF_FILE_ID, or CF_FILENAME_MATCHER. A numeric file ID is the clearest operational record. Do not select the pack's separately published server file: it normally lacks the CurseForge manifest required by AUTO_CURSEFORGE.
First start on empty data
Use a fresh ./data for the first installation:
mkdir -p data downloads
docker compose up -d
docker compose logs -f mc
The initial start downloads many artifacts and can take considerably longer than Paper. Wait for the server-ready message. If it fails, preserve the first error before the restart policy hides it behind repeated logs.
Handle projects that require manual downloads
CurseForge authors can prohibit third-party automated downloads. The image then logs a “Mods Need Download” list.
For each listed project:
- open the provided page in a browser
- download the exact requested file
- copy it into the host
./downloadsdirectory - run
docker compose up -d mcagain
Do not replace this with a guessed curl URL. The itzg documentation explicitly requires browser downloads for these restricted files.
Validate the installed pack
docker compose exec mc rcon-cli version
docker compose exec mc sh -c 'find /data/mods -maxdepth 1 -type f -name "*.jar" | wc -l'
docker compose logs --since=20m mc
Then join with the exact matching client pack and check custom blocks, items, dimensions, recipes, and a reconnect. Create the first backup after this validation.
Client-only files and synchronization
Use CF_EXCLUDE_MODS only for projects incorrectly delivered to the server, and CF_FORCE_INCLUDE_MODS only when metadata incorrectly marks a required server mod as client-only. Report the metadata problem upstream.
CF_FORCE_SYNCHRONIZE: "TRUE" synchronizes installed files with the selected pack and can remove files. Back up first and remove the flag when the correction is complete.
Upgrade and roll back the pack
Treat a new file ID as a server update:
- make an application-aware backup and stopped full copy
- change only
CF_FILE_ID - start under supervision
- test with the matching client
- restore the previous Compose and
/datatogether if validation fails
Follow the safe Docker update and rollback runbook. Never start an older pack against world data already migrated by the newer one.
Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
| Manifest missing | A server file was selected | Pin the normal modpack file instead |
| No matching file | Slug and file ID do not belong together | Copy both from the same pack release |
| Manual-download list appears | Distribution is restricted | Download exact files in a browser into /downloads |
| Unsupported class version | Wrong Java image | Use the pack's required Java release |
| Exit 137 during startup | Heap/container/host memory is insufficient | Use the OOMKilled runbook |
| Client cannot join | Pack or loader release differs | Install the exact same client pack file |
Next steps
- Diagnose repeated failed starts with the restart-loop runbook.
- Protect API keys and the host with the Docker security baseline.