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.
115 lines
5.1 KiB
Markdown
115 lines
5.1 KiB
Markdown
# 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`):
|
|
|
|
1. **Wipe** — every file in `/data/plugins/` matching `REMOVE_OLD_MODS_INCLUDE` and not matching `REMOVE_OLD_MODS_EXCLUDE` is deleted.
|
|
2. **Download** — every URL in `PLUGINS` and every Modrinth project in `MODRINTH_PROJECTS` is fetched into `/data/plugins/`.
|
|
3. **Copy** — anything listed in `COPY_PLUGINS_SRC` (or container paths inside `PLUGINS`) is rsynced in.
|
|
|
|
Our current compose has:
|
|
|
|
```yaml
|
|
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
|
|
|
|
```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:
|
|
|
|
```bash
|
|
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):
|
|
|
|
```bash
|
|
# 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:
|
|
|
|
```yaml
|
|
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
|