Skip to content

PenguinzTech/penguin-rust-base

Repository files navigation

copyright 2026 Penguinz

penguin-rust-base

GHCR Tests Security Build

A production-ready Docker image for Rust dedicated game servers with Oxide mod framework and plugins baked in. Game files (~6GB) are baked at build time to eliminate first-boot download waits. Automatically rebuilds every 4 hours when Oxide or Steam updates, with startup-time checks for plugin updates.

Perfect for operators, communities, and teams extending with proprietary plugins via FROM.

📖 Full configuration reference: docs/CONFIGURATION.md


What's Included

  • Rust Dedicated Server — Steam app 258550, latest version
  • Oxide Mod Framework — Auto-updated every 4 hours
  • Pre-Installed Plugins — all plugins published to penguin-rust-plugins (upstream secure plugin cache) are automatically baked in on every image build — no static list to maintain: AdminUtilities, BGrade, CopyPaste, Vanish, RemoverTool, UnburnableMeat, VehicleDecayProtection, NightLantern, TruePVE, StackSizeController, Whitelist
  • Custom Plugins (always active) — AutoAdmin, ExtensionManager
  • Custom Plugins (opt-in) — MorningFog (morning fog bell-curve effect), SafeSpace (kid-friendly content filters), Pets2 (tame animal companions) — enable via e.g. RUST_PLUGINS=morningfog,safespace
  • Patched Community Plugins — 11 popular community plugins pre-patched for Oxide API compatibility (removed APIs replaced so they work on current Rust builds): AntiOfflineRaid, BetterChat, BetterChatMute, DynamicPVP, NTeleportation, PlayerAdministration, Quests, TreePlanter, VehicleLicence, ZoneManager (+ 8 perf optimisations), Pets2 — see docs/PLUGINS.md and docs/ACKNOWLEDGEMENTS.md
  • MySQL→RCON User Sync — opt-in user-sync.sh runs every 5 minutes via supercronic; syncs admins, moderators, and bans from a rust_users MySQL table to the live server via RCON. Activated by setting USER_SYNC_DB_HOST, USER_SYNC_DB_USER, USER_SYNC_DB_PASS, and USER_SYNC_DB. No-op when env vars are absent.
  • WAF Sidecar — Go-based network-layer firewall that protects the game server from DDoS floods, cheater reconnect storms, RCON brute-force, and packet anomalies — works in pure vanilla mode with no Oxide required (see docs/waf.md)
  • Auto-Configuration — First-boot tuning of worldSize/maxPlayers based on available CPU/RAM
  • Wipe Scheduler — Configurable map wipes with in-game RCON warnings (60-minute lead time)
  • DDoS Protection — Per-source-IP rate limiting via iptables (opt-in, requires NET_ADMIN)
  • Debian 12 Bookworm Runtime — Lightweight, secure, production-hardened container

Quick Start

Basic Server (auto-tuned world size and player limit)

docker run -d \
  --name rust-server \
  -p 28015:28015/udp \
  -p 28015:28015/tcp \
  -p 28016:28016/tcp \
  -e RUST_SERVER_NAME="My Rust Server" \
  ghcr.io/penguinztech/penguin-rust-base:latest

With Admin Access + Persistent Volume

docker run -d \
  --name rust-server \
  -p 28015:28015/udp \
  -p 28015:28015/tcp \
  -p 28016:28016/tcp \
  -v rust-data:/steamcmd/rust/server \
  -e RUST_SERVER_NAME="My Rust Server" \
  -e RUST_ADMIN_STEAMIDS="76561198000000000,76561198000000001" \
  ghcr.io/penguinztech/penguin-rust-base:latest

Docker Compose

services:
  rust:
    image: ghcr.io/penguinztech/penguin-rust-base:latest
    container_name: rust-server
    ports:
      - "28015:28015/udp"
      - "28015:28015/tcp"
      - "28016:28016/tcp"
    volumes:
      - rust-data:/steamcmd/rust/server
    environment:
      RUST_SERVER_NAME: "My Community Server"
      RUST_SERVER_DESCRIPTION: "Weekly wipes, friendly community"
      RUST_SERVER_TAGS: "weekly,vanilla,pvp"
      WIPE_SCHED: "1w"
      WIPE_DAY: "Th"
      RUST_ADMIN_STEAMIDS: "76561198000000000"
    restart: unless-stopped

volumes:
  rust-data:

Configuration

All settings are controlled via environment variables. The most commonly set ones:

