Apps Artificial Intelligence CSS DevOps Go JavaScript Laravel Linux MongoDB MySQL PHP Python Rust Svelte Vue

Reverse Proxy with Nginx and Go for Microservices

2 min read .
Reverse Proxy with Nginx and Go for Microservices

As an application grows, splitting it into smaller services can make independent deployment and scaling easier. For example:

  • Product service on port 8080
  • Blog service on port 8081

Users should not need to know those internal ports. An Nginx reverse proxy can expose both services under one domain and route requests by URL path.

1. Configure the Nginx Reverse Proxy

Create a site configuration:

sudo nano /etc/nginx/sites-available/yourdomain.com

Add:

upstream api_product {
    server 127.0.0.1:8080;
}

upstream api_blog {
    server 127.0.0.1:8081;
}

server {
    listen 80;
    server_name yourdomain.com;

    # Proxy to the product service
    location /product/ {
        proxy_pass http://api_product/;
        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 to the blog service
    location /blog/ {
        proxy_pass http://api_blog/;
        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;
    }
}

Enable the configuration:

sudo ln -s /etc/nginx/sites-available/yourdomain.com /etc/nginx/sites-enabled/

Validate it:

sudo nginx -t

Then reload Nginx:

sudo systemctl reload nginx

2. Product Service

package main

import (
	"net/http"
	"github.com/gin-gonic/gin"
)

type Response struct {
	Message string    `json:"message"`
	Data    []Product `json:"data,omitempty"`
}

type Product struct {
	Name  string `json:"name"`
	Price int    `json:"price"`
}

func main() {
	r := gin.Default()

	r.GET("/", func(c *gin.Context) {
		c.JSON(http.StatusOK, Response{
			Message: "Success",
			Data: []Product{
				{Name: "Product 1", Price: 100},
				{Name: "Product 2", Price: 200},
				{Name: "Product 3", Price: 300},
			},
		})
	})

	r.POST("/create", func(c *gin.Context) {
		var product Product
		if err := c.ShouldBindJSON(&product); err != nil {
			c.JSON(http.StatusBadRequest, Response{Message: "Bad Request"})
			return
		}

		c.JSON(http.StatusCreated, Response{
			Message: "Product Created",
			Data:    []Product{product},
		})
	})

	r.Run(":8080")
}

3. Blog Service

package main

import (
	"net/http"
	"github.com/gin-gonic/gin"
)

type Response struct {
	Message string    `json:"message"`
	Data    []Article `json:"data,omitempty"`
}

type Article struct {
	Name    string `json:"name" binding:"required"`
	Content string `json:"content" binding:"required"`
}

func main() {
	r := gin.Default()

	r.GET("/", func(c *gin.Context) {
		c.JSON(http.StatusOK, Response{
			Message: "Success",
			Data: []Article{
				{Name: "Article 1", Content: "Content 1"},
				{Name: "Article 2", Content: "Content 2"},
				{Name: "Article 3", Content: "Content 3"},
			},
		})
	})

	r.POST("/create", func(c *gin.Context) {
		var article Article
		if err := c.ShouldBindJSON(&article); err != nil {
			c.JSON(http.StatusBadRequest, Response{Message: "Bad Request"})
			return
		}

		c.JSON(http.StatusCreated, Response{
			Message: "Article Created",
			Data:    []Article{article},
		})
	})

	r.Run(":8081")
}

4. Access the Services

Once both services and Nginx are running:

  • http://yourdomain.com/product/ → routes to the product service on port 8080.
  • http://yourdomain.com/blog/ → routes to the blog service on port 8081.

Clients use a single public domain and do not need to know the internal service ports.

5. Conclusion

With separate sites-available and sites-enabled configuration, Nginx can provide a clean routing layer for multiple microservices. Combined with lightweight Go services, this pattern gives you a simple foundation that can later be extended with TLS, health checks, load balancing, observability, and container orchestration as the system grows.

Related Posts

chevron-up