10 Step Guide: Varnish + Nginx + PHP On Ubuntu With SSL

adam_crampton

Adam Crampton

Posted on February 15, 2021

10 Step Guide: Varnish + Nginx + PHP On Ubuntu With SSL

Setting up Varnish with SSL can be tricky, largely because there isn't any one place to get all the information you need in a straightforward manner.

Having gone through the frustration of piecing it all together myself, I decided to write a quick guide that details the process from start to finish.

Initially, I attempted the SSL portion of the job by using Hitch - which ended up being a complete waste of time (mostly because of really poor documentation). HAProxy on the other hand ended up being a great solution, as well as having other really great features like load balancing included.

Let's get straight to it. Here's the stack I'm working through in this article:

  • Ubuntu 18.04
  • PHP 7.4
  • Nginx
  • Varnish 5.2.1
  • Letsencrypt SSL
  • HAProxy
  • Laravel 8

You can ignore the PHP and Laravel bits if you're using a different stack.

0. Getting Started

You will need:

  • Ubuntu 18.04 installation + sudo SSH access
  • DNS configured for the server block you are going to add to Nginx (it'll be example.com in this article)

1. Set Up Nginx

Install nginx using:

  • sudo apt update
  • sudo apt install nginx

Set the default ports:

  • sudo vim /etc/nginx/sites-available/default
server {
  listen 8080 default_server;
  listen [::]:8080 default_server;
  ...
}
Enter fullscreen mode Exit fullscreen mode

Note: Don't create the server block for your site just yet, we'll get to that shortly.

2. Install PHP 7.4 + Required Extensions

If PHP isn't already installed, run the following commands to get PHP 7.4 along with extensions required for a Laravel (and most modern PHP apps) project:

  • sudo apt install software-properties-common
  • sudo add-apt-repository ppa:ondrej/php
  • sudo apt update
  • sudo apt install php7.4 php7.4-cli php7.4-fpm php7.4-json php7.4-common php7.4-mysql php7.4-zip php7.4-gd php7.4-mbstring php7.4-curl php7.4-xml php7.4-pear php7.4-bcmath

3. Install FPM + Composer

Install FPM and Composer if you require it:

  • sudo apt install php7.4-fpm
  • sudo apt install composer

4. Create Nginx server block

Now we can create the Nginx server block for our site:

  • sudo vim /etc/nginx/sites-available/example.com
  • Paste this in (or use your preferred boilerplate):
server {
    listen 8080;
    server_name example.com www.example.com;
    root /var/www/example.com/public;

    add_header X-Frame-Options "SAMEORIGIN";
    add_header X-XSS-Protection "1; mode=block";
    add_header X-Content-Type-Options "nosniff";

    index index.html index.htm index.php;

    charset utf-8;

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    location = /favicon.ico { access_log off; log_not_found off; }
    location = /robots.txt  { access_log off; log_not_found off; }

    error_page 404 /index.php;

    location ~ \.php$ {
        fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
        include fastcgi_params;
    }

    location ~ /\.(?!well-known).* {
        deny all;
    }
}
Enter fullscreen mode Exit fullscreen mode
  • Save the file, then create the symlink by running:

sudo ls -n /etc/nginx/sites-available/example.com /etc/nginx/sites-enabled/

  • Restart Nginx: sudo service nginx restart

5. Install Cerbot

Certbot needs to be installed to request a Let's Encrypt certificate for our site. Ensure your DNS records are pointing to this server and run the following:

  • sudo add-apt-repository ppa:certbot/certbot
  • sudo apt install python-certbot-nginx
  • sudo certbot --nginx -d example.com -d www.example.com
  • Select No Redirect option
  • Edit /etc/nginx/sites-available/example.com and remove SSL lines added by Certbot at the bottom of the file - it will look something like this:
listen 443 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
Enter fullscreen mode Exit fullscreen mode

6. Prepare PEM File

Next we will need to create a PEM file for our SSL proxy to use further down the track. To do so, we'll append the private key and fullchain key values to a single file:

Switch to root (sudo su), then:

sudo cat /etc/letsencrypt/live/example.com/privkey.pem /etc/letsencrypt/live/example.com/fullchain.pem > /etc/ssl/private/exampledotcom.pem
exit
Enter fullscreen mode Exit fullscreen mode

7. Install + Configure Varnish

Varnish can now be installed and configured:

  • sudo apt -y install varnish
  • Edit /lib/systemd/system/varnish.service and change the default port from 6081 to 80:
ExecStart=/usr/sbin/varnishd -j unix,user=vcache -F -a :80 -T localhost:6082 -f /etc/varnish/default.vcl -S /etc/varnish/secret -s malloc,256m
Enter fullscreen mode Exit fullscreen mode
  • Edit /etc/varnish/default.vcl and ensure the backend default port is set to 8080
  • Run sudo systemctl daemon-reload && sudo service varnish restart

Varnish should now be working for your site for HTTP.

8. Install + Configure HAProxy

  • Install HAProxy: sudo apt-get install haproxy
  • Open for editing: sudo vim /etc/haproxy/haproxy.cfg
  • Add a front end binding, pointing towards PEM file created earlier:
frontend haproxynode
        bind *:443 ssl crt /etc/ssl/private/exampledotcom.pem
        mode http
        default_backend backendnodes
Enter fullscreen mode Exit fullscreen mode
  • Add back end config + node:
backend backendnodes
        balance roundrobin
        option forwardfor
        http-request set-header X-Forwarded-Port %[dst_port]
        http-request add-header X-Forwarded-Proto https if { ssl_fc }
        server example.com 172.1.35.35:80 check
Enter fullscreen mode Exit fullscreen mode

Important: IP address above must be that of the server this host sits on. use ifconfig to determine that address.

To test the config for errors, run sudo haproxy -c -f /etc/haproxy/haproxy.cfg:

9. Restart Everything

  • sudo service nginx restart && sudo service varnish restart && sudo service haproxy restart

10. Trust Proxy Config (Laravel only)

  • Add the server IP from step 8 to the $proxies property in App\Http\Middleware\TrustProxies:
protected $proxies = ['172.1.35.35'];
Enter fullscreen mode Exit fullscreen mode

Note: If you are behind a load balancer where you cannot reliably determine the IP, you can do this:

protected $proxies = '*';
Enter fullscreen mode Exit fullscreen mode

Useful Links

Thanks!

Hopefully this guide was helpful for you, thanks for taking a look.

If there are any corrections to the above, please leave a comment and I will update the article.

💖 💪 🙅 🚩
adam_crampton
Adam Crampton

Posted on February 15, 2021

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related