Hacker News new | past | comments | ask | show | jobs | submit login
Nginx for Developers: An Introduction (carrot.is)
434 points by jenius on June 19, 2013 | hide | past | favorite | 138 comments

If you like this article, I wrote a similar one called Devops for Dummies.


It teaches you how to setup a DigitalOcean (or any other) VPS from scratch to host N amount of Rails applications using Nginx and Passenger. It took me some time to get things working properly and I distilled it into this short article that holds your hand and takes you from A to Z.

Nice. One step I would add is after restarting ssh and before rebooting while still logged in as root is to start a second ssh session, log in as the new user, and verify you can sudo.

Your current instructions are predicated on success. By verifying your new user login and sudo capability before logging out as root (rebooting), you can fix typos or other Bad Things. Not that I would ever make a typo while editing sudoers. ;-)

One thing I would recommend is searching for deals on LowEndBox[1] blog. Most of the popular VPS's are ridiculously overpriced compared to what you can find on LowEndBox. It's a good site to get advice and reviews of various VPS providers, too.

[1] - http://www.lowendbox.com/

I'm quite familiar with LowEndBox, and I would say my current "Best Value" VPS provider would be Digital Ocean, who I found via HN. I probably can think of at least a dozen with solid reasons to avoid. FYI Digital Ocean's lowest offering is $5/m.

LowEndBox is great for non-mission critical servers. You aren't going to find many top tier providers on there, mostly smaller companies. I got a dedicated box (quad Xeon, 24GB RAM, 500GB) for $49/m.

I would love to get my hands on one of those. What provider did you get it from?

Who's the provider you're renting the box from ?

Why would anyone need to search LowEndBox, when they can get top tier cloud servers from DigitalOcean(which is linked on the original post)? There is absolutely no reason to use providers from LowEndBox with grandma's SolusVM, when you can spin up a server with DO anytime you want and pay by the hour?

And not to mention, how these providers are ddosing and hacking one another regularly.

Not all providers there are bad; BuyVM is one that has treated me excellently

You should probably have people use visudo instead of editing /etc/sudoers directly. If you make a typo or similar that prevents sudo from running correctly it will catch it.

Disabling root login without changing to using ssh-keys for authentication doesn't really buy you a whole lot of security; you can still access the box and root with knowing just one password -- the only thing you've avoided are brute force attempts against the root account.

With sudo and only keys based access, the attacker will need to get a copy of the key (barring any new problems with key generation, like the Debian ssl bug) and the password needed for sudo access (or the root password, for su -).

As other's have said, use visudo (possibly with "EDITOR=nano visudo) -- to avoid leaving your sudoers file in a broken state.

An as others mentioned -- make sure you can login and sudo before you log out of the root shell...

What does visudo do that nano -w doesn't? I've never understood this properly.

Locks to only one editing user and confirms syntax is clean before saving. I'm not aware of nano enforcing correct sudoers syntax. Plus plenty of us don't like nano.

man visudo for more info.

visudo, like vipasswd or crontab -e and other commands, respect the EDITOR environmental variable, so you can edit these files with whatever editor you prefer, while maintaining their protections.

True. Provisioning a new test VM for me usually entails something like this: ssh in; visudo; wtf, this is nano! Boo!; ctrl-x; update-alternatives --config editor... :)

Awesome! If you like to go a bit further I suggest learning Chef in order to automate this kind of tasks. I wrote a tutorial about it: http://matteodepalo.github.io/blog/2013/03/07/how-i-migrated...

Thank you for linking to your article, it was perfect timing as I'm about to throw up a tiny Ruby/Sinatra/PostgreSQL site I've been making for a local need. The quality of my actual code aside, I understand that servers are incredibly complex beasts, especially when it comes to security, and I want to ask (And because of their complexity, I assume it's a small question with a huge, complex answer), how relatively 'safe' would I be following a guide like yours along with other ones that specify some simple, good practices for setting up a server?

By safe, I mean in the context of the server getting hacked. I know people wouldn't bother but I'd rather at least feel a tiny bit safe. I'm going with a VPS (Digital Ocean) too so I can slowly learn all these things.

Hi thanks for your comments, I appreciate you taking the time to read it.

I'm _not_ a devops guy. Following my guide you _will_ get a running production server but I've only distilled things from other blogs I've hunted on the web. I would make sure I hire someone who actually does this for a living before putting production things on something I configured.

So feel safe, but cautiously safe - I'm not a guru.

Could I take your article and use it as a base for a Python version of that?

Feel free to use it. I wrote it to:

A) Solidify what I had learned by putting it into writing.

