Fix console FIFO blocked by SELinux
minecraft.socket had systemd open the FIFO, which SELinux refuses:
avc: denied { read write } for pid=1 comm="systemd" name="minecraft-console"
scontext=...:init_t:s0 tcontext=...:var_run_t:s0 tclass=fifo_file
init_t has no read/write on a var_run_t fifo_file under the stock Fedora
targeted policy, so the socket unit never started and the service failed with
"a dependency job for minecraft.service failed".
The socket unit is gone. The service now creates the FIFO in its own
RuntimeDirectory and opens it as fd 3 read-write before exec'ing the JVM, so
the open never blocks, the reader never sees EOF when a writer disconnects, and
MAINPID stays the JVM. Nothing goes through PID 1, so the policy gap does not
apply. An obsolete minecraft.socket is removed on upgrade.
Console path moves to /run/minecraft/console.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
main
parent
a141a31547
commit
6c85e30cc8
10
README.md
10
README.md
|
|
@ -131,18 +131,22 @@ up on a half-synced pack. Edit the config block at the top first — `PACK_DIR`,
|
|||
|
||||
## The server unit
|
||||
|
||||
`minecraft.service` pairs with `minecraft.socket`, a console FIFO at
|
||||
`/run/minecraft-console`. That's what makes a clean shutdown possible:
|
||||
`minecraft.service` holds a console FIFO at `/run/minecraft/console`. That's
|
||||
what makes a clean shutdown possible:
|
||||
|
||||
```bash
|
||||
sudo systemctl stop minecraft # sends "stop", world saves properly
|
||||
echo "say hello" | sudo tee /run/minecraft-console
|
||||
echo "say hello" | sudo tee /run/minecraft/console
|
||||
journalctl -u minecraft -f # console output
|
||||
```
|
||||
|
||||
Without the FIFO, systemd would SIGTERM the JVM and risk cutting a world save
|
||||
in half.
|
||||
|
||||
The service creates and opens the FIFO itself rather than delegating to a
|
||||
socket unit. SELinux denies `init_t` read/write on a `fifo_file` in `/run`, so
|
||||
anything routed through PID 1 fails with `EACCES` on a stock Fedora policy.
|
||||
|
||||
## Web server
|
||||
|
||||
`/minecraft` needs to be served over HTTP. Serve `pack.toml` and `index.toml`
|
||||
|
|
|
|||
|
|
@ -6,12 +6,12 @@
|
|||
# sudo ./mc-service-setup.sh --accept-eula -N 21.1.72 -X 12G
|
||||
#
|
||||
# Creates a `minecraft` system user, optionally installs the NeoForge server,
|
||||
# and writes minecraft.service + minecraft.socket. The socket is a console FIFO
|
||||
# at /run/minecraft-console, which is what lets systemd stop the server with a
|
||||
# real `stop` command so the world saves instead of being killed mid-write.
|
||||
# and writes minecraft.service. The service holds a console FIFO at
|
||||
# /run/minecraft/console, which lets systemd stop the server with a real `stop`
|
||||
# command so the world saves instead of being killed mid-write.
|
||||
#
|
||||
# systemctl start|stop|restart minecraft
|
||||
# echo "say hello" | sudo tee /run/minecraft-console # console commands
|
||||
# echo "say hello" | sudo tee /run/minecraft/console # console commands
|
||||
# journalctl -u minecraft -f # console output
|
||||
|
||||
set -euo pipefail
|
||||
|
|
@ -29,7 +29,7 @@ MCVER="1.21.1" # only used to pick the matching NeoForge series
|
|||
ADMIN="" # human user who authors the pack on the share
|
||||
ACCEPT_EULA=0
|
||||
UNIT_DIR="/etc/systemd/system"
|
||||
FIFO="/run/minecraft-console"
|
||||
FIFO="/run/minecraft/console" # console FIFO, inside the unit's RuntimeDirectory
|
||||
|
||||
die() { echo "error: $*" >&2; exit 1; }
|
||||
info() { echo ">>> $*"; }
|
||||
|
|
@ -287,22 +287,14 @@ fi
|
|||
|
||||
# ----------------------------------------------------------------- units ----
|
||||
|
||||
info "writing $UNIT_DIR/minecraft.socket"
|
||||
cat > "$UNIT_DIR/minecraft.socket" <<EOF
|
||||
[Unit]
|
||||
Description=Minecraft server console FIFO
|
||||
|
||||
# No Service= and no PartOf= here on purpose. minecraft.service already declares
|
||||
# Requires=/After=/Sockets= on this unit, and pointing this one back at the
|
||||
# service as well forms an ordering cycle that systemd resolves by failing the
|
||||
# job — which surfaces as "a dependency job for minecraft.service failed".
|
||||
[Socket]
|
||||
ListenFIFO=$FIFO
|
||||
SocketUser=$MCUSER
|
||||
SocketGroup=$MCUSER
|
||||
SocketMode=0660
|
||||
RemoveOnStop=yes
|
||||
EOF
|
||||
# A previous version shipped a minecraft.socket that had systemd itself open
|
||||
# the FIFO. SELinux denies init_t read/write on a var_run_t fifo_file, so that
|
||||
# never worked; remove it if it is still around.
|
||||
if [ -e "$UNIT_DIR/minecraft.socket" ]; then
|
||||
info "removing obsolete minecraft.socket"
|
||||
systemctl disable --now minecraft.socket >/dev/null 2>&1 || true
|
||||
rm -f "$UNIT_DIR/minecraft.socket"
|
||||
fi
|
||||
|
||||
info "writing $UNIT_DIR/minecraft.service"
|
||||
cat > "$UNIT_DIR/minecraft.service" <<EOF
|
||||
|
|
@ -311,8 +303,6 @@ Description=Minecraft Server (NeoForge)
|
|||
Documentation=https://docs.neoforged.net/
|
||||
After=network-online.target zfs-mount.service
|
||||
Wants=network-online.target
|
||||
Requires=minecraft.socket
|
||||
After=minecraft.socket
|
||||
RequiresMountsFor=$SHARE
|
||||
|
||||
[Service]
|
||||
|
|
@ -321,15 +311,20 @@ User=$MCUSER
|
|||
Group=$MCUSER
|
||||
WorkingDirectory=$SHARE
|
||||
|
||||
# The console FIFO becomes the server's stdin, so ExecStop can hand it a real
|
||||
# 'stop' command. Without this systemd would SIGTERM the JVM and risk a world
|
||||
# save being cut in half.
|
||||
Sockets=minecraft.socket
|
||||
StandardInput=socket
|
||||
StandardOutput=journal
|
||||
StandardError=journal
|
||||
|
||||
ExecStart=/usr/bin/java @$SHARE/user_jvm_args.txt @$ARGS_FILE nogui
|
||||
# Console FIFO. The service creates and opens it itself rather than having a
|
||||
# socket unit do it: SELinux denies init_t read/write on a fifo_file in /run,
|
||||
# so anything routed through PID 1 fails with EACCES.
|
||||
#
|
||||
# fd 3 is opened read-write so the open does not block and the reader never
|
||||
# sees EOF when a writer disconnects; java then inherits it as stdin. The
|
||||
# second exec replaces the shell, so MAINPID is the JVM.
|
||||
RuntimeDirectory=minecraft
|
||||
RuntimeDirectoryMode=0755
|
||||
ExecStartPre=/bin/sh -c 'rm -f $FIFO && mkfifo -m 0660 $FIFO'
|
||||
ExecStart=/bin/bash -c 'exec 3<>$FIFO; exec /usr/bin/java @$SHARE/user_jvm_args.txt @$ARGS_FILE nogui <&3'
|
||||
ExecStop=/bin/sh -c '/bin/echo stop > $FIFO'
|
||||
|
||||
# Generous: a big world with many chunks loaded can take a while to save.
|
||||
|
|
|
|||
Loading…
Reference in New Issue