Running Go Applications on DomainIndia VPS (systemd, nginx Reverse Proxy, 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:
- 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 DomainIndia VPS (AlmaLinux 9 or Ubuntu 22.04 recommended). SSH in as root:
- Create a non-root user for the app:
```bash
useradd -m -s /bin/bash goapp
mkdir -p /home/goapp/app
chown goapp:goapp /home/goapp/app
```
- Install essentials:
```bash
# AlmaLinux
sudo dnf install -y nginx firewalld certbot python3-certbot-nginx
# Ubuntu
sudo apt install -y nginx ufw certbot python3-certbot-nginx
```
- Install Go (optional — only if you'll compile on the server):
```bash
wget https://go.dev/dl/go1.22.0.linux-amd64.tar.gz
sudo tar -C /usr/local -xzf go1.22.0.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 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:
[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.targetStart 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
- Auto-renewal cron
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 — SSL appears within 60 seconds.
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 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:
# 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):
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 --pwpromptConnection string in .env:
DATABASE_URL=postgres://goapp:password@localhost/myapp?sslmode=disableMySQL: 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:
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 — 10k metrics, 50 GB logs free).
Common pitfalls
FAQ
No. Shared hosting doesn't allow long-running daemons or custom port binding. You need VPS (or our App Platform for simpler deploys).
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.
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.
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.
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