Currently I have the following HTTP server written in Go:
func main() {
http.HandleFunc("/", func(response http.ResponseWriter, request *http.Request) {
http.ServeFile(response, request, "/var/www/default/htdocs/index.html")
})
http.Handle("/public/", http.StripPrefix("/public/", http.FileServer(http.Dir("/var/www/default/htdocs/public"))))
http.HandleFunc("/json", func(response http.ResponseWriter, request *http.Request) {
// serves a JSON response
})
http.HandleFunc("/socket", func(w http.ResponseWriter, r *http.Request) {
// replies to the WebSocket
})
http.ListenAndServe(":3000", nil)
}
I've seen some benchmarks that show that nginx can serve a lot more requests per second when it comes to static files. Another useful feature of nginx is that it can gzip responses transparently and even serve pre-compressed files with the gzip_static
module.
Ideally, I want nginx to serve all existing (static) files and proxy everything that doesn't exist to Go:
location / {
try_files $uri $uri/ @go;
}
location @go {
proxy_pass http://127.0.0.1:3000/;
proxy_set_header Host $host;
}
Unfortunatly, nginx doesn't like the above configuration:
nginx: [emerg] "proxy_pass" cannot have URI part in location given by regular expression, or inside named location, or inside "if" statement, or inside "limit_except" block in /etc/nginx/sites-enabled/default:23
At this point, I know I have several options:
1) put proxy_pass
in the location /
block
But this will proxy everything, even the existing (static) files.
2) write individual /json
and /socket
location blocks in nginx
But if I want to add more handlers in Go, I also have to update the nginx vhost accordingly.
3) rewrite the Go code and use fastcgi_pass
in nginx instead of proxy_pass
location @go {
fastcgi_pass 127.0.0.1:9000;
}
I would also have to change the Go code to use net/http/fcgi
instead of net/http
, the problem with this is that I don't know how to specify the paths (/json
or /socket
) with fcgi.Serve()
.
Additionally, FastCGI seems to be 4 times slower than HTTP: https://gist.github.com/hgfischer/7965620.
4) discard nginx altogether
Make Go serve everything (including static files) and handle gzip compression on every request.
How can I make nginx and Go to behave like I want (preferably with the HTTP interface)?
Apologies if this question is too basic, this is my very first experience writing a Go web app.
Additional Question
In PHP, I point fastcgi_pass
to the php-fpm
Unix socket. If any request experiences a PHP fatal error, the upcoming requests will still be served. However, if my Go code calls panic()
the program will be terminated and the service will stop responding. What is the best way to handle that in Go?
Problem with "proxy_pass" seems to be because of trailing
/
, try to remove it, as it does nothing any way. If you need to alter URI before passing it to proxy, try to use rewrite, i.e to remove some part of URI try something like:I used the following nginx config - resource
Below is my directory structure:
According to this site I run a simple sinatra app:
And that are the responses
As You can see if the file does not exist the request goes to the the sinatra app.