Deployment.sh

Go app hosting with real binaries, systemd and graceful restarts

Go compiles to a single binary, which makes hosting it simple until you need to ship a new version without dropping connections, keep the old binary for rollback, and run background workers next to the API. Deployment builds your Go service on your own server (or takes the binary from your CI), runs it under systemd, and switches releases only after the new process passes its health check.

Backend engineer at a workbench beside an open server running a compiled service on a laptop

What Deployment detects in a Go module

go.mod marks a Go project and its go directive picks the toolchain version. Deployment looks for main packages: a single main.go at the root, or several commands under cmd/ (for example cmd/api and cmd/worker), and offers one process per command. A Makefile with a build target or a .goreleaser.yaml is used as the build step when present. Embedded assets through embed need nothing extra; a web/ or frontend/ folder with a package.json adds a Node build before compilation.

  • Go toolchain version from go.mod, installed per site
  • One managed process per command under cmd/
  • CGO disabled by default for static binaries, enabled when your module needs it
  • Optional Node build for embedded frontends

What Deployment installs for Go app hosting

Go services need very little on the server, and Deployment keeps it that way. Provisioning hardens the host (firewall, key-only SSH, unattended security updates, swap), installs the Go toolchain only if you build on the server, and sets up nginx or Caddy as the TLS-terminating reverse proxy with HTTP/2 and gzip. If you prefer, Caddy can sit in front with automatic certificates, or your binary can listen on a private port while the proxy handles domains, aliases, redirects and Let's Encrypt.

Close-up inside a server rack: a patch cable plugged into a switch port next to a row of small green link lights, out-of-focus cabinet behind

A Go build and deploy script

The module and build caches live in a shared folder, so incremental builds are quick. If your CI already produces binaries, replace the build lines with a download of the release artifact; Deployment does not care where the binary comes from, only that it starts and passes the health check.

bash
cd "$RELEASE_PATH"
export CGO_ENABLED=0 GOFLAGS=-trimpath
go mod download
go build -ldflags="-s -w -X main.version=$COMMIT_SHA" -o bin/api ./cmd/api
go build -ldflags="-s -w" -o bin/worker ./cmd/worker
./bin/api migrate

systemd units, workers and cron for Go services

Each command runs as its own systemd unit with Restart=on-failure, a memory limit, an environment file with your encrypted variables, and journald logs streamed to the panel. Workers that consume a queue (Redis streams, NATS, RabbitMQ or a database table) run as separate units and receive SIGTERM on deploy, so a well-behaved worker finishes its current task and exits. Periodic tasks run as cron jobs (./bin/api cleanup --older-than=30d) with every run's output stored in the cron log.

Graceful restart and zero downtime for Go

Deployment starts the new binary on a fresh port next to the old one, calls the health endpoint (for example /healthz), then points the proxy at the new process. The old process receives SIGTERM and should call http.Server.Shutdown with a timeout, which stops accepting new connections and lets in-flight requests finish. Go makes this a few lines of code, and Deployment waits for the process to exit before cleaning up. Every release keeps its binaries, so rollback means starting the previous binary and switching the proxy back, in seconds and without a rebuild. See zero downtime deployment for the full sequence and deploy from git for branches and webhooks.

go
srv := &http.Server{Addr: ":" + os.Getenv("PORT"), Handler: mux}
go srv.ListenAndServe()
stop := make(chan os.Signal, 1)
signal.Notify(stop, syscall.SIGTERM)
<-stop
ctx, cancel := context.WithTimeout(context.Background(), 25*time.Second)
defer cancel()
srv.Shutdown(ctx)

PostgreSQL, MySQL and Redis for Go services

Create PostgreSQL, MySQL or MariaDB databases with their own users and grants, and Redis for caching, rate limits and queues. Connection strings live in encrypted environment variables per environment. Migrations run from your binary, from golang-migrate, goose or Atlas, as a line in the deploy script, before the release switch. Backups go to your own S3-compatible bucket on the schedule your plan allows.

Which plan fits your Go app hosting

PlanMonthlyYearly, per monthServersSites
Starter49 USD24 USD315
Team199 USD99 USD15100
Agency499 USD249 USD60unlimited within servers
Enterprise1 499 USD749 USD250unlimited within servers

Go services are light, so a few microservices fit easily on Starter. Teams that run many services across regions, or need roles and the audit log, fit Team. Enterprise adds SSO (SAML) and a 99.9 percent SLA.

Go app hosting questions

Do I have to build on the server?

No. You can build on the server or download a binary your CI built. Either way the release gets a health check and a one-click rollback.

Can I run gRPC services?

Yes. The proxy can forward HTTP/2 and gRPC traffic to your service, or the service can listen directly on a port you open in the firewall.

How do I run several commands from one repository?

Each main package under cmd/ becomes its own process with its own command, logs and restart policy, all released together from one deploy.

Can I try Deployment before I pay?

Yes. The home page has a free one-time demo: paste a public repository URL and see the detected stack, the server plan and the first lines of the deploy script. Plans start at 49 USD a month, or 24 USD a month billed yearly.

Ship your Go binary with confidence

Connect a server and push. Deployment handles the switch.

Try the demo