Pular para o conteúdo
Esta página ainda não foi traduzida. O conteúdo abaixo está em inglês. Ler em inglês

Deployment

Single binary

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

Última atualização:

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.

Embedded assets#

The starter's resources package embeds resources/views and resources/public (including Vite's build/ output) and bootstrap serves them; nothing else is needed. With APP_ENV=production the embedded files are always used, even when a resources/ directory sits next to the binary. Run vite build before go build (as vukem build does) or the binary embeds no CSS and JavaScript.

Configure production#

.env.production
APP_ENV=production
APP_DEBUG=false
APP_URL=https://example.com
HOST=0.0.0.0           # the default, localhost, is unreachable from other machines and containers
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 and drains in-flight requests while running scheduled tasks and queue jobs finish, each within SHUTDOWN_TIMEOUT (those still running are then cancelled through their ctx; interrupted jobs go back to the queue). A runner that ignores ctx is logged and left behind three seconds later. Shutdown hooks and providers then run in reverse order with their own SHUTDOWN_TIMEOUT, so set your process manager's stop timeout to at least twice SHUTDOWN_TIMEOUT plus a few seconds.

The same process runs the scheduler when tasks exist (including the hourly session:prune with SESSION_DRIVER=database) and a queue worker for the memory, database and Redis queues, so one service is enough. With several replicas, or a separate ./bin/app schedule:work process, set SCHEDULE_IN_SERVE=false on the web replicas so run-once tasks are not fired by every replica (see Several replicas).

Health checks#

GET /up is the liveness probe: it answers 200 {"status":"ok"} once the app booted, without touching a dependency or creating a session. Use it as the container healthcheck.

For readiness, register a check per dependency and mount app.ReadyHandler() where the platform expects it:

Go
app.AddHealthCheck("redis", rc.Ping)                              // 3s timeout
app.AddHealthCheckTimeout("search", 500*time.Millisecond, search.Ping)

r.Handle("GET /ready", app.ReadyHandler())

app.DB() registers a db check by itself. The handler runs every check in parallel, each bounded by its own timeout (a check that ignores its context is abandoned at the deadline), and answers 200 or 503 with {"status":"ok"|"fail","checks":{"db":"ok","redis":"fail"}} and Cache-Control: no-store. Errors are logged, never returned to the client. GET /up?checks=1 gives the same answer; app.CheckHealth(ctx) returns the raw errors for a custom endpoint.

Behind a reverse proxy#

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

.env
TRUSTED_PROXIES=10.0.0.0/8     # CIDRs or IPs, comma-separated; nobody is trusted by default
TRUST_FORWARDED_PROTO=true     # send HSTS when a trusted proxy says the request was HTTPS

vukem.New applies them to the router's web.Services and to the SecureHeaders that DefaultMiddleware already installs, so do not build another web.Services or add a second SecureHeaders. An invalid entry stops the boot. Details: trusted proxies.

Containers and platforms#

Every starter ships a Dockerfile; see Docker and Railway for the image, the variables and a step-by-step Railway deploy.

Checklist#

  • APP_ENV=production, APP_DEBUG=false, a unique APP_KEY.
  • APP_URL set to the https origin.
  • TRUSTED_PROXIES set to the proxy's network; TRUST_FORWARDED_PROTO=true behind TLS (HSTS).
  • Logs shipped as JSON to durable storage, with alerts on security events.
  • govulncheck ./... in CI.
  • Scheduler: in serve by default; SCHEDULE_IN_SERVE=false when a single schedule:work process runs it, or OnOneServer() with a shared cache for run-once tasks with several replicas.
  • Queue: serve works the database queue by default; QUEUE_IN_SERVE=false when only queue:work processes should run jobs.