Configure and Deploy to Ubuntu 20.04 Droplet at Digital Ocean

A soup to nuts document

Configure and Deploy to Ubuntu 20.04 Droplet at Digital Ocean

by John Vincent


Posted on July 10, 2020


Article that describes the creation, configuration and deployment of johnvincent.io and many applications to a Ubuntu 20.04 droplet at Digital Ocean.

Installation and configuration topics include Ubuntu 20.04, Google Domains, DNS, SSH, Firewall, Nginx, Nginx http and https Server Blocks, SSL certificates, Certificate Authority Authorization, TLS V1.3, Node, MongoDB, Java, Application deployment, and Cron jobs.

Create Ubuntu Droplet at Digital Ocean

This is a large and complex undertaking. Let's start with SSH keys.

Create SSH Key

From Mac

cd .ssh
ssh-keygen
Enter file in which to save the key (/Users/<my-user>/.ssh/id_rsa): id_johnvincentio
  • passphrase: do not provide a passphrase

Generates two files

  • private: id_johnvincentio
  • public: id_johnvincentio.pub

Store key in keychain

chmod 600 id_johnvincentio*
ssh-add -K id_johnvincentio

Create Ubuntu Droplet

Sign in to Digital Ocean

  • Create Droplet
  • Ubuntu 20.04 (LTS) x64
  • Basic: $5/month
  • Choose a datacenter region
  • VPC Network: default-nyc1
  • Authentication: SSH Keys
  • Hostname: johnvincentio
  • SSH keys: New SSH Key

    • Paste Public key just created
    • Select the SSH key just created.

The Ubuntu droplet is created and an IP provided.

How To Connect To Your Droplet with SSH

How to Connect to your Droplet with OpenSSH

Initial Setup reference

Connect to droplet

ssh -i ./id_johnvincentio root@{your-ip}
The authenticity of host '<your-ip> (<your-ip>)' can't be established.
Are you sure you want to continue connecting (yes/no)?
  • Yes

Set Time Zone

Show the timezone

timedatectl

which shows something like

Local time: Fri 2020-12-04 16:42:13 UTC
Universal time: Fri 2020-12-04 16:42:13 UTC
RTC time: Fri 2020-12-04 16:42:14
Time zone: Etc/UTC (UTC, +0000)
System clock synchronized: yes
NTP service: active
RTC in local TZ: no

or, can view timezone symbolic link

ls -l /etc/localtime

or

cat /etc/timezone

To list time zones

timedatectl list-timezones

or more conveniently

timedatectl list-timezones | grep -i america

Set time zone

sudo timedatectl set-timezone your_time_zone

for example

sudo timedatectl set-timezone America/New_York

Review

timedatectl

which shows something like

Local time: Fri 2020-12-04 12:13:45 EST
Universal time: Fri 2020-12-04 17:13:45 UTC
RTC time: Fri 2020-12-04 17:13:46
Time zone: America/New_York (EST, -0500)
System clock synchronized: yes
NTP service: active
RTC in local TZ: no

Basic configuration

  • Change root password

    • passwd
  • Add user

    • adduser {remote-user}
    • {password}
  • Root privileges

    • usermod -aG sudo {remote-user}

Add aliases to root

vi /root/.bash_aliases
add
lf() { ls -FaC $*; }

Add aliases to {remote-user}

su - {remote-user}
vi .bash_aliases

add
lf() { ls -FaC $*; }

Disable Password Authentication

As root or your sudo user, open the SSH daemon configuration

sudo vi /etc/ssh/sshd_config

set:

PasswordAuthentication no

ensure:

PubkeyAuthentication yes
ChallengeResponseAuthentication no

reload the SSH daemon:

sudo systemctl reload sshd

SSH as User

SSH into droplet as root

ssh -i ./id_johnvincentio root@{your-ip}

Copy files

cp /root/.ssh/authorized_keys /home/{remote-user}/.ssh/authorized_keys

As remote-user

su - {remote-user}
cd .ssh
sudo chown jv:jv authorized_keys
chmod 600 authorized_keys

Test Log In

ssh -i ./id_johnvincentio {remote-user}@{your-ip}

should log in without any passwords.

SSH Config

Add to .ssh/config

Host johnvincent.io
    UseKeychain yes
    AddKeysToAgent yes
    HostName <your-ip>
    User <your-user>
    IdentityFile ~/.ssh/id_johnvincentio

Copy public keys to remote server (optional)

cd
cd .ssh
ssh-copy-id <remote-user>@<your-ip>

Verify Public Key on Remote Server

  • Login to digital ocean droplet
  • su - <remote-user>
  • cd .ssh
  • view authorized_keys

    • Key should be present
    • Remove all other keys

Test SSH to Remote Server

ssh <remote-user>@johnvincent.io

Set Up a Basic Firewall

Firewall Rules Reference

List applications:

sudo ufw app list

Available applications: OpenSSH

Ensure firewall allows SSH connection:

sudo ufw allow OpenSSH

enable the firewall:

sudo ufw enable

You can see that SSH connections are still allowed by typing:

sudo ufw status

Add Swap

Swap reference

Check System for Swap

sudo swapon -s

Check swap usage

free -h

Check current disk usage

df -h

Create Swap File

sudo dd if=/dev/zero of=/swapfile bs=1G count=4

if this fails with:

dd: memory exhausted by input buffer of size 1073741824 bytes (1.0 GiB)

then try:

sudo fallocate -l 4G /swapfile

Check swap file

ls -lh /swapfile

Enabling the Swap File

Secure the swap file:

sudo chmod 600 /swapfile

tell our system to set up the swap space:

sudo mkswap /swapfile

enable the swap:

sudo swapon /swapfile

verify:

sudo swapon -s

Check swap usage

free -h

Make the Swap File Permanent

Edit configuration file:

sudo vi /etc/fstab

Add to the end:

/swapfile   none    swap    sw    0   0

Tweak your Swap Settings

Current swappiness value by typing:

cat /proc/sys/vm/swappiness

For a VPS system, this number needs to be close to zero.

Edit configuration:

sudo vi /etc/sysctl.conf

At the bottom, add:

vm.swappiness=10

Another related value that you might want to modify is the vfs_cache_pressure. This setting configures how much the system will choose to cache inode and dentry information over other data.

cat /proc/sys/vm/vfs_cache_pressure
sudo vi /etc/sysctl.conf
add:
vm.vfs_cache_pressure = 50

Check Swap

sudo swapon --summary
free -h

Install Basics

sudo apt-get update
sudo apt-get upgrade
sudo apt-get install zip wget

Install and Configure Java

Update the system

sudo apt-get update && apt-get upgrade

install the default JDK

sudo apt-get install default-jdk

Check java version

java -version

Install Node V10 and Npm

