New hosting
The day has come and I have to say, it wasn't as painful as I was fearing. The Gray Matter blog is now running on Google's Cloud Platform, and the results are really encouraging so far. In this post, I'm going to explain how I shed my old school hosting provider and embraced "the cloud"!
First of all, some prerequisites:
You need a Google account. Gmail/Youtube/etc...all that stuff requires a Google account, so for most of the population, this is covered.
You need a basic understanding of how a "LAMP" stack works (Linux, Apache, MySQL and PHP). For this blog, I skipped the MySQL and PHP as I don't use them.
Comfort on the command Linux line.
This is basic knowledge for most entry-level system administrators and web developers so, there's nothing particularly onerous or new here.
For this blog I had a few design goals in mind, which I'm pleased to say I've tackled and will document the steps involved:
Run a modern Linux distribution (Debian 10 in my case)
Automate most of the ongoing management
Host it locally (in Australia)
Keep it lean!
The high-level process is:
Spin up a virtual machine with your preferred operating system.
Get remote shell access (either
gcloudorssh)Configure Apache
Configure DNS
Set up SSL via letsencrypt.org
Redirect non-encrypted requests to
https
1. Virtual Machine Setup
Firstly, the whole process of setting up a LAMP instance on Google Cloud Platform has been done to death and I simply worked from the wonderful guide published by Chris Titus (thanks Chris!). Keep in mind, I didn't install the tasksel package or any of the MySQL and PHP stuff; no need for a static site like mine. In Chris' process, I skipped steps 3, 5 and 6.
When setting up I selected a local zone australia-southeast1-b. Latency went from ~400ms to my existing provider (in Utah, USA) to ~15ms at Google in Australia! WIN!! Of course, the opposite is also true; latency for USA visitors just went up. 🤷🏻♂️
If you're running MacOS with Homebrew on your desktop, you can easily install the Google Cloud command line tools by running:
brew install google-cloud-sdk
Now you can use any gcloud commands suggested in Google's Cloud Platform or other sources etc.
The whole setup process took about 10 minutes and in the end I had a basic Debian 10 system running Apache with remote access via gcloud beta compute --project "project-foo" ssh --zone "australia-southeast1-b" "my_vm_name"..but that's a realy ugly command line. Lets make it better with plain old SSH!
2. Remote Shell access
Your freshly-minted virtual machine will have a public IP address and you can access it with Google's gcloud command line tool (as explained in Chris Titus' documentation), or with a little effort, you can copy your existing public ssh keys to the VM and use standard tools like ssh and rsync etc.
To accomplish this simply:
copy your existing public key(s) to the clipboard
log into your VM with
gcloudcommand line tooledit the
~/.ssh/authorized_keysfile on the VM and paste your key(s)log out
You can now log into your VM by simply:
ssh user@111.222.333.444
Where user is the username you configured for your VM and 111.222.333.444 is the public IP of your VM.
2.1 Tightening up shell access
Now you have access to your remote host via SSH. Unfortunately everyone else on the Internet can also try to log in too. The good news is, Google's default images have a tight SSH configuration out of the box and deny password based authentication; key based authentication only! Nice work Google!
However, the SSH daemon runs on the standard port of TCP/22 and as a result is a big target for script kiddies. You can relocate the daemon to run on a non-standard port, but in my experience this of limited used. Instead, I simply leave it on the standard port and install SSHGuard via Debian package:
sudo apt install sshguard
The defaults for SSHGuard are suitable for most hosting arrangements, but if you regularly connect from a static IP (home/office/etc) add that IP to the /etc/sshguard/whitelist file. For instance, if your static home IP is 444.333.222.111 you would add the following line to the SSHGuard whitelist:
444.333.222.111/32
These lines a are simply a single IP or network range in standard CIDR notation.
3. Configure Apache
The best bit about Apache is that its been around forever, and there's a LOT of documentation. The worst part about Apache is that its been around forever, and there's a LOT of (bad/outdated) documentation. However, for my purposes I'm running a single website with a few aliases and that setup is about as basic as it gets.
Here's the high-level steps
Create a directory for your content
Set appropriate permissions
Tell Apache to use your new directory
3.1 Creating a new directory and set permissions
This bit is simple. I usually create a directory with the site name or domain to make it easy to manage:
sudo mkdir /var/www/gray.net.au sudo chown root:adm /var/www/gray.net.au sudo chmod 2775 /var/www/gray.net.au
Those three commands create a directory and then set the permissions so that root and anyone in the adm group can create/edit and delete files and directories under /var/www/gray.net.au. The mode I use (2775) also sets the group ID bit so NEW files/directories created will be assigned the adm group.
For a static HTML site, the permissions for Apache only require that the web server process can read the files. So it really doesn't matter what user or group "owns" the file/directory as long as Apache can get to it. This is important to understand as your SSH login logs you in, not the Apache process user, or root etc. By keeping the permissions under my own user name and a group I'm a member of, I don't need to do any special SSH magic or post-upload scripting to set the permissions correctly.
3.2 Telling Apache how to serve my new site
The documentation Chris Titus put together covers most of this in step 4, so I wont go over it in too much more detail here, but I'll show you a few Apache rewrite tricks to make things more consistent in the next section.
BEWARE - Before you move to the next section, you need to understand if you have an existing website, the DNS changes will send all your visitors to the NEW setup on Google Cloud Platform. If this is NOT what you want, then DON'T CHANGE YOUR DNS SETTINGS!! You may want to configure a sub-domain (eg, test.mydomain.tld) but that is beyond the scope of this document.
4. Configure DNS
The Domain Name System is how everyone on the Internet finds your site; it's how a host name (web site) is translated into an IP address which you computer can actually use. Depending on your DNS hosting provider, you may want to set up a few addresses to point at your new Google Cloud Platform host.
I don't intend covering all the different record types in DNS but here's the key ones you will probably want to set up:
An
Arecord forwww.yourdomain.tldpointing to the Google Cloud public IP.An
@record foryourdomain.tldpointing to the Google Cloud public IP.A
CAArecord to nominate your SSL certification authority (not all DNS providers support this one yet)
The way these records look in your DNS provider's system could vary considerably. So here's how they look according to DNS after they are configured:
# Resource TTL Type Target www.yourdomain.tld. 120 IN A 111.222.333.444 yourdomain.tld. 120 IN A 111.222.333.444 yourdomain.tld. 300 IN CAA 0 issue "letsencypt.org" yourdomain.tld. 300 IN CAA 0 issuewild "letsencrypt.org"
Basically, this sets us up for the next step of configuring SSL/TLS in Apache with letsencrypt.org and also makes the site accessible via either http://www.yourdomain.tld OR http://yourdomain.tld.
4.1 Rewriting requests for fun (and profit?)
A lot of sites (mine included), are dropping the "www" prefix in favour of the plain domain. Apache can make your site more consistent, by sending all requests for "www.yourdomain.tld" to the short-hand "yourdomain.tld". To do this, we'll take advantage of Apache's rewrite module, which should be enabled by default in Debian 10. If not, you can enable it:
sudo a2enmod rewrite
After this, add the following to your /etc/apache2/sites-enabled/yourdomain.tld.conf inside the <VirtualHost *:80> section:
RewriteEngine on
# Redirect www.yourdomain.tld -> yourdomain.tld
RewriteCond %{HTTP_HOST} ^www\.(yourdomain\.tld.*)$ [NC]
RewriteRule ^(.*)$ http://%1/$1 [R=301,L]
Then reload Apache:
sudo systemctl restart apache2
Now when a visitor goes to http://www.yourdomain.tld their browser gets told to try again on http://yourdomain.tld. This is accomplished with a "permanently moved" redirect. Try it for yourself 🙂:
>curl -I http://www.gray.net.au <-- try the www address HTTP/1.1 301 Moved Permanently <-- get told its moved Date: Mon, 02 Dec 2019 00:58:22 GMT Server: Apache/2.4.38 (Debian) Location: http://gray.net.au/ <-- use this address instead Cache-Control: max-age=600 Expires: Mon, 02 Dec 2019 01:08:22 GMT Content-Type: text/html; charset=iso-8859-1
5. Setting up encryption with letsencrypt.org
By now, you should be able to access your new site by both http://www.youdomain.tld and http://yourdomain.tld. If not, STOP HERE, go back and fix up your DNS/Apache configurations. The letsencrypt.org process implements some validation steps that will fail without your site working. There are ways around this, but I'm not covering them here; path of least resistance.
The easiest way to configure a free SSL certificate with letsencrypt.org is to use the certbot tool. This will configure Apache, generate and install the certificates etc, and keep it all updated for you.
In my case I simply ran through the instructions for installation on Debian 10. If you're running a different Linux distribution tweak the drop-downs at the top of the page next to "My HTTP website is running...".
5.1 Fine tuning ciphers and protocols
Unfortunately, certbot does a pretty awful job of configuring the encryption in Apache and allows a whole raft of really poor ciphers and protocols (notably TLS 1.0 and TLS 1.1). You don't want them.
There's actually 3 files you need ensure have the same directives, which is a pain. Or you could simplify this task by ripping all the directives out into a single file, then include that file from the 3 locations. I went the latter path.
Create a new file
/etc/apache2/my-ssl.conf-
Populate the file in #1 with the following:
SSLProtocol -ALL +TLSv1.2 +TLSv1.3 SSLOpenSSLConfCmd Curves X25519:secp521r1:secp384r1:prime256v1 SSLHonorCipherOrder On SSLCipherSuite ECDH+AESGCM:ECDH+CHACHA20:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:RSA+AESGCM:RSA+AES:!aNULL:!MD5:!DSS:!AESCCM
-
Remove those 4 directives from the following files and replace with
Include /etc/apache2/my-ssl.conf:/etc/letsencrypt/options-ssl-apache.conf/etc/apache2/sites-enabled/yourdomain.tld-le-ssl.conf/etc/apache2/mods-available/ssl.conf
So basically, you now have a common point to fine-tune the encryption for Apache. Make sure you only have the Include /etc/apache2/my-ssl.conf ONCE in each of those files and the 4 directives it defines DO NOT appear anywhere else in the files listed in 3(a-c).
Assuming the configuration is still sane, you can now restart Apache and enjoy your encrypted site!:
sudo apachectl -k configtest sudo systemctl restart apache2
5.2 Sending all traffic to the encrypted site
Congratulations! If you've made it this far, you're nearly done. Lets close out the possibility of someone accidentally going to the unencrypted version of the site by leveraging another Apache rewrite rule!
Edit the /etc/apache2/sites-available/yourdomain.tld.conf file again, and add the following BELOW the rewrite rule we added 4.1:
# Send everything over HTTPS
RewriteCond %{SERVER_NAME} =yourdomain.tld
RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=permanent]
Assuming the configuration is still sane, you can now restart Apache and enjoy your FULLY encrypted site!:
sudo apachectl -k configtest sudo systemctl restart apache2
Test it for yourself 🙂
>curl -I http://gray.net.au <-- requested the unencrypted site HTTP/1.1 301 Moved Permanently <-- told its moved permanently Date: Mon, 02 Dec 2019 01:42:40 GMT Server: Apache/2.4.38 (Debian) Location: https://gray.net.au/ <-- use the encrypted site instead Cache-Control: max-age=600 Expires: Mon, 02 Dec 2019 01:52:40 GMT Content-Type: text/html; charset=iso-8859-1
Voila!
Comments
Comments powered by Disqus