Variable Default Description
RUST_SERVER_NAME Rust Server Server name in browser
RUST_SERVER_MAXPLAYERS (auto-detected) Max concurrent players
RUST_SERVER_WORLDSIZE (auto-detected) Map size in meters
RUST_SERVER_SEED 12345 World seed
RUST_RCON_PASSWORD (auto-generated) RCON password; generated and persisted to PVC if unset
RUST_ADMIN_STEAMIDS (none) Comma-separated admin Steam IDs
WIPE_SCHED (first Thu of month) 1w, 2w, 3w, or off
PLUGIN_SOURCE github github (baked→GitHub→umod chain), baked (no network), or umod (always umod.org)
PLUGIN_UMOD_FALLBACK 1 In github mode, fall back to umod.org for slugs not in penguin-rust-plugins (0 to disable)

📖 Everything else — browser listing (description, tags, URL, logo), server behaviour (PvE, radiation, tickrate), wipe schedule details, DDoS protection, admin provisioning, plugin toggles, auto-config tiers, performance tuning — is documented in docs/CONFIGURATION.md.

Specialist guides:


Image Tags & Versioning

Every build produces two tags:

Tag Mutability Use Case
latest Mutable Development, testing — always get the newest Oxide/Steam updates
<unix-epoch> Immutable Production, pinning — freeze a known-good build
# Pin to a specific build in production
FROM ghcr.io/penguinztech/penguin-rust-base:1747123456

List available tags:

curl -s https://ghcr.io/v2/penguinztech/penguin-rust-base/tags/list | jq '.tags'

Extending This Image

FROM ghcr.io/penguinztech/penguin-rust-base:1747123456

# Custom/proprietary plugins
COPY --chown=rustserver:rustserver my-plugins/ /steamcmd/rust/oxide/plugins/

# Pre-seeded plugin data
COPY --chown=rustserver:rustserver my-data/ /steamcmd/rust/oxide/data/

# Default overrides
ENV RUST_SERVER_NAME="My Custom Server"

Plugin Caching

Plugins are baked into the image as gzip-compressed .cs.gz files alongside a .hash sidecar. This serves two purposes:

Startup speed — On every boot, start.sh compares the baked hash against the latest release in penguin-rust-plugins. If they match, the plugin is decompressed and activated in milliseconds from the local layer — no network round-trip. Only plugins that have been updated since the image was built are downloaded at startup.

Efficient layer sharing for multi-server providers — All plugin .cs.gz files live in a single immutable Docker layer. Hosts running many Rust server containers (or different server images built FROM this base) share that layer on disk and in the registry pull cache. Plugins are only decompressed into the container's writable layer when activated, so the compressed originals remain shared.

oxide/plugins/disabled/     ← shared, compressed, in image layer
    truepve.cs.gz
    truepve.hash
    whitelist.cs.gz
    whitelist.hash
    ...

oxide/plugins/              ← per-container writable layer, uncompressed
    TruePVE.cs              ← only after RUST_PLUGINS=truepve
    Whitelist.cs

Plugins are disabled by default. Set RUST_PLUGINS to activate specific ones:

-e RUST_PLUGINS="truepve,whitelist,vanish"

Automatic Updates

  • Every 4 hours — check Oxide and Steam for updates, rebuild if changed
  • On dispatch — manual gh workflow run build.yml
  • On startup — compare baked plugin hashes against latest penguin-rust-plugins releases; download updates only when needed

WAF Sidecar (Network-Layer Protection)

The image ships a Go WAF sidecar that operates at the network layer — below the Rust game engine. It intercepts all traffic before it reaches the single-threaded C#/Mono game loop and drops malicious packets in Go's concurrent runtime where they are cheap.

Crucially, this works on pure vanilla servers. No Oxide, no plugins, no mods required. Every protection below runs at the packet level regardless of server configuration:

Protection How it works
DDoS / flood Per-IP packet-rate limiter; sustained floods auto-blocked
RCON brute-force Failed auth counter; offending IP throttled after N attempts
Ban evasion Steam64 ID extracted from handshake; banned player blocked across IP changes
Packet anomalies Malformed/oversized packets dropped before game sees them
Aimbot heuristics Inter-packet timing CV analysis; bot-like consistency flagged

When Oxide is running, plugins can push runtime rules to the WAF via a loopback REST API — reporting detected cheaters for immediate network-layer enforcement without a game restart.

Enable in Kubernetes (Helm):

helm install rust-server ./k8s/helm/rust-server --set waf.enabled=true

📖 Full WAF reference: docs/waf.md


