No description
  • Python 71.2%
  • HTML 22%
  • CSS 6.4%
  • Dockerfile 0.4%
Find a file
Brian 570a2ce597
All checks were successful
Build and Deploy / build (push) Successful in 8s
Build and Deploy / deploy (push) Successful in 5s
Link to xbox.com profile for patrons unsure of their gamertag
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-12 15:24:39 -06:00
.forgejo/workflows Add Forgejo build/deploy workflow and Portainer-ready compose file 2026-06-12 13:42:33 -06:00
app Link to xbox.com profile for patrons unsure of their gamertag 2026-06-12 15:24:39 -06:00
.gitignore Initial release: Patreon-to-Minecraft whitelist sync service 2026-06-12 13:38:38 -06:00
docker-compose.yml Changae default port for portainer 2026-06-12 14:22:54 -06:00
Dockerfile Initial release: Patreon-to-Minecraft whitelist sync service 2026-06-12 13:38:38 -06:00
README.md Add Forgejo build/deploy workflow and Portainer-ready compose file 2026-06-12 13:42:33 -06:00
requirements.txt Initial release: Patreon-to-Minecraft whitelist sync service 2026-06-12 13:38:38 -06:00

PatreonLink

A dockerized service that whitelists your Patreon supporters on a Minecraft server using their Xbox accounts, and removes them when their membership lapses.

  • No environment variables. All settings (Patreon/Discord credentials, Minecraft connection, sync interval) live in a SQLite database on the /data volume and are managed through the web GUI.
  • Web GUI with a first-run wizard: enter Patreon API credentials, connect your creator account via OAuth, pick a campaign, and test every connection.
  • Sync loop runs every 5 minutes (configurable): new active patrons with a linked gamertag are whitelisted; lapsed patrons are removed.
  • Patron self-service portal (/link): Patreon doesn't expose Xbox gamertags, so patrons log in with Discord. If their Discord account is connected on Patreon they're matched automatically; otherwise they can claim their membership by Patreon email. They then enter their Xbox gamertag, which is verified and resolved to an XUID via the public GeyserMC API.

Run it

docker-compose.yml deploys the prebuilt image from the registry — use it directly as a Portainer stack, or locally:

docker compose up -d            # pulls git.thenymans.com/brian/patreonlink:latest
# or build from source:
docker build -t git.thenymans.com/brian/patreonlink:latest .
docker compose up -d

Open http://localhost:8000 — you'll be taken to the first-run setup to create an admin password. Everything else is configured from the admin pages.

CI/CD

Pushes to main run .forgejo/workflows/deploy.yml: build and push the image to the Forgejo registry (:latest and :<sha>), then update the Portainer stack pinned to that commit's image. Required repository secrets:

Secret Purpose
REGISTRY_USER / REGISTRY_PASSWORD Push access to git.thenymans.com's container registry
PORTAINER_TOKEN Portainer API key
PORTAINER_STACK_ID Numeric ID of the PatreonLink stack
PORTAINER_ENDPOINT_ID Numeric ID of the Portainer environment

Create the stack once in Portainer (paste docker-compose.yml); the workflow updates it on every push afterwards.

Setup walkthrough

  1. General settings — set the public base URL (the address patrons will use, e.g. https://link.example.com). OAuth redirect URLs are derived from it. Put the app behind HTTPS (reverse proxy) for production.
  2. Patreon — create an API client at patreon.com/portal → Clients & API Keys, set its redirect URI to the one shown on the page, paste the client ID/secret, then click Connect Patreon account and Test connection.
  3. Discord — create an app at discord.com/developers, add the redirect shown on the page, paste the client ID/secret. This powers the patron portal login.
  4. Minecraft — pick one:
    • RCON (Java servers, including Geyser/Floodgate setups): host, port, password, and the add/remove command templates. For Floodgate use fwhitelist add {gamertag} / fwhitelist remove {gamertag}. Enable RCON in server.properties (enable-rcon, rcon.port, rcon.password).
    • allowlist.json (Bedrock Dedicated Server): mount your server directory into the container (see docker-compose.yml) and point at allowlist.json. BDS reloads the file automatically.
  5. Share https://your-base-url/link with your patrons.

How matching works

Each sync pulls all campaign members from Patreon (name, email, membership status, and — when the patron has connected it — their Discord user ID). A patron is whitelisted when their status is active_patron and a gamertag is on file. Gamertags arrive three ways:

  1. Patron logs into /link with Discord; their Discord ID matches the one Patreon reported → they enter their gamertag.
  2. Patron's Discord isn't on Patreon → they claim by Patreon email, then enter their gamertag.
  3. The admin sets a gamertag directly on the dashboard.

Notes

  • Data (settings + links + logs) persists in ./data/patreonlink.db.
  • The admin pages are password-protected, but there is no rate limiting or CSRF protection beyond same-site cookies — don't expose the admin UI to the open internet without a reverse proxy in front, and always use HTTPS.
  • Local development: pip install -r requirements.txt then uvicorn app.main:app --reload (state goes to ./data/).