curl -sL https://deb.nodesource.com/setup_10.x | sudo -E bash -
sudo apt-get install -y nodejs
which node
/usr/bin/node

which npm
/usr/bin/npm

node -v
v10.23.0

npm -v
v6.14.8

Install PM2

Use PM2, a production process manager for Node applications with a built-in load balancer.

Install PM2

sudo npm install pm2 -g
pm2 -v

Install HTML-Minifier

sudo npm install html-minifier -g

Install Mongo Ubuntu

How to Install MongoDB on Ubuntu 20.04

How to Install and Secure MongoDB on Ubuntu 16.04

sudo apt-get update

Adding the MongoDB Repository

Get public GPG key for latest stable version of MongoDB.

curl -fsSL https://www.mongodb.org/static/pgp/server-4.4.asc | sudo apt-key add -

Verify key was added correctly

apt-key list

Issue the following command to create a list file for MongoDB.

echo "deb [ arch=amd64,arm64 ] https://repo.mongodb.org/apt/ubuntu focal/mongodb-org/4.4 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-4.4.list

After adding the repository details, we need to update the packages list.

sudo apt-get update

Installing and Verifying MongoDB

Now we can install the MongoDB package itself.

sudo apt-get install -y mongodb-org

Verify installed

cd /usr/bin
ls mongo*

If failed, probably needs

sudo apt-get install -y --allow-unauthenticated mongodb-org

We'll create a unit file to manage the MongoDB service.

sudo vi /etc/systemd/system/mongodb.service
[Unit]
Description=High-performance, schema-free document-oriented database
After=network.target

[Service]
User=mongodb
ExecStart=/usr/bin/mongod --quiet --config /etc/mongod.conf

[Install]
WantedBy=multi-user.target

Next, start the newly created service with systemctl

sudo systemctl start mongodb

Check that the service has started properly.

sudo systemctl status mongodb

Enable automatically starting MongoDB when the system starts.

sudo systemctl enable mongodb

Verify database is running

mongo --eval 'db.runCommand({ connectionStatus: 1 })'

/etc/mongod.conf

# mongod.conf

# for documentation of all options, see:
#   http://docs.mongodb.org/manual/reference/configuration-options/

# Where and how to store data.
storage:
  dbPath: /var/lib/mongodb
  journal:
    enabled: true
#  engine:
#  mmapv1:
#  wiredTiger:

# where to write logging data.
systemLog:
  destination: file
  logAppend: true
  path: /var/log/mongodb/mongod.log

# network interfaces
net:
  port: 27017
  bindIp: 127.0.0.1

#processManagement:

#security:

#operationProfiling:

#replication:

#sharding:

## Enterprise-Only Options:

#auditLog:

#snmp:

Install Nginx on Ubuntu 20.04

Useful reference

Install Nginx

sudo apt-get update
sudo apt-get install nginx

Review the Installation

nginx -V
nginx version: nginx/1.18.0 (Ubuntu)
built with OpenSSL 1.1.1f  31 Mar 2020
TLS SNI support enabled
configure arguments: --with-cc-opt='-g -O2 -fdebug-prefix-map=/build/nginx-5J5hor/nginx-1.18.0=. -fstack-protector-strong -Wformat -Werror=format-security -fPIC -Wdate-time -D_FORTIFY_SOURCE=2' --with-ld-opt='-Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,-z,now -fPIC' --prefix=/usr/share/nginx --conf-path=/etc/nginx/nginx.conf --http-log-path=/var/log/nginx/access.log --error-log-path=/var/log/nginx/error.log --lock-path=/var/lock/nginx.lock --pid-path=/run/nginx.pid --modules-path=/usr/lib/nginx/modules --http-client-body-temp-path=/var/lib/nginx/body --http-fastcgi-temp-path=/var/lib/nginx/fastcgi --http-proxy-temp-path=/var/lib/nginx/proxy --http-scgi-temp-path=/var/lib/nginx/scgi --http-uwsgi-temp-path=/var/lib/nginx/uwsgi --with-debug --with-compat --with-pcre-jit --with-http_ssl_module --with-http_stub_status_module --with-http_realip_module --with-http_auth_request_module --with-http_v2_module --with-http_dav_module --with-http_slice_module --with-threads --with-http_addition_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_image_filter_module=dynamic --with-http_sub_module --with-http_xslt_module=dynamic --with-stream=dynamic --with-stream_ssl_module --with-mail=dynamic --with-mail_ssl_module

Adjust the Firewall

List applications:

sudo ufw app list

To allow only port 80:

sudo ufw allow 'Nginx HTTP'

Verify the change:

sudo ufw status

Check your Web Server

Check the systemd init system to make sure the service is running:

systemctl status nginx

Check from a browser:

<your-ip>

and should see Nginx page

Manage the Nginx Process

To stop your web server

sudo systemctl stop nginx

To start the web server

sudo systemctl start nginx

To restart the service

sudo systemctl restart nginx

If you are simply making configuration changes, Nginx can often reload without dropping connections.

sudo systemctl reload nginx

By default, Nginx is configured to start automatically when the server boots. If this is not what you want, you can disable this behavior

sudo systemctl disable nginx

To re-enable the service to start up at boot:

sudo systemctl enable nginx

Important Nginx Files and Directories

Content

  • /var/www/html: The actual web content, which by default only consists of the default Nginx page you saw earlier, is served out of the /var/www/html directory. This can be changed by altering Nginx configuration files.

Server Configuration

  • /etc/nginx: The Nginx configuration directory. All of the Nginx configuration files reside here.
  • /etc/nginx/nginx.conf: The main Nginx configuration file. This can be modified to make changes to the Nginx global configuration.
  • /etc/nginx/sites-available: The directory where per-site "server blocks" can be stored. Nginx will not use the configuration files found in this directory unless they are linked to the sites-enabled directory (see below). Typically, all server block configuration is done in this directory, and then enabled by linking to the other directory.
  • /etc/nginx/sites-enabled/: The directory where enabled per-site "server blocks" are stored. Typically, these are created by linking to configuration files found in the sites-availabledirectory
  • /etc/nginx/snippets: This directory contains configuration fragments that can be included elsewhere in the Nginx configuration. Potentially repeatable configuration segments are good candidates for refactoring into snippets.

Server Logs

  • /var/log/nginx/access.log: Every request to your web server is recorded in this log file unless Nginx is configured to do otherwise.
  • /var/log/nginx/error.log: Any Nginx errors will be recorded in this log.

Configure Nginx

sudo vi /etc/nginx/nginx.conf

user www-data;
worker_processes auto;
pid /run/nginx.pid;

events {
  worker_connections 768;
  # multi_accept on;
}