Networking

Port Protocol Purpose
28015 UDP + TCP Game server port (connections + queries)
28016 TCP RCON / WebRCON
28017 UDP Server browser query

Forward both UDP and TCP on port 28015. RCON and query ports are optional.

WAF port note: When the WAF sidecar is enabled, it occupies the public-facing ports (28015/28016/28017) and shifts the game server to loopback offsets (28115/28116/28117). No change to external port mappings required.


Security

Runs as non-root (rustserver:rustserver, UID 1000); no capabilities required unless DDoS protection is enabled. RCON password auto-generated on first boot and persisted to the PVC — never embedded. The WAF sidecar also runs as a dedicated non-root user (waf:waf) and adds zero inbound attack surface — its management API listens on loopback only.

Full details — CI scanners, what's not scanned, reporting vulnerabilities: docs/SECURITY.md.
DDoS protection setup: docs/ddos-protection.md.
WAF sidecar: docs/waf.md.


Troubleshooting

# Check logs
docker logs rust-server | tail -50

# Server won't start — typical causes:
# - Port conflict on 28015/28016
# - Memory limit below MONO_MAX_HEAP
# - Volume permissions (must be writable by UID 1000)

# Retrieve auto-generated RCON password
docker exec rust-server cat /steamcmd/rust/server/rust_server/.rcon.pw

# Plugin status
docker exec rust-server ls /steamcmd/rust/oxide/plugins/
docker exec rust-server tail -50 /steamcmd/rust/server/oxide/logs/log.txt

Full troubleshooting: docs/CONFIGURATION.md


Admin Make Targets

A Makefile is included for common server operations. All targets accept optional overrides for KUBE_CONTEXT, NAMESPACE, RELEASE, RCON_HOST, and RCON_PORT.

Run make help to see all targets.

Server Lifecycle

Target Description Example
make reboot Sends 5-minute countdown to players via RCON, saves world, restarts pod RCON_PASSWORD=<pw> make reboot
make wipe Same countdown, deletes .sav files (no save), restarts pod RCON_PASSWORD=<pw> make wipe
make force-restart Immediate pod restart — no RCON needed (use when server is hung) make force-restart
make helm-upgrade Applies Helm chart changes without restarting players TAG=gamma-1714000000 make helm-upgrade

In-Game RCON Commands

Target Description Example
make save Forces a server.save via RCON RCON_PASSWORD=<pw> make save
make message Broadcasts an admin message to all players RCON_PASSWORD=<pw> MESSAGE="Server restart in 10 min" make message

If MESSAGE is not set, you will be prompted interactively.

Player Management

All four targets accept PLAYER=<steamid or name>. If not set, you will be prompted. Providing a name instead of a SteamID searches the online player list (case-insensitive substring match) and asks for confirmation before acting.

Target Description Example
make ban Bans a player (banid + server.writecfg) RCON_PASSWORD=<pw> PLAYER=jim REASON="cheating" make ban
make admin Grants full admin (ownerid + server.writecfg) RCON_PASSWORD=<pw> PLAYER=76561198000000000 make admin
make mod Grants moderator (moderatorid + server.writecfg) RCON_PASSWORD=<pw> PLAYER=jim make mod
make whitelist Grants whitelist.allow Oxide permission RCON_PASSWORD=<pw> PLAYER=jim make whitelist

SteamID vs name:

  • SteamID (17-digit) — used directly, no confirmation prompt.
  • Name — searches online players, shows match + SteamID, prompts y/N. If multiple matches, lists them for you to pick by number. If the player is offline, they won't appear in the list — use their SteamID directly instead.

Monitoring

Target Description Example
make logs Tails live server logs make logs
make status Shows pod and LoadBalancer service status make status
make fps Queries current server FPS via RCON RCON_PASSWORD=<pw> make fps

Prerequisites

  • kubectl configured with the target cluster context
  • python3 with websockets package (pip3 install websockets) for RCON targets
  • helm for helm-upgrade

Contributing

Issues, feature requests, and pull requests welcome on GitHub.


License

  • Container image and custom plugins: GPL-3.0-only
  • Bundled community plugins: Their respective authors' licenses (see umod.org)
  • Rust / Steam: Licensed by Facepunch Studios — by using this image you agree to the Rust Server License

Support


Built by PenguinzTech — Reliable, production-ready Rust infrastructure.

About

Rust dedicated server with Oxide + umod plugins — community base image

Resources

License

Security policy

Stars

Watchers

Forks

Packages

 
 
 

Contributors