尚未收集儲存庫資訊。
尚未偵測到更新。GitHub 發布版本後會顯示在這裡。
A lightweight Go web controller for Palworld server containers with auto-pause, captcha verification, Discord integration, backups, and RCON broadcasting.
翻譯準備中
取自儲存庫 README
正在載入完整 README。
檢視完整 README ↗A lightweight web application that controls and manages a Palworld server running in a Docker container, including auto-pausing/stopping on idle, scheduled RCON broadcasts, automatic backups, and Discord invite link caching.
DOCKER_HOST or standard socket).go run .
go test -v ./...
go build -o palworld-starter .
Set the following environment variables:
| Variable | Description | Default |
|---|---|---|
DOCKER_HOST | URI of the Docker daemon socket | unix:///var/run/docker.sock |
DOCKER_CONTAINER_NAME | Name of the container managing Palworld | my_container |
DISCORD_BOT_TOKEN | Token for the Discord bot | Optional |
DISCORD_GUILD_ID | Guild ID of your Discord Server | Optional |
DISCORD_CHANNEL_ID | Channel ID for generating invites | Optional |
DISCORD_FALLBACK_URL | Fallback invitation link | https://discord.gg/XXXXXINVITENOTFOUNDXXXXXX |
SERVER_ADDRESS | Public game address shown on the page (IP:port) | 80.66.59.216:8211 |
REST_API_HOST | Hostname/IP of the Palworld REST API | host.docker.internal |
REST_API_URL | Full REST API base URL, e.g. https://pal.example.com:8212 (overrides REST_API_HOST; /v1/api is appended when no path is given). HTTPS certificates are verified; add a private CA via SSL_CERT_FILE | unset (http://REST_API_HOST:8212) |
WEBSITE_URL | Website URL used for in-game broadcasts | https://pal.wowcraft.pw/ |
GOOGLE_SITE_VERIFICATION | Google Search Console verification token | Optional |
BING_SITE_VERIFICATION | Bing Webmaster Tools verification token | Optional |
YANDEX_SITE_VERIFICATION | Yandex Webmaster verification token | Optional |
SERVERS | Comma-separated server ids to enable multi-server mode | unset (single server) |
ADMIN_PASSWORD | Palworld REST API admin password | scraped from the game container's env |
ADMIN_GUI_PASSWORD | Global admin-GUI login password. Enables the admin GUI at /admin when set | unset (admin GUI disabled) |
SESSION_KEY | Secret used to encrypt session cookies; set it so sessions survive restarts | random per start |
STOP_TOKEN | Shared secret for POST /stop via the X-Stop-Token header (needed behind a reverse proxy) | unset (loopback-only) |
ALLOWED_HOSTS | Comma-separated hostnames the site is served under. When WEBSITE_URL is unset, canonical/sitemap URLs only use a request host from this list (else the first entry) | unset (any Host header) |
TRUST_PROXY_HEADERS | Set to true behind a reverse proxy so rate limits use the client IP from X-Forwarded-For instead of the proxy's address. Never enable without a proxy that sets the header | false |
TURNSTILE_SITE_KEY / TURNSTILE_SECRET_KEY | Enable Cloudflare Turnstile on the captcha pages; the token is verified server-side before a server is started or extended. Set both or neither | unset (disabled) |
COOKIE_SECURE | true always marks the session cookie Secure, false never; unset sets it automatically for HTTPS requests (directly or via X-Forwarded-Proto: https) | auto |
robots.txt paths, and canonical <link> elements use WEBSITE_URL when set, otherwise the requesting host header. This ensures search engine crawlers index the correct domain (e.g., freepalworld.wowcraft.pw). In production set WEBSITE_URL or ALLOWED_HOSTS so a forged Host header cannot inject another domain (e.g. via a caching proxy).GOOGLE_SITE_VERIFICATION, BING_SITE_VERIFICATION, or YANDEX_SITE_VERIFICATION environment variables to automatically output verification tags into the landing page <head>.google*.html, yandex_*.html, pinterest-*.html, BingSiteAuth.xml) directly inside the static/ folder. The application serves them directly at the root (e.g., /google123456789.html).Set SERVERS to a comma-separated list of server ids to manage several
Palworld containers from one page. Each server is configured with its own
variables (id uppercased, non-alphanumeric characters replaced by _):
| Variable | Description | Default |
|---|---|---|
SERVER_<ID>_CONTAINER | Docker container name | the id |
SERVER_<ID>_NAME | Display name on the website | the id |
SERVER_<ID>_ADDRESS | Public game address (IP:port) | empty |
SERVER_<ID>_RESTHOST | Hostname/IP of the Palworld REST API | host.docker.internal |
SERVER_<ID>_RESTPORT | Host port of the container's Palworld REST API | 8212 |
SERVER_<ID>_RESTURL | Full REST API base URL (http or https), overrides RESTHOST/RESTPORT | unset |
SERVER_<ID>_ADMIN_PASSWORD | REST API admin password for this server | ADMIN_PASSWORD |
SERVER_<ID>_ADMIN_GUI_PASSWORD | Seeds a per-server admin-GUI password granting access to this server only | unset |
Example:
environment:
SERVERS: "pal1,pal2"
SERVER_PAL1_CONTAINER: "palworld-1"
SERVER_PAL1_NAME: "Palworld Main"
SERVER_PAL1_ADDRESS: "80.66.59.216:8211"
SERVER_PAL1_RESTHOST: "palworld-1"
SERVER_PAL1_RESTPORT: "8212"
SERVER_PAL2_CONTAINER: "palworld-2"
SERVER_PAL2_NAME: "Palworld Hardcore"
SERVER_PAL2_ADDRESS: "80.66.59.216:8221"
SERVER_PAL2_RESTHOST: "palworld-2"
SERVER_PAL2_RESTPORT: "8222"
Each server keeps its own timer (/hostmem/gamecontroller-<id>-time_remaining.json),
tickers, backups and boot page; without SERVERS the legacy single-server
variables keep working unchanged.
Set ADMIN_GUI_PASSWORD to enable an authenticated admin dashboard at /admin.
Without it the admin routes are not registered at all (they return 404).
ADMIN_GUI_PASSWORD) grants access to every managed
server.SERVER_<ID>_ADMIN_GUI_PASSWORD. Per-server passwords are stored as salted
PBKDF2-HMAC-SHA256 hashes in admin.json in the state directory (hashes from
older versions are upgraded automatically on the next successful login).ADMIN_GUI_PASSWORD or seeded password
still works for now but logs a warning at startup — please change it.Login is a single password field: the app resolves it to the matching scope.
Repeated failed logins lock out the client IP with exponential backoff (5 free
attempts, then 1 minute doubling up to 1 hour), with an additional global limit
across all clients. Sessions are the same encrypted cookies used elsewhere and
last 8 hours; logging out (a CSRF-protected POST) revokes the session
server-side. Revocations are stored in STATE_DIR/admin-revoked.json until the
session would have expired, so a copied cookie stays dead across restarts even
with a fixed SESSION_KEY; the app refuses to start with the admin GUI enabled
if that file cannot be written. All admin actions are CSRF-protected.
Use the admin GUI only over HTTPS (a TLS reverse proxy in front of port
5000). The session cookie is HttpOnly and SameSite=Lax, and is marked
Secure automatically for HTTPS requests (see COOKIE_SECURE). Behind a proxy,
set TRUST_PROXY_HEADERS=true so login rate limits apply per client.
Add daily (at HH:MM) or one-time (at a specific date/time) reboots per
server. Each schedule has an announcement lead time (default 10 minutes). Times
are interpreted in the container's local timezone — set the TZ environment
variable to control it (defaults to UTC).
Before a reboot, players are warned in-game on this cadence, counting down to the restart:
Announcements are only sent while players are online; an empty (or auto-paused) server is restarted immediately without a countdown. A freshly rebooted server is kept alive for at least an hour so the idle timer does not stop it again right away.
The bundled compose files (docker-compose.yml, docker-compose.ghcr.yml) do
not mount the Docker socket into the app. Instead:
DOCKER_GID to the docker
group id of the host (getent group docker | cut -d: -f3), e.g. in a .env
file next to the compose file.10001:10001 with a read-only root
filesystem, all capabilities dropped and no-new-privileges. Make the data
directory writable for it once: sudo chown -R 10001:10001 ./data.:sha-<commit> or a digest) rather than
:latest.If the proxy denies a call your setup needs, start it with -loglevel=debug to
see the request. The image itself still runs as root by default so older
deployments that mount /var/run/docker.sock directly keep working; that setup
is deprecated because socket access equals root on the host.
Each captcha is stored server-side and can be answered exactly once — a wrong answer consumes it, and a solved cookie cannot be replayed. Repeated wrong answers lock the client IP out with backoff. Captcha solves extend the timer by 12 hours up to a maximum of 48 hours remaining.
The number images are randomly distorted on every request (dot size, shear, jitter, colour and overdrawn clutter), which makes scripted reading harder but cannot rule it out. Two further layers limit automation:
TRUST_PROXY_HEADERS=true, otherwise all visitors share
the proxy's address.TURNSTILE_SITE_KEY and TURNSTILE_SECRET_KEY.
The widget appears below the puzzle and its token is checked against
Cloudflare before the action runs; the Content-Security-Policy then allows
challenges.cloudflare.com.The Palworld REST API uses HTTP Basic auth, so the admin password travels in
cleartext over plain HTTP. Keep that hop on a private network (the default
compose setup talks container-to-container), or point REST_API_URL /
SERVER_<ID>_RESTURL at an https:// endpoint, e.g. a TLS proxy in front of
the game server. A plain-HTTP URL to a public host logs a warning at startup.
REST redirects are never followed, so a tampered response cannot redirect the
credentials or a POST elsewhere.
The bundled socket-proxy rules only allow container calls for
palworld-server. If your game containers have other names (e.g. multiple
servers), edit the -allowGET / -allowPOST rules to list them, e.g.
containers/(palworld-server-1|palworld-server-2)/(json|logs).
bot > Permissions: Create Instant Invite > Paste URL to invite bot to server.