A Go web service is one compiled binary that listens on a port. Getting it into production on a Linux VPS takes five steps, and this guide covers each with copy-ready config.
Go (Golang) produces a single compiled binary — ideal for lean production deployments on a Domain India VPS. Build the binary, run it as a systemd service under its own user, put nginx or Caddy in front of it on ports 80/443, and add a free Let's Encrypt certificate. Shared hosting cannot run your own long-running binary, so Go needs a VPS or the App Platform with a Dockerfile.
Why Go on a VPS (and not shared)
Go apps are long-running compiled processes listening on a port. Domain India shared hosting (cPanel, DirectAdmin, Webuzo) runs PHP sites, plus Node.js and Python apps through the panel tools on cPanel and DirectAdmin; it does not run your own long-running binaries, and processes outside the web server are stopped. A VPS gives you systemd, port control and your own firewall.
Any Go app — REST API, WebSocket server, gRPC service, scheduled job — runs the same way on a VPS:
- Compile to a binary on your laptop (or on the VPS)
- Upload the binary
- Run it as a systemd service
- Proxy HTTP via nginx/Caddy
- Get SSL via Let's Encrypt
Step 1 — Prepare the VPS
Order a Domain India VPS and pick a current Linux release (the examples use AlmaLinux 9 and Ubuntu 24.04 LTS). SSH in as root, and harden SSH first with the SSH security checklist:
- Create a non-root user for the app:
bash useradd -m -s /bin/bash goapp mkdir -p /home/goapp/app/data chown -R goapp:goapp /home/goapp/app - Install essentials:
bash # AlmaLinux (certbot comes from EPEL) sudo dnf install -y epel-release sudo dnf install -y nginx firewalld certbot python3-certbot-nginx sudo systemctl enable --now nginx firewalld sudo firewall-cmd --permanent --add-service=http --add-service=https sudo firewall-cmd --reload # Ubuntu sudo apt install -y nginx ufw certbot python3-certbot-nginx sudo ufw allow OpenSSH && sudo ufw allow 'Nginx Full' && sudo ufw enable - Install Go (optional — only if you'll compile on the server):
bash # Use the current stable version listed on go.dev/dl GO_VERSION=1.xx.x wget https://go.dev/dl/go${GO_VERSION}.linux-amd64.tar.gz sudo rm -rf /usr/local/go sudo tar -C /usr/local -xzf go${GO_VERSION}.linux-amd64.tar.gz echo 'export PATH=$PATH:/usr/local/go/bin' | sudo tee /etc/profile.d/go.sh source /etc/profile.d/go.sh go version
Step 2 — Build your binary
On your laptop (recommended) — cross-compile for Linux:
GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -o myapp ./cmd/serverUpload:
scp myapp goapp@your-vps-ip:/home/goapp/app/Or build on the VPS:
cd /home/goapp/app
git clone https://github.com/yourcompany/myapp .
go build -o myapp ./cmd/serverKeep the binary small. CGO_ENABLED=0 go build -trimpath -ldflags="-s -w" strips debug symbols (often about a quarter to a third smaller) and removes local file paths from the binary.
Step 3 — Run under systemd
Create /etc/systemd/system/myapp.service:
[Unit]
Description=My Go Application
After=network.target
[Service]
Type=simple
User=goapp
Group=goapp
WorkingDirectory=/home/goapp/app
ExecStart=/home/goapp/app/myapp
Restart=on-failure
RestartSec=5
# Environment: keep secrets such as DATABASE_URL in the .env file
# (chmod 600, owned by goapp), not in the unit file, which any user can read
Environment="PORT=8080"
EnvironmentFile=-/home/goapp/app/.env
# Security hardening
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ProtectHome=read-only
ReadWritePaths=/home/goapp/app/data
# Logging
StandardOutput=journal
StandardError=journal
[Install]
WantedBy=multi-user.targetReadWritePaths must point at a folder that exists (created in Step 1), or the service fails to start. Start and enable:
sudo systemctl daemon-reload
sudo systemctl enable --now myapp
sudo systemctl status myappCheck logs:
sudo journalctl -u myapp -fStep 4 — nginx reverse proxy
Go listens on port 8080 (internal). nginx takes port 80/443 public traffic and forwards it.
/etc/nginx/conf.d/myapp.conf:
upstream myapp_backend {
server 127.0.0.1:8080;
}
server {
listen 80;
server_name api.yourcompany.com;
# Redirect to HTTPS after SSL setup
# return 301 https://$host$request_uri;
location / {
proxy_pass http://myapp_backend;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_read_timeout 300s;
}
}Test and reload:
sudo nginx -t && sudo systemctl reload nginxStep 5 — Let's Encrypt SSL
sudo certbot --nginx -d api.yourcompany.comCertbot modifies your nginx config to add:
- SSL certificate paths
- HTTP → HTTPS redirect
The certbot package also installs a systemd timer that renews certificates automatically.
Verify renewal:
sudo certbot renew --dry-runAlternative: Caddy (much simpler)
Caddy auto-obtains Let's Encrypt SSL and auto-renews. /etc/caddy/Caddyfile:
api.yourcompany.com {
reverse_proxy 127.0.0.1:8080
}That's it. Run sudo systemctl reload caddy; Caddy requests the certificate as soon as the domain's DNS points at the VPS and ports 80 and 443 are open.
See our Nginx vs Caddy comparison article for the trade-offs.
Zero-downtime deployments
For a production API, deploying via "stop → replace binary → start" causes a few seconds of downtime. Two better approaches:
Approach 1 — Graceful restart with SIGHUP:
Use a package like github.com/cloudflare/tableflip: the old process keeps serving existing requests while the new one picks up new connections. Whatever you choose, handle SIGTERM in your app and call http.Server.Shutdown so in-flight requests finish before the process exits.
Approach 2 — Blue-green with systemd:
Run two services (myapp-blue.service + myapp-green.service) on different ports. nginx upstream points to the active one. To deploy:
# Stop green, deploy new binary, start green
sudo systemctl stop myapp-green
cp new-binary /home/goapp/app/myapp-green
sudo systemctl start myapp-green
# Wait for green to become healthy
curl -f http://127.0.0.1:8081/health
# Switch nginx to green, reload
sudo sed -i 's/server 127.0.0.1:8080/server 127.0.0.1:8081/' /etc/nginx/conf.d/myapp.conf
sudo nginx -s reloadDatabase access
PostgreSQL (recommended for Go):
# AlmaLinux
sudo dnf install -y postgresql-server postgresql-contrib
sudo postgresql-setup --initdb
sudo systemctl enable --now postgresql
# Ubuntu: sudo apt install -y postgresql
sudo -u postgres createdb myapp
sudo -u postgres createuser goapp --pwpromptConnection string in .env:
DATABASE_URL=postgres://goapp:password@localhost/myapp?sslmode=disableMySQL or MariaDB: install the server package from your distribution and use github.com/go-sql-driver/mysql.
SQLite: fine for small apps, zero setup. github.com/mattn/go-sqlite3 needs cgo, which clashes with CGO_ENABLED=0; the pure-Go modernc.org/sqlite driver works with it.
Monitoring
Expose a Prometheus /metrics endpoint in your Go app:
import "github.com/prometheus/client_golang/prometheus/promhttp"
http.Handle("/metrics", promhttp.Handler())On the server, install Prometheus and Grafana, or send metrics to a hosted service such as Grafana Cloud (check its free-tier limits on its pricing page). Don't expose /metrics publicly: block it in nginx or serve it on a separate internal port.
Common pitfalls
GOARCH=amd64 explicitly.sudo systemctl stop myapp, then sudo ss -tlnp to find the holder.GOMEMLIMIT (for example Environment="GOMEMLIMIT=256MiB") to give the runtime a memory budget.--dry-run while testing.sudo journalctl -u myapp -n 100.Running this on Domain India
- VPS: self-managed KVM with full root access, so everything above applies. There is no VPS page or console in the client area; you reboot from inside over SSH, and for a console, reinstall or resize you open a support ticket. Backups and snapshots are not included.
- App Platform: deploys from GitHub (Deploy Now) or with a deploy token. Only Node.js is detected automatically, so add a multi-stage Dockerfile that builds your Go binary. PostgreSQL and free SSL are included on every plan; WebSockets and SSH are not available.
- Shared hosting: not suitable for Go services.
FAQ
Can I run Go on Domain India shared hosting?
No. Shared hosting does not run your own long-running binaries or let you bind ports. Use a VPS, or the App Platform with your own Dockerfile (Go is not detected automatically there).
How much RAM do I need?
Go itself is memory-efficient, and a small API often runs in well under 100 MB. Size the server for everything on it, especially PostgreSQL or MySQL, and measure your app under realistic load before choosing.
Should I use gin, echo, fiber or chi?
Since Go 1.22 the standard library router supports methods and path parameters, so net/http alone covers many APIs. chi adds middleware and route groups while staying net/http-compatible; gin and echo are full-featured; fiber is built on fasthttp and does not use net/http handlers.
How do I update Go without breaking my running app?
Compile the binary with the new Go version, drop it in, systemctl restart myapp. The Go runtime is statically linked — the Go version on disk doesn't matter to an already-compiled binary.
How much does a Domain India VPS cost for a Go app?
Domain India VPS plans start from ₹553 a month excluding GST. They are self-managed KVM servers with full root access; backups and snapshots are not included, so back up your own data. Compare plans on the VPS page.
Ready to deploy Go? Compare VPS plans, or package your binary with a Dockerfile for the App Platform.
A self-managed Domain India VPS gives you full root access for systemd, nginx and your database.
View VPS plans