Configure and Deploy to Ubuntu Droplet at Digital Ocean
by John Vincent
Posted on October 15, 2023
Article that describes the creation, configuration and deployment of johnvincent.io and many applications to a Ubuntu droplet at Digital Ocean.
This is a large and complex undertaking. 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.
This article covers
- Create SSH Key
- Create Ubuntu Droplet
- Basic configuration
- Set Up a Basic Firewall
- Add Swap
- Install Basics
- Install MongoDB
- Install Nginx
- Configure Nginx
- Configure Google Domains
- Configure HTTP Nginx
- Configuring Nginx to implement HTTP Basic Authentication
- SSL Certificates
- Create SSL Certificate
- Manage SSL Certificate
- Configure TLS/SSL on Nginx Web Server
- Adjust the Firewall for Https
- Configure Nginx for SSL
- TLS Version 1.3
- Clean files
- Deployment scripts
- Configure PM2
- Test Https
- Test Nginx TLS 1.2 support
- Test Nginx TLS 1.3 support
- Test TLS 1.0
- Test TLS 1.1
- Test SSL Certificates
- Verify SSL Certificates
- SSL Certificate Search
- SSL Certificates Expiry Date
- SSL Certificate Renewal
- DNS CAA
- HTTP Strict Transport Security (HSTS)
- Start MongoDB
- Cron Jobs
Create SSH Key
Let's start with SSH keys.
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
-
Create Droplet
-
Ubuntu
20.04 (LTS) x64
-
Basic: $6/month
-
Choose a data center 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
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
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
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
See 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 V16 and npm
curl -sL https://deb.nodesource.com/setup_16.x | sudo -E bash -
sudo apt-get install -y nodejs
which node
/usr/bin/node
which npm
/usr/bin/npm
node -v
v16.20.x
npm -v
8.19.x
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 MongoDB 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
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 thesites-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 thesites-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
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
halai
hangman
images
internet-resources
lightsout
linkedin
music
mygithub
nextjs
omnifood
peg-solitaire
philately
rijksmuseum
shopify
stamps
test
yahtzee
Verify Domain Configuration
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.halai.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.philately.johnvincent.io
- www.rijksmuseum.johnvincent.io
- www.shopify.johnvincent.io
- www.stamps.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 philately/html/.well-known
sudo mkdir -p rijksmuseum/html/.well-known
sudo mkdir -p shopify/html/.well-known
sudo mkdir -p stamps/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 philately/html/.well-known
sudo mkdir -p rijksmuseum/html/.well-known
sudo mkdir -p shopify/html/.well-known
sudo mkdir -p stamps/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/halai
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/philately
sudo rm /etc/nginx/sites-enabled/rijksmuseum
sudo rm /etc/nginx/sites-enabled/shopify
sudo rm /etc/nginx/sites-enabled/stamps
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/halai /etc/nginx/sites-enabled/halai
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/philately /etc/nginx/sites-enabled/philately
sudo ln -s /etc/nginx/sites-available/http/rijksmuseum /etc/nginx/sites-enabled/rijksmuseum
sudo ln -s /etc/nginx/sites-available/http/stamps /etc/nginx/sites-enabled/stamps
sudo ln -s /etc/nginx/sites-available/http/shopify /etc/nginx/sites-enabled/shopify
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/halai
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/philately
sudo rm /etc/nginx/sites-enabled/rijksmuseum
sudo rm /etc/nginx/sites-enabled/shopify
sudo rm /etc/nginx/sites-enabled/stamps
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/halai /etc/nginx/sites-enabled/halai
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/philately /etc/nginx/sites-enabled/philately
sudo ln -s /etc/nginx/sites-available/https/rijksmuseum /etc/nginx/sites-enabled/rijksmuseum
sudo ln -s /etc/nginx/sites-available/https/stamps /etc/nginx/sites-enabled/stamps
sudo ln -s /etc/nginx/sites-available/https/shopify /etc/nginx/sites-enabled/shopify
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.halai.johnvincent.io
http://halai.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.philately.johnvincent.io
http://philately.johnvincent.io
http://www.rijksmuseum.johnvincent.io
http://rijksmuseum.johnvincent.io
http://www.shopify.johnvincent.io
http://shopify.johnvincent.io
http://www.stamps.johnvincent.io
http://stamps.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
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
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, halai.johnvincent.io, www.halai.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, philately.johnvincent.io, www.philately.johnvincent.io, rijksmuseum.johnvincent.io, www.rijksmuseum.johnvincent.io, stamps.johnvincent.io, www.stamps.johnvincent.io, shopify.johnvincent.io, www.shopify.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 Nginx Web Server
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 for Https
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 detail:
Gatsby Overview of johnvincent.io
Overview of port to Next.js from Gatsby
Overview of Deployment of a Node API Server
Building and deploying MyTunes to johnvincent.io
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 Https 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.halai.johnvincent.io
https://halai.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.philately.johnvincent.io
https://philately.johnvincent.io
https://www.rijksmuseum.johnvincent.io
https://rijksmuseum.johnvincent.io
https://www.shopify.johnvincent.io
https://shopify.johnvincent.io
https://www.stamps.johnvincent.io
https://stamps.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 TLS 1.0
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
Test TLS 1.1
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=halai.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=philately.johnvincent.io
https://www.ssllabs.com/ssltest/analyze.html?d=rijksmuseum.johnvincent.io
https://www.ssllabs.com/ssltest/analyze.html?d=shopify.johnvincent.io
https://www.ssllabs.com/ssltest/analyze.html?d=stamps.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.halai.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.philately.johnvincent.io
https://www.ssllabs.com/ssltest/analyze.html?d=www.rijksmuseum.johnvincent.io
https://www.ssllabs.com/ssltest/analyze.html?d=www.shopify.johnvincent.io
https://www.ssllabs.com/ssltest/analyze.html?d=www.stamps.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
- Name:
@
- Type:
CAA
- TTL:
1h
- Data:
0 issue "letsencrypt.org"
-
0 iodef "mailto:myemail@johnvincent.io"
-
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
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";
Start MongoDB
If not running, start MongoDB
~/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