
Show HN: Easy-to-configure Web Server in Go  - oakaz
http://github.com/azer/boxcars
======
laumars
A word of warning guys, I've had a look through the code and unless I've
missed the obvious, there's nothing in there to change user ID; which means
this would either need to be run as root, or would need to listen on a port >
1024.

In the case of the former, that's a huge step backwards in terms of security.

In the case of the latter, that would mean you'd need another reverse proxy
hooked up - which would negate the need for this web server to begin with.

This can easily be fixed within Go though:

    
    
        import (
        	"log"
    	"syscall"
        )
        
        const (
        	user_id  int = 1000
        	group_id int = 1000
        )
        
        func secureDaemon() {
        	// set group id first as you need to be root to change group
        	err := syscall.Setgid(group_id)
        	if err != nil {
        		log.Fatalln(err)
        	}
        	
        	err = syscall.Setuid(user_id)
        	if err != nil {
        		log.Fatalln(err)
        	}	
        }
    

You can also add chroot to your code if you want to be ultra paranoid:

    
    
        import (
    	"os"
        )
        
        const (
        	chroot_dir string = "/opt/go-webserver"
        )
        
        func chrootDaemon() {
        	err := os.Chdir(chroot_dir)
        	if err != nil {
        		log.Fatalln(err)
        	}
    
        	err = syscall.Chroot(chroot_dir)
        	if err != nil {
        		log.Fatalln(err)
        	}
        }
    

This will need to be done before you change your user ID (as you need root
permissions to chroot) and you may need to compile the Go without CGO because
some of the standard Go libraries will have SO dependencies (I found this to
be the case with domain name lookups).

(the above code is adapted from my own Go web framework that I'm in the
processes of building)

~~~
1331
A program run as a non-privileged user can access privileged ports using
authbind:

[http://en.wikipedia.org/wiki/Authbind](http://en.wikipedia.org/wiki/Authbind)

~~~
pjmlp
Seems to be GNU/Linux only.

~~~
coolsunglasses
Come in, the water's warm.

------
justinsb
I remain not-entirely-convinced (1) by Go, but things like this are turning
the tide. If it is indeed slower than nginx, it is not dramatically so.
Considering the amount of time that went in to writing each, the Go version
clearly "wins" from the point of view of anyone thinking of writing new code.

(1) I find error handling just too tedious to get right (Edit: "I find error
handling _in Go_ just too tedious...")

~~~
joebo
Looking at the benchmark
([https://gist.github.com/azer/5955772](https://gist.github.com/azer/5955772)),
which measure suggests that its slower than nginx? I was looking at the
transaction rate and the longest transaction. For reverse proxying, it seems
to be as fast as nginx. For static file serving, it appears to be slightly
slower. Between the two use cases, it seems like it's a negligible difference.

~~~
justinsb
I would like to know how the benchmarks are generated, but my point is that it
wasn't slower-enough to ignore it, and that's amazing considering how much
micro-optimization has gone into nginx and how much easier the Go version is
to write.

The Go version may in fact be faster, but I don't think that's necessarily
fair either: if the Go version adds features to be more comparable to nginx it
would definitely slow down.

~~~
rdtsc
> The Go version may in fact be faster, but I don't think that's necessarily
> fair either: if the Go version adds features to be more comparable to nginx
> it would definitely slow down.

Good point. That is often how alternative parallel implementations are
started. A small example is written. Benchmarks are published. The new project
is hailed as better than predecessor. Many jump ship. Request for features
comes in. New features starts to slow down the product. Someone new comes,
writes a simple benchmark and so on.

------
stevekemp
So it's a reverse HTTP proxy, which can also serve files locally? That's an
interesting thing, no doubt, but it doesn't feel like a web-server.

I wrote a flexible reverse proxy[0] using node.js, a year or so ago, and
haven't missed the ability to serve static files directly - so I'm wondering
what the use-case for that is? I guess proxying to rails, or similar?

0- [http://steve.org.uk/Software/node-reverse-
proxy/](http://steve.org.uk/Software/node-reverse-proxy/)

~~~
justinsb
Did you benchmark your node.js version? I would love to know how node stacks
up here.

I agree that static serving is not as interesting, but it is useful to be able
to serve up a fail-whale page!

~~~
stevekemp
Honestly I never have. Because in practise it is fast enough that it just
didn't come up.

I'm sure that if I were to pimp the project properly then that would be a good
thing to do, but half the fun of my proxy is to allow "interesting" rewrites,
dynamically.

To benchmark I'd be too tempted try to game the results by doing a straight
pass-through comparison to mod_proxy, nginx, etc. That would lose half of the
appeal of the project in the first place.

~~~
oakaz
In my experience, NodeJS was slow. I first write a boxcars-like server in
NodeJS; [http://github.com/azer/door](http://github.com/azer/door)

and here is the benchmarks of it;
[https://gist.github.com/azer/5946227](https://gist.github.com/azer/5946227)

------
Uchikoma
I always wonder with this kind of posts, is it minimalistic or is it an
alternative?

~~~
jacques_chester
The point is that it's written in language-du-jour and therefore fascinating
and novel.

In fairness though, json will probably wind up being a common configuration
format anyhow. And the idea of programmatically configurable system software
is nice. I liked the Mongrel2 approach of having it in SQLite.

~~~
harrytuttle
json is fine until your config system needs accurate numeric values.

~~~
shuzchen
Nothing in the json spec requires that numbers are limited to those internally
representable in a javascript runtime. With the right tooling, you can
encode/decode very accurate numeric values. I'm not familiar with the go
libraries, but python's simplejson has a use_decimal flag that interprets
floats using python's Decimal module.

That said, I can't think of any reason a web server needs super accurate
numbers. All the config options I can think of require nice round ints. Maybe
specifying weights to individual backends to proxy to (so all the weights sum
up to 1.0)?

~~~
harrytuttle
99% of sites are CRUD apps, but we're math heavy financial software. We store
a lot of reference data in configuration for performance reasons. This needs
to be decimal format.

JSON is a subset of the ECMA JavaScript standard which declares only floating
point.

Do "100!" on wolfram alpha and find me a parser that will load that as an
example.

~~~
shuzchen
works for me:
[https://gist.github.com/sirpengi/609711](https://gist.github.com/sirpengi/609711)

~~~
harrytuttle
I get a 404. ?

~~~
shuzchen
Bad copy pasta (missing 3 at the end):
[https://gist.github.com/sirpengi/6097113](https://gist.github.com/sirpengi/6097113)

------
JoeAcchino
I'm very interested in this because this is the kind of web server I was
planning to write for my work, but from a quick glance I didn't find HTTPS
support.

Is HTTPS supported or planned?

~~~
oakaz
have you tried it?

------
pandeiro
Code organization question: is this a common convention in Go, to nest the
main package in a subdirectory and put all of the 'modules' in different files
but with the same package name?

(I'm more used to the Clojure namespace/filesystem symmetry, so this is
somewhat new to me. I like the more shallow project tree but it's not
immediately apparent where things are defined.)

~~~
redbad
In a package, main or otherwise, files are purely for programmer convenience.
They define import scope but are otherwise transparent to the toolchain.

------
alexchamberlain
Nice to see an alternative on the cards. Of course, we need some independent
security reviews before this can be used seriously.

------
tszming
json format is too limited for a web server configuration if you want to be
the nginx alternative. Think about how you would represent conditional
statements, how to include and reuse external configurations and how to have
comments in json.

------
simonw
The custom 404 page example in the readme looked incomplete - how do you
ensure those pages are served with the correct HTTP status code?

