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.
Do not independently choose a newer loader because it looks preferable. Pin one tested modpack file and use the Java and memory requirements published 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" is a troubleshooting switch, not a harmless permanent default. Synchronization intentionally reconciles installed files with the selected pack. 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
- Compare this workflow with the Modrinth modpack guide.
- Diagnose repeated failed starts with the restart-loop runbook.
- Protect API keys and the host with the Docker security baseline.