Skip to content

Instantly share code, notes, and snippets.

@boaf
Last active October 20, 2016 21:13
Show Gist options
  • Save boaf/87a65df7adbe07f12d35dac699598123 to your computer and use it in GitHub Desktop.
Save boaf/87a65df7adbe07f12d35dac699598123 to your computer and use it in GitHub Desktop.
Setting up Ubuntu 16.04 — Nginx, MariaDB, PHP-FPM

Setting up Ubuntu 16.04 — Nginx, MariaDB, PHP-FPM

1. Update

sudo apt-get update

2. Install Nginx

sudo apt-get install nginx
systemctl status nginx

3. Install MariaDB

Note: This might say "software-properties-common is already the newest version"

sudo apt-get install software-properties-common

3a. Get repository information

For example: https://downloads.mariadb.org/mariadb/repositories/#mirror=digitalocean-sfo&distro=Ubuntu&distro_release=xenial--ubuntu_xenial&version=10.1

sudo apt-key adv --recv-keys --keyserver hkp://keyserver.ubuntu.com:80 0xF1656F24C74CD1D8
sudo add-apt-repository 'deb [arch=amd64,i386,ppc64el] http://sfo1.mirrors.digitalocean.com/mariadb/repo/10.1/ubuntu xenial main'

3b. Install

apt-get install will ask for root password to be set

sudo apt-get update
sudo apt-get install mariadb-server

4. Configure MariaDB

First, make sure MariaDB is not running. Then, configure MariaDB:

sudo systemctl stop mysql
sudo mysql_install_db
sudo systemctl start mysql
sudo mysql_secure_installation

Finally, make sure it's running:

mysql -v
mysql -uroot -p

5. Install PHP

sudo apt-get install php-fpm php-mysql

6. Configure Nginx

sudo vi /etc/nginx/sites-available/default
server {
    listen 80 default_server;
    listen [::]:80 default_server;
    
    server_name example.com
    
    root /var/www/html;
    index index.php index.html;
    
    include snippets/restrictions.conf;
    
    location / {
        try_files $uri $uri/ =404;
    }
    
    include snippets/fastcgi-php.conf;
}
sudo vi /etc/nginx/snippets/restrictions.conf
location = /favicon.ico {
    log_not_found off;
    access_log off;
}

location = /robots.txt {
    allow all;
    log_not_found off;
    access_log off;
}

location ~ /\. {
    deny all;
}

location ~* /(?:uploads|files)/.*\.php$ {
    deny all;
}
sudo vi /etc/nginx/snippets/fastcgi-php.conf
location ~ \.php$ {
    fastcgi_split_path_info ^(.+?\.php)(/.*)$;

    if (!-f $document_root$fastcgi_script_name) {
         return 404;
    }

    include fastcgi.conf;
    fastcgi_index index.php;

    fastcgi_pass unix:/run/php/php7.0-fpm.sock;
}

Test for errors, then reload config:

sudo nginx -t
sudo systemctl reload nginx

Bonus: Let's Encrypt

1. Install letsencrypt

sudo apt-get install letsencrypt

2. Obtain certificate

2a. Make sure Nginx serves .well-known properly

sudo vi /etc/nginx/sites-available/default
server {
    # ...
    index index.php;
    
    location ~ /\.well-known {
        allow all;
    }
    
    include snippets/restrictions.conf;
    # ...
}

2b. Get the certificate

sudo letsencrypt certonly --webroot -w /var/www/html -d example.com

3. Add DH SSL group

sudo openssl dhparam -out /etc/ssl/certs/dhparam.pem 2048

4. Create Nginx conf files for SSL

4a. One for loading SSL certs specific to our site

sudo vi /etc/nginx/snippets/ssl-example.com.conf
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

4b. ... and one for loading generic SSL parameters

sudo vi /etc/nginx/snippets/ssl-params.conf
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH";
ssl_ecdh_curve secp384r1;
ssl_session_cache shared:SSL:10m;
ssl_session_tickets off;
ssl_stapling on;
ssl_stapling_verify on;

resolver 8.8.8.8 8.8.4.4 valid=300s;
resolver_timeout 5s;

# Disable preloading HSTS for now.  You can use the commented out header line that includes
# the "preload" directive if you understand the implications.
#add_header Strict-Transport-Security "max-age=63072000; includeSubdomains; preload";
add_header Strict-Transport-Security "max-age=63072000; includeSubdomains";
add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;

ssl_dhparam /etc/ssl/certs/dhparam.pem;

5. Configure Nginx

sudo vi /etc/nginx/sites-available/default
server {
    listen 80 default_server;
    listen [::]:80 default_server;

    server_name example.com;

    return 301 https://$server_name$request_uri;
}

server {
    listen 443 ssl default_server;
    listen [::]:443 ssl default_server;
    
    server_name example.com;
    
    include snippets/ssl-example.com.conf;
    include snippets/ssl-params.conf;
    
    # ...
}

5a. (optional alternative) Allow both HTTP and HTTPs traffic

sudo vi /etc/nginx/sites-available/default
server {
    listen 80 default_server;
    listen [::]:80 default_server;

    listen 443 ssl http2 default_server;
    listen [::]:443 ssl http2 default_server;
    
    server_name example.com;
    
    include snippets/ssl-example.com.conf;
    include snippets/ssl-params.conf;
    
    # ...
}

Test config and reload Nginx:

sudo nginx -t
sudo systemctl reload nginx

6. (optional, but recommended) Set up letsencrypt auto-renewal

Renewing manually is easy:

sudo letsencrypt renew

But let's make this automatic:

sudo crontab -e

We're adding two cron jobs. The first attempts to renew letsencrypt certs every Monday at 2:30am, followed by a reload of nginx at 2:35am.

30 2 * * 1 /usr/bin/letsencrypt renew >> /var/log/letsencrypt-renew.log
35 2 * * 1 /bin/systemctl reload nginx

Bonus: WordPress

1. Configure Nginx for WordPress

sudo vi /etc/nginx/snippets/wordpress.conf
location / {
    try_files $uri $uri/ index.php?$args;
}

rewrite /wp-admin$ $scheme::$host$uri/ permanent;

location ~* ^.+\.(ogg|ogv|svg|svgz|eot|otf|woff|mp4|ttf|rss|atom|jpg|jpeg|gif|png|ico|zip|tgz|gz|rar|bz2|doc|xls|exe|ppt|tar|mid|midi|wav|bmp|rtf)$ {
    log_not_found off;
    access_log off;
    expires max;
}
sudo vi /etc/nginx/sites-available/default
server {
    # ...
    # Note: Remove `location / {}` from original setup
    include snippets/restrictions.conf;
    include snippets/wordpress.conf;
    include snippets/fastcgi-php.conf;
}

Test config and reload Nginx:

sudo nginx -t
sudo systemctl reload nginx

2. Create database and user

mysql -uroot -p
create database wordpress;
grant all privileges on wordpress.* to 'wordpress'@'localhost' identified by password('something complicated please!');
flush privileges;

Then, install WordPress from a .zip/.tar.gz as you would normally!

Other Stuff

Prerequisites

sudo apt-get install php7.0-xml zip

Node

curl -sL https://deb.nodesource.com/setup_6.x | sudo -E bash -
sudo apt-get install -y nodejs

Composer

php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
php -r "if (hash_file('SHA384', 'composer-setup.php') === 'e115a8dc7871f15d853148a7fbac7da27d6c0030b848d9b3dc09e2a0388afed865e6a3d6b3c0fad45c48e2b5fc1196ae') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;"
php composer-setup.php
php -r "unlink('composer-setup.php');"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment