A Go server deploys on Hangar straight from its repository. The automatic builder compiles it into a small static binary and runs it as a long-lived process, so goroutines, WebSockets and in-memory caches work as they do on your machine.
Before you start
- A Go module in a Git repository, with
go.modat the root. - A Hangar account.
1. Listen on the right address
Read the port from PORT and listen on all interfaces. A Go address such as :8080 already means every interface:
port := os.Getenv("PORT")
if port == "" {
port = "8080"
}
log.Fatal(http.ListenAndServe(":"+port, mux))
Do not listen on 127.0.0.1:8080: the proxy in front of your service could not reach it.
2. Create the service
Create a project, add a service and pick your repository and branch. Choose the region closest to your users and leave the builder on Automatic. It detects go.mod, uses the Go version declared there, downloads the modules and builds the binary.
If the repository has several programs, the builder takes the root package when it has Go files, otherwise the first directory under cmd/. To pick another one, set this variable in the Variables tab:
RAILPACK_GO_BIN=cmd/api
3. Set the variables
Hangar sets PORT to the domain's container port, so the code above listens on 8080 once you add the domain below. Set your own configuration in the Variables tab.
4. Deploy and add a domain
Deploy the service. In Settings → Networking, add a domain with container port 8080 and HTTPS on.
Adding PostgreSQL
Add a PostgreSQL service in the same project and region, copy its internal connection URL and set it on the app:
DATABASE_URL=<the internal connection URL>
With pgx:
pool, err := pgxpool.New(ctx, os.Getenv("DATABASE_URL"))
Run migrations, with a tool such as goose or golang-migrate, from your program at startup or as a cron job you run by hand.
Shut down cleanly
On every deploy the old container receives SIGTERM before it stops. Catch it and let requests in flight finish:
ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
defer stop()
go srv.ListenAndServe()
<-ctx.Done()
srv.Shutdown(context.Background())
Troubleshooting
- 502 on the domain: the server listens on
127.0.0.1, or on a port other than the domain's container port. - The wrong program starts: set
RAILPACK_GO_BINto the package you want. cgoor C library errors: setCGO_ENABLED=1, or build with a Dockerfile.