2026-09-12 14:33:01 -06:00
2026-09-12 14:31:27 -06:00
2026-09-12 14:31:27 -06:00
2026-09-12 14:31:27 -06:00
2026-09-12 14:31:27 -06:00
2026-09-12 14:31:27 -06:00
2026-09-12 14:31:27 -06:00
2026-09-12 14:33:01 -06:00
2026-09-12 14:31:27 -06:00

git pu# Hardened Fedora Minecraft Server (Ansible)

Ansible playbook that turns a fresh Fedora 42 server into a hardened, containerized Minecraft game server — Java and Bedrock clients — running with rootless Podman via systemd Quadlet units.

Everything is managed declaratively from harden_fedora_minecraft.yml: OS hardening, firewall, SELinux, SSH access control, the Podman runtime, and the Minecraft/Geyser containers are all deployed by one command.

Features

  • 🔒 [Hardening] SELinux enforcing, firewalld default-DROP policy, password policy (pwquality + aging), root account locked, automatic security updates (dnf-automatic).
  • 🔑 [SSH] Key-only authentication for a dedicated admin user, root login disabled, AllowUsers restriction, and a fail2ban SSH jail.
  • 🐳 [Runtime] Rootless Podman with user lingering, subuid/subgid ranges, IPv4 forwarding, and the overlay storage driver.
  • ⛏️ [Minecraft] Portable Java server built from itzg/docker-minecraft-server (PAPER by default, version/memory/difficulty configurable).
  • 🪨 [Geyser] A second container, geysermc/geyser, in the same pod so Bedrock (phone/console) players can join the Java world.
  • 🗄️ [Data] World data and backups live on the host in /srv/minecraft with correct SELinux labels.

Architecture

Both game containers run in a single Podman pod (shared network namespace) as the non-root user mcadmin:

        Internet
           │
   ┌───────┴────────┐
   │ firewall (DROP)│   only the ports below are allowed
   └───────┬────────┘
           │
   pod: minecraft (rootless, user mcadmin)
   ├── minecraft-server  JVM on 0.0.0.0:25565  (Java clients)
   │        └── world data → /srv/minecraft/data
   └── geyser            Bedrock listener :19132/udp
            └── config   → /srv/minecraft/geyser
                 └── forwards Bedrock players to 127.0.0.1:25565
Port Protocol Purpose
22 TCP SSH (configurable via ssh_port)
25565 TCP Minecraft Java server
25565 UDP Optional Java server UDP (game query)
19132 UDP Bedrock (Geyser), when enable_geyser: true

Repository layout

.
├── harden_fedora_minecraft.yml   # entry point: hosts: external-apps → 7 roles
├── inventory.yml                 # target host definition
├── ansible.cfg                   # inventory + role path + pipelining
├── requirements.yml              # Ansible collections (ansible.posix)
├── group_vars/all.yml            # shared variables
├── host_vars/external-apps.yml   # per-server settings (IP, SSH key, MC tuning)
└── roles/
    ├── packages/     # base + container tooling, full dnf update, dnf-automatic
    ├── firewall/     # firewalld: DROP target, open SSH + Minecraft + Geyser
    ├── selinux/      # enforcing mode + container_file_t context for /srv/minecraft
    ├── auth/         # admin user, SSH key, sudoers, password policy, lock root
    ├── ssh_harden/   # sshd drop-in + fail2ban jail
    ├── podman/       # socket, linger, subuid/subgid, ip_forward, storage
    └── minecraft/    # data dirs, Quadlet pod/container units, image pulls

Prerequisites

  • Ansible control node (this repo) with Ansible Core ≥ 2.14 and ansible.posix
  • A Fedora 42 target server reachable over SSH with an account that has sudo
  • The ansible.user in the inventory must be able to become root on the target

Quick start

# 1. Install the required collection
ansible-galaxy collection install -r requirements.yml

# 2. Configure the target server (REQUIRED before first run)
#    - host_vars/external-apps.yml
#      * ansible_host: real IP or DNS name
#      * admin_user_ssh_key: your real SSH public key
#      * game settings to taste (version, memory, whitelist…)

# 3. Run the playbook
ansible-playbook harden_fedora_minecraft.yml

⚠️ admin_user_ssh_key must be a real key before the first run — the playbook disables SSH password authentication and root login once the ssh_harden role executes.

Configuration

All tunables live in host_vars/external-apps.yml (per server) and group_vars/all.yml (cluster-wide). Highlights:

Variable Default Meaning
admin_user mcadmin Non-root user running the containers
minecraft_version LATEST Server version (1.21.1, …)
minecraft_server_type PAPER PAPER / VANILLA / FABRIC / FORGE
minecraft_memory 2G JVM memory limit
minecraft_whitelist "" Comma-separated allowed usernames (empty = off)
enable_geyser true Deploy the Bedrock bridge
geyser_port 19132 Bedrock UDP port
geyser_auth_type online offline only with a paired Floodgate key
ssh_port 22 SSH port used by firewall + sshd

Operations

After the playbook has run, manage the servers as mcadmin:

sudo machinectl shell mcadmin@ -- systemctl --user status minecraft-server geyser
sudo machinectl shell mcadmin@ -- systemctl --user restart minecraft-server
sudo machinectl shell mcadmin@ -- podman ps              # container list
sudo machinectl shell mcadmin@ -- journalctl --user-unit minecraft-server -f

References

License

MIT

Description
No description provided
Readme 63 KiB
Languages
Jinja 81.3%
Makefile 18.7%