mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-10-14 01:45:00 +03:00
1f2738eda5
ProtectKernelTunables=yes (#6718) mounts all of /proc/sys read-only, and a WireGuard outbound in kernel-TUN mode zeroes net.ipv4.conf.all.rp_filter (and its ipv6 and per-device siblings) while Xray creates its handlers, so the core aborted with "failed to disable ipv4 rp_filter for all: ... read-only file system". The unit is reinstalled on every update, so a hand edit did not stick. Keep ProtectKernelTunables and reopen only /proc/sys/net. Turning the protection off (#6797) also lets the core start, but leaves kernel.core_pattern writable to the root panel, which turns any panel-level code execution into a way out of the whole sandbox. net.* is per network namespace and grants nothing beyond the CAP_NET_ADMIN the panel already holds. Verified on systemd 257 (Debian trixie) with the shipped unit and the pinned core: the v3.10.0 unit reproduces the error, the new one starts the kernel TUN, and kernel.core_pattern stays read-only for the service. Closes #6796
100 lines
5.0 KiB
Plaintext
100 lines
5.0 KiB
Plaintext
[Unit]
|
|
Description=x-ui Service
|
|
After=network.target
|
|
Wants=network.target
|
|
StartLimitIntervalSec=180
|
|
StartLimitBurst=10
|
|
|
|
[Service]
|
|
EnvironmentFile=-/etc/conf.d/x-ui
|
|
Environment="XRAY_VMESS_AEAD_FORCED=false"
|
|
Type=simple
|
|
WorkingDirectory=/usr/local/x-ui/
|
|
ExecStart=/usr/local/x-ui/x-ui
|
|
ExecReload=/bin/kill -USR1 $MAINPID
|
|
Restart=on-failure
|
|
RestartSec=5s
|
|
|
|
# The panel intentionally stays root: it supervises the Xray child processes,
|
|
# edits netfilter state and reads TLS private keys. These settings only bound
|
|
# what a panel-level flaw can reach.
|
|
#
|
|
# PrivateTmp=yes is deliberately absent: the web updater writes its script into
|
|
# /tmp and hands the absolute path to a "systemd-run" transient unit, which
|
|
# does not share this service's private /tmp (the download would vanish).
|
|
NoNewPrivileges=yes
|
|
ProtectSystem=full
|
|
# Default stores: DB/update status/node-token in XUI_DB_FOLDER (/etc/x-ui),
|
|
# xray binary/config/geo in XUI_BIN_FOLDER under /usr/local/x-ui, logs in
|
|
# XUI_LOG_FOLDER (/var/log/x-ui). These are the plain-install defaults and the
|
|
# floor, not the whole list: install.sh and update.sh regenerate a drop-in
|
|
# (x-ui.service.d/10-xui-sandbox.conf) with the folders resolved from the XUI_*
|
|
# variables, so a relocated XUI_DB_FOLDER or XUI_LOG_FOLDER stays writable and
|
|
# the list survives an update instead of being reset to these defaults. Changing
|
|
# one of those variables in the env file is not enough by itself: the drop-in has
|
|
# to be refreshed as well, i.e. install or update the panel again.
|
|
# Add local extras in your own drop-in (e.g. 20-local.conf).
|
|
# The leading '-' keeps the unit startable if a path does not exist yet.
|
|
# What ProtectSystem=full covers, precisely: /usr, /boot, /efi and /etc become
|
|
# read-only, everything else stays writable. So this list matters for stores
|
|
# under those trees -- the default main folder under /usr/local is one.
|
|
#
|
|
# The in-panel updater is expected to leave this sandbox: it runs update.sh
|
|
# through a transient systemd-run unit, which does not inherit these settings.
|
|
# Its plain-child fallback (taken when systemd-run is unavailable) cannot work
|
|
# here -- update.sh stages the release archive beside the main folder, replaces
|
|
# /usr/bin/x-ui and calls the package manager -- so it stops with one clear
|
|
# message instead of failing halfway, and the sandbox deliberately does not
|
|
# grant /usr or /etc to accommodate it.
|
|
# ReadWritePaths= requires systemd >= 231; ReadWriteDirectories= is the deprecated
|
|
# alias for older systemd, needed so ProtectSystem=full keeps /etc/x-ui writable.
|
|
ReadWritePaths=-/etc/x-ui -/usr/local/x-ui -/var/log/x-ui
|
|
ReadWriteDirectories=-/etc/x-ui -/usr/local/x-ui -/var/log/x-ui
|
|
# A kernel-TUN WireGuard outbound zeroes net.ipv{4,6}.conf.*.rp_filter as Xray starts
|
|
# (#6796). Reopen only /proc/sys/net: kernel.* (core_pattern among them) stays read-only.
|
|
# No ReadWriteDirectories alias needed: ProtectKernelTunables itself requires systemd 232.
|
|
ReadWritePaths=-/proc/sys/net
|
|
ProtectKernelTunables=yes
|
|
ProtectKernelModules=yes
|
|
ProtectKernelLogs=yes
|
|
ProtectClock=yes
|
|
ProtectHostname=yes
|
|
# read-only rather than yes: installs keep TLS certs under /root/cert, and the
|
|
# panel must still be able to read them.
|
|
ProtectHome=read-only
|
|
LockPersonality=yes
|
|
RestrictRealtime=yes
|
|
RestrictSUIDSGID=yes
|
|
RestrictNamespaces=yes
|
|
UMask=0077
|
|
# AF_NETLINK for interface/route lookups and the ip(8) child used by the
|
|
# AmneziaWG IPv6-alias feature.
|
|
RestrictAddressFamilies=AF_INET AF_INET6 AF_UNIX AF_NETLINK
|
|
# NET_ADMIN for ip(8)/tproxy, NET_BIND_SERVICE for ports below 1024, NET_RAW
|
|
# for raw sockets and SO_BINDTODEVICE.
|
|
#
|
|
# DAC_OVERRIDE has to stay. The panel runs as root, but a bounding set is
|
|
# subtracted from root's own privileges too: without it root can only read a
|
|
# file when the owner/group/other bits let uid 0 through, and any TLS private
|
|
# key belonging to another account becomes unreadable -- a certificate issued to
|
|
# Caddy, an acme.sh home, any 0600 file that root does not own. TLS then fails
|
|
# quietly: the panel listener catches the tls.LoadX509KeyPair error, logs it and
|
|
# keeps serving plain HTTP, and every Xray inbound using that key stops. Those
|
|
# reads worked before the sandbox because the panel is root.
|
|
# DAC_READ_SEARCH is deliberately absent: directory search is already covered by
|
|
# DAC_OVERRIDE, so it would only widen the set without adding anything.
|
|
CapabilityBoundingSet=CAP_DAC_OVERRIDE CAP_NET_ADMIN CAP_NET_BIND_SERVICE CAP_NET_RAW
|
|
SystemCallArchitectures=native
|
|
# No seccomp whitelist here on purpose. @system-service needs systemd >= 239
|
|
# (other @-named groups exist since 231), and older systemd does not ignore an
|
|
# unknown group name gracefully: on
|
|
# <231 the name fails to resolve and the filter stays the built-in whitelist of
|
|
# execve/exit/exit_group/rt_sigreturn/sigreturn, on 231..238 it degrades to
|
|
# @default -- either way the panel then gets EPERM on read/openat/mmap/clone and
|
|
# cannot start. install.sh and update.sh add SystemCallFilter=@system-service and
|
|
# SystemCallErrorNumber=EPERM to the generated drop-in, but only when
|
|
# "systemctl --version" reports 239 or newer.
|
|
|
|
[Install]
|
|
WantedBy=multi-user.target
|