The well known, good’ol LAMP stack has slowly made place for a LEMP stack in many of my configurations. Enough articles have been written on why Apache or Nginx are better in certain situations, but I like the clean way of configuration that Nginx uses. (pronounced Engine X, hence the E in LEMP). So I generally use Nginx. I however never made an article about it, so here it is, long overdue.


Install Nginx

There are generally three options to install Nginx. First option is to use packages from the vendor, this however leaves you with a older version of Nginx. In the base repository’s of Centos 7, Nginx is not included. So you need to install epel-release if you wish to go that route, at the time of writing, the available package is 1.10.2.This is the fastest option and large chance it will be updated more frequently then when you manually download and compile it. However if you wan’t the newest features this is the better option. A third option is to use external repository’s. All methods will result in a working setup.

1) Install Nginx using epel

(recommended method)

yum install epel-release
yum install nginx
2) Install Nginx from binary packages

Add /etc/yum.repos.d/nginx.repo

[nginx]
name=nginx repo
baseurl=http://nginx.org/packages/mainline/centos/$releasever/$basearch/
gpgcheck=0
enabled=1

Then run yum install nginx

note this installs the mainline.

3) Install Nginx straight from source

Notice that there is a difference between mainline and stable version

cd /opt
mkdir nginx
cd nginx

# check the latest version on : http://nginx.org/en/download.html
wget http://nginx.org/download/nginx-1.11.10.tar.gz

# untar
tar xzvf nginx-1.11.10.tar.gz

# install dependencies
yum install gcc pcre-devel zlib-devel openssl-devel

# configure
./configure --with-http_ssl_module

# make and make install
make
make install
4) Install Nginx from external repo

You could use webtatic to install nginx; This is similar to how I am going to install php-fpm :

rpm -Uvh https://mirror.webtatic.com/yum/el7/webtatic-release.rpm
yum install nginx1w

for more detailed instructions, and dynamic modules, see there blogpost.

Install PHP

Installing PHP (lemP) is done using the php-fpm package (PHP FastCGI Process Manager) now sadly in the epel-release the version is super outdated at this writing : PHP 5.4. This version is no longer supported, on top of that, its pretty clear that PHP 7+ is faster and less resource hungry. Whatever version you chose, either should work. I use webtatic as repository and have found no issue’s so far. For PHP 7.1 : (on Centos 7)

rpm -Uvh https://mirror.webtatic.com/yum/el7/webtatic-release.rpm

After that you are ready to install PHP :

yum install php71w-fpm php71w-opcache php71w-mysql php71w-mcrypt php71w-gd
Configure php-fpm

After the installation its time to finetune our setup a bit. Let’s start with php-fpm , we need to change /etc/php-fpm.d/www.conf

Change both the user and the group to nginx.

; Start a new pool named 'www'.
[www]

; Unix user/group of processes
; Note: The user is mandatory. If the group is not set, the default user$
;       will be used.
; RPM: apache Choosed to be able to access some dir as httpd
user = nginx
; RPM: Keep a group allowed to write in log dir.
group = nginx


[...]

note : it’s possible to let Nginx use a socket instead of loopback device. This is a bit faster, but I found that the headache is not really worth it.

Configure Nginx

Depending on the installation there is already a default server configuration. I tend to remove it and replace it with an empty file and create a file [name].conf in /etc/nginx/conf.d/

