Categories
DevOps

Learning NGINX

Install NGINX

sudo su -
apt update
apt upgrade
apt install nginx
nginx -v

Confirm NGINX is working by navigation to localhost

NGINX Files and Directories

  • /etc/nginx (Configurations)
  • var/log/nginx (Access and error logs)
  • var/www/html (Default directory)

Commonly Used Commands

systemctl status nginx # check status
systemctl start nginx # start server
systemctl stop nginx # stop server
systemctl is-active nginx
systemctl reload nginx
nginx -h # help
nginx -t # test config without reboot
nginx -T # test config and cat file on screen

Main configuration file of nginx is located in /etc/nginx/nginx.conf (review this) but we will keep our configuration in /etc/nginx/conf.d

Unlink default unlink /etc/nginx/sites-enabled/default

Configuring Virtual Host

Add file in /etc/nginx/sites-enabled with the convention of site-name.conf.

Define server directive

server {
  listen 80;
  root /var/html/[folder_name]
}

nginx -t for test and then systemctl reload nginx. Check status via systemctl status nginx and navigate to localhost to confirm the change.

Defines define server and set virtual host i.e. http://site-name.local

server {
  listen 80 default_server; # set this as default because nginx can host multiple sites
  root /var/www/[site_name]; # folder
  server_name [site_name].local www.[site_name].local; # virtual host name
  index index.html;
}

Configure Location

Use the location directive to extend our configuration based on URI

server {
  location [modifier] location_definition {
    location [modifier] location_definition { # can be nested }
  }
}

Examples

server {
  location / {
    try_files $uri $uri/ =404;
  }

  location /images/ {
    # show content of images folder
    autoindex on;
  }
}

Error Page Directives

error_page 404 /404.html;
location = /404.html {
    internal;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
    internal;
}
location = /500 {
    fastcgi_pass unix:/this/will/fail;
}

Configuring LEMP Stack

Install php-fpm and mysql on our machine.

apt install php-fpm mysql-server
mysql_secure_installation # for easy security setup
php --version
mysql --version

Configure PHP

Add nginx configuration for php files.

location ~ \.php$ {
    include snippets/fastcgi-php.conf;
    fastcgi_pass unix:/var/run/php/php7.2-fpm.sock;
    fastcgi_intercept_errors on;
}

Create php file on your site root and test it by accessing it from browser. For test purposes you can use following code.

<?php
  phpinfo(); // Show all information, defaults to INFO_ALL
  phpinfo(INFO_MODULES); // Show just the module information.
?>

Configure MySQL

Create user, grant privileges and confirm the new user.

CREATE USER 'newuser'@'localhost' IDENTIFIED BY 'password';
CREATE DATABASE database-name;
GRANT ALL PRIVILEGES ON database-name.* TO "newuser"@"hostname";
FLUSH PRIVILEGES;
mysql -u newuser -p

NGINX Security

We can allow and deny certain urls from nginx configurations.

location /secure_directive_url/ {
  # only allow IPs from the same network the server is on
  allow 192.168.0.0/24;
  allow 10.0.0.0/8;
  deny all;
}

Create 403 page and and path that is always denied for testing purposes.

location /deny {
    deny all;
}

error_page 403 /403.html;
location = /403.html {
    internal;
}

Configure Password Authentication

Install http basic auth module, test installation and setup authentication.

apt install apache2-utils -y
htpasswd

htpasswd -c /etc/nginx/passwords username # create encrypted password file with user and their passwords

chown www-data /etc/nginx/passwords # add nginx user as owner for security
chmod 600 /etc/nginx/passwords # change permissions

Now configure nginx to use this password for our secure_directive_url directory.

location /secure_directive_url/ {
  auth_basic 'Authentication is required...';
  auth_basic_user_file /etc/nginx/passwords;

  # This will get prioritized
  location ~ \.php$ {
    include snippets/fastcgi-php.conf;
    fastcgi_pass unix:/var/run/php/php7.2-fpm.sock;
    fastcgi_intercept_errors on;
  }

  # only allow IPs from the same network the server is on
  # allow 192.168.0.0/24;
  # allow 10.0.0.0/8;
  # deny all;
}

Configure HTTPS

Create a SSL Certificate

Check openssl and install if necessary

which openssl
apt install openssl -y

There are several methods but we will use the simplest one which create a key and certificate in one command.

openssl req -x509 -nodes -newkey rsa:2048 -keyout /etc/ssl/private/nginx.key -out /etc/ssl/certs/nginx.csr -batch

Certificates should be public and private keys should be private.

Install an SSL Certificate on NGINX

Open configuration file and make following changes.

Force all traffic to https

server {
  listen 80 default_server;
  return 301 https://$server_addr$request_uri;
}

Configure traffic coming from https

server{
  listen 443 ssl default_server;
  ssl_certificate [path_to_certificate];
  ssl_certificate_key [path_to_private_key];
}

If you are using Amazon Certificate Manager for ssl and Amazon ELB for forwarding requests to your web server then all of those requests will be forwarded by just port 80 so in this case nginx configs will be updated as following:

server {
  listen 80 default_server;

  # ELB stores the protocol used between the client
  # and the load balancer in the X-Forwarded-Proto request header.
  # Check for 'https' and redirect if not
  if ($http_x_forwarded_proto != 'https')
  {
    return 301 https://$host$request_uri;
  }
}