238 lines
15 KiB
Markdown
238 lines
15 KiB
Markdown
# Installation, updates and first start
|
|
|
|
Use maintained packages whenever possible. For custom installations, use the scripts included with this source version; do not combine parts of different releases.
|
|
|
|
## Supported entry points
|
|
|
|
| Installation | Recommended starting point |
|
|
|---|---|
|
|
| Linux DEB/RPM (RustProxy server) | https://rustproxy.linuxiarz.pl/ |
|
|
| Docker host discovery agent (independent DEB/RPM) | `sudo apt install rustproxy-docker-agent` or `sudo dnf install rustproxy-docker-agent`; see [Docker discovery](DOCKER_DISCOVERY.md) |
|
|
| OPNsense plugin | https://rustproxy-opn.linuxiarz.pl/ |
|
|
| Debian 13+ source bootstrap | `install-debian13.sh` from the project repository |
|
|
| Manual Linux/systemd install | Compile the application; use `install.sh` and `update.sh` |
|
|
| OCI container | Included `Dockerfile`; see [Container](CONTAINER.md) |
|
|
|
|
Package/plugin instructions and maintenance policies are maintained separately from the source archive. The optional Docker agent is packaged independently of RustProxy's main service for **Linux amd64/x86_64 only**, not FreeBSD pkg. On a Docker host, the agent can also be installed manually from `docker-agent/install.sh`; the installer and packages preserve existing tokens and TLS keys. See [Docker discovery](DOCKER_DISCOVERY.md) and [agent operations](../docker-agent/README.md).
|
|
|
|
## Debian 13+ source bootstrap
|
|
|
|
Review the remote script before execution. On a managed installation, `auto` selects install or update from `/opt/rustproxy/install.json`.
|
|
|
|
```bash
|
|
# Initial install or existing managed update
|
|
wget -qO- https://git.linuxiarz.pl/gru/RustProxy/raw/branch/master/install-debian13.sh | bash
|
|
|
|
# Explicit managed update
|
|
wget -qO- https://git.linuxiarz.pl/gru/RustProxy/raw/branch/master/install-debian13.sh | bash -s -- update
|
|
```
|
|
|
|
The script installs dependencies, builds with `cargo build --release --locked` as an unprivileged build user, then uses the local deployment scripts. Run it only on Debian 13+ and with access to its required repositories. Installing from a moving `master` branch does **not** pin a specific audited release; use a reviewed commit when reproducibility matters.
|
|
|
|
## Build from the source
|
|
|
|
The current `Cargo.toml` declares **Rust 1.99 minimum**, with a `stable` toolchain in `rust-toolchain.toml`. Use Cargo, a C compiler/linker, Bash and Python 3 (Python 3.11+ is advisable for project checks). Run as a normal build user:
|
|
|
|
```bash
|
|
bash dev.sh doctor
|
|
bash dev.sh check
|
|
bash dev.sh test
|
|
bash dev.sh release
|
|
```
|
|
|
|
`dev.sh release` builds the application; it is not equivalent to a successful production rollout. Cargo dependencies and Swagger assets must be available to the build environment. An example systemd unit is in `deploy/`.
|
|
|
|
For a first Linux/systemd installation:
|
|
|
|
```bash
|
|
bash install.sh --plan --binary target/release/rust-proxy
|
|
sudo bash install.sh --binary target/release/rust-proxy
|
|
```
|
|
|
|
Use `--plan` to inspect changes first. The installer refuses existing unmanaged/nonempty state rather than overwriting it. Common options include `--prefix`, `--data-dir`, `--http`, `--https`, `--no-https`, `--admin`, `--allow-remote-admin` and `--no-start` (see `install.sh --help`).
|
|
|
|
## Defaults and administrator setup
|
|
|
|
For the standard managed Linux installation:
|
|
|
|
| Item | Default |
|
|
|---|---|
|
|
| HTTP frontend | `0.0.0.0:80` |
|
|
| HTTPS frontend | `0.0.0.0:443` with an initially self-signed certificate |
|
|
| Administration | `127.0.0.1:9090`, HTTP on loopback |
|
|
| Installation | `/opt/rustproxy/current/` |
|
|
| Private data | `/var/lib/rustproxy` |
|
|
| Service account | `rustproxy` |
|
|
|
|
The first installation has no predefined administrator and no application Vhosts. Obtain the one-time setup token locally:
|
|
|
|
```bash
|
|
sudo -u rustproxy /opt/rustproxy/current/rust-proxy \
|
|
--data-dir /var/lib/rustproxy admin setup-token
|
|
```
|
|
|
|
Use the setup page, or initialize the account interactively using `admin init`. To access loopback administration from another machine, tunnel over SSH:
|
|
|
|
```bash
|
|
ssh -L 9090:127.0.0.1:9090 operator@server
|
|
```
|
|
|
|
Then visit `http://127.0.0.1:9090` on your workstation. For a directly reachable administration listener, configure **Settings → Administration → HTTPS** and a suitable certificate, restrict the network, save and restart. Do not publish unauthenticated or plain-HTTP administration over the Internet. Public frontend HTTPS and administration HTTPS are separate.
|
|
|
|
### Listeners and networking
|
|
|
|
- Assign a trusted public certificate to the relevant hosts before exposing them.
|
|
- Configure DNS to reach the intended public listener; check IPv4/IPv6 and firewall rules.
|
|
- HTTP/3 needs UDP on the HTTPS port as well as TCP for normal HTTPS.
|
|
- Listener bindings supplied explicitly via service arguments/systemd are locked against panel changes. Network bind, administration TLS and some monitoring changes take effect after a restart.
|
|
- Ports below 1024 need the appropriate OS privileges/capability; use the installed service model rather than running the whole application as root.
|
|
|
|
## Linux DEB/RPM: read-only access to external paths
|
|
|
|
New Linux packages (package-builder filesystem-access policy, revision 5) and
|
|
the maintained manual service template use `ProtectHome=read-only` rather than
|
|
`ProtectHome=true`. This makes document roots under `/home`, `/var/www` and
|
|
`/srv` readable if the service account has **ordinary Unix group or ACL
|
|
permissions**. `ProtectSystem=strict` remains enabled: the service cannot
|
|
modify these files merely because a group or ACL permits it. No systemd
|
|
drop-in or extra `ReadOnlyPaths=` entry is needed to **read** site content or
|
|
an external certificate. This also applies when paths are stored in the panel.
|
|
|
|
The service runs as the unprivileged `rustproxy` user. To use a dedicated web
|
|
group, give that group directory traversal and file read permissions on the
|
|
site, then add RustProxy to it:
|
|
|
|
```bash
|
|
sudo usermod -aG web-readers rustproxy # use an existing narrow site group
|
|
sudo systemctl restart rustproxy # renew the service process's group list
|
|
```
|
|
|
|
Alternatively, to expose only `/home/alice/public_html` (install `acl` to get
|
|
`setfacl`), grant traversal of the private home and read/traversal of the site:
|
|
|
|
```bash
|
|
sudo setfacl -m u:rustproxy:--x /home/alice
|
|
sudo setfacl -R -m u:rustproxy:r-X /home/alice/public_html
|
|
sudo -u rustproxy test -r /home/alice/public_html/index.html && echo readable
|
|
sudo systemctl restart rustproxy
|
|
```
|
|
|
|
Use appropriate **default ACLs** or group ownership on directories where the
|
|
deployment process creates new files. Never expose the entire home directory
|
|
or use world-writable permissions to work around access errors. The
|
|
`sudo -u` check tests Unix permissions on the host, not the effective systemd
|
|
mount namespace.
|
|
|
|
External PEM files have **additional application security checks**. The
|
|
certificate/key and every real ancestor directory must be owned by root or
|
|
the RustProxy service user, and ancestors cannot be group/world-writable;
|
|
private keys cannot be world-readable. For Certbot files at
|
|
`/etc/letsencrypt/live/example.com`, for example:
|
|
|
|
```bash
|
|
sudo setfacl -m u:rustproxy:--x /etc/letsencrypt /etc/letsencrypt/live \
|
|
/etc/letsencrypt/live/example.com /etc/letsencrypt/archive \
|
|
/etc/letsencrypt/archive/example.com
|
|
sudo setfacl -m u:rustproxy:r-- "$(readlink -f /etc/letsencrypt/live/example.com/fullchain.pem)"
|
|
sudo setfacl -m u:rustproxy:r-- "$(readlink -f /etc/letsencrypt/live/example.com/privkey.pem)"
|
|
sudo systemctl reload rustproxy
|
|
```
|
|
|
|
Apply the file ACL again when a renewal replaces the symlink's target, then
|
|
reload. Arbitrary user-owned parent directories (for example `/home/alice`)
|
|
are suitable for static websites but **not** for external keys under the
|
|
current trusted-path validation. Use root-owned certificate storage instead.
|
|
Keep all key access narrow and read-only.
|
|
|
|
To diagnose unresolved errors, run `systemctl cat rustproxy` and
|
|
`systemctl show rustproxy -p ProtectHome -p ProtectSystem -p User -p Group`,
|
|
check parent permissions with `namei -l /path/to/file`, and examine
|
|
`journalctl -u rustproxy`. A legacy whole-unit file in
|
|
`/etc/systemd/system/rustproxy.service` takes precedence over the packaged
|
|
unit and is **not** automatically removed by an upgrade. On SELinux/AppArmor
|
|
hosts, additional mandatory access-control policy may be required; POSIX ACLs
|
|
cannot bypass it. See [Web Server](WEB_SERVER.md) and
|
|
[Certificates](ACME_PROVIDERS.md).
|
|
|
|
**Write access is intentionally different.** An app that needs to upload or
|
|
modify files under an arbitrary document root needs a separately planned
|
|
writable location/policy; group membership alone does not bypass the read-only
|
|
systemd mount. Keep mutable data isolated from served files.
|
|
|
|
## Optional systemd JSON configuration
|
|
|
|
This is **optional**. Without `--config`, RustProxy keeps its active configuration in `/var/lib/rustproxy/config.sqlite3` (SQLite). With `--config`, panel/API saves and history restores write `/etc/rustproxy/config.json` atomically; SQLite still contains history, administrator state and audit entries. In **Settings → Manual config** you can see which mode and path are active.
|
|
|
|
1. First export your existing, validated **full configuration** (do not start with `{}` on an established host). On the running instance with administration reachable at `127.0.0.1:9090`, use a privileged shell with `set -o pipefail`:
|
|
|
|
```bash
|
|
sudo install -d -o root -g root -m 0700 /etc/rustproxy
|
|
sudo install -o root -g root -m 0600 /dev/null /etc/rustproxy/config.json
|
|
sudo -u rustproxy /usr/bin/rust-proxy --data-dir /var/lib/rustproxy \
|
|
--admin-listen 127.0.0.1:9090 config get | sudo tee /etc/rustproxy/config.json >/dev/null
|
|
```
|
|
|
|
If the installed binary is at `/opt/rustproxy/current/rust-proxy`, use that path in **both** commands and the override. The export requires an existing initialized administrator. You may instead use **Settings → Manual config → Export JSON**, then install that file securely with `sudo install -o root -g root -m 0600 exported.json /etc/rustproxy/config.json`.
|
|
|
|
2. Keep the directory and initial file owned by `root`, allow only the RustProxy service identity through **named POSIX ACLs** (install the `acl` package first, e.g. `sudo apt-get install acl` on Debian, to obtain `setfacl`/`getfacl`). The directory needs `rwx` for atomic create/rename; the original JSON needs `rw` for startup and backup tools. `root` retains ownership until the first atomic panel save, after which the new `0600` file is normally owned by `rustproxy`:
|
|
|
|
```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
|
|
sudo -u rustproxy test -r /etc/rustproxy/config.json
|
|
sudo -u rustproxy test -w /etc/rustproxy
|
|
```
|
|
|
|
Never make `/etc/rustproxy` world-writable. RustProxy checks that `--config` is an existing absolute **regular non-symlink** file. The parent directory must be on a filesystem that supports atomic rename. Restoring a file as root may require reapplying its named ACL; atomic saves generate a new owner-only `0600` file.
|
|
|
|
3. Edit the systemd drop-in with `sudo systemctl edit rustproxy` and add the following example (the binary path must match your installation):
|
|
|
|
```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
|
|
```
|
|
|
|
`ReadWritePaths=` is needed when the unit has `ProtectSystem=strict`; it does **not** grant Unix file permissions, hence the ACLs above. An existing `ExecReload` can remain; it reloads through the local control API. Keep the existing unit's sandboxing, state/log writable paths, network capabilities and runtime user. Do not expose the example's `0.0.0.0:9090` admin listener over plaintext on an untrusted network: enable administration HTTPS and strict network controls first, or use the safer `127.0.0.1:9090` binding without `--allow-remote-admin`.
|
|
|
|
4. Verify and restart during a maintenance window:
|
|
|
|
```bash
|
|
sudo systemctl daemon-reload
|
|
sudo systemctl cat rustproxy
|
|
sudo systemd-analyze verify rustproxy.service
|
|
sudo systemctl restart rustproxy
|
|
sudo systemctl status rustproxy
|
|
sudo journalctl -u rustproxy -n 60 --no-pager
|
|
```
|
|
|
|
Confirm in **Settings → Manual config** that the source is **JSON file** and the path is `/etc/rustproxy/config.json`. Save a harmless edit and confirm that the file is rewritten and readable by `rustproxy`; check that a revision appears in SQLite. To import a deliberate external file edit without restarting, run `sudo systemctl reload rustproxy` (if the unit has `ExecReload`) or `rust-proxy --data-dir /var/lib/rustproxy --admin-listen 127.0.0.1:9090 config reload`. The file is not watched automatically. An incompatible external edit must fail validation rather than silently overwrite the live configuration.
|
|
|
|
For the alternate environment-variable method, set `RUST_PROXY_CONFIG=/etc/rustproxy/config.json` in the service's protected EnvironmentFile. Do not set **both** unrelated config paths. See [Configuration](CONFIGURATION.md) and the [deployment example](../deploy/README.md).
|
|
|
|
## Managed update
|
|
|
|
Test the new build first. Then execute:
|
|
|
|
```bash
|
|
bash update.sh --plan --binary target/release/rust-proxy
|
|
sudo bash update.sh --binary target/release/rust-proxy
|
|
```
|
|
|
|
Managed updates preserve the saved configuration, create a private backup, switch releases and attempt rollback on failed startup/health checks. **They interrupt traffic and are not a substitute for a separate off-host backup.** Keep your backup password and test a restore on a separate installation. Source-tree/unmanaged migrations require the dedicated stopped upgrade path: see [Migration](MIGRATION.md).
|
|
|
|
## ACME prerequisites
|
|
|
|
The managed certificate service can create a private Python/Certbot environment in the data directory; a usable system Certbot may be used as fallback. DNS-01 providers need credentials and appropriate permissions. HTTP-01 needs incoming public TCP `80`. On systems without an available Python/Certbot runtime, PEM import and external certificate references can still be used. See [Certificates](ACME_PROVIDERS.md).
|
|
|
|
## After installation
|
|
|
|
Verify `systemctl status rustproxy` and `journalctl -u rustproxy` (managed systemd), the panel login, frontend certificates, first Vhost, real backend response, access policies, optional QUIC, current logs and a full backup/restore test. For error diagnosis, consult [Troubleshooting](TROUBLESHOOTING.md).
|
|
|
|
**Release verification:** RustProxy 0.34.2 is a source package; complete a Rust 1.99+ build and target-platform HTTP/systemd/security acceptance tests before Internet-facing production use.
|