Deploying Go web applications with Apache

There's no mod_go. (At least I've not heard of such a thing.)

A go web app by itself is a capable web server. You can listen to port 80 in your app and then directly run it on your server. Trust me: it really works!

But if you are not doing that (for reasons such as having other virtual servers on the same machine, load balancing, etc.), you can use a HTTP server such as nginx or Apache as a HTTP proxy in front of your Go app. I use nginx and it's great. Here's an outdated but still very useful guide on how to do that with nginx. I haven't done it with Apache, but this should help.

I recommend your Go web app by itself or nginx as a HTTP proxy.


For those interested there is a recently released mod_go for Apache in here:

https://github.com/idaunis/mod_go


While not ideal, you can run Go programs as CGI scripts by placing them in the cgi-bin directory. You can invoke them like any other page through server.com/cgi-bin/myapp?foo=bar

An example program would look like this:

package main

import (
    "fmt"
    "net/http"
    "net/http/cgi"
)

func hello(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "Hello from Go!")
}

func main() {
    http.HandleFunc("/", hello)
    cgi.Serve(nil)
}

The reason this is not as optimal as running the program as its own server, is that with a cgi approach, the program is invoked for every single request. So any state inside it does not persist.

For clarity: You should place the compiled binary in the cgi-bin directory. Not the program source.


In addition to the other options, there's also the net/http/fcgi package. This is similar to the CGI option, but it uses FastCGI and your application can keep state if it needs to.

Here's the FastCGI version of jimt's example. Note that only two lines are different. Depending on how you configure Apache, you may have to change the first argument to something different, but nil is the common case.

package main

import (
    "fmt"
    "net/http"
    "net/http/fcgi"
)

func hello(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "Hello from Go!")
}

func main() {
    http.HandleFunc("/", hello)
    fcgi.Serve(nil, nil)
}