Files

94 lines
6.4 KiB
Markdown

# Example Linux service
`rustproxy.service` is an operator-reviewed deployment example, not an installed or
tested service. With RustProxy 0.34.2, the example includes `ExecReload` so `systemctl reload rustproxy` uses the authenticated CLI soft reload. If using `RUST_PROXY_CONFIG`, configure it in the service EnvironmentFile so both `ExecStart` and `ExecReload` share the same file source. It runs the compiled executable as a dedicated `rustproxy` account,
uses the public administration profile shown below and grants only the capability needed
for low-port binding. It does not run the proxy as root or grant Docker socket access.
Before installation, run the real Rust acceptance suite, build a release executable,
create the unprivileged account/group through your normal system administration
process and install the executable at `/opt/rustproxy/rust-proxy`. The service
manager creates `/var/lib/rustproxy` as private writable state; the actual private
data directory is `/var/lib/rustproxy`. `LogsDirectory=rustproxy` provisions
`/var/log/rustproxy` for the JSONL access-log sink while the rest of the filesystem
remains protected by `ProtectSystem=strict`. The service enables 80/443 startup
defaults, does not start a demo backend and uses a self-signed fallback certificate
until trusted certificates are imported. Firewall, DNS and trust configuration are
separate operator responsibilities.
Existing SQLite listener overrides take precedence over these startup defaults.
Review Settings before moving an old database into this service. Public addresses
are deliberately explicit in the example. Customize the unit for other paths,
addresses, limits or a service-account convention. Never point it at a user-owned
source directory containing writable executables or real public web content.
After starting through your service manager, run account/certificate CLI operations
as the same service account with `--data-dir /var/lib/rustproxy`. The reference
uses `ProtectHome=read-only`, so site roots in `/home` and trusted external
certificates can be read according to Unix permissions, groups and ACLs,
without overriding the systemd sandbox. The reference binds administration
to `0.0.0.0:9090`; restrict this to loopback before running on an untrusted
network, or use administration HTTPS and strict network controls. Use an SSH
tunnel to access a loopback-only admin port remotely. Public HTTP/HTTPS
listeners remain explicit. For direct remote administration, enable Administration HTTPS and persist
a non-loopback bind from the panel rather than exposing the plain-HTTP bootstrap listener. For a
systemd drop-in, reset `ExecStart` before replacing it. Example preserving the loopback-safe admin:
```ini
[Service]
ExecStart=
ExecStart=/opt/rustproxy/current/rust-proxy --data-dir /var/lib/rustproxy --admin-listen 127.0.0.1:9090 serve --proxy-listen 0.0.0.0:80 --tls-listen 0.0.0.0:443
ReadWritePaths=/var/log/rustproxy
```
Saving HTTP/TLS or TCP/UDP stream listener changes in the UI does not restart this service. Restart explicitly
only after checking permission, free ports and certificate readiness. A bad saved
bind can prevent startup; preserve a pre-change database backup and consult
`docs/MIGRATION.md` for recovery. Verify the unit on the target system with
`systemd-analyze verify` and exercise actual non-root binding before accepting a
production deployment. This packaging environment did not run systemd or bind
privileged ports through this unit.
## Optional JSON backing file (`--config`)
Use `sudo systemctl edit rustproxy` to override the startup command, **not** to edit the packaged unit directly. For the `/usr/bin` installation requested below (switch to `/opt/rustproxy/current/rust-proxy` on the managed deployment), configure:
```ini
[Service]
ExecStart=
ExecStart=/usr/bin/rust-proxy --data-dir /var/lib/rustproxy --admin-listen 0.0.0.0:9090 serve --proxy-listen 0.0.0.0:80 --tls-listen 0.0.0.0:443 --allow-remote-admin --config /etc/rustproxy/config.json
ReadWritePaths=/etc/rustproxy
```
Only activate after exporting a complete, valid JSON config. The directory and initial file may remain `root:root`, restricted to `0700` and `0600`; use:
```bash
sudo chown root:root /etc/rustproxy /etc/rustproxy/config.json
sudo chmod 0700 /etc/rustproxy
sudo chmod 0600 /etc/rustproxy/config.json
sudo setfacl -m u:rustproxy:rwx /etc/rustproxy
sudo setfacl -m u:rustproxy:rw- /etc/rustproxy/config.json
sudo getfacl /etc/rustproxy /etc/rustproxy/config.json
```
**Atomic panel saves replace the file**: the service needs directory traversal/create/rename permission (`rwx`), not just file write. New config files are written `0600`, normally owned by `rustproxy`; do not assume named file ACLs survive replacement. `ProtectSystem=strict` additionally requires `ReadWritePaths=/etc/rustproxy` in the unit; ACLs do not override the systemd sandbox. Keep the original private data directory and SQLite state. Check the active source in **Settings → Manual config**, inspect the unit with `systemctl cat rustproxy`, then `systemctl restart rustproxy` and verify a save. An external JSON edit needs `systemctl reload rustproxy`; there is no automatic file watching.
**Security:** the shown `0.0.0.0:9090` requires administration HTTPS and network access controls before remote exposure; use loopback administration otherwise. The complete export, privilege commands, validation and rollback guidance live in [Installation](../docs/INSTALL.md#optional-systemd-json-configuration).
External certificate files under `/etc/letsencrypt`, `/etc/ssl` or another
trusted root/service-owned directory remain read-only under the systemd
sandbox. No path-specific `ReadOnlyPaths=` allowlist is necessary;
`ReadOnlyPaths=` does not grant Unix permissions anyway. Use narrow POSIX ACLs
for the `rustproxy` user. For traversal of a protected root, for example:
```bash
setfacl -m u:rustproxy:--x /etc/ssl/
```
Grant `r--` only on the certificate/key files RustProxy actually needs; never grant write access to the service identity.
If Certbot or another renewer recreates a key as `0600`, reapply the named file ACL to the newly resolved target in the renewal hook before calling the RustProxy reload API.
External certificate parent directories and PEM files must be owned by root
or the service account and meet the application's safe-file checks; arbitrary
user-owned `/home` trees work as Web Server roots, but not as PEM ancestry.
See [Installation: external paths](../docs/INSTALL.md#linux-debrpm-read-only-access-to-external-paths).