feat(deb): package the server, and ask the questions that fail silently
DR-015, DR-016. §8 already shipped a static binary and an optional container; this adds the third form, and it packages the SAME binary the musl job proved static rather than building its own. Two builds of the same commit could diverge, and the whole point of that assertion is that the artifact an operator installs is the one that was checked. Built with dpkg-deb from an explicit staging tree rather than cargo-deb. debconf's `config` script and `templates` live in the control archive next to the maintainer scripts, and controlling that archive directly beats discovering what a wrapper will copy into it. dpkg-dev is on every Debian builder, so this adds no build dependency. Why debconf at all: two settings fail SILENTLY when unset. Without JRAY_TMDB_API_KEY every upload stays `pending` and is never listed; without JRAY_TRUSTED_PROXIES the X-Forwarded-For header is ignored, so every client shares one rate-limit bucket and every abuse report points at the proxy. Both leave a server that works and is quietly doing the wrong thing — the worst thing to leave to a README nobody reads. Three properties, each a way packaging usually goes wrong: The generated config is NOT a dpkg conffile. It is written from the debconf answers, so shipping it as one would make dpkg prompt on every upgrade about changes the package itself had made. Hand edits survive. postinst rewrites only the keys debconf manages; comments, ordering and any other setting are left alone. A blank key on reconfigure keeps the existing one. Otherwise pressing Enter through a dpkg-reconfigure would unpublish every future upload. The seeding guard is worth its comment, because the obvious version is wrong twice over. `config` seeds unanswered questions from the env file so a reconfigure shows what is actually in force. Seeding unconditionally overwrites a preseed — debconf-set-selections marks what it sets as seen — so every unattended install would quietly reconfigure itself back to whatever was on disk. Guarding on an empty value does not work either: server-id and bind carry template Defaults, so db_get returns "localhost" for a question nobody answered. The test is the `seen` flag, which is the actual question being asked. Purge keeps the database, knowingly departing from the expectation that purge removes everything. Manifests are the output of real CV compute on media the operator may no longer have, and §8 says federation is explicitly not a backup. Destroying that during an `apt purge` is not a trade worth making for tidiness; postrm names the path instead. The nginx example is documentation, not installed configuration. The proxy usually runs on a different host from the server, so a file dropped into this machine's nginx would be in the wrong place — and §8 leaves the edge to the operator deliberately. Verified by running it, not by reading it: a full lifecycle in a bookworm container — build, preseeded install, mode-600 env file, key absent from debconf's database afterwards, `systemd-analyze verify` on the unit, the installed binary answering /health and /ready, reconfigure preserving both the key and an unmanaged setting, and purge leaving the database. It failed on the seeding bug above the first time, which is why that guard exists. CI runs the same checks against every build. TRACES: DR-015, DR-016 | PR-004
This commit is contained in:
@@ -0,0 +1,66 @@
|
||||
#!/bin/sh
|
||||
# debconf question script. Runs before unpacking, and again on
|
||||
# `dpkg-reconfigure jray-server`.
|
||||
#
|
||||
# Existing values are read back out of /etc/jray-server/env first, so a
|
||||
# reconfigure shows what is actually in force rather than the package defaults.
|
||||
# Without this, an operator who edited the env file by hand would be shown stale
|
||||
# answers and silently have their edits reverted by postinst.
|
||||
set -e
|
||||
. /usr/share/debconf/confmodule
|
||||
|
||||
ENV_FILE=/etc/jray-server/env
|
||||
|
||||
# Read one KEY=value out of the env file, ignoring comments. Values are written
|
||||
# unquoted by postinst, so no unquoting is needed.
|
||||
env_value() {
|
||||
[ -f "$ENV_FILE" ] || return 0
|
||||
sed -n "s/^$1=//p" "$ENV_FILE" | tail -1
|
||||
}
|
||||
|
||||
# Seed only a question debconf has never had an answer to.
|
||||
#
|
||||
# The test is the `seen` flag, not whether the value is empty: two of these
|
||||
# templates carry a Default, so db_get returns "localhost" or "127.0.0.1:8080"
|
||||
# for a question nobody has answered, and an emptiness check would never seed
|
||||
# them. `seen` distinguishes "this is the template default" from "somebody chose
|
||||
# this", which is the actual question.
|
||||
#
|
||||
# And it has to be a guard rather than an unconditional db_set. debconf-set-
|
||||
# selections marks what it sets as seen, so an unconditional seed would overwrite
|
||||
# a value the operator had just preseeded — every unattended install would
|
||||
# quietly reconfigure itself back to whatever was already on disk. Preseeding is
|
||||
# the entire point of the unattended path, so debconf wins wherever it has an
|
||||
# answer and the env file only fills in what it does not.
|
||||
seed() { # seed <debconf-key> <env-key>
|
||||
db_fget "$1" seen || RET=""
|
||||
[ "$RET" = "true" ] && return 0
|
||||
v=$(env_value "$2")
|
||||
[ -n "$v" ] && db_set "$1" "$v"
|
||||
return 0
|
||||
}
|
||||
|
||||
seed jray-server/server-id JRAY_SERVER_ID
|
||||
seed jray-server/bind JRAY_BIND
|
||||
seed jray-server/trusted-proxies JRAY_TRUSTED_PROXIES
|
||||
seed jray-server/contact JRAY_CONTACT
|
||||
|
||||
# The API key is deliberately NOT seeded back into the prompt: it is a password
|
||||
# template, so debconf would render it as a filled-in field the operator cannot
|
||||
# read, and accepting it would just rewrite what is already there. Blank means
|
||||
# "keep the existing key" and postinst implements exactly that.
|
||||
|
||||
db_fget jray-server/publish-peer-directory seen || RET=""
|
||||
if [ "$RET" != "true" ] && [ "$(env_value JRAY_PUBLISH_PEER_DIRECTORY)" = "1" ]; then
|
||||
db_set jray-server/publish-peer-directory true
|
||||
fi
|
||||
|
||||
db_input high jray-server/server-id || true
|
||||
db_input high jray-server/bind || true
|
||||
db_input high jray-server/trusted-proxies || true
|
||||
db_input high jray-server/tmdb-api-key || true
|
||||
db_input medium jray-server/contact || true
|
||||
db_input medium jray-server/publish-peer-directory || true
|
||||
db_go || true
|
||||
|
||||
exit 0
|
||||
@@ -0,0 +1,120 @@
|
||||
#!/bin/sh
|
||||
# Configure jray-server from the debconf answers.
|
||||
#
|
||||
# /etc/jray-server/env is deliberately NOT a dpkg conffile. A conffile is for a
|
||||
# file the package ships and the operator may edit; this one is *generated* from
|
||||
# debconf, so shipping it would make dpkg prompt on every upgrade about changes
|
||||
# the package itself had made. Instead it is written here and updated key by
|
||||
# key, which leaves comments, ordering and any setting debconf does not manage
|
||||
# untouched.
|
||||
set -e
|
||||
. /usr/share/debconf/confmodule
|
||||
|
||||
CONF_DIR=/etc/jray-server
|
||||
ENV_FILE="$CONF_DIR/env"
|
||||
|
||||
# Update one KEY=value in place, appending if absent. Everything else in the
|
||||
# file - comments, blank lines, settings this package does not ask about - is
|
||||
# preserved, which is what makes hand-editing and dpkg-reconfigure coexist.
|
||||
set_kv() {
|
||||
key="$1"; val="$2"
|
||||
if grep -q "^$key=" "$ENV_FILE" 2>/dev/null; then
|
||||
# `|` as the delimiter: values are hostnames, IP lists and URLs, none of
|
||||
# which contain it, whereas `/` appears in contacts and base URLs.
|
||||
sed -i "s|^$key=.*|$key=$val|" "$ENV_FILE"
|
||||
else
|
||||
printf '%s=%s\n' "$key" "$val" >> "$ENV_FILE"
|
||||
fi
|
||||
}
|
||||
|
||||
case "$1" in
|
||||
configure)
|
||||
mkdir -p "$CONF_DIR"
|
||||
chmod 0755 "$CONF_DIR"
|
||||
|
||||
if [ ! -f "$ENV_FILE" ]; then
|
||||
cat > "$ENV_FILE" <<'EOF'
|
||||
# jray-server configuration.
|
||||
#
|
||||
# Written by the package from your debconf answers; re-run
|
||||
# dpkg-reconfigure jray-server
|
||||
# to change them. Hand edits to this file are preserved: the package updates
|
||||
# only the keys it manages and leaves everything else alone.
|
||||
#
|
||||
# The full set of variables is in SPEC.md section 8 and src/config.rs.
|
||||
|
||||
EOF
|
||||
fi
|
||||
# 0600 before anything is written into it: the TMDB key lands here.
|
||||
chmod 0600 "$ENV_FILE"
|
||||
|
||||
db_get jray-server/server-id && set_kv JRAY_SERVER_ID "$RET"
|
||||
db_get jray-server/bind && set_kv JRAY_BIND "$RET"
|
||||
db_get jray-server/trusted-proxies && set_kv JRAY_TRUSTED_PROXIES "$RET"
|
||||
db_get jray-server/contact && set_kv JRAY_CONTACT "$RET"
|
||||
|
||||
db_get jray-server/publish-peer-directory
|
||||
if [ "$RET" = "true" ]; then
|
||||
set_kv JRAY_PUBLISH_PEER_DIRECTORY 1
|
||||
else
|
||||
set_kv JRAY_PUBLISH_PEER_DIRECTORY 0
|
||||
fi
|
||||
|
||||
# Blank means "keep whatever is already configured" - see the note in the
|
||||
# debconf template. Only overwrite when the operator actually supplied one.
|
||||
db_get jray-server/tmdb-api-key
|
||||
if [ -n "$RET" ]; then
|
||||
set_kv JRAY_TMDB_API_KEY "$RET"
|
||||
elif ! grep -q '^JRAY_TMDB_API_KEY=' "$ENV_FILE" 2>/dev/null; then
|
||||
set_kv JRAY_TMDB_API_KEY ""
|
||||
fi
|
||||
# Drop the secret from debconf's database now that it is in the env file.
|
||||
# config.dat is root-only, so this is defence in depth rather than a fix for
|
||||
# a leak - but there is no reason for a second copy to outlive its use.
|
||||
db_set jray-server/tmdb-api-key "" || true
|
||||
|
||||
set_kv JRAY_DB "/var/lib/jray-server/jray.db"
|
||||
|
||||
# Warn about the two settings whose absence fails silently rather than
|
||||
# loudly. Both are recoverable with dpkg-reconfigure, and neither stops the
|
||||
# service starting, so the operator would otherwise find out from a log line
|
||||
# they had no reason to read.
|
||||
if ! grep -q '^JRAY_TMDB_API_KEY=.' "$ENV_FILE" 2>/dev/null; then
|
||||
echo "jray-server: no TMDB API key set - uploads will stay pending and never be listed." >&2
|
||||
echo " Set one with: dpkg-reconfigure jray-server" >&2
|
||||
fi
|
||||
if ! grep -q '^JRAY_TRUSTED_PROXIES=.' "$ENV_FILE" 2>/dev/null; then
|
||||
echo "jray-server: no trusted proxies set - X-Forwarded-For will be ignored, so every" >&2
|
||||
echo " client shares one rate-limit bucket. Set your proxy's address with:" >&2
|
||||
echo " dpkg-reconfigure jray-server" >&2
|
||||
fi
|
||||
;;
|
||||
|
||||
abort-upgrade|abort-remove|abort-deconfigure) ;;
|
||||
*) echo "postinst called with unknown argument \`$1'" >&2; exit 1 ;;
|
||||
esac
|
||||
|
||||
# systemd wiring, in the form dh_installsystemd generates. StateDirectory= in the
|
||||
# unit creates and owns /var/lib/jray-server, so there is no directory or user to
|
||||
# set up here.
|
||||
if [ "$1" = "configure" ] || [ "$1" = "abort-upgrade" ]; then
|
||||
if [ -d /run/systemd/system ]; then
|
||||
systemctl --system daemon-reload >/dev/null 2>&1 || true
|
||||
fi
|
||||
if deb-systemd-helper debian-installed jray-server.service 2>/dev/null; then
|
||||
deb-systemd-helper unmask jray-server.service >/dev/null || true
|
||||
if deb-systemd-helper --quiet was-enabled jray-server.service; then
|
||||
deb-systemd-helper enable jray-server.service >/dev/null || true
|
||||
else
|
||||
deb-systemd-helper update-state jray-server.service >/dev/null || true
|
||||
fi
|
||||
fi
|
||||
if [ -d /run/systemd/system ]; then
|
||||
# Starting an unconfigured install is safe by construction: JRAY_BIND
|
||||
# defaults to loopback, so it is not reachable until the operator says
|
||||
# otherwise.
|
||||
deb-systemd-invoke restart jray-server.service >/dev/null || true
|
||||
fi
|
||||
fi
|
||||
|
||||
exit 0
|
||||
@@ -0,0 +1,51 @@
|
||||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
DB_DIR=/var/lib/jray-server
|
||||
|
||||
if [ -d /run/systemd/system ]; then
|
||||
systemctl --system daemon-reload >/dev/null 2>&1 || true
|
||||
fi
|
||||
|
||||
case "$1" in
|
||||
purge)
|
||||
# Configuration goes, including the TMDB key.
|
||||
rm -f /etc/jray-server/env
|
||||
rmdir --ignore-fail-on-non-empty /etc/jray-server 2>/dev/null || true
|
||||
|
||||
if [ -f /usr/share/debconf/confmodule ]; then
|
||||
. /usr/share/debconf/confmodule
|
||||
db_purge || true
|
||||
fi
|
||||
|
||||
if [ -x /usr/bin/deb-systemd-helper ]; then
|
||||
deb-systemd-helper purge jray-server.service >/dev/null || true
|
||||
deb-systemd-helper unmask jray-server.service >/dev/null || true
|
||||
fi
|
||||
|
||||
# The database is deliberately NOT deleted on purge, and that is a knowing
|
||||
# deviation from the usual expectation that purge removes everything.
|
||||
#
|
||||
# Manifests are the output of real CV compute on media the operator may no
|
||||
# longer have, and federation (SPEC section 9a) gives partial resilience but
|
||||
# is explicitly not a backup. Silently destroying that during an `apt purge`
|
||||
# - a command people run to clean up - is not a trade worth making for
|
||||
# tidiness. Say where it is instead, and let the operator decide.
|
||||
if [ -d "$DB_DIR" ]; then
|
||||
echo "jray-server: purged, but the database was kept at $DB_DIR" >&2
|
||||
echo " It holds contributed manifests, which are not recoverable" >&2
|
||||
echo " from this package. Remove it yourself if you mean to:" >&2
|
||||
echo " rm -rf $DB_DIR" >&2
|
||||
fi
|
||||
;;
|
||||
|
||||
remove|upgrade|failed-upgrade|abort-install|abort-upgrade|disappear)
|
||||
if [ "$1" = remove ] && [ -x /usr/bin/deb-systemd-helper ]; then
|
||||
deb-systemd-helper mask jray-server.service >/dev/null || true
|
||||
fi
|
||||
;;
|
||||
|
||||
*) echo "postrm called with unknown argument \`$1'" >&2; exit 1 ;;
|
||||
esac
|
||||
|
||||
exit 0
|
||||
@@ -0,0 +1,11 @@
|
||||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
if [ -d /run/systemd/system ] && [ "$1" = remove ]; then
|
||||
# SIGTERM, which main.rs handles: stop accepting, drain in-flight requests,
|
||||
# let the cast-check worker finish its tick. TimeoutStopSec in the unit gives
|
||||
# it 30 s before systemd escalates.
|
||||
deb-systemd-invoke stop jray-server.service >/dev/null || true
|
||||
fi
|
||||
|
||||
exit 0
|
||||
@@ -0,0 +1,64 @@
|
||||
Template: jray-server/server-id
|
||||
Type: string
|
||||
Default: localhost
|
||||
Description: Public hostname of this JRay server:
|
||||
Identifies this instance in federation (SPEC section 9a) and is recorded on
|
||||
every manifest it originates, so peers can tell whose judgement they are
|
||||
replicating.
|
||||
.
|
||||
Use the name operators will reach you on, for example jray.example.org.
|
||||
Leaving it as "localhost" is fine for a private trial and wrong for anything
|
||||
federated.
|
||||
|
||||
Template: jray-server/bind
|
||||
Type: string
|
||||
Default: 127.0.0.1:8080
|
||||
Description: Address and port to listen on:
|
||||
The server speaks plain HTTP and expects TLS to be terminated by your reverse
|
||||
proxy (SPEC section 8).
|
||||
.
|
||||
Keep the default if the proxy runs on this same host. If the proxy is
|
||||
elsewhere - a separate container or VM, which is the common case - this must
|
||||
be an address that host can reach, for example 0.0.0.0:8080. Firewall the
|
||||
port to the proxy if you do that: the default is loopback precisely so an
|
||||
unconfigured install is not reachable.
|
||||
|
||||
Template: jray-server/trusted-proxies
|
||||
Type: string
|
||||
Description: Trusted reverse proxy addresses (comma-separated):
|
||||
Rate limiting and abuse-report attribution both key on the client IP, so
|
||||
X-Forwarded-For is honoured only from addresses listed here. A header trusted
|
||||
unconditionally would let any client mint itself a fresh rate-limit budget and
|
||||
pin its reports on someone else.
|
||||
.
|
||||
If the proxy runs on this host, enter 127.0.0.1. If it runs elsewhere, enter
|
||||
the address it connects from - not the address you reach it on.
|
||||
.
|
||||
Leaving this empty is safe but coarse: X-Forwarded-For is then ignored
|
||||
entirely and every request is attributed to the proxy, so all clients share
|
||||
one rate-limit bucket.
|
||||
|
||||
Template: jray-server/tmdb-api-key
|
||||
Type: password
|
||||
Description: TMDB API key:
|
||||
Uploaded manifests are cross-checked against the TMDB cast list before being
|
||||
published (SPEC section 6, stage 3). Without a key the server still serves
|
||||
reads normally, but every upload stays in "pending" and is never listed -
|
||||
the correct failure mode, but a silent one.
|
||||
.
|
||||
Leave blank to configure later with: dpkg-reconfigure jray-server
|
||||
If a key is already configured, leaving this blank keeps it.
|
||||
|
||||
Template: jray-server/contact
|
||||
Type: string
|
||||
Description: Operator contact (optional):
|
||||
Published so other operators can arrange peering out of band. An email
|
||||
address or a URL. Leave blank to publish no contact.
|
||||
|
||||
Template: jray-server/publish-peer-directory
|
||||
Type: boolean
|
||||
Default: false
|
||||
Description: Publish this server's peer directory?
|
||||
Section 9a makes this deliberately optional: publishing lists the peers you
|
||||
replicate from, which discloses your federation topology. A server that would
|
||||
rather not disclose it simply does not, and federation still works.
|
||||
@@ -0,0 +1,78 @@
|
||||
# Example nginx site for jray-server. NOT installed anywhere by the package —
|
||||
# the proxy usually runs on a different host from the server, so a file dropped
|
||||
# into this machine's nginx would be in the wrong place. Copy it to the proxy.
|
||||
#
|
||||
# /etc/nginx/sites-available/jray-server (then symlink into sites-enabled)
|
||||
#
|
||||
# Replace jray.example.org and the upstream address, and point ssl_certificate
|
||||
# at your own certificate.
|
||||
|
||||
upstream jray_server {
|
||||
# The address jray-server listens on. If the proxy runs on the SAME host,
|
||||
# this is 127.0.0.1:8080 and JRAY_BIND can stay at its loopback default. If
|
||||
# the proxy is elsewhere, put the server's address here, set JRAY_BIND to
|
||||
# something that host can reach (0.0.0.0:8080), and firewall the port to
|
||||
# this proxy.
|
||||
server 10.0.0.42:8080;
|
||||
keepalive 8;
|
||||
}
|
||||
|
||||
server {
|
||||
listen 443 ssl;
|
||||
http2 on;
|
||||
server_name jray.example.org;
|
||||
|
||||
ssl_certificate /etc/letsencrypt/live/jray.example.org/fullchain.pem;
|
||||
ssl_certificate_key /etc/letsencrypt/live/jray.example.org/privkey.pem;
|
||||
|
||||
# SPEC section 6 stage 1 body caps, mirrored at the edge. Section 8 asks for
|
||||
# them in both places: the proxy rejects the bulk before it reaches the
|
||||
# application, and the application stays correct if it is ever run without a
|
||||
# proxy. These must not be tightened below the application's own limits or
|
||||
# legitimate uploads get a 413 from nginx that the server never sees.
|
||||
client_max_body_size 2m;
|
||||
|
||||
location = /api/v1/manifests/bundle {
|
||||
# Series bundles only (section 2). This is why the cap is per-location
|
||||
# rather than one global 25m: widening it everywhere would hand every
|
||||
# other endpoint a 25 MiB budget it has no use for.
|
||||
client_max_body_size 25m;
|
||||
proxy_pass http://jray_server;
|
||||
include snippets/jray-server-proxy.conf;
|
||||
}
|
||||
|
||||
# Liveness. Kept out of the access log because uptime checks poll it hard.
|
||||
location = /health {
|
||||
proxy_pass http://jray_server;
|
||||
include snippets/jray-server-proxy.conf;
|
||||
access_log off;
|
||||
}
|
||||
|
||||
location / {
|
||||
proxy_pass http://jray_server;
|
||||
include snippets/jray-server-proxy.conf;
|
||||
}
|
||||
}
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# /etc/nginx/snippets/jray-server-proxy.conf
|
||||
# ---------------------------------------------------------------------------
|
||||
#
|
||||
# proxy_http_version 1.1;
|
||||
# proxy_set_header Connection "";
|
||||
#
|
||||
# proxy_set_header Host $host;
|
||||
# proxy_set_header X-Forwarded-Proto $scheme;
|
||||
#
|
||||
# # $proxy_add_x_forwarded_for appends the real peer on the RIGHT of any header
|
||||
# # the client sent. That is the safe form for this server: client_ip() in
|
||||
# # src/auth.rs reads X-Forwarded-For from the right and walks left past further
|
||||
# # trusted hops, so a client that forges its own entries only pollutes the part
|
||||
# # that is ignored. Do not "harden" this to $remote_addr unless you have exactly
|
||||
# # one proxy layer — with two, overwriting loses the real client.
|
||||
# proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
#
|
||||
# # Longer than JRAY_REQUEST_TIMEOUT_SEC (30 by default) so the application's own
|
||||
# # timeout fires first and returns a real status rather than nginx reporting 504
|
||||
# # for a request the server was still handling.
|
||||
# proxy_read_timeout 60s;
|
||||
@@ -0,0 +1,57 @@
|
||||
[Unit]
|
||||
Description=JRay public server
|
||||
Documentation=https://gitea.tourolle.paris/dtourolle/JRay-public-server
|
||||
After=network-online.target
|
||||
Wants=network-online.target
|
||||
|
||||
[Service]
|
||||
Type=exec
|
||||
ExecStart=/usr/bin/jray-server
|
||||
EnvironmentFile=/etc/jray-server/env
|
||||
|
||||
# No user to create at install time: systemd allocates one for the lifetime of
|
||||
# the unit and remaps StateDirectory ownership to it, so the package ships no
|
||||
# useradd and leaves nothing behind on purge.
|
||||
DynamicUser=yes
|
||||
StateDirectory=jray-server
|
||||
StateDirectoryMode=0700
|
||||
WorkingDirectory=/var/lib/jray-server
|
||||
|
||||
# main.rs installs a SIGTERM handler that stops accepting, drains in-flight
|
||||
# requests and lets the cast-check worker finish its tick before exit. SIGTERM is
|
||||
# already systemd's default; this only gives it room to finish rather than being
|
||||
# killed mid-drain.
|
||||
TimeoutStopSec=30
|
||||
Restart=on-failure
|
||||
RestartSec=5
|
||||
|
||||
# The binary is static (musl, bundled SQLite, bundled TLS roots). It opens one
|
||||
# database file under StateDirectory and makes outbound HTTPS calls to TMDB. It
|
||||
# needs nothing else, so everything else is denied.
|
||||
NoNewPrivileges=yes
|
||||
CapabilityBoundingSet=
|
||||
AmbientCapabilities=
|
||||
PrivateTmp=yes
|
||||
PrivateDevices=yes
|
||||
ProtectSystem=strict
|
||||
ProtectHome=yes
|
||||
ProtectProc=invisible
|
||||
ProtectKernelTunables=yes
|
||||
ProtectKernelModules=yes
|
||||
ProtectControlGroups=yes
|
||||
RestrictNamespaces=yes
|
||||
RestrictRealtime=yes
|
||||
RestrictSUIDSGID=yes
|
||||
# No AF_UNIX: musl resolves DNS itself from /etc/resolv.conf and the TLS roots
|
||||
# are compiled in (reqwest `rustls-tls` uses webpki-roots), so there is no NSS
|
||||
# socket and no CA bundle to read. A glibc build would need AF_UNIX added back.
|
||||
RestrictAddressFamilies=AF_INET AF_INET6
|
||||
LockPersonality=yes
|
||||
MemoryDenyWriteExecute=yes
|
||||
SystemCallArchitectures=native
|
||||
SystemCallFilter=@system-service
|
||||
SystemCallFilter=~@privileged @resources
|
||||
UMask=0077
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
Reference in New Issue
Block a user