http server
server {
    
    # listen to port 80 
    listen 80;

    # server name or names
    server_name svennd.be;

    # the location of webroot
    # I always use /var/www/html/*
    # Nginx by default uses another structure
    # but this made the transition from Apache allot easier!
    root  /var/www/html/svennd.be;

    # in root location
    location / {
        # look for index.php/index.html/index.htm as "index file"
        index  index.php index.html index.htm;
        
        # this is specifically for wordpress
        # makes it possible to have url rewrites
        try_files $uri $uri/ /index.php?$args;
    }

    # default error pages
    # note that wp already catches most
    error_page 404 /404.html;
    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;
    }

    # here we have to let nginx know what to do with these php files
    # as html files are just send directly to the client
    location ~ \.php$ {

        # if the file is not there show a error : mynonexistingpage.php -> 404
        try_files $uri =404;
        
        # pass to the php-fpm server
        fastcgi_pass 127.0.0.1:9000;

        # also for fastcgi try index.php
        fastcgi_index index.php;

        # some tweaking
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param SCRIPT_NAME $fastcgi_script_name;
        fastcgi_buffer_size 128k;
        fastcgi_buffers 256 16k;
        fastcgi_busy_buffers_size 256k;
        fastcgi_temp_file_write_size 256k;

        include fastcgi_params;
    }
}

Note that fastcgi_params are installed by php-fpm. In case its missing use the link.

https server

Be sure to check cipherli.st for the latest updates.

server {
  listen       443 ssl;
  server_name  svennd.be;
  root  /var/www/html/svennd.be;

  ssl_certificate /opt/letsencrypt/certs/svennd.be/fullchain.pem;
  ssl_certificate_key /opt/letsencrypt/certs/svennd.be/privkey.pem;
  # verify chain of trust of OCSP response using Root CA and Intermediate certs
  ssl_trusted_certificate /opt/letsencrypt/certs/svennd.be/chain.pem;

  ssl_session_timeout 1d;
  ssl_session_cache shared:SSL:50m;
  ssl_session_tickets off;

  # Diffie-Hellman parameter for DHE ciphersuites, recommended 2048 bits
  ssl_dhparam /opt/letsencrypt/certs/dhparam.pem;

  # needs more info
  ssl_ecdh_curve secp384r1; # Requires nginx >= 1.1.0

  # suggested conf (interwebz)
  ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
  ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:ECDHE-RSA-AES128-GCM-SHA256:AES256+EECDH:DHE-RSA-AES128-GCM-SHA256:AES256+EDH:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4";
  ssl_prefer_server_ciphers on;

  # OCSP Stapling ---
  # fetch OCSP records from URL in ssl_certificate and cache them
  ssl_stapling on;
  ssl_stapling_verify on;

  # need to lookup options
  resolver 8.8.8.8 valid=300s;
  resolver_timeout 5s;

  # headers
  # note HSTS might break your website if initial setup !
  # add_header Strict-Transport-Security "max-age=15768000; includeSubDomains; preload";
  # add_header X-Frame-Options DENY;
  add_header X-Content-Type-Options nosniff;
  add_header X-XSS-Protection "1; mode=block";

  # hide version
  server_tokens off;

    location / {
        index  index.php index.html index.htm;
        try_files $uri $uri/ /index.php?$args;
    }

    error_page 404 /404.html;
    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;
    }

    location ~ \.php$ {
        try_files $uri =404;
        fastcgi_pass unix:/var/run/php-fpm/php-fpm.sock;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param SCRIPT_NAME $fastcgi_script_name;
        fastcgi_buffer_size 128k;
        fastcgi_buffers 256 16k;
        fastcgi_busy_buffers_size 256k;
        fastcgi_temp_file_write_size 256k;

        include fastcgi_params;
    }
}
Install MariaDB

There are two options to install MariaDB, either from the Centos/RHEL repo’s or a newer version from MariaDB‘s repo helper. For simplicity I use the Centos, MariaDB 5.5.52 version. But you can get the 10.1/10.2 if you like.

Install from base repository :

yum install mariadb-server

Start the mariadb-server prior to configuration :

systemctl enable mariadb
systemctl start mariadb

configure mariadb :

mysql_secure_installation
Start the server

After that you are ready to run the server :

systemctl start php-fpm
systemctl enable php-fpm

systemctl start nginx
systemctl enable nginx

And that’s how I generally set up Nginx and php-fpm.