- Shell 46.6%
- Python 29%
- Go Template 24.4%
| .forgejo/workflows | ||
| scripts | ||
| templates | ||
| extensions.yaml | ||
| LICENSE | ||
| mirror-watch.tsv | ||
| README.md | ||
geyser-ci — keep a Geyser stack on the bleeding edge
A small, reusable control plane for Geyser + Floodgate + Geyser extensions on a Velocity proxy (itzg/mc-proxy, Java 21). It automatically tracks the latest Geyser/Floodgate builds and keeps extensions current, rebuilding the ones whose upstream has gone away.
Nothing here is tied to a particular server: paths, the proxy container name and the Git host
are all supplied through environment variables, so you can drop it onto your-server as-is.
Why
Geyser has no stable releases — it ships continuous CI builds and bumps its supported Bedrock/Java protocol whenever Mojang updates. If you lag, a phone/console auto-update can lock Bedrock players out. So we track the latest build automatically. Extensions ride Geyser's API and can break on those bumps.
Two update tiers
- Modrinth-maintained extensions (their authors rebuild + publish): we just fetch the newest build that is (a) API-compatible with the running Geyser and (b) fits the proxy JRE. No build on our side.
- Unmaintained / discontinued (e.g. GeyserExtras, archived upstream): we rebuild it
against the latest Geyser
coreand publish the jar; the host updater then pulls it like any other extension.
Components
1. Host updater (the engine)
scripts/geyser-edge-update.sh (+ scripts/update_modrinth_ext.py), run from cron (e.g.
10 4 * * *, just after a nightly backend restart).
- Geyser + Floodgate: pull the latest build from
download.geysermc.org/v2— sha256-verified, old jar backed up. - Modrinth extensions (
extensions.yaml): newest build whoseextension.yml api:is compatible and whose base main-class bytecode fits the proxy JRE (so a Java-24 build can never brick a Java-21 proxy — it auto-falls-back to the newest JRE-safe build). - GeyserExtras: pulls
GeyserExtras-Extension.jarfrom the latest release of your fork. - Restarts the proxy only if a jar actually changed (no-op / no disruption on quiet days).
Configure it with environment variables:
| var | meaning |
|---|---|
SERVER_DIR |
server root that contains proxy/plugins (required) |
VELOCITY_CONTAINER |
Docker container name/id of the Velocity + Geyser proxy (required) |
FORGEJO_URL |
base URL of the Forgejo/Gitea instance hosting your GeyserExtras fork + CI |
GEYSEREXTRAS_REPO |
owner/repo of your self-built GeyserExtras release source |
2. GeyserExtras rebuild pipeline (Forgejo Actions)
.forgejo/workflows/rebuild-geyserextras.yml (install into your GeyserExtras fork). On
schedule / dispatch / new-Geyser-version-line: bump the core dep to the latest Geyser version,
:extension:shadowJar on JDK 21, and publish a geyser-<ver> release with
GeyserExtras-Extension.jar. It runs on a self-hosted runner (label nas-build) and is
action-free (no actions/checkout / setup-java — plain git + an eclipse-temurin:21-jdk
container).
Forks (in your own Git org)
| repo | upstream | mode |
|---|---|---|
| GeyserExtras | github.com/GeyserExtras/GeyserExtras (archived) | you maintain (patched branch) |
| GeyserFloatingPoints | github.com/oryxel1/GeyserFloatingPoints | pull-mirror (fetch from Modrinth) |
| GeyserReversion | github.com/oryxel1/GeyserReversion | pull-mirror (fetch from Modrinth) |
| MCXboxBroadcast | github.com/MCXboxBroadcast/Broadcaster | pull-mirror (fetch from Modrinth) |
| BetterBreaking | github.com/onechris-dev/BetterBreaking | pull-mirror (candidate) |
| EmoteOffhand | github.com/GeyserMC/EmoteOffhandExtension | pull-mirror (candidate) |
The pull-mirrors are insurance: if any upstream goes the way of GeyserExtras, flip it to a
patched branch + add it to the rebuild pipeline.
Run by hand
SERVER_DIR=/path/to/server VELOCITY_CONTAINER=my-velocity \
./scripts/geyser-edge-update.sh
Idempotent. Logs to $SERVER_DIR/geyser-edge/update.log; state (build numbers, backups) in
$SERVER_DIR/geyser-edge/state/.