# Running Go Applications on DomainIndia VPS (systemd, nginx Reverse Proxy, SSL)
TL;DR
Go (Golang) produces a single compiled binary — ideal for lean production deployments on a DomainIndia VPS. This guide covers the full stack: building your binary, running it under systemd, fronting it with nginx or Caddy, and adding Let's Encrypt SSL.
## Why Go on a VPS (and not shared)
Go apps are long-running compiled processes listening on a port. Shared hosting (cPanel, DirectAdmin) runs PHP per-request via FastCGI — there's no equivalent for Go. A VPS gives you the systemd services, port control, and iptables needed.
Any Go app — REST API, WebSocket server, gRPC service, static-site generator on a schedule — runs the same way on our VPS:
1. Compile to a binary on your laptop (or on the VPS)
2. Upload the binary
3. Run it as a systemd service
4. Proxy HTTP via nginx/Caddy
5. Get SSL via Let's Encrypt
## Step 1 — Prepare the VPS
Order a DomainIndia VPS (AlmaLinux 9 or Ubuntu 22.04 recommended). SSH in as root:
1
Create a non-root user for the app:
3
Install Go (optional — only if you'll compile on the server):
## Step 2 — Build your binary
**On your laptop (recommended)** — cross-compile for Linux:
```bash
GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -o myapp ./cmd/server
```
Upload:
```bash
scp myapp goapp@your-vps-ip:/home/goapp/app/
```
**Or build on the VPS:**
```bash
cd /home/goapp/app
git clone https://github.com/yourcompany/myapp .
go build -o myapp ./cmd/server
```
Insight
Keep the binary tiny. CGO_ENABLED=0 go build -ldflags="-s -w" strips debug symbols and cuts binary size 30%. Paired with -trimpath, your binary is reproducible and lean.
## Step 3 — Run under systemd
Create `/etc/systemd/system/myapp.service`:
```ini
[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
Environment="PORT=8080"
Environment="DATABASE_URL=postgres://user:pass@localhost/dbname?sslmode=disable"
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.target
```
Start and enable:
```bash
sudo systemctl daemon-reload
sudo systemctl enable --now myapp
sudo systemctl status myapp
```
Check logs:
```bash
sudo journalctl -u myapp -f
```
## Step 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`:
```nginx
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:
```bash
sudo nginx -t && sudo systemctl reload nginx
```
## Step 5 — Let's Encrypt SSL
```bash
sudo certbot --nginx -d api.yourcompany.com
```
Certbot modifies your nginx config to add:
- SSL certificate paths
- HTTP → HTTPS redirect
- Auto-renewal cron
Verify renewal:
```bash
sudo certbot renew --dry-run
```
## Alternative: 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` — SSL appears within 60 seconds.
See our [Nginx vs Caddy comparison article](https://domainindia.com/support/kb/nginx-vs-caddy-for-app-gateways-2025-engineer-s-guide) 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` or `github.com/facebookgo/grace` — the old process keeps serving existing requests while the new one picks up new connections.
**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:
```bash
# 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 reload
```
## Database access
**PostgreSQL (recommended for Go):**
```bash
sudo dnf install -y postgresql-server postgresql-contrib
sudo postgresql-setup --initdb
sudo systemctl enable --now postgresql
sudo -u postgres createdb myapp
sudo -u postgres createuser goapp --pwprompt
```
Connection string in `.env`:
```
DATABASE_URL=postgres://goapp:password@localhost/myapp?sslmode=disable
```
**MySQL:** install `mysql-server`, use `github.com/go-sql-driver/mysql`.
**SQLite:** fine for small apps, zero setup. Use `github.com/mattn/go-sqlite3`.
## Monitoring
Expose a Prometheus `/metrics` endpoint in your Go app:
```go
import "github.com/prometheus/client_golang/prometheus/promhttp"
http.Handle("/metrics", promhttp.Handler())
```
On the server, install Prometheus + Grafana (or use [Grafana Cloud's free tier](https://grafana.com/products/cloud/) — 10k metrics, 50 GB logs free).
## Common pitfalls
## FAQ
Q
Can I run Go on shared hosting?
No. Shared hosting doesn't allow long-running daemons or custom port binding. You need VPS (or our App Platform for simpler deploys).
Q
How much RAM do I need?
Lightweight Go APIs run fine on 1 GB VPS. For ~1000 concurrent requests with DB, 2 GB is safer. Go is memory-efficient by default.
Q
Should I use gin, echo, fiber, or chi?
For REST APIs, chi (standard-library-friendly) and echo (full-featured) are popular. fiber (fasthttp-based) is fastest but deviates from net/http. For serious production, stick with net/http or chi.
Q
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.
Q
What's the cheapest DomainIndia VPS for Go?
Start with VPS Starter — 1 vCPU, 2 GB RAM, 40 GB SSD. Enough for most API workloads up to 200 req/sec.
Ready to deploy Go? Order a VPS and get root access today.
View VPS plans