Files

15 KiB

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
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

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 and agent operations.

Debian 13+ source bootstrap

Review the remote script before execution. On a managed installation, auto selects install or update from /opt/rustproxy/install.json.

# 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 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 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:

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:

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:

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:

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:

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 and Certificates.

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:

    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:

    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):

    [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:

    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 and the deployment example.

Managed update

Test the new build first. Then execute:

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.

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.

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.

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.