openec2 Article Description

Debian 11 and Nginx – Part 7

Configure Nginx, SSL certificate

Make sure you have your previous SES e-mail bucket lessons covered, particularly the lesson “AWS – SES e-mail bucket – Part 3 – SES Identity, DNS, SSL” and that you already have a paid SSL certificate, or, after configuring Nginx, we add a free Let’s Encrypt certificate.

This lesson has the toggle called “Attend to important SSL and DNS Prerequisites”: https://openec2.com/lesson/aws-ses-e-mail-bucket-part-3-ses-identity-dns-ssl/

First, we will configure Nginx for http:// rather than https://
Replace “mydomain.com” with your own domain name.

cd /etc/nginx
cp -p nginx.conf nginx.conf.bak

vi nginx.conf

user  nginx;
worker_processes  auto;
error_log  /var/log/nginx/error.log notice;
pid        /var/run/nginx.pid;

events {
    worker_connections  1024;
}

http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;
    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';
    access_log  /var/log/nginx/access.log  main;
    sendfile        on;
    tcp_nopush     on;
    keepalive_timeout  65;
    gzip  on;
    # include /etc/nginx/conf.d/*.conf;
    server_names_hash_bucket_size 64;
    add_header Strict-Transport-Security "max-age=31536000; includeSubdomains";
    ssl_session_timeout 10m;
    add_header Content-Security-Policy "default-src 'self' https: data: 'unsafe-inline' 'unsafe-eval';" always;
    add_header X-Xss-Protection "1; mode=block" always;
    add_header X-Frame-Options "SAMEORIGIN" always;
    add_header X-Content-Type-Options "nosniff" always;
    add_header Referrer-Policy "origin-when-cross-origin" always;

    client_max_body_size 50M;
    upstream _php {
    server unix:/run/php/php8.2-fpm.sock;
    }

