pelican: game server panel + wings containers
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
55dc95dd2b
commit
00ec9a9759
4 changed files with 142 additions and 0 deletions
|
|
@ -27,6 +27,7 @@ in
|
||||||
# Services #
|
# Services #
|
||||||
./services/server-permissions.nix
|
./services/server-permissions.nix
|
||||||
./services/game-servers.nix
|
./services/game-servers.nix
|
||||||
|
./services/pelican.nix
|
||||||
# ./services/dr-server.nix
|
# ./services/dr-server.nix
|
||||||
./services/qbittorrent-nox.nix
|
./services/qbittorrent-nox.nix
|
||||||
./services/nginx.nix
|
./services/nginx.nix
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,14 @@ name = "SSH"
|
||||||
port = 22
|
port = 22
|
||||||
protocol = "tcp"
|
protocol = "tcp"
|
||||||
|
|
||||||
|
# Pelican game-server allocation range (services/pelican.nix). wings publishes
|
||||||
|
# each game container's port on the host via the shared docker daemon, so these
|
||||||
|
# land on 10.0.0.1 directly. Keep in sync with the node's allocations in the panel.
|
||||||
|
[[forward]]
|
||||||
|
name = "Pelican game servers"
|
||||||
|
ports = "25565-25600"
|
||||||
|
protocol = "both"
|
||||||
|
|
||||||
# 7DTD forwards commented out — servers disabled in services/game-servers.nix.
|
# 7DTD forwards commented out — servers disabled in services/game-servers.nix.
|
||||||
# [[forward]]
|
# [[forward]]
|
||||||
# name = "7DTD game"
|
# name = "7DTD game"
|
||||||
|
|
|
||||||
|
|
@ -106,6 +106,22 @@ in
|
||||||
"jellyfin.nordhammer.it" = proxy 8096; # streaming to external clients
|
"jellyfin.nordhammer.it" = proxy 8096; # streaming to external clients
|
||||||
"seerr.nordhammer.it" = proxy 5055; # own auth via Jellyfin sign-in
|
"seerr.nordhammer.it" = proxy 5055; # own auth via Jellyfin sign-in
|
||||||
|
|
||||||
|
# Pelican game panel — own auth. Not Authelia-protected: wings polls
|
||||||
|
# the panel API and the browser console opens a websocket straight to
|
||||||
|
# the node, neither of which can follow a forward-auth redirect.
|
||||||
|
"panel.nordhammer.it" = lib.recursiveUpdate (proxy 8092) {
|
||||||
|
locations."/".extraConfig = "client_max_body_size 100m;";
|
||||||
|
};
|
||||||
|
# wings daemon (see services/pelican.nix). Uploads through the file
|
||||||
|
# manager are whole server archives, so no body-size cap; the console
|
||||||
|
# websocket idles between keystrokes, hence the long read timeout.
|
||||||
|
"node.nordhammer.it" = lib.recursiveUpdate (proxy 8443) {
|
||||||
|
locations."/".extraConfig = ''
|
||||||
|
client_max_body_size 0;
|
||||||
|
proxy_read_timeout 7d;
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
# --- Protected by Authelia ---
|
# --- Protected by Authelia ---
|
||||||
"bazarr.nordhammer.it" = protectedProxy 6767;
|
"bazarr.nordhammer.it" = protectedProxy 6767;
|
||||||
"sonarr.nordhammer.it" = protectedProxy 8989;
|
"sonarr.nordhammer.it" = protectedProxy 8989;
|
||||||
|
|
|
||||||
117
services/pelican.nix
Normal file
117
services/pelican.nix
Normal file
|
|
@ -0,0 +1,117 @@
|
||||||
|
# services/pelican.nix — Pelican game-server panel (Pterodactyl's successor).
|
||||||
|
#
|
||||||
|
# Neither Pelican nor Pterodactyl is in nixpkgs, so both halves run as
|
||||||
|
# containers (like shelfarr/profilarr). Two pieces:
|
||||||
|
#
|
||||||
|
# panel — Laravel web UI. Single container, SQLite + file cache (no
|
||||||
|
# MariaDB/Redis needed). All state lives in /var/lib/pelican-panel.
|
||||||
|
# wings — Go daemon that actually starts game servers. Talks to the *host*
|
||||||
|
# docker daemon over docker.sock, so game containers are siblings,
|
||||||
|
# not nested. That's why every wings path below is mounted at the
|
||||||
|
# same path inside the container as outside: wings hands those paths
|
||||||
|
# to the host dockerd, which resolves them on the host.
|
||||||
|
#
|
||||||
|
# Neither is declarative — servers, eggs and users are configured in the web
|
||||||
|
# UI and stored in the panel's SQLite DB. Back up /var/lib/pelican-panel and
|
||||||
|
# /var/lib/pelican (server files); the nix side here is only the plumbing.
|
||||||
|
#
|
||||||
|
# FIRST-RUN (wings crash-loops until step 3 — that's expected):
|
||||||
|
# 1. https://panel.nordhammer.it → installer wizard, make admin user.
|
||||||
|
# 2. Admin → Nodes → Create. FQDN node.nordhammer.it, SSL *on*, port 443
|
||||||
|
# (nginx terminates TLS and proxies to wings' plain :8080 below).
|
||||||
|
# Allocations: IP 10.0.0.1, ports 25565-25600 (matches ports.toml).
|
||||||
|
# 3. Node → Configuration tab → copy the generated YAML to
|
||||||
|
# /etc/pelican/config.yml on this host, then
|
||||||
|
# `systemctl restart docker-pelican-wings`.
|
||||||
|
{ config, pkgs, lib, ... }:
|
||||||
|
let
|
||||||
|
# Replaces the image's default Caddyfile, which would try to fetch its own
|
||||||
|
# Let's Encrypt cert. nginx already terminates TLS for us, so serve plain
|
||||||
|
# HTTP on :80 and trust the forwarded headers. private_ranges rather than a
|
||||||
|
# literal IP: requests arrive from the docker bridge gateway, not 127.0.0.1,
|
||||||
|
# and the published port is localhost-only anyway.
|
||||||
|
caddyfile = pkgs.writeText "pelican-Caddyfile" ''
|
||||||
|
{
|
||||||
|
admin off
|
||||||
|
servers {
|
||||||
|
trusted_proxies static private_ranges
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
:80 {
|
||||||
|
root * /var/www/html/public
|
||||||
|
encode gzip
|
||||||
|
|
||||||
|
php_fastcgi 127.0.0.1:9000
|
||||||
|
file_server
|
||||||
|
}
|
||||||
|
'';
|
||||||
|
in
|
||||||
|
{
|
||||||
|
config = lib.mkIf (config.networking.hostName == "FredOS-Mediaserver") {
|
||||||
|
|
||||||
|
systemd.tmpfiles.rules = [
|
||||||
|
"d /var/lib/pelican-panel 0755 root root -"
|
||||||
|
"d /var/lib/pelican-panel/logs 0755 root root -"
|
||||||
|
"d /etc/pelican 0755 root root -"
|
||||||
|
"d /var/lib/pelican 0755 root root -"
|
||||||
|
"d /var/log/pelican 0755 root root -"
|
||||||
|
"d /tmp/pelican 0755 root root -"
|
||||||
|
];
|
||||||
|
|
||||||
|
virtualisation.oci-containers.containers.pelican-panel = {
|
||||||
|
image = "ghcr.io/pelican-dev/panel:latest";
|
||||||
|
volumes = [
|
||||||
|
"/var/lib/pelican-panel:/pelican-data"
|
||||||
|
"/var/lib/pelican-panel/logs:/var/www/html/storage/logs"
|
||||||
|
"${caddyfile}:/etc/caddy/Caddyfile:ro"
|
||||||
|
];
|
||||||
|
# Localhost-only; nginx fronts it (see nginx.nix).
|
||||||
|
ports = [ "127.0.0.1:8092:80" ];
|
||||||
|
environment = {
|
||||||
|
XDG_DATA_HOME = "/pelican-data";
|
||||||
|
APP_URL = "https://panel.nordhammer.it";
|
||||||
|
ADMIN_EMAIL = "fredrik@nordhammer.it";
|
||||||
|
APP_ENV = "production";
|
||||||
|
APP_DEBUG = "false";
|
||||||
|
# Laravel otherwise renders http:// asset URLs behind the proxy.
|
||||||
|
TRUSTED_PROXIES = "*";
|
||||||
|
TZ = "Europe/Stockholm";
|
||||||
|
};
|
||||||
|
extraOptions = [ "--add-host=host.docker.internal:host-gateway" ];
|
||||||
|
};
|
||||||
|
|
||||||
|
virtualisation.oci-containers.containers.pelican-wings = {
|
||||||
|
image = "ghcr.io/pelican-dev/wings:latest";
|
||||||
|
volumes = [
|
||||||
|
"/var/run/docker.sock:/var/run/docker.sock"
|
||||||
|
"/var/lib/docker/containers/:/var/lib/docker/containers/"
|
||||||
|
"/etc/pelican/:/etc/pelican/"
|
||||||
|
"/var/lib/pelican/:/var/lib/pelican/"
|
||||||
|
"/var/log/pelican/:/var/log/pelican/"
|
||||||
|
"/tmp/pelican/:/tmp/pelican/"
|
||||||
|
"/etc/ssl/certs:/etc/ssl/certs:ro"
|
||||||
|
];
|
||||||
|
ports = [
|
||||||
|
# Daemon API + console websocket — nginx fronts it as node.nordhammer.it.
|
||||||
|
"127.0.0.1:8443:8080"
|
||||||
|
# SFTP into server files. LAN-reachable; not in ports.toml, so no WAN.
|
||||||
|
"2022:2022"
|
||||||
|
];
|
||||||
|
environment.TZ = "Europe/Stockholm";
|
||||||
|
# Image is distroless with no entrypoint script — needs a tty allocated.
|
||||||
|
extraOptions = [ "--tty" ];
|
||||||
|
};
|
||||||
|
|
||||||
|
# Same guard the 7DTD containers had: wings exits immediately until
|
||||||
|
# /etc/pelican/config.yml exists, and an unbounded restart loop spawns a
|
||||||
|
# veth pair every few seconds, flooding systemd-networkd and risking WAN
|
||||||
|
# DHCP on this host (it's the router). Give up after 5 tries in 5 min.
|
||||||
|
systemd.services."docker-pelican-wings".serviceConfig = {
|
||||||
|
Restart = lib.mkForce "on-failure";
|
||||||
|
RestartSec = "30s";
|
||||||
|
StartLimitIntervalSec = 300;
|
||||||
|
StartLimitBurst = 5;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue