84 lines
5.9 KiB
Markdown
84 lines
5.9 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 example
|
|
uses `ProtectHome=true`, so certificate files intended for runtime use must be in
|
|
the data directory, not in a home directory. Use an SSH tunnel to access the local
|
|
admin port remotely. This reference unit keeps administration on `127.0.0.1:9090`; 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
|
|
ReadOnlyPaths=-/etc/letsencrypt -/etc/ssl
|
|
```
|
|
|
|
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` or `/etc/ssl` remain read-only under the systemd sandbox. `ReadOnlyPaths=` does not grant Unix permissions; 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.
|