Nginx + FastCGI + Go Setup.




UPDATE : Previous code example no longer work since Golang version 1.5. Updated the code example below to work with the latest version

In most examples of Go that I came across that deal with net/http package, accessing the Go program is usually done via http://localhost:8080/..

This is useful if you want to use Go web server on a port.

However, there are times you need a front web server to handle incoming requests and proxy the requests to multiple Go processes.

In this tutorial, we will learn how to connect a Go process via FastCGI and Nginx web server. This tutorial assumes that you already know how to setup Nginx and FastCGI.

In the Nginx server block, you need to configure FastCGI to listen to certain port. For example :

 location ~ /go.* {
  include fastcgi.conf;
  fastcgi_pass 127.0.0.1:9001;
 }

NOTE : Make sure to include this FastCGI block in HTTPS part of the nginx.conf file if your web server redirects all traffic to HTTPS

We will try to achieve the following :

  1. Print out a "Hello World!" string via the localhost:8080 way

  2. Change the Go program to output via FastCGI.

Ok, let's get started with the "traditional" way

File : nginx_fastcgi.go

 package main

 import (
  "net/http"
 )

 func HelloHandler(w http.ResponseWriter, r *http.Request) {
  html := "Hello"
  html = html + " World"

  w.Write([]byte(html))
 }

 func main() {
  http.HandleFunc("/", HelloHandler)
  http.ListenAndServe(":8080", nil)
 }

Pointing the browser to http://example.com:8080/nginx_fastgci will give us "Hello World!" output.

Now, change the above codes to :

 package main

 import (
  "github.com/gorilla/mux"
  "log"
  "net"
  "net/http"
  "net/http/fcgi"
 )

 type customHandler struct {
  cmux http.Handler
 }

 // must have at least ServeHTTP(), otherwise you will get this error
 // *customHandler does not implement http.Handler (missing ServeHTTP method)

 func (c *customHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
  html := "Hello"
  html = html + " World"

  w.Write([]byte(html))
 }

 func main() {

  mux := mux.NewRouter()

  // bind cmux to mx(route)
  fcgiHandler := &customHandler{cmux: mux}

  mux.Path("/").Handler(fcgiHandler)

  listener, _ := net.Listen("tcp", "127.0.0.1:9001") // bind to port 9001 because of - fastcgi_pass 127.0.0.1:9001; in nginx.conf file

  err := fcgi.Serve(listener, fcgiHandler)

  if err != nil {
 log.Fatal(err)
  }

 }

NOTE : The above code is adapted from previous tutorial on how to create custom handler with Gorilla framework

Test out by running > go run nginx_fastcgi.go and point your browser to http://example.com/go

you should see the output as the same, but this time without the :8080 port.

Why go at the end of the URL ? Err.... because it is configured in the Nginx server block.

 location ~ /go.* {
  include fastcgi.conf;
  fastcgi_pass 127.0.0.1:9001;
 }

To wrap this up, what we did here is to tell nginx_fastcgi.go to listen to new requests pass down via FastCGI and serve the simple Hello World HTML.

Happy coding!

References:

https://www.socketloop.com/tutorials/golang-example-of-custom-handler-for-gorilla-s-path-usage

https://golang.org/pkg/net/http/fcgi/





By Adam Ng

IF you gain some knowledge or the information here solved your programming problem. Please consider donating to the less fortunate or some charities that you like. Apart from donation, planting trees, volunteering or reducing your carbon footprint will be great too.


Advertisement