Skip to content
You are reading the v0.20 documentation. Go to the latest version (v1.0)

Deployment

Single binary

Build one static Go binary with embedded assets and run it behind a TLS-terminating proxy with graceful shutdown.

Last updated:

A Vukem app compiles to a single executable. With embed, views and public assets ship inside it, so a deployment is one file plus its environment.

Build#

Terminal
CGO_ENABLED=0 go build -trimpath -ldflags "-s -w" -o bin/app ./cmd/app

SQLite uses the pure-Go modernc.org/sqlite driver, so no cgo toolchain is needed and cross-compiling is a matter of GOOS/GOARCH.

vukem build does this for you: it runs npx vite build when a vite.config.* exists, then go build -trimpath -ldflags="-s -w" -o bin/app ./cmd/app (-o changes the output). The starter embeds resources/views and resources/public with //go:embed, so the binary is self-contained.

Embed public assets#

cmd/app/main.go
//go:embed public
var publicFS embed.FS

func staticMiddleware() (middleware.Middleware, error) {
	sub, err := fs.Sub(publicFS, "public")
	if err != nil {
		return nil, err
	}
	return middleware.StaticFS(sub, middleware.StaticConfig{}), nil
}

Configure production#

.env.production
APP_ENV=production
APP_DEBUG=false
APP_URL=https://example.com
HOST=0.0.0.0
PORT=3000
LOG_FORMAT=json
SHUTDOWN_TIMEOUT=20s

Provide APP_KEY through the environment or a secret file (APP_KEY=@file:/run/secrets/app_key). The app refuses to boot with APP_DEBUG=true in production.

Run#

Terminal
APP_ENV=production ./bin/app

On SIGINT or SIGTERM the HTTP server stops accepting connections, drains in-flight requests, then runs shutdown hooks and providers in reverse order within SHUTDOWN_TIMEOUT. Pair it with your process manager's stop timeout.

Behind a reverse proxy#

Terminate TLS at the proxy (Caddy, nginx, a load balancer) and tell Vukem which proxies to trust:

Go
_, proxy, _ := net.ParseCIDR("10.0.0.0/8")

services := &web.Services{TrustedProxies: []*net.IPNet{proxy}}

r.UseServer(middleware.SecureHeaders(middleware.SecureHeadersConfig{
	TrustForwardedProto: true, // send HSTS when the proxy says the request was HTTPS
}))

Checklist#

  • APP_ENV=production, APP_DEBUG=false, a unique APP_KEY.
  • APP_URL set to the https origin.
  • Trusted proxies configured; HSTS enabled behind TLS.
  • Logs shipped as JSON to durable storage, with alerts on security events.
  • govulncheck ./... in CI.