SpipCP
Sites

Go sites

Point SpipCP at a Go repo and get a single static binary, built and supervised by systemd on its own port โ€” a compile error fails the build, never a broken running site.

Go is a first-class site type. A Go site launches the same way as any other โ€” pick the type, pick the instance โ€” and SpipCP installs the Go toolchain if it isn't there yet, writes a starter app, builds it to a single static binary, and runs that binary behind a systemd unit that restarts on failure and survives a reboot.

Go is arguably the most natural fit for this model: a Go app compiles to one self-contained binary. There is no interpreter to keep alive, no virtualenv, no node_modules โ€” the runtime is needed only to build. At run time, systemd executes a static binary that depends on nothing. (Rust works the same way โ€” the other compiled site type.)

Choosing the Go site type
๐Ÿ“ทPick Go in the launch wizard; SpipCP offers to install the toolchain if the instance doesn't have it.img/sites-go-launch.avif
Pick Go in the launch wizard; SpipCP offers to install the toolchain if the instance doesn't have it.

Launch

Pick Go, pick an instance, and launch. If the instance doesn't already have the Go toolchain, SpipCP installs it on the way. The starter SpipCP writes is a zero-dependency net/http server that serves a 200 on /, so a fresh site is live immediately โ€” it can be replaced with real code (or a git deploy). The served port defaults to 8080.

The app lives in /srv/app/<site>

SpipCP builds each release into /srv/app/<site>/current/.bin/<binary> and runs that โ€” current is the symlink a deploy moves, so the unit executes whichever release is live. The build and module caches sit in /srv/app/<site>/shared/cache, outside any one release, so they survive a deploy instead of forcing a cold rebuild each time. Like a Node site runs npm install only when a package.json is present, the build runs go mod init only when the repo has no go.mod yet.

Build vs run โ€” the one concept

A compiled type has a hard boundary that interpreted types don't. SpipCP builds the 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.

This makes a Go 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, smoke-checks it, and cuts over atomically. A commit that doesn't compile aborts before cutover โ€” the build fails, the symlink never flips, and the site keeps serving the previous binary. A broken push can't take the site down.

The Go build-config tab
๐Ÿ“ทThe Go tab โ€” set the build command, binary name, and port, then Save & apply.img/sites-go-deploy.avif
The Go tab โ€” set the build command, binary name, and port, then Save & apply.

Configure the build

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

SettingWhat it does
Build commandOverride the default go build -o .bin/app .. Name a package for a multi-command repo (e.g. go build -o .bin/app ./cmd/web) or pass flags (-ldflags '-s -w'). The command must write its output to .bin/<binary name> โ€” that is the file the service runs, and a build that produces nothing there fails the launch with that path named. The default builds the module root โ€” a repo with more than one main package must name the one to build here.
Binary nameThe output artifact under .bin/ (also the systemd ExecStart target). Default: app.
PortThe port the app serves on, behind the node edge. The starter reads PORT; a real app should too. Default: 8080.

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 modules & env

Go module settings ride the environment editor, not the build knobs above, because they are environment: GOFLAGS, GOPROXY, and โ€” for a private module โ€” GOPRIVATE plus an access token. The token is stored as a secret (encrypted, revealed once with an audit trail). This is explicit and operator-added, not auto-magic: the needed variables are added and the build picks them up from the app's env file.

Backups & logs

Both are inherited, no extra setup:

  • Backups capture the site directory at /srv/app/<site> โ€” every release, the shared tree and any data/ dir. See Backups.
  • Logs stream from the unit's journalctl in the site's Monitoring โ†’ Logs view.

Why not just Docker?

A Go binary can already run in a Docker site, but that means hand-authoring the image and compose file. The Go type is the paved road โ€” point at a 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 can be installed. ยท How a type is defined: Blueprints.

On this page