# include /etc/nginx/memcached.conf;

    server {
        listen       80;
        listen       [::]:80;
        server_name  mydomain.com www.mydomain.com;
#       return 301 https://mydomain.com$request_uri;
        root         /var/www/html;
        index index.php index.html index.htm;
        include /etc/nginx/default.d/*.conf;

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

        location ~ \.php$ {
        # SECURITY : Zero day Exploit Protection
        try_files $uri =404;
        # ENABLE : Enable PHP, listen fpm sock
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass unix:/run/php/php8.2-fpm.sock;
        fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
        include fastcgi_params;
        }

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

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

        error_page 404 /404.html;
        location = /404.html {
        }

        error_page 500 502 503 504 /50x.html;
        location = /50x.html {
        }

# end port 80
}

# end nginx config
}

[save and exit]

We will uncomment and modify the file shortly.

Fix a “racing” error:

When we start nginx, we likely receive an error from the status command: [you have to make your shell terminal screen quite wide to see full error messages displayed]

systemctl status -l nginx
nginx.service: Can't open PID file /run/nginx

[If you get this, our reference for the fix is: https://serverfault.com/questions/1042526/open-run-nginx-pid-failed-13-permission-denied]

mkdir -p /etc/systemd/system/nginx.service.d

[Create these lines:]

vi /etc/systemd/system/nginx.service.d/override.conf

[Service]
ExecStartPost=/bin/sleep 0.1

[save and exit]

systemctl daemon-reload
systemctl restart nginx
systemctl status -l nginx

 

Start nginx:

systemctl stop nginx

nginx -t

[If no errors to correct - if so refer to systemctl status -l nginx, and the /var/log error logs]

systemctl restart nginx

You should be able to check these:

http://mydomain.com and http://mydomain.com/phpinfo.php

Do not log into phpMyAdmin as you are not using https:// as yet.

You can scroll through the phpinfo page and see you are on php8.2.

To check for memcached, search on session.save_path showing the 127 values rather than “file”.

session.save_handler memcached memcached
session.save_path 127.0.0.1:11211 127.0.0.1:11211

Search for max_input_vars, and memory_limit to verify your php.ini edits.

Search for Opcode Caching to verify it is up and running.[/vc_wp_text][mk_padding_divider][vc_wp_text]

Paid SSL Certificate

Let’s say you have your paid SSL certificate, you have edited it to have the full content, as per my previous SES e-mail bucket Part 3 lesson, and that DNS shows the correct CAA record.

You will need to upload the mydomain_com.crt and mydomain_com.key files using FileZilla to /home/admin.
From there, install the certificate:

cd /etc/ssl/certs
cp /home/admin/*crt .
ls
cd ../private
cp /home/admin/*.key .
ls

We now add this to the SSL section of nginx.conf and remove a couple of commented fields.

[Remember to use your own domain and SSL certificate names]

cd /etc/nginx

vi memcached.conf

upstream memcached_backend {
    server 127.0.0.1:11211; # Address and port of your Memcached server
}

[save and exit]

vi nginx.conf

[uncomment the line # include /etc/nginx/memcached.conf;]
[uncomment the line # return 301 https://mydomain.com$request_uri;]

[Before the last curly } bracket, add the port 443 SSL section:]

# port 443

    server {
        listen       443 ssl;
        listen       [::]:443 ssl;
        http2 on;
        server_name  mydomain.com;
        root         /var/www/html;

        ssl_certificate "/etc/ssl/certs/mydomain_com.crt";
        ssl_certificate_key "/etc/ssl/private/mydomain_com.key";
        ssl_protocols TLSv1.2 TLSv1.3;
        ssl_ciphers EECDH+CHACHA20:EECDH+AES;
        ssl_ecdh_curve X25519:prime256v1:secp521r1:secp384r1;
        sl_prefer_server_ciphers on;
        ssl_session_cache shared:SSL:1m;
        ssl_session_timeout  10m;
 
        include /etc/nginx/default.d/*.conf;
  
        location / {
        set $memcached_key "$uri?$args";
        error_page     404 502 504 = @fallback;
        default_type text/html;
        index index.php index.html index.htm;
        try_files $uri $uri/ /index.php?$args;
        }

        location ~ \.php$ {
        # SECURITY : Zero day Exploit Protection
        try_files $uri =404;
        # ENABLE : Enable PHP, listen fpm sock
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass unix:/run/php/php8.2-fpm.sock;
        fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
        include fastcgi_params;
        }

        location = /robots.txt {
        allow all;
        log_not_found off;
        access_log off;
        try_files $uri /index.php?$args;
        }

# include /etc/nginx/w3tc.conf;
# include /etc/nginx/wpsuper.conf;
# include /etc/nginx/inc.conf;
# DISABLE DB.CONF if issues with phpmyadmin
# include /etc/nginx/db.conf;

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


# end port 443
}


Remember, there will be the last } bracket below the above port 443 stanza/section.

Now try “nginx -t”

Of okay, use “systemctl restart nginx”. Then try https://mydomain.com

At this stage you can test the https://mydomain.com/phpMyAdmin login.
Remember, if it fails with a permissions error, go to the directories in the error message and change all group ownerships from apache to nginx with a “chgrp -R DIRECTORIES” command for each directory.

You see above a few other included .conf files that can help with WordPress plugins (if you use WP Super Cache or W3 Total Cache), and various security protections. As an example, in inc.conf, we will have lines that block a WordPress login unless it is your own IP address, and lines that prevent WordPress updates. You may install these and work out which stanzas you would like to remove, or simply comment out the include files, restart nginx, and do an WordPress update. Up to you. I have not spent too much time on this so far.

If you want a way of restarting all services, you can use this shell script:

cd /home/admin

vi restart.sh

#!/bin/sh
 /usr/bin/systemctl stop nginx
 /usr/bin/systemctl stop mariadb
 /usr/bin/systemctl stop memcached
 /usr/bin/systemctl reload php8.2-fpm
 /usr/bin/systemctl start memcached
 /usr/bin/systemctl start mariadb
 /usr/bin/systemctl start nginx
exit

[save and exit]

chown root restart.sh
chgrp admin restart.sh
chmod 777 restart.sh

To run the script, which is a good idea to do now:

/home/admin/restart.sh

To see shell scripts and additional Nginx .conf files, please see my webpage for those examples.

I do not use deny lists in Nginx, as we can use the script blacklist.sh to block known BAD ip addresses and/or countries.

Please rename the phpinfo.php to phpinfo.php.bak as it too quickly reveals information to hackers:

cd /var/www/html
mv phpinfo.php phpinfo.php.bak

[/vc_wp_text][mk_padding_divider][vc_wp_text]

Let’s Encrypt / Certbot Free SSL

We will use the next lesson for Let’s Encrypt free certificates, as there is quite a bit of information to put there.[/vc_wp_text][mk_padding_divider][vc_wp_text]

Multiple Sites

There is no configuration difficulty for mutiple top level domains or subdomain websites, however, this impacts the use of PHP memory_limit, and how many sites are practical to have, given your CPU and RAM.

Please see the next lesson on installing multiple free certificates which shows how you edit “includ” .conf files for each site.
Very straight forward.

Once running WordPress, you can include other .conf files, such as inc.conf and db.conf my scripting examples shown elsewhere.
These includes go into the port 443 stanzas. If not using a plugin like w3tc and its associated .conf file, you can manuall add gzip lines in the port 443 stanza as shown below. Anywhere you duplicate an entry, nginx -t will let you know the line you need to look at. I use the “cat -n FILE | more” command to help find these lines.

cd /etc/nginx

vi shop.mydomain.com.conf

[Go to the port 443 stanxa and after the "root" line - or anywhere really, add these lines if gzip is not already enabled elswhere:]

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_min_length 256;
gzip_types
  application/atom+xml
  application/geo+json
  application/javascript
  application/x-javascript
  application/json
  application/ld+json
  application/manifest+json
  application/rdf+xml
  application/rss+xml
  application/xhtml+xml
  application/xml
  font/eot
  font/otf
  font/ttf
  image/svg+xml
  text/css
  text/javascript
  text/plain
  text/xml;


[save and exit]

nginx -t

SSL Labs and Pingdom Tests

You can see if your certificate is okay, or if a paid certificate that you edited it correctly for the right bundled order with ssllabs.com.
You can see how your website shapes up with https://tools.pingdom.com/

Pingdom is a quick way to see how the site is, but varies in that you could have two sites configured the same and one gets good results and the other 80% type of results. A little odd, but still useful.