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
|
## The server unit
|
||||||
|
|
||||||
`minecraft.service` pairs with `minecraft.socket`, a console FIFO at
|
`minecraft.service` holds a console FIFO at `/run/minecraft/console`. That's
|
||||||
`/run/minecraft-console`. That's what makes a clean shutdown possible:
|
what makes a clean shutdown possible:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
sudo systemctl stop minecraft # sends "stop", world saves properly
|
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
|
journalctl -u minecraft -f # console output
|
||||||
```
|
```
|
||||||
|
|
||||||
Without the FIFO, systemd would SIGTERM the JVM and risk cutting a world save
|
Without the FIFO, systemd would SIGTERM the JVM and risk cutting a world save
|
||||||
in half.
|
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
|
## Web server
|
||||||
|
|
||||||
`/minecraft` needs to be served over HTTP. Serve `pack.toml` and `index.toml`
|
`/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
|
# sudo ./mc-service-setup.sh --accept-eula -N 21.1.72 -X 12G
|
||||||
#
|
#
|
||||||
# Creates a `minecraft` system user, optionally installs the NeoForge server,
|
# Creates a `minecraft` system user, optionally installs the NeoForge server,
|
||||||
# and writes minecraft.service + minecraft.socket. The socket is a console FIFO
|
# and writes minecraft.service. The service holds a console FIFO at
|
||||||
# at /run/minecraft-console, which is what lets systemd stop the server with a
|
# /run/minecraft/console, which lets systemd stop the server with a real `stop`
|
||||||
# real `stop` command so the world saves instead of being killed mid-write.
|
# command so the world saves instead of being killed mid-write.
|
||||||
#
|
#
|
||||||
# systemctl start|stop|restart minecraft
|
# 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
|
# journalctl -u minecraft -f # console output
|
||||||
|
|
||||||
set -euo pipefail
|
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
|
ADMIN="" # human user who authors the pack on the share
|
||||||
ACCEPT_EULA=0
|
ACCEPT_EULA=0
|
||||||
UNIT_DIR="/etc/systemd/system"
|
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; }
|
die() { echo "error: $*" >&2; exit 1; }
|
||||||
info() { echo ">>> $*"; }
|
info() { echo ">>> $*"; }
|
||||||
|
|
@ -287,22 +287,14 @@ fi
|
||||||
|
|
||||||
# ----------------------------------------------------------------- units ----
|
# ----------------------------------------------------------------- units ----
|
||||||
|
|
||||||
info "writing $UNIT_DIR/minecraft.socket"
|
# A previous version shipped a minecraft.socket that had systemd itself open
|
||||||
cat > "$UNIT_DIR/minecraft.socket" <<EOF
|
# the FIFO. SELinux denies init_t read/write on a var_run_t fifo_file, so that
|
||||||
[Unit]
|
# never worked; remove it if it is still around.
|
||||||
Description=Minecraft server console FIFO
|
if [ -e "$UNIT_DIR/minecraft.socket" ]; then
|
||||||
|
info "removing obsolete minecraft.socket"
|
||||||
# No Service= and no PartOf= here on purpose. minecraft.service already declares
|
systemctl disable --now minecraft.socket >/dev/null 2>&1 || true
|
||||||
# Requires=/After=/Sockets= on this unit, and pointing this one back at the
|
rm -f "$UNIT_DIR/minecraft.socket"
|
||||||
# service as well forms an ordering cycle that systemd resolves by failing the
|
fi
|
||||||
# job — which surfaces as "a dependency job for minecraft.service failed".
|
|
||||||
[Socket]
|
|
||||||
ListenFIFO=$FIFO
|
|
||||||
SocketUser=$MCUSER
|
|
||||||
SocketGroup=$MCUSER
|
|
||||||
SocketMode=0660
|
|
||||||
RemoveOnStop=yes
|
|
||||||
EOF
|
|
||||||
|
|
||||||
info "writing $UNIT_DIR/minecraft.service"
|
info "writing $UNIT_DIR/minecraft.service"
|
||||||
cat > "$UNIT_DIR/minecraft.service" <<EOF
|
cat > "$UNIT_DIR/minecraft.service" <<EOF
|
||||||
|
|
@ -311,8 +303,6 @@ Description=Minecraft Server (NeoForge)
|
||||||
Documentation=https://docs.neoforged.net/
|
Documentation=https://docs.neoforged.net/
|
||||||
After=network-online.target zfs-mount.service
|
After=network-online.target zfs-mount.service
|
||||||
Wants=network-online.target
|
Wants=network-online.target
|
||||||
Requires=minecraft.socket
|
|
||||||
After=minecraft.socket
|
|
||||||
RequiresMountsFor=$SHARE
|
RequiresMountsFor=$SHARE
|
||||||
|
|
||||||
[Service]
|
[Service]
|
||||||
|
|
@ -321,15 +311,20 @@ User=$MCUSER
|
||||||
Group=$MCUSER
|
Group=$MCUSER
|
||||||
WorkingDirectory=$SHARE
|
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
|
StandardOutput=journal
|
||||||
StandardError=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'
|
ExecStop=/bin/sh -c '/bin/echo stop > $FIFO'
|
||||||
|
|
||||||
# Generous: a big world with many chunks loaded can take a while to save.
|
# Generous: a big world with many chunks loaded can take a while to save.
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue