[{"data":1,"prerenderedAt":159},["ShallowReactive",2],{"seo-verification":3,"blog-deploying-a-go-gin-application-on-a-vps-ma-en":6,"promo-bar-likely":158},{"google":4,"bing":5},"EycwPY2XMyTkVzas3n1ygeNJFGAH513qrMjfDljzsMQ","",{"key":7,"data":8},"blog-deploying-a-go-gin-application-on-a-vps-ma-en",{"id":9,"slug":10,"slugs":11,"title":15,"excerpt":16,"readTime":17,"views":18,"isPinned":19,"noindex":19,"publishedAt":20,"updatedAt":21,"category":22,"categories":28,"featuredImage":30,"bgImage":31,"posterImage":32,"relatedSolution":33,"intro":36,"sections":37,"ctaTitle":101,"ctaBody":102,"ctaButton":103,"ctaUrl":104,"relatedPosts":105},51,"deploying-a-go-gin-application-on-a-vps",{"fr":12,"en":10,"ar":13,"es":14},"deployer-golang-vps","نشر-تطبيق-go-gin-على-خادم-vps","desplegar-aplicacion-go-gin-en-un-vps","Deploying a Go (Gin) application on a VPS","Deploy a Go (Gin) API on a Cloud VPS: static binary, Docker scratch, reverse proxy and SSL. A tutorial for Go developers.",8,1,false,"2026-04-30T00:00:00+00:00","2026-11-04T16:30:25+00:00",{"id":23,"name":24,"slug":25,"color":26,"icon":27},4,"Development","developpement","bg-warning\u002F10 text-warning","dev",[29],{"id":23,"name":24,"slug":25,"color":26,"icon":27},null,"\u002Fblog\u002Fcovers\u002Fbg.svg","\u002Fblog\u002Fcovers\u002Fdeployer-golang-vps-poster.svg",{"categorySlug":34,"appSlug":35},"development","golang","Go compiles into a single static binary with no dependencies: it's the ideal language for self-hosting. A Gin API fits in 15 to 30 MB of RAM and starts in milliseconds. This guide takes you from zero to a complete production stack: multi-stage Dockerfile with a `scratch` image, Docker Compose with Nginx and Certbot, live reload in development via `air`, secrets management, and troubleshooting the most common errors.",[38,42,52,55,58,83,86,89,92,95,98],{"type":39,"title":40,"body":41},"h2","Why self-host a Go API on a VPS","Unlike Java or Node, a Go application (with the Gin framework) compiles into a single static binary that needs neither an interpreter, nor a runtime, nor a shared library. You can literally drop the binary onto a VPS and run it. This lightness changes everything for self-hosting: a Gin API runs in 15 to 30 MB of RAM and starts in a few milliseconds. On a VPS, you make the most of this efficiency: an entry-level server is enough to serve a load that interpreted languages would require a much bigger machine for. You also avoid the complexity of bulky Docker images: a 10 MB `scratch` image is enough, and builds and pulls are near-instant.",{"type":43,"title":44,"items":45},"ul","Concrete benefits",[46,47,48,49,50,51],"Single static binary: no runtime to install, deployment by a simple file copy","Tiny memory footprint (15-30 MB) allowing you to saturate a small VPS with requests","`scratch` or `distroless` Docker image of 10-15 MB: near-instant builds and pulls","Startup in milliseconds: redeployments and restarts with no perceptible interruption","Native concurrency via goroutines: a single vCPU handles thousands of simultaneous connections","Reduced attack surface: no interpreter or system packages to patch",{"type":39,"title":53,"body":54},"Hardware and software prerequisites","This is where Go shines: a Gin API without a database fits on a VPS with 1 vCPU and 1 GB of RAM, and stays at ease. With co-located PostgreSQL, aim for 2 GB to be comfortable. You don't even need Go on the server if you compile in CI or by local cross-compilation (`GOOS=linux GOARCH=amd64 go build`). Install Docker and Docker Compose on the VPS. Point an `api.mydomain.com` domain at the VPS IP via an A record. 5 GB of disk is more than enough. On your development machine, Go 1.27+ is recommended — download from go.dev\u002Fdl.",{"type":39,"title":56,"body":57},"Multi-stage Dockerfile with scratch image","The multi-stage Dockerfile is the key to a minimal final image. The first stage compiles the binary inside a full Go container; the second copies it into an empty `scratch` image — no shell, no OS, just your binary and the CA certificates for outbound HTTPS calls. Here is a complete Dockerfile for a Gin project:\n\n```\nFROM golang:1.27-alpine AS build\nWORKDIR \u002Fapp\nCOPY go.mod go.sum .\u002F\nRUN go mod download\nCOPY . .\nRUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags=\"-s -w\" -o server .\n\nFROM scratch\nCOPY --from=build \u002Fetc\u002Fssl\u002Fcerts\u002Fca-certificates.crt \u002Fetc\u002Fssl\u002Fcerts\u002F\nCOPY --from=build \u002Fapp\u002Fserver \u002Fserver\nEXPOSE 8080\nENTRYPOINT [\"\u002Fserver\"]\n```\n\nThe `CGO_ENABLED=0` flag forces a 100% static binary, essential for `FROM scratch` to work. The `-ldflags=\"-s -w\"` flags strip debug tables and reduce binary size by about 30%. The CA certificates COPY is essential as soon as your API contacts external HTTPS services (Stripe, SendGrid, etc.). If you need a shell for debugging, replace `FROM scratch` with `FROM gcr.io\u002Fdistroless\u002Fstatic-debian12` — same footprint, but with a few basic tools.",{"type":59,"title":60,"steps":61},"steps","Production Docker Compose with Nginx and Certbot",[62,65,68,71,74,77,80],{"title":63,"body":64},"Create the file structure on the VPS","Connect via SSH and create the project directory: `mkdir -p \u002Fopt\u002Fmyapp\u002F{nginx\u002Fconf.d,certbot\u002Fwww,certbot\u002Fconf} && cd \u002Fopt\u002Fmyapp`. This structure will hold the Nginx configuration and Certbot volumes.",{"title":66,"body":67},"Write the docker-compose.yml file","Create `\u002Fopt\u002Fmyapp\u002Fdocker-compose.yml` with three services: `app` (your Go image), `nginx` (reverse proxy) and `certbot` (SSL renewal). Minimal example:\n```\nservices:\n  app:\n    image: monapp:latest\n    restart: unless-stopped\n    env_file: .env\n    expose:\n      - \"8080\"\n  nginx:\n    image: nginx:1.27-alpine\n    restart: unless-stopped\n    ports:\n      - \"80:80\"\n      - \"443:443\"\n    volumes:\n      - .\u002Fnginx\u002Fconf.d:\u002Fetc\u002Fnginx\u002Fconf.d:ro\n      - .\u002Fcertbot\u002Fwww:\u002Fvar\u002Fwww\u002Fcertbot:ro\n      - .\u002Fcertbot\u002Fconf:\u002Fetc\u002Fletsencrypt:ro\n    depends_on:\n      - app\n  certbot:\n    image: certbot\u002Fcertbot\n    volumes:\n      - .\u002Fcertbot\u002Fwww:\u002Fvar\u002Fwww\u002Fcertbot\n      - .\u002Fcertbot\u002Fconf:\u002Fetc\u002Fletsencrypt\n```",{"title":69,"body":70},"Configure Nginx as a front-end proxy","Create `nginx\u002Fconf.d\u002Fapp.conf`. Start with an HTTP-only block to validate the ACME challenge, then add the HTTPS block after obtaining the certificate:\n```\nserver {\n    listen 80;\n    server_name api.mydomain.com;\n    location \u002F.well-known\u002Facme-challenge\u002F {\n        root \u002Fvar\u002Fwww\u002Fcertbot;\n    }\n    location \u002F {\n        return 301 https:\u002F\u002F$host$request_uri;\n    }\n}\nserver {\n    listen 443 ssl;\n    server_name api.mydomain.com;\n    ssl_certificate \u002Fetc\u002Fletsencrypt\u002Flive\u002Fapi.mydomain.com\u002Ffullchain.pem;\n    ssl_certificate_key \u002Fetc\u002Fletsencrypt\u002Flive\u002Fapi.mydomain.com\u002Fprivkey.pem;\n    location \u002F {\n        proxy_pass http:\u002F\u002Fapp:8080;\n        proxy_set_header Host $host;\n        proxy_set_header X-Real-IP $remote_addr;\n    }\n}\n```",{"title":72,"body":73},"Obtain the Let's Encrypt certificate","Start Nginx alone first, then run Certbot in webroot mode: `docker compose up -d nginx && docker compose run --rm certbot certonly --webroot -w \u002Fvar\u002Fwww\u002Fcertbot -d api.mydomain.com --email you@domain.com --agree-tos`. Once the certificate is issued, restart Nginx: `docker compose restart nginx`.",{"title":75,"body":76},"Build and start the application","Build the Go image on the VPS (or transfer it via `docker save\u002Fload` or a private registry): `docker build -t monapp:latest .`. Then start the full stack: `docker compose up -d`. Check logs with `docker compose logs -f app`.",{"title":78,"body":79},"Automate SSL renewal","Add a crontab on the VPS to automatically renew the certificate weekly: `(crontab -l 2>\u002Fdev\u002Fnull; echo \"0 3 * * 0 cd \u002Fopt\u002Fmyapp && docker compose run --rm certbot renew && docker compose restart nginx\") | crontab -`. Certbot only actually renews if expiration is within 30 days.",{"title":81,"body":82},"Configure Gin for production","In your code, switch Gin to release mode with `gin.SetMode(gin.ReleaseMode)` or the `GIN_MODE=release` environment variable to disable verbose debug logs. Read the port and secrets from the environment (`os.Getenv`), never hard-coded in the code.",{"type":39,"title":84,"body":85},"Live reload in development with air","In development, manually recompiling and restarting on each change is tedious. `air` (github.com\u002Fair-verse\u002Fair, currently v1.67.4) watches your source tree and restarts the binary on every `.go` file change. Installation: `go install github.com\u002Fair-verse\u002Fair@latest`. Simply run `air` at your project root — a default `.air.toml` config is generated automatically on first run. To customize watched directories or exclude `vendor\u002F`:\n```\n[build]\n  cmd = \"go build -o .\u002Ftmp\u002Fserver .\"\n  bin = \".\u002Ftmp\u002Fserver\"\n  include_ext = [\"go\", \"html\", \"tmpl\"]\n  exclude_dir = [\"vendor\", \"testdata\"]\n```\nair is for local development only: never install air in your production Docker image.",{"type":39,"title":87,"body":88},"Environment variables and secrets","Never hard-code secrets (API keys, database passwords, JWT tokens) in source code. The standard Go practice is to read them from the environment with `os.Getenv(\"DB_PASSWORD\")`. For local development, a `.env` file loaded by `godotenv` simplifies the workflow: `go get github.com\u002Fjoho\u002Fgodotenv`, then at startup:\n```\nimport \"github.com\u002Fjoho\u002Fgodotenv\"\nfunc main() {\n    _ = godotenv.Load() \u002F\u002F loads .env if present, silent in prod\n    db := os.Getenv(\"DB_DSN\")\n    port := os.Getenv(\"PORT\")\n    if port == \"\" { port = \"8080\" }\n    \u002F\u002F ...\n}\n```\nIn production, pass variables via Docker Compose's `env_file: .env` directive (this file must never be committed — add `.env` to your `.gitignore`). For highly sensitive secrets (tokens, private keys), prefer Docker secrets or an external vault. The golden rule: a secret in a `git log` is a compromised secret.",{"type":90,"body":91},"tip","Enable Go's `pprof` profiling behind a protected endpoint: `import _ \"net\u002Fhttp\u002Fpprof\"` exposed on an internal port accessible only via SSH tunnel (`ssh -L 6060:localhost:6060 user@vps`). You get CPU and memory flame graphs in real production without noticeable overhead. Also consider compiling with `-ldflags=\"-s -w\"` to reduce the binary size by ~30% by stripping the debug tables.",{"type":39,"title":93,"body":94},"Troubleshooting: common errors","Here are the five most frequent errors on a first Go VPS deployment, with their exact error messages and the fix to apply.\n\n**1. `standard_init_linux.go:228: exec user process caused: no such file or directory`** — The binary was compiled with CGO enabled and the `scratch` image contains no libc. Fix: recompile with `CGO_ENABLED=0 go build -o server .`.\n\n**2. `exec format error`** — The binary was compiled for a different architecture (e.g., macOS ARM → Linux AMD64). Fix: verify `GOOS=linux GOARCH=amd64` before building, or build directly on the VPS.\n\n**3. `bind: address already in use` (port 8080)** — Another process is already listening on that port. Check with `ss -tlnp | grep 8080` and stop the conflicting process, or change the port in your `.env`.\n\n**4. `x509: certificate signed by unknown authority` or `certificate has expired`** — Your `scratch` container lacks CA certificates (`\u002Fetc\u002Fssl\u002Fcerts\u002Fca-certificates.crt`), or the Let's Encrypt certificate has expired. Fix: verify the `COPY --from=build \u002Fetc\u002Fssl\u002Fcerts\u002Fca-certificates.crt` is present in your Dockerfile, and re-run Certbot to renew.\n\n**5. `permission denied` on binary startup** — The binary is not executable. Fix: check permissions with `ls -la server` and apply `chmod +x server` if needed. In a Dockerfile, `COPY --from=build` normally preserves permissions, but an explicit `RUN chmod +x \u002Fserver` guarantees the result.",{"type":39,"title":96,"body":97},"Deploy Go (Gin) in one click from the ServOrbit Marketplace","The ServOrbit Marketplace offers a preconfigured Go (Gin) Stack template: Go from the official go.dev binary, Nginx and PostgreSQL 16 are installed automatically on your VPS from the order form. No SSH session for the base setup — you arrive directly at the step of compiling your project and uploading the binary. The marketplace page contains the exact specifications, use cases, and a first-connection guide.",{"type":39,"title":99,"body":100},"Going further","You now have a complete Go VPS deployment under your belt. To go even further: configure **Traefik v3** as your reverse proxy instead of Nginx — it handles routing, Let's Encrypt certificates and load balancing in a single container with declarative Docker label configuration (see our [Traefik v3 on VPS guide](\u002Fblog\u002Ftraefik-v3-vps-reverse-proxy)). For zero-downtime production updates, check our article on [Docker Compose update best practices](\u002Fblog\u002Fdocker-compose-mise-a-jour-best-practices-vps): rolling deployments, health checks and rollback strategies. If you prefer to delegate the infrastructure, our [Go (Gin) template in the Marketplace](\u002Fapplications\u002Fdeveloppement\u002Fgolang) provisions the entire stack in minutes.","Deploy your Go (Gin) Stack in minutes","The ServOrbit Go (Gin) Stack template installs Go 1.22+, Nginx, and PostgreSQL 16 on your VPS. Cross-compile your project and deploy the binary immediately.","Deploy Go (Gin) Stack","\u002Fapplications\u002Fdevelopment\u002Fgolang",[106,123,141],{"id":107,"slug":108,"slugs":109,"title":113,"excerpt":114,"readTime":115,"views":23,"isPinned":19,"noindex":19,"publishedAt":116,"updatedAt":21,"category":117,"categories":118,"featuredImage":30,"bgImage":31,"posterImage":120,"relatedSolution":121},45,"deploy-a-fastapi-application-on-a-vps",{"fr":110,"en":108,"ar":111,"es":112},"deployer-fastapi-vps","نشر-تطبيق-fastapi-على-vps","desplegar-una-aplicacion-fastapi-en-un-vps","Deploy FastAPI on a VPS: the complete production guide","Deploy FastAPI on a VPS with multi-stage Docker, Gunicorn, PostgreSQL, GitHub Actions CI\u002FCD and monitoring. Complete Python production guide 2025.",10,"2026-05-06T00:00:00+00:00",{"id":23,"name":24,"slug":25,"color":26,"icon":27},[119],{"id":23,"name":24,"slug":25,"color":26,"icon":27},"\u002Fblog\u002Fcovers\u002Fdeployer-fastapi-vps-poster.svg",{"categorySlug":34,"appSlug":122},"fastapi",{"id":124,"slug":125,"slugs":126,"title":130,"excerpt":131,"readTime":132,"views":133,"isPinned":19,"noindex":19,"publishedAt":134,"updatedAt":21,"category":135,"categories":136,"featuredImage":30,"bgImage":31,"posterImage":138,"relatedSolution":139},44,"deploy-a-django-application-on-a-vps",{"fr":127,"en":125,"ar":128,"es":129},"deployer-django-vps","نشر-تطبيق-django-على-vps","desplegar-una-aplicacion-django-en-un-vps","Deploy a Django Application on a VPS","Deploy Django on a VPS: Gunicorn, Nginx, PostgreSQL, Docker, and SSL. A complete guide for Python developers who want to self-host.",3,7,"2026-05-07T00:00:00+00:00",{"id":23,"name":24,"slug":25,"color":26,"icon":27},[137],{"id":23,"name":24,"slug":25,"color":26,"icon":27},"\u002Fblog\u002Fcovers\u002Fdeployer-django-vps-poster.svg",{"categorySlug":34,"appSlug":140},"django",{"id":142,"slug":143,"slugs":144,"title":148,"excerpt":149,"readTime":17,"views":18,"isPinned":19,"noindex":19,"publishedAt":150,"updatedAt":151,"category":152,"categories":153,"featuredImage":30,"bgImage":31,"posterImage":155,"relatedSolution":156},43,"deploy-a-nodejs-application-on-a-vps",{"fr":145,"en":143,"ar":146,"es":147},"deployer-nodejs-vps","نشر-تطبيق-nodejs-على-vps","desplegar-una-aplicacion-nodejs-en-un-vps","Deploy a Node.js Application on a VPS","Deploy a Node.js application to production on a VPS: PM2, Nginx reverse proxy, Let's Encrypt SSL, and automatic startup at boot.","2026-05-08T00:00:00+00:00","2026-11-08T01:13:12+00:00",{"id":23,"name":24,"slug":25,"color":26,"icon":27},[154],{"id":23,"name":24,"slug":25,"color":26,"icon":27},"\u002Fblog\u002Fcovers\u002Fdeployer-nodejs-vps-poster.svg",{"categorySlug":34,"appSlug":157},"nodejs-stack",true,1794270388838]