B) Help others avoid my dumb mistakes.

So if it helps people I'm all for it. :)

My thoughts also. I'm going to start up a blog and get to it after work.

This is great, I've been on the fence about firing up a VPS or two rather than use Heroku, this may be just what I need to get going.

Awesome, thanks @sergiotapia!

Good article. Be wary of the well documented zero-day exploits if you're using php.

This is one of my other favorite articles: http://docs.ngx.cc/en/latest/topics/tutorials/config_pitfall...

Some good introductory stuff here as well: http://pineapple.io/resources/tagged/nginx

How can a zero-day be well documented? By definition it's not yet public.

It sounds scarier than saying: "If you use PHP, remember to set the following in your .ini"

    cgi.fix_pathinfo = 0

So not zero day and not an exploit. A terrible idea for a feature though, PHP seems to be rich with those.

Not really a terrible idea at all. They are simply conforming to the CGI specification. In realizing the potential security issues associated with doing so, they offer a way to disable that behavior.

That first article was awesome. I found 2 things in my configs that were security holes :/


Yikes, I'm supposed to be the grammar and spelling nazi :P

Everybody make's mistakes!


See Muphry's law. :)

haha well executed trolling

I think the sites-available is a debianism, not present on all distros. One nice thing that nginx supports is include directives with wildcards so you can e.g. have /srv/example.com/nginx.conf and /srv/api.example.com/nginx.conf and include them in the main configuration file with include /srv/*/nginx.conf.

Today You Learn that is because the original package maintainer of the NginX package in Debian (and thus later, Ubuntu) simply copied the structure of the Apache package. It's most useless because there is no script to manage the sites available like with apache.

I have been complaining about this for years!

On FreeBSD and all my client's sites (whether they run Linux or what), I always set mine to include sites/*.conf and delete those apache-isms.

It's especially bizarre given how trivial such a script is - as far as I am aware, it's a glorified symlink-maker.

Hrm, looking now, a2ensite is 340 lines long...

Quite the glorified symlink maker!

It is my experience from years of administration that `ln` and `rm` (or perhaps `mv`) are the only commands necessary to work with the directories without the scripts.

You know how many times I had to restart the nginx daemon on a VPS for me to figure this out. Thank you for complaining!

There are "official" nginx packages for Ubuntu and other major Linux distributions which are always up-to-date and use a standard conf.d directory for including configuration files http://nginx.org/en/linux_packages.html

I may be misunderstanding you, but sites-available and the conf files are usually two separate entities. sites-available | sites-enabled is analogous to using a2ensite in Apache without the automagic (you symlink yourself)

On systems that have both, yes, they're separate. But that separation is something the distribution does to help you organize your rules — to nginx, they're all the same AFAIK.

It's distro-specific and it doesn't present by default in stock nginx.

Yeah, I run nginx on both Ubuntu and RedHat boxes. On RedHat, the conf files go in /opt/nginx/conf ... there is no sites-avail/enabled

He did mention specifically that the structure was provided by the `apt` install.

I ran into a version of Nginx on CentOS had sites-avail/enabled.

I'm currently running Centos 6 on my VPS and it has this file structure.

For starter nginx's configuration, the h5bp nginx config [1] is pretty awesome, e.g. sending correct mime types, protecting hidden files, cross domain webfont, expires, gzip, server tunings all included.

[1] https://github.com/h5bp/server-configs/tree/master/nginx

Great suggestion, thanks @tszming!

> The default port for the internet is 80, so if there’s no port in a url, that means it’s 80.

The Internet has no default port; 80 is for HTTP. If the port is omitted, then the default for the scheme[1] is assumed.


[1]: https://en.wikipedia.org/wiki/URI_scheme

haha fair enough, if I changed "the internet" to "http" would that satisfy you?

Yes, that would be good to change it to "http" to be clear about the protocol you are talking about. :-)

I am a little hesitant on restarting nginx. When you do that, it drops the connections that are currently attached. Instead, you may want to do `nginx reload`

Yeah, I disliked that part to. The commands you need to know is:

nginx -t (test your configuration)

nginx -s reload (reload your configuration)

Also I prefer "nginx -s restart".

Great feedback guys - we'll look this over and probably change it in the article : )

The reason it's as such is because of what @timroman said in his reply, but if this method is no different and scales better no reason not to use it instead.

Possibly want to compare when to use restart and reload, and the drawbacks of both.

I can't imagine there are many connections to worry about if you're configuring a new server.

It's not a problem on a new server of cause, but on a live server it makes a difference, so you might as well learn the "correct" approach initially, so you won't hurt yourself in the future.

Right but if you are modifying and existing server, then this needs to be taken into account. We have several servers who are constantly serving connections and we can't have any of them drop otherwise it will result in a poor user experience.

I just wish the article talked about using reload as well as restart and when to use them.

Hi, author of the article here. I'm actually not familiar with reload, but after reading this comment thread I'm definitely going to read up on it and make sure it's reflected in the article. Any suggestions of knowledge you want to drop is more than welcome!

Me as well. I always use reload but I don't really know how it works. Does it maintain the old and new configs and drops the old after the last connection using it is complete?

When NginX's master process receives the HUP signal[1], NginX will process and test the new configuration. If it is correct, the new configuration will be loaded into new worker processes. The old worker processes will stop receiving connections, but finish their current work. Eventually (within milliseconds usually), all the old processes will be gone and only new processes with new configuration will be working on requests.

[1] On FreeBSD, we just use `killall -HUP nginx` to reload; your distro will probably send HUP to the master process' PID

One of my favorite nginx features I just discovered is that you can use a regex in the server_name and then you can use the capture as a variable later [1] ... this lets you serve domains or subomains from completely different directories without a new conf file or a reload.

I'm using it at http://www.utterson.me to serve up static Jekyll blogs on a subdomain.

I may be wrong, but I don't think Apache can do this (it can do regex but you don't get a variable).

[1] http://nginx.org/en/docs/http/server_names.html#regex_names

I've done something similar in Apache with mod_vhostalias, where you set a VirtualDocumentRoot that specifies the pattern to match against and the dynamic directory path to serve up.

I like just keeping a single "etc/nginx/sites" folder, including "sites/*.ON" in my main nginx.conf and then appending .ON to the sites that are enabled:


That's clever. Coming from Apache I was disappointed not to see something equivalent to: a2ensite (site)

Wouldn't it be kind of trivial to right a function to would take a directory name as a parameter and symlink it from site-available to site-enabled?

It would be. That's exactly what a2ensite does. That's what I ended up doing.

That's a debian feature. Not an Apache feature.

You can also use the Debian-style setup with sites-enabled/*, though I don't know of enable/disable scripts for nginx.

For some strange reason I was expecting an article on nginx module development. http://www.evanmiller.org/nginx-modules-guide.html

You aren't at all alone. I was really hoping for updated module development information from someone currently in the trenches.

Completely off-topic: Is that a custom WP theme? I love the look and feel of this article.

On-topic: Thank you for this. I am going to purchase a DO box this weekend and play around with nginx instead of apache. For some reason when I last tried to use nginx, I could not get location {} to work. Granted it was some time ago.

Does anyone have any resources on nginx as a load balancer?

Actually it's a very simple custom non-wordpress theme I put together in about an hour, the entire thing built on top of http://roots.cx dynamic content : )

Another note, the share button at the bottom (just pushed a minute ago so hard refresh if it's cached) is from this plugin we put together and have been enjoying so far: https://github.com/carrot/share-button

Glad you enjoyed the article! Let us know if you run into any trouble, happy to help or add debugging techniques etc

I can't read the article on my Android phone because I can't resize it to fit on screen. So please remove the theme or fix it...

Oh man, I'm sorry! I totally dropped the ball on mobile - I'm going to push a responsive design right now. Sorry Justin!

EDIT: Updated, should work great on mobile devices now

Much better!

Avoid using Digital Ocean(DO).

We had very very bad experience with them, file-system corruption, hardware failures.

And we are still unable to recover all our data. And so far, no hope!

They don't answer any of the questions properly, my team is very upset. We felt, they don't have much technical expertise in managing servers.

DO might be okay for testing and learning, but never use them for any production setups.

Update: we are still struggling to get our data back. No hopes so far.

We shall write a detailed blog post on the whole experience with Digital Ocean.

My experience is the complete opposite. They've responded fast and helped when I needed them. They're cheap and fast enough.

I'm not too worried about data losses tho, we do regular offsite backups.

On the contrary, if you just need a box to tinker with sysops stuff and learn, digital ocean is a fantastic solution. Cheap and I've never had a bad experience or anything unreliable.

I can't speak to using it to store lots of not-backed-up files or running a gigantic production server, but for learning about syops it works great, to get back to the purpose of this article.

That's kind of where I'm at right now. Normally all of my side projects are hosted on PAAS (Appfog is my current choice, but we will see since their acquisition).

I really just want to practice setting up and tearing down configurations. I think DO will be a good choice for this.

Was in that exact same spot a couple months ago and did the same thing. I was eyeing DO for a while and one day folded and paid the (really no brainer) $5. I've learned a ton since then and it has been absolutely worth it for me.

I actually transitioned all my apps off any other PAAS platforms (mostly nodejitsu, timed nicely with their 3x price increase) and am now hosting everything I run off a single $5 digital ocean box, which actually is saving me a bit of money, and deploys are a lot smoother. The company I work at, Carrot, is also hosting all of carrot.is on a $5 DO box, including this article, which has had no issues coping with the 600+ people on site at a time that have come with this HN blitz.

Wow that sounds like it was quite an issue. Where are you thinking about migrating to? IMO, I can't really trust Linode anymore. MediaTemple is stupid expensive for VPS... Maybe SoftLayer? I've heard mixed reviews.

We are moving to SoftLayer or Hetzner.

They do more granular level monitoring to detect faulty hardware early and replace them faster.

Also greater technical support, having used both of them previously.

My experience is that every host has it's pros and cons. I never trust these types of statements.

Just because you didn't perform backups, it doesn't mean that you should blame the host.

Even the best-of-the-best hosts will fail, but thing to consider is how fast can they resolve issues and are they proactively trying to improve.

It's kinda depressing that this article is basically just a copy of one I wrote in 2010 and it's still something that gets attention as interesting stuff. Nginx documentation obviously still has a long way to go.

I've actually had your article bookmarked for some time. I got it from the nginx wiki page at http://wiki.nginx.org/Configuration.

I was more surprised than depressed about the upvotes for the current article. It really makes me wonder if the technical level of the audience here hasn't declined substantially. The current article is well written but it's aimed at a "Dummies" rather than developer level.

yeah, you got to checkout the number of twitter bootstrap tutorials.

Hey mfjordvald,

We were not aware of your article at all, and if it's "basically a copy" it was entirely coincidental. I think the way you're looking at is very negative though -- any and all efforts to improve understanding of a great and powerful dev tool I think are a positive thing for the community.

I'd love to see your article too, could you link to it?

It's not your article that's depressing, it's the fact that nginx documentation hasn't come further than this over the years. Obviously there's still a need for even basic nginx information and there's absolutely no blame from me for filling that need. If anything I should blame myself for not marketing my own stuff more. :)

The article I mentioned can be found here: http://blog.martinfjordvald.com/2010/07/nginx-primer/

I instantly thought of your article when I saw this one. I also defended NginX's documentation and linked to the actual documentation, which I think most people forget exists over at http://nginx.org/en/docs/.

The official nginx documentation is better but it's still mostly just an API documentation, there's no red thread through it to tell people "read this first, then this and then jump over here".

Since this kind of article still gathers this amount of popularity 3 years later I actually do think it's a problem of the documentation.

I've always wanted to use nginx to build web apps in Lua .. does anyone know/can recommend any great tutorials with this in mind? It'd be nice if I could learn how to use nginx+lua to build a blog, and so on .. I'll use google, but on the off chance someone on HN knows of something already, I'm all ears ..

You might be interested to know that NginX can even embed Lua internally as a scripting language in the configuration[1].

As for your goals of connecting NginX to serve your Lua project, well that's quite simple really. Unlike Apache or Lighttpd, NginX is not an application server. NginX is only a reverse proxying HTTP server that speaks HTTP, FastCGI, and UWSGI. To connect your Lua application to NginX, your Lua application will either need to speak HTTP, FastCGI, or UWSGI. I don't know anything about Lua so I can't really help you figure out which is best, but in terms of setting up with NginX, it mostly just changes which flavor of pass you will use.

[1]- http://wiki.nginx.org/HttpLuaModule

Thanks for the reply - I am definitely learning a lot from this feedback, and appreciate the effort.

Check out Lapis - http://leafo.net/lapis/ and OpenResty which is what lapis is built upon http://openresty.org/

Looks like I'll be studying Lapis for the next few days - great stuff, thanks for the recommendation!

There is an intro talk and slides from London Lua here http://www.londonlua.org/scripting_nginx_with_lua/index.html

It is pretty easy once you get started...

Great - that looks like exactly what I need to get myself educated on the subject - really appreciate the great response, thank you!

This article is just fine for IDE-side development, but I would not recommend for anyone to use the version of nginx in the standard Ubuntu package manager. It traditionally is several version back missing important key features that you might want to take advantage of.

Generally, it's installed using apt, but from a source maintained by nginx. It's just a quick modification of sources.list.


Slightly off-topic, but I'm sad that people still use apt-get. aptitude is pretty much just better[1].

Also, if you're reading this article you probably don't need the slightly better performance/throughput of nginx. Nginx's configuration is just terrible. You can cause segfaults and all sorts of unexpected behavior with the If directive[2]. And who came up with the idea that rewrite[3] should sometimes redirect instead of rewriting?

If the replacement string begins with http:// then the client will be redirected, and any further rewrite directives are terminated.

Apache's configuration might be ugly and unwieldy and the community might be horribly infested, but at least the configuration makes sense. Lighttpd has none of the above problems, though.

[1] http://superuser.com/questions/93437/

[2] http://wiki.nginx.org/IfIsEvil

[3] http://wiki.nginx.org/HttpRewriteModule#rewrite

I'm extremely biased as I have been using NginX for many years now; however, I've got to completely disagree with you.

NginX's configuration is beautiful, elegant, and concise. It kicks the ever living crap out of configuring Apache or Lighttpd (the two other HTTPd's I have extensive experience with). It seems so strange, because it's different.

NginX's configuration language is declarative. If is imperative and actually using if inside locations in NginX creates an inner location and executes a mini language to process.

    14:42 <+merlincorey> !ifisevil
    14:42 < ngxbot> please see above
Please see http://wiki.nginx.org/IfIsEvil for more about that in particular.

Finally, I have to disagree with OP... NginX has great documentation, written by Igor himself initially (and edited by the community) available here: http://nginx.org/en/docs/

Yes, I linked to IfIsEvil. The fact that you need a page to document the horrible behavior because it's too late to fix it is a sign that something is very wrong with the config syntax.

The fact that you think it is a problem with the configuration syntax is an indication that you didn't read the wiki page, or the important part of my comment.

NginX's configuration is declarative.

The reason the imperative if was given powers beyond its means was because people clamored for the feature.

The reason it's still there is because removing it would break some working configurations that use if.

If you don't have experience with declarative programming and you think in terms of imperative programming, it might seem "horrible behavior", but actually, it's what is to be expected from mixing the two paradigms in the way it is being mixed.

The real wart is under the hood where-in location based if's are converted to sub-locations. This is where many problems related to IfIsEvil stem from.

I'm rather annoyed that you're not reading anything I've said.

No, the problem is not that I haven't read the page. I have. It can cause segfaults. Your configuration can cause segfaults. Your configuration can cause segfaults. Your configuration can cause segfaults.

And yes, I acknowledged that they can't remove it because it's too late, using those exact words. That doesn't mean it's not a problem. It means you should jump ship to something saner, like lighttpd, which also doesn't have the rewrite-sometimes-redirects problem.

> Your configuration can cause segfaults.

MY configuration never causes segfaults, because I understand the declarative nature of the configuration language, and I don't mistakenly attempt to shoehorn imperative constructs into it.

By your logic, software should not be written in C/C++, because it can cause segfaults!

> It means you should jump ship to something saner, like lighttpd,

Ah, you're a lighttpd guy. I'll stick with not having the http server also be an application server, and we'll agree to disagree.

Have a nice day.

I was using "your" in the third-person, a quirk of the English language that is too late to fix.

Configuration should not be able to cause your software to segfault. Configuration shouldn't be software. And, in case it's not clear, configuration should not be written in C/C++.

Aptitude is awesome and it's in my fingers, but it's slightly different from apt-get... which may turn into a problem if you do stuff with something like puppet, which uses apt-get.

I think I also had to install aptitude on this box (ub 12.04) as it only came with apt-get installed - apt-get is more universal.

Edit: Hrm. 'aptitude' is not the tool of choice for dist-upgrading Debian. I was fresh-installing my debian laptop last year from testing to sid and it was failing to work properly. Hunting down the issue online, it turns out that for dist-upgrades, you just use apt-get. One of those domain-knowledge gotchas :/ Used apt-get, and it went flawlessly.

Well Ubuntu doesn't ship aptitude by default any more which would explain parts of it.

Guys, don't link to the community wiki, it contains a lot of obsolete or just wrong information. Always use official documentation: http://nginx.org/en/docs/

I like this article because it reaffirms the demand for competent devops who've taken an afternoon to read all of http://wiki.nginx.org/DirectiveIndex.

Just a note on readability. You have a font color of #555 against #fff; Its a light grey against white background and very hard to read.

Very nice article useful for Nginx newbies. While we are on that subject, can anyone please let me know if we can use Nginx for page cache busting purposes.

It is easy to configure Nginx to check if the cached version of the requested URL exists and serve it. But i would like to know if the configuration can be extended bit further to serve the cached file only if is less than a few days old?

This is fantastic, thank you! The way it's written is great because it doesn't treat me like an idiot (I get why books do that, but it can grow tiresome). I wish more tech books were written like this.

While we're picking nits, I thought this might be worth mentioning:

> The default port for the internet is 80

I'd change that to:

> The default port for the web is 80

Again, wonderful guide!

If you liked this, consider checking out Mastering Nginx by Dimitri Aivaliotis. I was quite surprised how helpful this book was.


Nice introductory article. Maybe it should have included a word about SSL support, especially the fact that you need to build nginx with ssl support, it doesn't come out of the box, so make sure you plan for when you'll need it

If you are interested in running NGINX on Heroku, checkout my buildpack: https://github.com/ryandotsmith/nginx-buildpack

Been thinking about nginx for some time. If I could get an easy Mono/F# implementation working with it, I'd jump on it in a heartbeat.

If it can talk to a socket, nginx can talk to it. Is there something I'm missing?

try this:


it worked perfectly for me on digitalocean

I haven't tried it myself but the mono guys have an article on getting nginx up and running with fastcgi-mono-server2


In the example given "listen 80;" is completely unnecessary since it's a default.

If you had read carefully, you would notice that it said that right under ; )

" nginx (pronounced engine-x). "

I have literally never heard anyone call it that.

Well, me, I had never talked or heard anyone talk in "real"-life about nginx before up until one month ago and apparently, it's pronounced that way.

Look here: http://wiki.nginx.org/Pronunciation

I have literally never heard it called anything else, even before it started getting traction. I'm curious how you've heard it said before?

How on earth else would you pronounce it? Now, lighttpd, on the other hand ...

I've always pronounced it "en gee eye en ecks".

Not the most elegant, but it rolls of the tongue relatively well and nobody who was familiar with nginx has ever been confused.

What makes this "for developers"? Whats the difference if a sysadmin is reading this, or a Linux user?

Im surprised to see this on the frontpage, it is less than basics in anything any hacker worth its name can do.

In my view, you answered your own question with the second sentence. Sysadmins and linux hackers are no doubt familiar with this stuff anyway and used to reading through sysops-style docs and wikis.

Many other developers, we assumed, would not be as familiar with ops at first, and would prefer more of a basic introduction that walks through the steps and explains things clearly.

You're correct, the audience is really just a matter of semantics. The reason we wrote this post, knowing that this is very basic stuff, is that we found that a lot of the tutorials we'd come across didn't cover the introductory process end-to-end.

You're just as surprised as we are to see it on the frontpage!

I think it should read "Web Developers" - those who may be less experienced in setting up a web server like nginx.

Why would a Web Developer be less experienced in setting up a Web server than a Developer? - a touchy Web Developer :)

Guidelines | FAQ | Support | API | Security | Lists | Bookmarklet | Legal | Apply to YC | Contact