http {

  ##
  # Basic Settings
  ##

  server_tokens off;
  include /etc/nginx/mime.types;
  default_type application/octet-stream;

  charset_types text/css text/plain text/vnd.wap.wml application/javascript application/json application/rss+xml application/xml;

  keepalive_timeout 65;
  sendfile on;
  tcp_nopush on;
  tcp_nodelay on;
  types_hash_max_size 2048;
  # server_tokens off;

  server_names_hash_bucket_size 64;
  # server_name_in_redirect off;


  ##
  # SSL Settings
  ##

    ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; # Dropping SSLv3, ref: POODLE
  ssl_prefer_server_ciphers on;

  ##
  # Logging Settings
  ##

  access_log /var/log/nginx/access.log;
  error_log /var/log/nginx/error.log;

  ##
  # Gzip Settings
  ##

  gzip on;
  gzip_comp_level 6;
  gzip_min_length 256;
  gzip_proxied any;
  gzip_vary on;

  gzip_disable "msie6";
  gzip_buffers 16 8k;
  gzip_http_version 1.1;

  gzip_types
    application/atom+xml
    application/javascript
    application/json
    application/ld+json
    application/manifest+json
    application/rss+xml
    application/vnd.geo+json
    application/vnd.ms-fontobject
    application/x-font-ttf
    application/x-web-app-manifest+json
    application/xhtml+xml
    application/xml
    font/opentype
    image/bmp
    image/svg+xml
    image/x-icon
    text/cache-manifest
    text/css
    text/plain
    text/vcard
    text/vnd.rim.location.xloc
    text/vtt
    text/x-component
    text/x-cross-domain-policy;

  ##
  # Virtual Host Configs
  ##

  include /etc/nginx/conf.d/*.conf;
  include /etc/nginx/sites-enabled/*;
}

Advanced Nginx Configuration

Clone to /home/jv/h5bp

git clone https://github.com/h5bp/server-configs-nginx.git h5bp

Copy to Nginx

cd h5bp
sudo cp -r h5bp /etc/nginx

Restart Nginx:

sudo systemctl restart nginx

Configuring Google Domains

Sign in to Google Domains

Select domain: johnvincent.io

  • Configure DNS
  • Registered Hosts
Host name: johnvincent.io
IP: 165.22.3.198

Host name: www.johnvincent.io
IP: 165.22.3.198

Add Custom resource records.

name: @
Type: A
TTL: 1h
Data: 165.22.3.198
name: www
Type: A
TTL: 1h
Data: 165.22.3.198

Google Subdomains

Do not use subdomain forward.

Add Custom resource records.

Type: A
TTL: 1h
Data: 165.22.3.198

for each of

www.subdomain
subdomain

subdomain

apis
feediator
gomoku
hangman
images
internet-resources
lightsout
linkedin
music
mygithub
nextjs
omnifood
peg-solitaire
rijksmuseum
test
yahtzee

Verify Domain Configuration

Google Domains

Ensure all are domains and subdomains are forwarding to the correct ip.

Test Domains

dig A www.johnvincent.io
dig A johnvincent.io

and repeat for all subdomains.

Output for each should look like:

dig A www.johnvincent.io

; <<>> DiG 9.10.6 <<>> A www.johnvincent.io
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 51430
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4000
;; QUESTION SECTION:
;www.johnvincent.io.        IN  A

;; ANSWER SECTION:
www.johnvincent.io. 3600    IN  A   104.236.194.244

;; Query time: 35 msec
;; SERVER: 192.168.0.1#53(192.168.0.1)
;; WHEN: Tue Sep 24 15:29:57 EDT 2019
;; MSG SIZE  rcvd: 63

Verify ANSWER: 1

Configure HTTP Nginx

Create HTTP configurations for

  • www.johnvincent.io
  • www.apis.johnvincent.io
  • www.feediator.johnvincent.io
  • www.gomoku.johnvincent.io
  • www.hangman.johnvincent.io
  • www.images.johnvincent.io
  • www.internet-resources.johnvincent.io
  • www.lightsout.johnvincent.io
  • www.linkedin.johnvincent.io
  • www.music.johnvincent.io
  • www.mygithub.johnvincent.io
  • www.nextjs.johnvincent.io
  • www.omnifood.johnvincent.io
  • www.peg-solitaire.johnvincent.io
  • www.rijksmuseum.johnvincent.io
  • www.test.johnvincent.io
  • www.yahtzee.johnvincent.io

Configuration

Stop Nginx

sudo systemctl stop nginx

Remove default site

cd /etc/nginx/
sudo rm sites-enabled/default

Create directories for http and https configurations

cd /etc/nginx/sites-available
sudo mkdir http https

Configuration for each domain and subdomains

Create http and https web server files

cd /var/www
sudo mkdir http https
cd http
sudo mkdir -p johnvincent.io/html/.well-known
sudo mkdir -p apis/html/.well-known
sudo mkdir -p feediator/html/.well-known
sudo mkdir -p gomoku/html/.well-known
sudo mkdir -p hangman/html/.well-known
sudo mkdir -p images/html/.well-known
sudo mkdir -p internet-resources/html/.well-known
sudo mkdir -p lightsout/html/.well-known
sudo mkdir -p linkedin/html/.well-known
sudo mkdir -p mygithub/html/.well-known
sudo mkdir -p music/html/.well-known
sudo mkdir -p nextjs/html/.well-known
sudo mkdir -p omnifood/html/.well-known
sudo mkdir -p peg-solitaire/html/.well-known
sudo mkdir -p rijksmuseum/html/.well-known
sudo mkdir -p test/html/.well-known
sudo mkdir -p yahtzee/html/.well-known

Note, the .well-known is for the SSL certs tasks if using Webroot plugin.

cd /var/www
cd https
sudo mkdir -p johnvincent.io/html/.well-known
sudo mkdir -p apis/html/.well-known
sudo mkdir -p feediator/html/.well-known
sudo mkdir -p gomoku/html/.well-known
sudo mkdir -p hangman/html/.well-known
sudo mkdir -p images/html/.well-known
sudo mkdir -p internet-resources/html/.well-known
sudo mkdir -p lightsout/html/.well-known
sudo mkdir -p linkedin/html/.well-known
sudo mkdir -p mygithub/html/.well-known
sudo mkdir -p music/html/.well-known
sudo mkdir -p nextjs/html/.well-known
sudo mkdir -p omnifood/html/.well-known
sudo mkdir -p peg-solitaire/html/.well-known
sudo mkdir -p rijksmuseum/html/.well-known
sudo mkdir -p test/html/.well-known
sudo mkdir -p yahtzee/html/.well-known

For each http and https domain/subdomain, create file

* sudo vi /var/www/http(s)/{domain-name}/html/index.html
<html>
    <head>
        <title>Welcome!</title>
    </head>
    <body>
        <h1>Success! The www.{{sub-domain-name}}.johnvincent.io server block is working!</h1>
    </body>
</html>

Change the directory ownership

sudo chown -R jv:jv /var/www/http(s)/{domain-name}/html

Change ownership of files

cd /var/www/http(s)/{domain-name}/html
find . -type d -print0 | xargs -0 chmod 0755 # For directories
find . -type f -print0 | xargs -0 chmod 0644 # For files

Configure johnvincent.io

sudo vi /etc/nginx/sites-available/http/johnvincent.io
server {
  listen 80 default_server;
  listen [::]:80 default_server;

  server_name johnvincent.io www.johnvincent.io;
  root /var/www/johnvincent.io/html;
  index index.html;

  location / {
    try_files $uri $uri/ =404;
  }
  location ~ /.well-known {
    allow all;
  }
}

Configure subdomains

sudo vi /etc/nginx/sites-available/http/{sub-domain}
server {
  listen 80;
  listen [::]:80;

  server_name {sub-domain}.johnvincent.io www.{sub-domain}.johnvincent.io;
  root /var/www/{sub-domain}.com/html;
  index index.html;

  location / {
    try_files $uri $uri/ =404;
  }
  location ~ /.well-known {
    allow all;
  }
}

Create Script files

Create script file ~/bin/enable-http

#!/bin/sh
#
#  script to enable non-SSL
#
cd /etc/nginx/sites-enabled/
#
echo "Remove previous symbolic links"
sudo rm /etc/nginx/sites-enabled/johnvincent.io

sudo rm /etc/nginx/sites-enabled/apis
sudo rm /etc/nginx/sites-enabled/feediator
sudo rm /etc/nginx/sites-enabled/gomoku
sudo rm /etc/nginx/sites-enabled/hangman
sudo rm /etc/nginx/sites-enabled/images
sudo rm /etc/nginx/sites-enabled/internet-resources
sudo rm /etc/nginx/sites-enabled/linkedin
sudo rm /etc/nginx/sites-enabled/lightsout
sudo rm /etc/nginx/sites-enabled/music
sudo rm /etc/nginx/sites-enabled/mygithub
sudo rm /etc/nginx/sites-enabled/nextjs
sudo rm /etc/nginx/sites-enabled/omnifood
sudo rm /etc/nginx/sites-enabled/peg-solitaire
sudo rm /etc/nginx/sites-enabled/rijksmuseum
sudo rm /etc/nginx/sites-enabled/test
sudo rm /etc/nginx/sites-enabled/yahtzee

#
echo "Create symbolic links to HTTP files"
sudo ln -s /etc/nginx/sites-available/http/johnvincent.io /etc/nginx/sites-enabled/johnvincent.io

sudo ln -s /etc/nginx/sites-available/http/apis /etc/nginx/sites-enabled/apis
sudo ln -s /etc/nginx/sites-available/http/feediator /etc/nginx/sites-enabled/feediator
sudo ln -s /etc/nginx/sites-available/http/gomoku /etc/nginx/sites-enabled/gomoku
sudo ln -s /etc/nginx/sites-available/http/hangman /etc/nginx/sites-enabled/hangman
sudo ln -s /etc/nginx/sites-available/http/images /etc/nginx/sites-enabled/images
sudo ln -s /etc/nginx/sites-available/http/internet-resources /etc/nginx/sites-enabled/internet-resources
sudo ln -s /etc/nginx/sites-available/http/linkedin /etc/nginx/sites-enabled/linkedin
sudo ln -s /etc/nginx/sites-available/http/lightsout /etc/nginx/sites-enabled/lightsout
sudo ln -s /etc/nginx/sites-available/http/music /etc/nginx/sites-enabled/music
sudo ln -s /etc/nginx/sites-available/http/mygithub /etc/nginx/sites-enabled/mygithub
sudo ln -s /etc/nginx/sites-available/http/nextjs /etc/nginx/sites-enabled/nextjs
sudo ln -s /etc/nginx/sites-available/http/omnifood /etc/nginx/sites-enabled/omnifood
sudo ln -s /etc/nginx/sites-available/http/peg-solitaire /etc/nginx/sites-enabled/peg-solitaire
sudo ln -s /etc/nginx/sites-available/http/rijksmuseum /etc/nginx/sites-enabled/rijksmuseum
sudo ln -s /etc/nginx/sites-available/http/test /etc/nginx/sites-enabled/test
sudo ln -s /etc/nginx/sites-available/http/yahtzee /etc/nginx/sites-enabled/yahtzee
#

ls -la
#
echo "Restarting Nginx"
nginx-restart
#
echo "Completed"

Create script file /bin/enable-https

#!/bin/sh
#
#  script to enable SSL
#
cd /etc/nginx/sites-enabled/
#
echo "Remove previous symbolic links"
sudo rm /etc/nginx/sites-enabled/johnvincent.io

sudo rm /etc/nginx/sites-enabled/apis
sudo rm /etc/nginx/sites-enabled/feediator
sudo rm /etc/nginx/sites-enabled/gomoku
sudo rm /etc/nginx/sites-enabled/hangman
sudo rm /etc/nginx/sites-enabled/images
sudo rm /etc/nginx/sites-enabled/internet-resources
sudo rm /etc/nginx/sites-enabled/linkedin
sudo rm /etc/nginx/sites-enabled/lightsout
sudo rm /etc/nginx/sites-enabled/music
sudo rm /etc/nginx/sites-enabled/mygithub
sudo rm /etc/nginx/sites-enabled/nextjs
sudo rm /etc/nginx/sites-enabled/omnifood
sudo rm /etc/nginx/sites-enabled/peg-solitaire
sudo rm /etc/nginx/sites-enabled/rijksmuseum
sudo rm /etc/nginx/sites-enabled/test
sudo rm /etc/nginx/sites-enabled/yahtzee
#
echo "Create symbolic links to HTTPS files"
sudo ln -s /etc/nginx/sites-available/https/johnvincent.io /etc/nginx/sites-enabled/johnvincent.io

sudo ln -s /etc/nginx/sites-available/https/apis /etc/nginx/sites-enabled/apis
sudo ln -s /etc/nginx/sites-available/https/feediator /etc/nginx/sites-enabled/feediator
sudo ln -s /etc/nginx/sites-available/https/gomoku /etc/nginx/sites-enabled/gomoku
sudo ln -s /etc/nginx/sites-available/https/hangman /etc/nginx/sites-enabled/hangman
sudo ln -s /etc/nginx/sites-available/https/images /etc/nginx/sites-enabled/images
sudo ln -s /etc/nginx/sites-available/https/internet-resources /etc/nginx/sites-enabled/internet-resources
sudo ln -s /etc/nginx/sites-available/https/linkedin /etc/nginx/sites-enabled/linkedin
sudo ln -s /etc/nginx/sites-available/https/lightsout /etc/nginx/sites-enabled/lightsout
sudo ln -s /etc/nginx/sites-available/https/music /etc/nginx/sites-enabled/music
sudo ln -s /etc/nginx/sites-available/https/mygithub /etc/nginx/sites-enabled/mygithub
sudo ln -s /etc/nginx/sites-available/https/nextjs /etc/nginx/sites-enabled/nextjs
sudo ln -s /etc/nginx/sites-available/https/omnifood /etc/nginx/sites-enabled/omnifood
sudo ln -s /etc/nginx/sites-available/https/peg-solitaire /etc/nginx/sites-enabled/peg-solitaire
sudo ln -s /etc/nginx/sites-available/https/rijksmuseum /etc/nginx/sites-enabled/rijksmuseum
sudo ln -s /etc/nginx/sites-available/https/test /etc/nginx/sites-enabled/test
sudo ln -s /etc/nginx/sites-available/https/yahtzee /etc/nginx/sites-enabled/yahtzee
#

ls -la
#
echo "Handle PM2 tasks"
handle-pm2
#
echo "Restarting Nginx"
nginx-restart
#
echo "Mongo restart"
mongo-restart
#
echo "Mongo Status"
mongo-status
#
echo "Completed"

Create script file ~/bin/nginx-restart

#!/bin/bash
#
# script to restart nginx
#
echo "Restarting Nginx"
sudo nginx -t
sudo systemctl restart nginx

Create script file ~/bin/nginx-stop

#!/bin/bash
#
# script to stop nginx
#
echo "Stopping Nginx"
sudo nginx -t
sudo systemctl stop nginx
Completed"

Create script file ~/bin/mongo-status

#!/bin/bash
#
# script to show mongo status
#
echo "Mongo Status"
sudo systemctl status mongodb

Create script file ~/bin/mongo-start

#!/bin/bash
#
# script to start mongo
#
echo "Mongo start"
sudo systemctl start mongodb

Create script file ~/bin/mongo-restart

#!/bin/bash
#
# script to restart mongo
#
echo "Mongo restart"
sudo systemctl restart mongodb

Create script file ~/bin/mongo-stop

#!/bin/bash
#
# script to stop mongo
#
echo "Mongo stop"
sudo systemctl stop mongodb

Enable Server Blocks

enable-http

Test from browser, now using port 80:

They all should be working.

http://www.johnvincent.io
http://johnvincent.io

http://www.apis.johnvincent.io
http://apis.johnvincent.io

http://www.feediator.johnvincent.io
http://feediator.johnvincent.io

http://www.gomoku.johnvincent.io
http://gomoku.johnvincent.io

http://www.hangman.johnvincent.io
http://hangman.johnvincent.io

http://www.images.johnvincent.io
http://images.johnvincent.io

http://www.internet-resources.johnvincent.io
http://internet-resources.johnvincent.io

http://www.lightsout.johnvincent.io
http://lightsout.johnvincent.io

http://www.linkedin.johnvincent.io
http://linkedin.johnvincent.io

http://www.music.johnvincent.io
http://music.johnvincent.io

http://www.mygithub.johnvincent.io
http://mygithub.johnvincent.io

http://www.nextjs.johnvincent.io
http://nextjs.johnvincent.io

http://www.omnifood.johnvincent.io
http://omnifood.johnvincent.io

http://www.peg-solitaire.johnvincent.io
http://peg-solitaire.johnvincent.io

http://www.rijksmuseum.johnvincent.io
http://rijksmuseum.johnvincent.io

http://www.test.johnvincent.io
http://test.johnvincent.io

http://www.yahtzee.johnvincent.io
http://yahtzee.johnvincent.io

Configuring Nginx to implement HTTP Basic Authentication

For details, see Restricting Access with HTTP Basic Authentication

Create SSL Certificates

Need one SSL cert for:

  • johnvincent.io, www.johnvincent.io and all subdomains

Self-Signed SSL Certificate are not trusted by browsers. Do not use them.

Webroot. Webroot is not my preferred method as I prefer 1 certificate for the domains and sub-domains.

Install Certbot

Start with Certbot

Select Nginx on Ubuntu 20.04, which links to Certbot instructions)

Choose: wildcard

Check if Google has support for Certbot

Select check if your DNS provider supports Certbot

Note certbot-dns-google requires requires Google Cloud Platform API credentials.

Note certbot-dns-digitalocean. This may need Digital Ocean to be the DNS provider. This is not the case.

Thus DNS provider is not supported.

Need to use the manual plug-in. See Manual DNS Plugin

Install snapd

If not already installed

sudo apt update
sudo apt install snapd

Get latest version of snapd

sudo snap install core; sudo snap refresh core

Remove certbot packages (may not exist)

sudo apt-get remove certbot

Install Certbot

sudo snap install --classic certbot

Prepare Certbot to be run

sudo ln -s /snap/bin/certbot /usr/bin/certbot

Using Certbot Manual Plug-in

Certbot manual

Create script file ~/bin/encrypt-ssl

#!/bin/sh
#
#  script to create or renew SSL certs
#
echo "Creating SSL certificate"
sudo certbot --cert-name johnvincent.io --email <my-email-address> --config $HOME/config-helpers/certbot.cfg --manual --preferred-challenges dns certonly
#
echo "Restarting Nginx"
nginx-restart
#
echo "Completed"

Notice --cert-name johnvincent.io. This needs to match the domain name.

$HOME/config-helpers/certbot.cfg lists all domains and sub-domains.

domains=johnvincent.io, www.johnvincent.io, apis.johnvincent.io, www.apis.johnvincent.io, feediator.johnvincent.io, www.feediator.johnvincent.io, gomoku.johnvincent.io, www.gomoku.johnvincent.io, hangman.johnvincent.io, www.hangman.johnvincent.io, images.johnvincent.io, www.images.johnvincent.io, internet-resources.johnvincent.io, www.internet-resources.johnvincent.io, lightsout.johnvincent.io, www.lightsout.johnvincent.io, linkedin.johnvincent.io, www.linkedin.johnvincent.io, mygithub.johnvincent.io, www.mygithub.johnvincent.io, music.johnvincent.io, www.music.johnvincent.io, nextjs.johnvincent.io, www.nextjs.johnvincent.io, omnifood.johnvincent.io, www.omnifood.johnvincent.io, peg-solitaire.johnvincent.io, www.peg-solitaire.johnvincent.io, rijksmuseum.johnvincent.io, www.rijksmuseum.johnvincent.io, test.johnvincent.io, www.test.johnvincent.io, yahtzee.johnvincent.io, www.yahtzee.johnvincent.io

Create SSL Certificate

Execute ~/bin/encrypt-ssl, there will be a response similar to the following

Please deploy a DNS TXT record under the name
_acme-challenge.johnvincent.io with the following value:

large_random_generated_key

Before continuing, verify the record is deployed.

Press enter to continue

Do not continue until the following has been completed.

Google Domains and select the domain.

Add the following DNS record

Name: _acme-challenge
Type: TXT
TTL: 1h
Data: "large_random_generated_key"

Allow some time for the DNS record to propagate.

Verify the record has been added.

dig -t txt _acme-challenge.johnvincent.io

Successful if

;; ANSWER SECTION:
_acme-challenge.johnvincent.io. 3600 IN TXT "large_random_generated_key"

When TXT record is verified, go back to ~/bin/encrypt-ssl and press Enter

The script will continue and complete with the following

IMPORTANT NOTES:
 - Congratulations! Your certificate and chain have been saved at:
   /etc/letsencrypt/live/johnvincent.io/fullchain.pem
   Your key file has been saved at:
   /etc/letsencrypt/live/johnvincent.io/privkey.pem
   Your cert will expire on 2021-02-25. To obtain a new or tweaked
   version of this certificate in the future, simply run certbot
   again. To non-interactively renew *all* of your certificates, run
   "certbot renew"

Notice where to find the key files.

/etc/letsencrypt/archive/johnvincent.io

Files are:
cert1.pem, chain1.pem, fullchain1.pem, privkey1.pem

However, Let's Encrypt creates symbolic links to the most recent certificate files in the /etc/letsencrypt/live/your_domain_name directory. Because the links will always point to the most recent certificate files, this is the path that you should use to refer to your certificate files.

see: /etc/letsencrypt/live/johnvincent.io

Manage SSL Certificates

List SSL certificates

sudo certbot certificates

Delete SSL Certificate

sudo certbot delete --cert-name MyDomain 

It is possible to make a mess of things, for example

Renewal configuration file /etc/letsencrypt/renewal/www.test.johnvincent.io.conf produced an unexpected error: expected /etc/letsencrypt/live/www.test.johnvincent.io/cert.pem to be a symlink. Skipping.

Then may need to manually remove the certificates

rm -rf /etc/letsencrypt/live/${DOMAIN}
rm -rf /etc/letsencrypt/renewal/${DOMAIN}.conf
rm -rf /etc/letsencrypt/archive/${DOMAIN}

Provide email address to LetsEncrypt

If you failed to set the email address when the certificate was created, it may be added now.

sudo certbot update_account --email <my-email-address>

LetsEncrypt will email certificate expiry warnings to the email address.

Generate Strong Diffie-Hellman Group

To further increase security, you should also generate a strong Diffie-Hellman group. To generate a 2048-bit group, use this command:

sudo openssl dhparam -out /etc/nginx/dhparam.pem 4096

This may take a few minutes but when it's done you will have a strong DH group at

/etc/nginx/dhparam.pem

Configure TLS/SSL on Web Server (Nginx)

Now that you have an SSL certificate, you need to configure your Nginx web server to use it.

Create a Configuration Snippet Pointing to the SSL Key and Certificate

First, let's create a new Nginx configuration snippet in the /etc/nginx/snippets directory. This is done for the domain.

sudo vi /etc/nginx/snippets/ssl-johnvincent.io.conf

add

ssl_certificate /etc/letsencrypt/live/johnvincent.io/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/johnvincent.io/privkey.pem;

Create a Configuration Snippet with Strong Encryption Settings

The parameters we will set can be reused in future Nginx configurations, so we will give the file a generic name:

sudo vi /etc/nginx/snippets/ssl-params.conf

add

ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
ssl_dhparam /etc/nginx/dhparam.pem;
# ssl_ciphers ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
#
ssl_ecdh_curve secp384r1;
#
ssl_session_timeout  10m;
ssl_session_cache shared:SSL:10m;
ssl_session_tickets off;
#
# OCSP stapling
#
ssl_stapling on;
ssl_stapling_verify on;
#
resolver 8.8.8.8 8.8.4.4 valid=300s;
resolver_timeout 5s;
#
# HSTS
#
add_header Strict-Transport-Security "max-age=15724800; includeSubDomains; preload";
#
add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";

Adjust the Firewall

Check available profiles

sudo ufw app list

Check if SSL enabled:

sudo ufw status

To additionally let in HTTPS traffic, we can allow the "Nginx Full" profile and then delete the redundant "Nginx HTTP" profile allowance:

sudo ufw allow 'Nginx Full'
sudo ufw delete allow 'Nginx HTTP'

sudo ufw status

Configure Nginx for SSL

Now that we have our snippets, we can adjust our Nginx configuration to enable SSL.

Stop Nginx:

sudo systemctl stop nginx

Now configure each domain and subdomain

Configure Https Server Block

Create server block for each domain and sub-domain.

Each server block may be configured differently as each server will have differing requirements, however domain and sub-domains use the same SSL certificate. Thus all server blocks will use

include snippets/ssl-johnvincent.io.conf;
include snippets/ssl-params.conf;

As an example

sudo vi /etc/nginx/sites-available/https/johnvincent.io
server {
    listen 80;
    listen [::]:80;
    server_name johnvincent.io www.johnvincent.io;
    return 301 https://www.johnvincent.io$request_uri;
}

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    include snippets/ssl-johnvincent.io.conf;
    include snippets/ssl-params.conf;

    server_name johnvincent.io;
    return 301 https://www.johnvincent.io$request_uri;
}

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    include snippets/ssl-johnvincent.io.conf;
    include snippets/ssl-params.conf;
    include h5bp/basic.conf;

    root /var/www/https/johnvincent.io/html;

    index index.html;

    server_name www.johnvincent.io;

    location / {
        try_files $uri $uri/ =404;
    }
    location = /analytics.js {
        proxy_pass https://www.google-analytics.com;
        expires 31536000s;
        proxy_set_header Pragma "public";
        proxy_set_header Cache-Control "max-age=31536000, public";
    }
    location /junk {
        try_files $uri =503;
    }
    error_page 404 /error;
}

Enable Server Blocks

enable-https

which also restarts Nginx

TLS Version 1.3

OpenSSL at Wiki How To Configure Nginx to use TLS 1.2 / 1.3 only

TLS V1.3 requires openssl v1.1.1+

To verify

openssl version

Verify Nginx supports TLS v1.3

nginx -V

should be

nginx version: nginx/1.18.0 (Ubuntu)
built with OpenSSL 1.1.1f  31 Mar 2020
TLS SNI support enabled

Check Nginx TLS V1.3 Status

openssl s_client -connect johnvincent.io:443 -tls1_3

If this yields

CONNECTED(00000003)
139740834669888:error:1409442E:SSL routines:ssl3_read_bytes:tlsv1 alert protocol version:../ssl/record/rec_layer_s3.c:1543:SSL alert number 70
---
no peer certificate available
---
No client certificate CA names sent
---
SSL handshake has read 7 bytes and written 238 bytes
Verification: OK
---
New, (NONE), Cipher is (NONE)
Secure Renegotiation IS NOT supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
Early data was not sent
Verify return code: 0 (ok)
---

check your /etc/nginx/snippets/ssl-params.conf

A correct response will include

CONNECTED(00000003)
depth=2 O = Digital Signature Trust Co., CN = DST Root CA X3
verify return:1
depth=1 C = US, O = Let's Encrypt, CN = Let's Encrypt Authority X3
verify return:1
depth=0 CN = johnvincent.io
verify return:1
---
Certificate chain
 0 s:CN = johnvincent.io
   i:C = US, O = Let's Encrypt, CN = Let's Encrypt Authority X3
 1 s:C = US, O = Let's Encrypt, CN = Let's Encrypt Authority X3
   i:O = Digital Signature Trust Co., CN = DST Root CA X3

and a certificate and

SSL handshake has read 4158 bytes and written 621 bytes
Verification: OK
---
New, TLSv1.3, Cipher is TLS_AES_256_GCM_SHA384
Server public key is 2048 bit

and

Post-Handshake New Session Ticket arrived:
SSL-Session:
    Protocol  : TLSv1.3

and

Post-Handshake New Session Ticket arrived:
SSL-Session:
    Protocol  : TLSv1.3

Clean files

On Mac, remove quarantine from all files going to the website. For example

cd /Users/jv/Desktop/MyDevelopment/github

Look for files with com.apple.quarantine

xattr -r -l  feediator | grep -i com.apple.quarantine

To remove quarantine:

xattr -r -d com.apple.quarantine feediator

Deployment scripts

These can very complex. I have discussed some on them in details

Gatsby Overview of johnvincent.io

Overview of port to Next.js from Gatsby

TaskMuncher Overview

Overview of React Gomoku

Overview of Deployment of a Node API Server

Building and deploying MyTunes to johnvincent.io

Technology Articles

Overview of React Hangman

Configure PM2

Create ~/bin/handle-pm2

Add

#!/bin/bash
#
# script to add tasks to pm2 if not already added, or to restart
# the tasks if they have already been added.
#
echo "Current PM2 status"
pm2 list
#
echo "Check status of music-server"
pm2 describe music-server > /dev/null
RUNNING=$? 
if [ "${RUNNING}" -ne 0 ]; then
  echo "Adding music server to PM2"
  cd /var/www/https/music/server
  pm2 start server.js --name "music-server"
else
  echo "Restarting music-server"
  pm2 restart music-server
fi;

echo "Check status of peg-solitaire-server"
pm2 describe peg-solitaire-server > /dev/null
RUNNING=$? 
if [ "${RUNNING}" -ne 0 ]; then
  echo "Adding peg-solitaire-server to PM2"
    cd /var/www/https/peg-solitaire/server
  pm2 start peg-solitaire-server.json --name "peg-solitaire-server"
else
  echo "Restarting peg-solitaire-server"
  pm2 restart peg-solitaire-server
fi;

echo "Check status of server-project"
pm2 describe server-project > /dev/null
RUNNING=$? 
if [ "${RUNNING}" -ne 0 ]; then
  echo "Adding server-project to PM2"
  cd /var/www/https/server-project/server
  pm2 start server.js --name "server-project"
else
  echo "Restarting server-project"
  pm2 restart server-project
fi;

echo "Check status of gomoku-server"
pm2 describe gomoku-server > /dev/null
RUNNING=$? 
if [ "${RUNNING}" -ne 0 ]; then
  echo "Adding gomoku-server to PM2"
  cd /var/www/https/gomoku/server
    pm2 start gomoku-server.json --name "gomoku-server"
else
  echo "Restarting gomoku-server"
  pm2 restart gomoku-server
fi;

#
echo "Check status of feediator-server"
pm2 describe feediator-server > /dev/null
RUNNING=$? 
if [ "${RUNNING}" -ne 0 ]; then
  echo "Adding feediator-server to PM2"
  cd /var/www/https/feediator/html
  pm2 start server.js --name "feediator-server"
else
  echo "Restarting feediator-server"
  pm2 restart feediator-server
fi;

#
echo "Save current process list"
pm2 save

#
echo "Show current pm2 status"
pm2 list

echo "Restarting PM2"
pm2 restart all

This will need to be configured for your own needs.

Test from browser, now using port 80:

They all should be working.

https://www.johnvincent.io
https://johnvincent.io

https://www.apis.johnvincent.io
https://apis.johnvincent.io

https://www.feediator.johnvincent.io
https://feediator.johnvincent.io

https://www.gomoku.johnvincent.io
https://gomoku.johnvincent.io

https://www.hangman.johnvincent.io
https://hangman.johnvincent.io

https://www.images.johnvincent.io
https://images.johnvincent.io

https://www.internet-resources.johnvincent.io
https://internet-resources.johnvincent.io

https://www.lightsout.johnvincent.io
https://lightsout.johnvincent.io

https://www.linkedin.johnvincent.io
https://linkedin.johnvincent.io

https://www.music.johnvincent.io
https://music.johnvincent.io

https://www.mygithub.johnvincent.io
https://mygithub.johnvincent.io

https://www.nextjs.johnvincent.io
https://nextjs.johnvincent.io

https://www.omnifood.johnvincent.io
https://omnifood.johnvincent.io

https://www.peg-solitaire.johnvincent.io
https://peg-solitaire.johnvincent.io

https://www.rijksmuseum.johnvincent.io
https://rijksmuseum.johnvincent.io

https://www.test.johnvincent.io
https://test.johnvincent.io

https://www.yahtzee.johnvincent.io
https://yahtzee.johnvincent.io

Test Nginx TLS 1.2 support

Review for domain and sub-domains

curl -I -v --tlsv1.2 --tls-max 1.2 https://www.johnvincent.io/
curl -I -v --tlsv1.2 --tls-max 1.2 https://johnvincent.io/

TLS 1.2 should be supported for all.

Test Nginx TLS 1.3 support

Review for domain and sub-domains

curl -I -v --tlsv1.3 --tls-max 1.3 https://www.johnvincent.io/
curl -I -v --tlsv1.3 --tls-max 1.3 https://johnvincent.io/

TLS 1.3 should be supported for all.

Test 1.0 and 1.1

curl -I -v --tlsv1 --tls-max 1.0 https://www.johnvincent.io/
curl -I -v --tlsv1 --tls-max 1.0 https://johnvincent.io/

should yield

curl: (35) error:1400442E:SSL routines:CONNECT_CR_SRVR_HELLO:tlsv1 alert protocol version
curl -I -v --tlsv1.1 --tls-max 1.1 https://www.johnvincent.io/
curl -I -v --tlsv1.1 --tls-max 1.1 https://johnvincent.io/

should yield

curl: (35) error:1400442E:SSL routines:CONNECT_CR_SRVR_HELLO:tlsv1 alert protocol version

Test SSL Certificates

Use SSLLabs

https://www.ssllabs.com/ssltest/analyze.html?d=johnvincent.io
https://www.ssllabs.com/ssltest/analyze.html?d=apis.johnvincent.io
https://www.ssllabs.com/ssltest/analyze.html?d=feediator.johnvincent.io
https://www.ssllabs.com/ssltest/analyze.html?d=gomoku.johnvincent.io
https://www.ssllabs.com/ssltest/analyze.html?d=hangman.johnvincent.io
https://www.ssllabs.com/ssltest/analyze.html?d=images.johnvincent.io
https://www.ssllabs.com/ssltest/analyze.html?d=internet-resources.johnvincent.io
https://www.ssllabs.com/ssltest/analyze.html?d=lightsout.johnvincent.io
https://www.ssllabs.com/ssltest/analyze.html?d=linkedin.johnvincent.io
https://www.ssllabs.com/ssltest/analyze.html?d=mygithub.johnvincent.io
https://www.ssllabs.com/ssltest/analyze.html?d=music.johnvincent.io
https://www.ssllabs.com/ssltest/analyze.html?d=nextjs.johnvincent.io
https://www.ssllabs.com/ssltest/analyze.html?d=omnifood.johnvincent.io
https://www.ssllabs.com/ssltest/analyze.html?d=peg-solitaire.johnvincent.io
https://www.ssllabs.com/ssltest/analyze.html?d=rijksmuseum.johnvincent.io
https://www.ssllabs.com/ssltest/analyze.html?d=test.johnvincent.io
https://www.ssllabs.com/ssltest/analyze.html?d=yahtzee.johnvincent.io                                                                       

and

https://www.ssllabs.com/ssltest/analyze.html?d=www.johnvincent.io
https://www.ssllabs.com/ssltest/analyze.html?d=www.apis.johnvincent.io
https://www.ssllabs.com/ssltest/analyze.html?d=www.feediator.johnvincent.io
https://www.ssllabs.com/ssltest/analyze.html?d=www.gomoku.johnvincent.io
https://www.ssllabs.com/ssltest/analyze.html?d=www.hangman.johnvincent.io
https://www.ssllabs.com/ssltest/analyze.html?d=www.images.johnvincent.io
https://www.ssllabs.com/ssltest/analyze.html?d=www.internet-resources.johnvincent.io
https://www.ssllabs.com/ssltest/analyze.html?d=www.lightsout.johnvincent.io
https://www.ssllabs.com/ssltest/analyze.html?d=www.linkedin.johnvincent.io
https://www.ssllabs.com/ssltest/analyze.html?d=www.mygithub.johnvincent.io
https://www.ssllabs.com/ssltest/analyze.html?d=www.music.johnvincent.io
https://www.ssllabs.com/ssltest/analyze.html?d=www.nextjs.johnvincent.io
https://www.ssllabs.com/ssltest/analyze.html?d=www.omnifood.johnvincent.io
https://www.ssllabs.com/ssltest/analyze.html?d=www.peg-solitaire.johnvincent.io
https://www.ssllabs.com/ssltest/analyze.html?d=www.rijksmuseum.johnvincent.io
https://www.ssllabs.com/ssltest/analyze.html?d=www.test.johnvincent.io
https://www.ssllabs.com/ssltest/analyze.html?d=www.yahtzee.johnvincent.io

Ensure all scores are A or A+

Check Certificates

In the url, click on the lock. Will get details regarding the certificate. Review.

Verify SSL Certificates

openssl s_client -connect johnvincent.io:443

produces all the relevant information.

curl -I https://johnvincent.io
curl -I https://www.johnvincent.io

provide useful header information.

SSL Certificate Search

Using crt.sh Certificate Search

Enter domain name: johnvincent.io

Lists matching identities. There are loads of them, including those that no longer exist.

SSL Certificates Expiry Date

sudo certbot certificates

This also shows

  • Certificate name
  • Domains
  • Certificate Path
  • Private Key Path

SSL Certificate Renewal

To non-interactively renew your certificates

~/bin/encrypt-ssl

Review Results

All scores are A.

There are a few improvements that could be made.

DNS CAA is not set.

The line item references CAA Mandated by CA/Browser Forum

Lets Encrypt has an excellent document Certificate Authority Authorization (CAA) which basically describes the steps needed.

How to fix DNS CAA is None

CAA Record Helper is extremely helpful.

This references Who Supports CAA?. Verified the Google Domains DNS is supported.

Start CAA Record Helper

Domain Name: johnvincent.io

Select: Empty Policy

Filter by CA name: letsencrypt, which locates Let's Encrypt

Select: Non-wildcard and wildcard

Email Address: enter your email address

Google Domains uses the Generic CAA Policy.

Using Google Domains, add the following DNS record

This will take some to propagate.

Verify DNS Record

dig -t CAA johnvincent.io

Should get something like

;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 15528
;; flags: qr rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 512
;; QUESTION SECTION:
;johnvincent.io.            IN  CAA

;; ANSWER SECTION:
johnvincent.io.     3600    IN  CAA 0 issue "letsencrypt.org"
johnvincent.io.     3600    IN  CAA 0 iodef "mailto:myemail@johnvincent.io"

Can also verify with

Entrust CAA LOOKUP TOOL

Enter domain johnvincent.io

Should find CAA record for domain johnvincent.io

Verify CAs Authorized and IOdef email are correct.

HTTP Strict Transport Security (HSTS)

In section Protocol Details, notice

Strict Transport Security (HSTS)    Yes
max-age=15724800; includeSubDomains; preload

If instead you get

Strict Transport Security (HSTS)    No

review /etc/nginx/snippets/ssl-params.conf, will need

add_header Strict-Transport-Security "max-age=15724800; includeSubDomains; preload";

Mongo

If not running, start Mongo

~/bin/mongo-start

May need to run mongo scripts to populate the database.

Cron Jobs

All cronjobs are placed in /home/jv/cronjobs

For example, application feediator requires a cronjob /home/jv/cronjobs/feediator-app/update-feeds

chmod 744 /home/jv/cronjobs/feediator-app/update-feeds

Add a cron job

Using crontab -e

0 * * * *  /home/jv/cronjobs/feediator-app/update-feeds

To view cron settings

crontab -l

End