Replaces EZShop 1.0-SNAPSHOT (bespoke, sell-only, 27-slot) and Kiranhart
AuctionHouse 1.4.6 (ARR no-LICENSE, dupe history) with a single GPL-3
stack: ExcellentShop 5.0.1 + CoinsEngine 2.7.0 + nightcore 2.15.3.
Per SHOP-SYSTEM-DECISION.md (commit 9565f0b), Stack A wins on three
counts: GPL-3 source (vs ARR/proprietary), unified theme across shop
and AH, single-vendor support story under NightExpress.
Jars sourced from upstream Reposilite repo.nightexpressdev.com — same
artefacts a local mvn package would produce, just reproducible without
the alex9849 integration that breaks on TLS handshake. SHA256SUMS
committed for receipt; never re-fetched at swap time.
Bundle:
build/ — three jars + SHA256SUMS (~2.1MB total)
configs/ — post-first-run overrides (chest module off, /shop alias,
AH 1% tax + BIN+bid + 10 listings matches Kiranhart)
scripts/ — swap.sh, rollback.sh, lp-shop-migration.sh,
lp-shop-rollback.sh, docker-compose.patch.yml
itzg integration: COPY_PLUGINS_SRC=/plugins-custom mount per
ITZG-CUSTOM-JAR-PERSISTENCE.md, plus REMOVE_OLD_MODS_EXCLUDE expanded
with the three new globs.
LP migration grants default-tier excellentshop.* + coinsengine.*
nodes; staff tier gets *.admin equivalents to legacy
auctionhouse.moderator. Group prefixes/suffixes untouched per
feedback_lp_prefixes_locked.md.
DOES NOT touch live /data/plugins/EZShop or /data/plugins/AuctionHouse
— staging only. Operator runs swap.sh in scheduled maintenance window.
Refs: SHOP-SYSTEM-DECISION.md, AUDIT-2026-05-07.md F-11,
ITZG-CUSTOM-JAR-PERSISTENCE.md, MIGRATION-PLAN-EXCELLENTSHOP.md.
5.1 KiB
itzg/minecraft-server — Custom Plugin Jar Persistence
Date: 2026-05-07
Context: ChatChat-1.0.0-SNAPSHOT-racked-1.jar was dropped manually into /data/plugins/ and disappeared after the next container restart.
1. Why the ChatChat jar disappeared
itzg's entrypoint runs this sequence on every start (when REMOVE_OLD_MODS=TRUE):
- Wipe — every file in
/data/plugins/matchingREMOVE_OLD_MODS_INCLUDEand not matchingREMOVE_OLD_MODS_EXCLUDEis deleted. - Download — every URL in
PLUGINSand every Modrinth project inMODRINTH_PROJECTSis fetched into/data/plugins/. - Copy — anything listed in
COPY_PLUGINS_SRC(or container paths insidePLUGINS) is rsynced in.
Our current compose has:
REMOVE_OLD_MODS: "true"
REMOVE_OLD_MODS_INCLUDE: "*.jar"
REMOVE_OLD_MODS_EXCLUDE: "AuthLimbo*.jar"
So step 1 deletes every *.jar except AuthLimbo*.jar. The hand-placed ChatChat jar was not in any download list and not in the exclude glob, so it was nuked and never re-downloaded. AuthLimbo survives only because we explicitly excluded it.
This is documented behaviour, not a bug — itzg's design assumes plugins are declarative, sourced from URLs/Modrinth/COPY_PLUGINS_SRC, never hand-dropped.
2. Three mechanisms to make custom jars persist
| # | Mechanism | How |
|---|---|---|
| A | REMOVE_OLD_MODS_EXCLUDE glob |
Add ChatChat*.jar to the exclude list. Quick but fragile — depends on filename and only protects already-present files; doesn't handle re-deploy on a fresh volume. |
| B | COPY_PLUGINS_SRC bind-mount |
Mount a host dir of custom jars read-only at e.g. /plugins-custom, set COPY_PLUGINS_SRC=/plugins-custom. Entrypoint copies them in after the wipe. Survives wipes, version-controllable, declarative. |
| C | PLUGINS URL → Forgejo Release |
Upload the jar as a Forgejo Release asset, add the download URL to the existing PLUGINS list. Same flow as EssentialsX/spark already use. |
Note: PLUGINS also accepts container paths directly (e.g. PLUGINS=/plugins-custom/ChatChat.jar), so mechanism B can collapse into the existing PLUGINS env if preferred.
3. Recommended path for racked.ru — Mechanism B
COPY_PLUGINS_SRC is the cleanest fit:
- Custom jars live in the repo (or
/opt/docker/minecraft-custom-plugins/), so they're under version control / backup. - No external host dependency (Forgejo could be down — bind mount can't be).
- Build artefacts from
staging/chatchat/drop straight into the mounted dir.
docker-compose.yml diff
MODRINTH_LOADER: paper
SPIGET_RESOURCES: ""
REMOVE_OLD_MODS: "true"
REMOVE_OLD_MODS_INCLUDE: "*.jar"
- REMOVE_OLD_MODS_EXCLUDE: "AuthLimbo*.jar"
+ REMOVE_OLD_MODS_EXCLUDE: "AuthLimbo*.jar,ChatChat*.jar"
+ COPY_PLUGINS_SRC: "/plugins-custom"
volumes:
- /opt/docker/minecraft:/data
+ - /opt/docker/minecraft-custom-plugins:/plugins-custom:ro
Then on the host:
sudo mkdir -p /opt/docker/minecraft-custom-plugins
sudo cp staging/chatchat/ChatChat-1.0.0-SNAPSHOT-racked-1.jar \
/opt/docker/minecraft-custom-plugins/
sudo cp /opt/docker/minecraft/plugins/AuthLimbo-*.jar \
/opt/docker/minecraft-custom-plugins/ # optional: source-of-truth
sudo chown -R 1000:1000 /opt/docker/minecraft-custom-plugins
docker compose up -d --force-recreate mc
The EXCLUDE line still lists ChatChat*.jar so that if the bind mount ever vanishes, an existing copy in /data/plugins/ isn't wiped — belt and braces.
4. Bonus — Forgejo Release upload procedure (mechanism C)
If you'd rather host the jar at git.s8n.ru (e.g. for cobblestone or a friend's box without the bind mount):
# 1. Tag and push
cd staging/chatchat
git tag -a chatchat-racked-1 -m "ChatChat racked build 1"
git push origin chatchat-racked-1
# 2. Create release + upload asset (uses Forgejo PAT from ~/.config/veilor-forgejo)
TOKEN=$(cat ~/.config/veilor-forgejo/pat)
curl -X POST \
-H "Authorization: token $TOKEN" \
-H "Content-Type: application/json" \
https://git.s8n.ru/api/v1/repos/s8n/minecraft-server/releases \
-d '{"tag_name":"chatchat-racked-1","name":"ChatChat racked-1","draft":false}'
RELEASE_ID=$(curl -s -H "Authorization: token $TOKEN" \
https://git.s8n.ru/api/v1/repos/s8n/minecraft-server/releases/tags/chatchat-racked-1 \
| jq -r .id)
curl -X POST \
-H "Authorization: token $TOKEN" \
-H "Content-Type: application/java-archive" \
--data-binary @ChatChat-1.0.0-SNAPSHOT-racked-1.jar \
"https://git.s8n.ru/api/v1/repos/s8n/minecraft-server/releases/$RELEASE_ID/assets?name=ChatChat-1.0.0-SNAPSHOT-racked-1.jar"
Then add to compose:
PLUGINS: |
...existing...
https://git.s8n.ru/s8n/minecraft-server/releases/download/chatchat-racked-1/ChatChat-1.0.0-SNAPSHOT-racked-1.jar
References
- itzg docs: https://docker-minecraft-server.readthedocs.io/en/latest/mods-and-plugins/
- Source: https://github.com/itzg/docker-minecraft-server/blob/master/docs/mods-and-plugins/index.md
- Issue #310 (COPY_PLUGINS_SRC behaviour): https://github.com/itzg/docker-minecraft-server/issues/310