305 lines
16 KiB
Markdown
305 lines
16 KiB
Markdown
# Installing and updating RustProxy 0.27.2
|
|
|
|
The scripts prepare a Linux/systemd installation. This source archive is **not a
|
|
verified production build**: Rust/Cargo, real CA operations, live systemd startup
|
|
and rollback against a real Rust database have not been exercised in the packaging
|
|
environment. Perform the acceptance steps below on an isolated server first.
|
|
|
|
Ready-to-use Debian packages are published separately at `https://rustproxy.linuxiarz.pl`. The Debian package-build repository and metadata are intentionally maintained outside this source tree.
|
|
|
|
## Debian 13+ one-line source install/update
|
|
|
|
```bash
|
|
# auto: first install or managed update
|
|
wget -qO- https://git.linuxiarz.pl/gru/RustProxy/raw/branch/master/install-debian13.sh | bash
|
|
|
|
# force the update path
|
|
wget -qO- https://git.linuxiarz.pl/gru/RustProxy/raw/branch/master/install-debian13.sh | bash -s -- update
|
|
```
|
|
|
|
The bootstrap installs build dependencies, installs Rust with rustup for an unprivileged build user,
|
|
clones `https://git.linuxiarz.pl/gru/RustProxy` and builds with `cargo build --release --locked`.
|
|
Its default `auto` mode calls `install.sh` only when no managed installation exists. When
|
|
`/opt/rustproxy/install.json` exists it calls `update.sh`, which uses the saved installation record,
|
|
backs up private state, switches the release, verifies health/version and rolls code/data/unit back
|
|
on failure. First install keeps administration on `127.0.0.1:9090` over HTTP, matching the normal
|
|
`install.sh` loopback-safe default. Updates preserve the saved admin/listener settings. For initial
|
|
remote access use an SSH tunnel, then enable Administration HTTPS before persisting a non-loopback bind.
|
|
Plain remote HTTP requires both an explicit non-loopback `RUSTPROXY_ADMIN_LISTEN` and
|
|
`RUSTPROXY_ALLOW_REMOTE_ADMIN=1`, and should be limited to a trusted private network.
|
|
|
|
Equivalent prerequisite commands are:
|
|
|
|
```bash
|
|
apt install -y build-essential gcc git ca-certificates python3 python3-venv python3-pip pkg-config wget sudo certbot python3-certbot-dns-rfc2136 python3-certbot-dns-cloudflare python3-certbot-dns-ovh
|
|
wget -qO- --https-only --secure-protocol=TLSv1_2 https://sh.rustup.rs | sh
|
|
```
|
|
|
|
## Build as a normal user
|
|
|
|
Requirements: stable Rust (minimum declared 1.88), Cargo, a C compiler/linker,
|
|
Python 3.10+, Bash. Linux/systemd deployment also requires `systemctl`, `runuser`
|
|
and a usable non-login service account (created by the installer when missing).
|
|
The static TOML checker additionally needs Python 3.11+. No script downloads an
|
|
executable or installs a compiler as root.
|
|
|
|
```bash
|
|
cd RustProxy
|
|
bash dev.sh doctor
|
|
bash dev.sh check
|
|
bash dev.sh test
|
|
bash dev.sh release
|
|
```
|
|
|
|
The first build resolves and creates `Cargo.lock`; retain the real lockfile and
|
|
binary hash for repeatable subsequent builds. There is no fabricated lockfile or
|
|
precompiled binary in the archive. Set `--binary` explicitly when using a custom
|
|
`CARGO_TARGET_DIR`. Review and trust the source and built binary before installation.
|
|
|
|
## First installation
|
|
|
|
The normal first install also downloads `user-country-ipv4.csv` and
|
|
`user-country-ipv6.csv` from the `sapics/ip-location-db` latest release over HTTPS and
|
|
verifies each file against the publisher SHA-256 release before writing it privately to
|
|
`DATA_DIR/geoip`. This enables country access/rate rules. Use `--skip-geoip` only when
|
|
you intentionally do not want the database; allow-only country policies then fail
|
|
closed for unresolved clients. Updates preserve the installed database.
|
|
|
|
|
|
```bash
|
|
bash install.sh --plan --binary target/release/rust-proxy
|
|
sudo bash install.sh --binary target/release/rust-proxy
|
|
```
|
|
|
|
Defaults: HTTP `0.0.0.0:80`, HTTPS `0.0.0.0:443`, administration
|
|
`127.0.0.1:9090`, code `/opt/rustproxy`, all private state `/var/lib/rustproxy`,
|
|
service account `rustproxy`. The initial page is a small informational response; no demonstration
|
|
backend or sample application is started. The first database has no configured
|
|
vhosts. Existing, nonempty data is refused rather than reset.
|
|
|
|
The first install also writes `/etc/profile.d/rustproxy-path.sh`, which prepends the
|
|
managed `PREFIX/current` directory (normally `/opt/rustproxy/current`) to `PATH` for
|
|
new login shells. Open a new login shell, or source that profile explicitly, before
|
|
expecting `rust-proxy` to resolve without its absolute path.
|
|
|
|
HTTPS is enabled by default and starts with a **self-signed certificate**, not a
|
|
publicly trusted certificate. For an explicit HTTP-only installation use:
|
|
|
|
```bash
|
|
sudo bash install.sh --binary target/release/rust-proxy --no-https
|
|
```
|
|
Assign the intended certificate in the panel before exposing applications. Existing
|
|
HTTP/3 defaults enable QUIC on TLS listeners: permit the corresponding UDP port
|
|
when desired, or explicitly disable H3 in Listeners. Review firewall rules yourself;
|
|
the installer does not change them. Public frontend TLS and administration TLS are
|
|
independent settings.
|
|
|
|
Generate the one-time setup capability directly from the installed release CLI:
|
|
|
|
```bash
|
|
sudo -u rustproxy /opt/rustproxy/current/rust-proxy \
|
|
--data-dir /var/lib/rustproxy admin setup-token
|
|
```
|
|
|
|
This works before the first server start. After an administrator exists, setup
|
|
tokens remain invalid. You can alternatively initialize the account interactively:
|
|
|
|
```bash
|
|
sudo -u rustproxy /opt/rustproxy/current/rust-proxy \
|
|
--data-dir /var/lib/rustproxy admin init
|
|
```
|
|
|
|
For direct remote administration, first sign in on the default loopback listener and
|
|
open **Settings -> Administration**. Enable HTTPS, choose the application-managed
|
|
certificate or a certificate from the inventory, set the bind address (for example
|
|
`0.0.0.0:9090`) and optionally add DNS names accepted by Host/Origin validation.
|
|
Save and restart RustProxy. The persisted remote bind is accepted only while
|
|
administration TLS is enabled. Keep the listener behind a firewall/private network;
|
|
the certificate must be trusted by the browser if you want a clean HTTPS connection.
|
|
|
|
An SSH tunnel remains available without exposing the listener directly:
|
|
|
|
```bash
|
|
ssh -L 9090:127.0.0.1:9090 operator@your-server
|
|
```
|
|
|
|
Open `http://127.0.0.1:9090` on that workstation while the administration listener
|
|
is still using its default HTTP mode. No default administrator/password is added.
|
|
|
|
Plain-HTTP remote administration is possible with the explicit allow flag:
|
|
|
|
```bash
|
|
sudo bash install.sh --binary target/release/rust-proxy \
|
|
--admin 0.0.0.0:9090 --allow-remote-admin
|
|
```
|
|
|
|
That plain-HTTP path has no transport confidentiality and should be limited to a trusted
|
|
private network. Prefer the built-in administration HTTPS mode for a direct remote
|
|
listener.
|
|
|
|
Other installation switches: `--prefix`, `--data-dir`, `--user`, `--http`, `--https`,
|
|
`--no-https`, `--admin`, `--allow-remote-admin`, `--sha256` (expected binary digest), `--no-start`. Paths must be dedicated,
|
|
absolute, separate, non-nested and without spaces or symlink components.
|
|
`--plan` reads the supplied binary but changes nothing; it does not prove port
|
|
availability, compiler success or systemd readiness.
|
|
|
|
|
|
### Startup-owned listeners
|
|
|
|
When HTTP, HTTPS or administration listen addresses are supplied explicitly by systemd, CLI
|
|
arguments or the corresponding `RUST_PROXY_*_LISTEN` environment variables, RustProxy treats
|
|
those exact binds as process-owned. Settings shows them as locked and configuration updates
|
|
cannot remove, disable or rewrite them. Listeners not supplied at process start remain normal
|
|
editable desired-state entries.
|
|
|
|
## ACME prerequisites
|
|
|
|
Automatic renewal runs inside RustProxy, not a separately installed cron timer. RustProxy
|
|
prefers a private Python environment at `<data-dir>/acme-python`. When that environment is
|
|
missing or incomplete, the service creates it automatically and installs the pinned Certbot
|
|
core plus the Cloudflare, OVH and RFC2136 plugins with `pip`. The application never executes
|
|
`sudo` and never modifies distribution-owned Python site-packages.
|
|
|
|
The host should provide Python 3 with either the standard `venv` module or `pip`; RustProxy can
|
|
bootstrap `virtualenv` into its own data directory when a distribution splits `venv` into a
|
|
separate package. OpenSSL remains a local certificate-inspection fallback. If the private
|
|
environment cannot be created, RustProxy uses a runnable distribution `certbot` from `PATH`
|
|
when one is available.
|
|
|
|
If Python is absent (a possible layout on appliances such as OPNsense), or Python is present
|
|
but no local environment can be created and no system Certbot exists, the Certificates panel
|
|
shows ACME as unavailable. PEM upload and references to existing certificate files remain
|
|
available.
|
|
|
|
On the standard service installation the managed environment therefore lives at
|
|
`/var/lib/rustproxy/acme-python`. Do not run a second Certbot renewal timer over RustProxy's
|
|
`certs/acme` profiles. See [renewal](RENEWAL.md).
|
|
|
|
A source-tree preflight can still inspect a distribution-provided fallback environment with:
|
|
|
|
```bash
|
|
sudo -u rustproxy env PATH=/usr/local/bin:/usr/bin:/bin \
|
|
python3 scripts/acme_provider.py --doctor
|
|
```
|
|
|
|
The provider script is embedded in the RustProxy binary; this command is diagnostic only.
|
|
|
|
### Using a separate system Certbot
|
|
|
|
If another service already owns a certificate through the system Certbot, keep that lineage
|
|
outside RustProxy's managed ACME profiles and create/use a **manual** RustProxy certificate id.
|
|
A Certbot deploy hook can publish every successful renewal to all vhosts that already select
|
|
that id:
|
|
|
|
```bash
|
|
/opt/rustproxy/current/rust-proxy --data-dir /var/lib/rustproxy tls deploy --id shared-cert \
|
|
--cert /etc/letsencrypt/live/example/fullchain.pem \
|
|
--key /etc/letsencrypt/live/example/privkey.pem
|
|
```
|
|
|
|
The command reads the Certbot files locally and sends them to the authenticated loopback `POST /api/certificates/deploy` endpoint. The running RustProxy service writes the private generation with its own filesystem identity and hot-publishes it for new public TLS/H2/H3 handshakes. No per-vhost edit is needed. If another
|
|
local process instead replaces the exact files already referenced by RustProxy, run
|
|
`/opt/rustproxy/current/rust-proxy --data-dir /var/lib/rustproxy tls reload` (or authenticated `POST /api/certificates/reload`) afterward. If the replacement belongs to one configured manual certificate ID, automation may instead call `POST /api/certificates/{certificate_id}/reload`; the same endpoint accepts a scoped Certificate API Key ID + Bearer token and does not change the configuration revision.
|
|
Administration TLS is startup-fixed and may still require a service restart.
|
|
|
|
Optional environment overrides go in a root-owned `/etc/rustproxy/environment`
|
|
(mode 0600); create the directory when needed. Restart after changing service
|
|
environment values. Provider secrets remain in private profile files, not this
|
|
file or the exported configuration. A systemd environment file is not a shell script.
|
|
|
|
## Update an installation created by install.sh
|
|
|
|
Build and test the new release as a normal user first, then:
|
|
|
|
```bash
|
|
bash update.sh --plan --binary target/release/rust-proxy
|
|
sudo bash update.sh --binary target/release/rust-proxy
|
|
```
|
|
|
|
Before stopping the service, the updater fetches the current publisher SHA-256
|
|
files for the `user-country` GeoIP IPv4/IPv6 assets. Matching local files are left
|
|
untouched; stale or missing assets are staged, verified and published only after
|
|
the private-data backup exists. Use `--skip-geoip` only when intentionally accepting
|
|
a stale/missing country database (for example during an upstream outage).
|
|
|
|
Use the original `--prefix` for a non-default installation. Other startup/account/
|
|
data settings are read from root-owned `install.json`; update does not silently
|
|
replace them with command-line defaults. Change intentional listener settings in
|
|
RustProxy, or maintain the unit separately when needed.
|
|
|
|
Update mode checks that `/etc/profile.d/rustproxy-path.sh` still matches the saved
|
|
installation prefix, but deliberately does not rewrite it. A missing or changed file
|
|
produces an explicit warning before service downtime; repair the profile separately
|
|
if direct `rust-proxy` shell invocation is required.
|
|
|
|
The updater verifies the supplied binary hash and runs only its `--version` as the
|
|
service account. Immediately before stopping a RustProxy 0.14.0+ service it creates a
|
|
private one-shot managed-update marker. During graceful shutdown the process forces hot
|
|
objects into the enabled cold tier even when ordinary `cold_on_shutdown=false`; the marker
|
|
is removed before backup. The managed unit allows up to 120 seconds for controlled stop.
|
|
If cold storage is disabled, RAM-only cache cannot survive the process exit. The updater
|
|
then stages an immutable release, stops the service and backs up the **entire** data directory. This includes SQLite and sidecars, certificates, account
|
|
keys, provider credentials, Certbot renewal configs and internal relative symlinks.
|
|
Code changes use an atomic `current` symlink switch. It then starts the new process
|
|
and requires systemd activity, minimal local `/healthz` readiness, and the actual
|
|
MainPID executable matching the staged, locally version-checked binary. The local
|
|
health probe follows the persisted administration bind and HTTP/HTTPS mode (including
|
|
the configured Host allowlist), rather than assuming the install-time plain-HTTP
|
|
address. Version is no longer exposed by the anonymous health endpoint.
|
|
The managed systemd unit is regenerated from the saved installation record and
|
|
`daemon-reload` is run before startup. The previous unit is included in the backup
|
|
and restored on rollback. Keep custom service policy outside this managed unit or
|
|
reapply it after an update.
|
|
|
|
A failed start/health check restores the previous release, private data **and**
|
|
managed systemd unit. The reported error now includes the original update failure;
|
|
recent service status/journal output is emitted before rollback when available.
|
|
Failed-generation data is retained alongside the original data directory; the
|
|
backup is retained under `/opt/rustproxy/backups`. A failed rollback health check is
|
|
reported explicitly. Protect these directories: they contain private keys and
|
|
credentials. They are never automatically pruned. Plan enough free space for the
|
|
full backup, restored data, retained failed state and old/new executable releases.
|
|
|
|
During development, if an older saved vhost/settings document is intentionally
|
|
incompatible with the current format, use:
|
|
|
|
```bash
|
|
sudo bash update.sh --reset-config --binary target/release/rust-proxy
|
|
```
|
|
|
|
This happens only after the backup is created. It deletes the saved desired
|
|
configuration row so the new process creates current listener defaults; administrator
|
|
account data, certificates, ACME/provider files and other private state are retained.
|
|
Do not use this flag when the old vhost/settings configuration must be preserved.
|
|
After a failed update, **do not run `install.sh`**: rollback leaves the previous
|
|
installation installed. Fix the reported cause and rerun `update.sh` (optionally
|
|
with `--reset-config` for this development-only incompatible-config case).
|
|
|
|
An update interrupts traffic; zero-downtime deployment is not implemented. `--no-start`
|
|
leaves the service stopped and cannot certify a healthy installation. Backup failure
|
|
leaves the old code/data in place and attempts to restart a previously running service.
|
|
Keep an independent off-host backup; local rollback is not a disaster-recovery plan.
|
|
|
|
## Existing source-tree installations from earlier archives
|
|
|
|
Do not point a first installer at your old live data. To keep the current source-
|
|
tree deployment, stop RustProxy and use the retained source updater:
|
|
|
|
```bash
|
|
bash /path/to/new/RustProxy/update.sh --source-tree /path/to/old/RustProxy --stopped
|
|
```
|
|
|
|
This mode keeps the old `upgrade.sh` contract and does not install a systemd service
|
|
or build a binary. Back up **all** private data and ACME profiles separately before
|
|
starting it. See [migration](MIGRATION.md). To adopt the new service layout, make an
|
|
explicit offline migration with ownership, absolute Certbot paths and port settings
|
|
reviewed; do not merely move a Certbot account tree to another location.
|
|
|
|
## Server acceptance
|
|
|
|
Check actual non-root HTTP/TLS/QUIC binds, certificate assignment, a real renewal
|
|
validation (`Dry run`), backend failures, live traffic, Basic Auth over TLS, ACLs,
|
|
WebSocket enable/disable and location isolation. Verify the backup can be restored
|
|
on another isolated instance. Run `systemctl status rustproxy` and
|
|
`journalctl -u rustproxy` after installation/update. Only then decide on rollout.
|