SpipCP
Sites

Rust sites

Point SpipCP at a Rust repo and get a single binary, built with cargo and supervised by systemd on its own port — a compile error fails the build, never a broken running site.

Rust is a first-class site type. You launch a Rust site the same way you launch any other — pick the type, pick the instance — and SpipCP installs the Rust toolchain if it isn't there yet, writes a starter app, builds it with cargo build --release, and runs that binary behind a systemd unit that restarts on failure and survives a reboot.

Rust works the same way as Go: a Rust web app (axum, actix-web, rocket) compiles to one binary. There is no interpreter to keep alive, no virtualenv, no node_modulesthe toolchain is needed only to build. At run time, systemd executes a binary that depends on nothing but the system C library.

Choosing the Rust site type
📷Pick Rust in the launch wizard; SpipCP offers to install the toolchain (and the C linker it needs) if the instance doesn't have it.img/sites-rust-launch.avif
Pick Rust in the launch wizard; SpipCP offers to install the toolchain (and the C linker it needs) if the instance doesn't have it.

Launch

Pick Rust, pick an instance, and launch. If the instance doesn't already have the Rust toolchain, SpipCP installs it on the way — via rustup with the minimal profile, plus the build-essential package (cargo links through the system cc). The starter SpipCP writes is a zero-dependency std-only HTTP server, so a fresh site is live in seconds — you replace it with your own code (or a git deploy). The served port defaults to 8090.

The first real build is the slow one

The std-only starter builds in seconds. Your first real deploy — a repo with an axum/actix crate graph — compiles hundreds of crates and takes minutes on a small instance. That is Rust, not SpipCP: every build after the first is fast, because the build cache persists across deploys (see Build vs run). If your repo pins a toolchain with a rust-toolchain.toml, we respect it — rustup fetches that toolchain on the first build, so expect that one to be slower too.

Your app lives in /srv/app

SpipCP builds your repo and installs the artifact to /srv/app/.bin/app, then runs that. The cargo build cache and registry live under /srv/app/.cache, so they persist across deploys — but they are excluded from backups (reproducible build output is not state; see Disk & backups). Like a Node site runs npm install only when a package.json is present, the build runs cargo init only when your repo has no Cargo.toml yet.

Build vs run — the one concept

A compiled type has a hard boundary that interpreted types don't. SpipCP builds your repo to a binary, then runs only that binary:

  • On launch, the build runs before the service starts. A compile error fails the launch at the build step, with the error to fix — the site never goes live with a missing binary.
  • On restart or reboot, systemd re-executes the already-built binary. No rebuild, no toolchain needed at run time — which is why the run path is the most robust of any site type.

The build cache (CARGO_TARGET_DIR) lives outside the release directories and persists across deploys, so deploy N+1 recompiles only the crates that changed — the difference between minutes and seconds. This makes a Rust site's deploy story arguably safer than an interpreted one: a broken commit is caught at build time, before it can ever serve.

Deploy with git

Connect a git source and git push deploys: SpipCP fetches the commit, rebuilds the binary with cargo build --release, smoke-checks it, and cuts over atomically. A commit that doesn't compile aborts before cutover — the build fails, the symlink never flips, and your site keeps serving the previous binary. A broken push can't take the site down.

The Rust build-config tab
📷The Rust tab — set the build command, binary name, and port, then Save & apply.img/sites-rust-deploy.avif
The Rust tab — set the build command, binary name, and port, then Save & apply.

Configure the build

The Rust tab on a site (shown only for Rust sites) exposes three build knobs:

SettingWhat it does
Build commandOverride the default cargo build --release. Name a workspace member (e.g. cargo build --release -p my-svc) or add features (--features prod). The default builds the crate at the repo root.
Binary nameThe artifact under target/release/ to install — usually your [package].name (default app). This names the source artifact; the panel installs it to a fixed run path (/srv/app/.bin/app), so the run path never moves even if you rename the binary.
PortThe port the app serves on, behind the node edge. The starter reads PORT; a real app should too. Default: 8090.

Save & apply persists the change and relaunches the site so the new build actually lands inside the instance — the same process the first launch ran, never a faked in-place edit. The status goes to launching; watch the Deploys tab for the result.

Private registries & env

Cargo registry settings ride the environment editor, not the build knobs above, because they are environment: RUST_LOG, CARGO_* knobs, and — for a private registry — a CARGO_REGISTRIES_*_TOKEN. The token is stored as a secret (encrypted, revealed once with an audit trail). This is explicit and operator-added, not auto-magic: you add the variables you need and the build picks them up from the app's env file.

Sharing an instance

Runtimes coexist freely — an instance can hold the Rust toolchain and Go and Node and PHP and a database side by side, and a Rust API can share an instance with a WordPress/PHP/static site (disjoint paths + ports, per-hostname routing) — e.g. a Rust API next to the WordPress it serves. Every app-on-a-port type has a distinct default port (Node 3000 · Python 8000 · Go 8080 · Rust 8090), so nothing collides out of the box.

The one hard limit: one app-dir site per instance. A Rust site uses /srv/app, so it can't share an instance with another Rust, Go, Node, or Python site — use a separate instance (the cheap unit), or Docker for many apps in one instance.

Disk & backups

A Rust toolchain is ~1.4 GB (the minimal profile), and a per-app build cache can reach gigabytes — size your instance accordingly (the default instance has headroom for a normal crate graph). Both are stated plainly rather than hidden:

  • Backups capture the app tree at /srv/app (your source, the built binary, and any data/ dir) but exclude the build caches — a multi-GB target/ of reproducible .rlib files is not state. See Backups.
  • Logs stream from the unit's journalctl in the site's Monitoring → Logs view — set RUST_LOG in the env editor to control verbosity. See Logs.

Why not just Docker?

You can already run a Rust binary in a Docker site, but you'd hand-author the image and compose file. The Rust type is the paved road — point at your repo and get a built, supervised binary with git-deploy, an env editor, backups, and a domain. Docker stays the escape hatch for a pre-built image or a multi-service app.

→ The full menu: What you can install. · How a type is defined: Blueprints.

On this page