Finnian's blog

Software Engineer based in New Zealand

How does my stuff work?

See how I deploy my code to squeeze as much performance out of them as possible using technologies like Nginx, Docker and Node.js.

4-Minute Read

I have a bit of a complex set up with all my sites and services, mainly due to using a multitude of different tools and languages to deploy different things. Currently, I have one main OVH server which most of my stuff is hosted on, including different database engines, Node.js and PHP apps.

Static sites

The first thing that traffic comes into contact with on my server is Nginx. It serves as an ultra lightweight traffic ‘handler’, whereupon it routes the incoming request to the appropriate location. I do this by using different Nginx config files for different domains. Here is an example:

server {
  include /etc/nginx/mime.types;
  listen 80;
  listen [::]:80; # IPV6
  server_name finnian.io;

  # compress everything!
  gzip on;
  gzip_disable "msie6";
  gzip_vary on;
  gzip_proxied any;
  gzip_comp_level 6;
  gzip_buffers 16 8k;
  gzip_http_version 1.1;
  gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript;

  root /var/www/nginx/;
  location ~* /.(?:ico|css|js|gif|jpe?g|png)$ {
    # Some basic caching for static files to be sent to the browser
    expires max;
  }
  location / {
    try_files $uri $uri/ =404;
    index index.html
  }
}

All this does is to set up where to listen (port 80) and for what for (finnian.io in this case). Then it turns on gzip for compression, specifies the document root and enables some cache-control for static assets. Lastly, it tries to find the file which was requested. Pretty simple, eh?

Node

This is all well and good for static sites but to be honest with you, I don’t have very many of those. The real fun starts when I want to run a Node.js app. Essentially, what I do is to route all the traffic through Nginx for cache control and compression reasons (and load balancing, in the future) and then via a reverse proxy to Node. Here is how I do that:

location / {
  proxy_set_header X-Real-IP $remote_addr;
  proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  proxy_set_header Host $http_host;
  proxy_set_header X-NginX-Proxy true;

  proxy_pass http://127.0.0.1:3000; # not always 3000 or we get conflicts
  proxy_redirect off;
 }

This passes all the traffic through to the Node app, without needing to redirect the browser.

PM2

For actually deploying the Node apps, I use PM2. I cannot recommend PM2 enough, it’s ultra easy to use and running your code could not be simpler. It even integrates into the KeyMetrics web UI, giving you a great overview of the health of your apps. It will even restart them if they crash or on server reboot!

PM2 app monitoring with KeyMetrics

PM2 CLI output

PHP

One of the hardest things to get working was PHP, because I needed to run it in tandem with Apache. Yeah, I know I could have run it with Nginx, but I have a rather large codebase for a project and it utilises Apache’s mod_rewrite module. No biggie, I just configured Apache to run on different ports. What this did mean though, was that I had to get Nginx to hand traffic off to Apache for specific domains. This turned out to be a lot easier than I had imagined as I could just use another reverse proxy:

location ~ ^/ {
  proxy_set_header X-Real-IP $remote_addr;
  proxy_set_header X-Forwarded-For $remote_addr;
  proxy_set_header Host $host;
  proxy_pass http://127.0.0.1:8043;
}

SSL

For one of my projects, I use SSL because it handles personal information. I use Let’s Encrypt because it’s really easy to set up and it’s free. I use Nginx to serve all of my SSL certs because Apache was mucking around when I tried to send them with it. No problem, Nginx works just fine:

ssl_certificate /etc/letsencrypt/live/finnian.io/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/finnian.io/privkey.pem;

Of course, I change the listen port in the server block to be 443 and add a redirection server block from :80 -> :443.

server {
  listen 80;
  listen [::]:80;
  server_name finnian.io;
  return 301 https://$server_name$request_uri;
}

That’s pretty much it for my setup! Further down the road, I will probably start using HAProxy or similar for load balancing if it’s needed. I suspect I’ll use Docker with it so as to make it much easier to handle multiple instances of apps.

Let me know what you think, any ideas or suggestions welcome.

Recent Posts