Setting Up a New Blog

September 1, 2024

I’ve made multiple attempts at starting a personal blog, but they’ve all fizzled out. This time, I’m going about it by documenting everything I’m doing, and basically trying to write all the time, so I build momentum and a writing habit.

As a fun first topic, let’s walk through how I set up web hosting for my blog.

Step 1. Getting a domain

For earlier attempts, I’d already bought sbarua.com, but I didn’t want to use that domain for this attempt. It didn’t line up with my online presence elsewhere, where I’ve tended to use my full name.

So I went to GoDaddy (where I had my earlier domain), and bought srimantabarua.com.

I said no to all the extras about setting up a professional email address, I just wanted this domain for my blog. Then I went ahead and paid, and now I was the owner of my very own domain!

Step 2. Setting up hosting for my website

Since I’m a programmer, I wanted to go about this the hardest way possible. Also, I wanted to pick up some sysadmin skills along the way. So I decided to roll my own web hosting on a DigitalOcean droplet.

Step 2.1. Creating a new droplet

I’d already created a DigitalOcean droplet before for one of my previous attempts at a blog, which I’d subsequently deleted. So I already had a DigitalOcean account. For this blog, I went ahead and created a new droplet, going for the most basic option possible ($4 per month).

configuring_droplet

I already had an SSH key in my account, but that was for my old Linux laptop. I went ahead and created a new SSH key-pair for my Mac, and added the public key to DigitalOcean, so I’d be able to SSH into my new droplet.

barua ~ ssh-keygen

Then I clicked on New SSH Key in the DigitalOcean console, and pasted the public key from /Users/barua/.ssh/id_ed25519.pub in the text box.

add_ssh_public_key

Finally I clicked on Create Droplet and now I had my own VPS (Virtual Private Server) to host my website on!

Step 2.2. Creating a non-root user

I created an entry for my droplet in ~/.ssh/config so I didn’t have to remember the IP address.

Host com-srimantabarua-1
  HostName 165.232.148.254
  Compression yes

Then I SSH-ed into the droplet.

barua ~ ssh root@com-srimantabarua-1

Enter passphrase for key '/Users/barua/.ssh/id_ed25519':
Welcome to Ubuntu 24.04 LTS (GNU/Linux 6.8.0-41-generic x86_64)
...

root@com-srimantabarua-1:~#

Created a new user called barua with adduser. The CLI asks a bunch of questions which I answered. Then I also added sudo permissions for the user.

root@com-srimantabarua-1:~# adduser barua

info: Adding user `barua' ...
...

root@com-srimantabarua-1:~# usermod -aG sudo barua

Next, I had to enable SSH access for the barua user from my Mac. Since I’d chosen an SSH key during droplet created, that disabled password authentication for SSH, so I had to set up public key authentication. I already had an SSH key-pair which I used for the root user, so I just copied it for my user, and changed ownership and permissions.

# 1. Temporarily become the new user, and create the ~/.ssh directory
root@com-srimantabarua-1:~# su - barua
barua@com-srimantabarua-1:~$ mkdir ~/.ssh
barua@com-srimantabarua-1:~$ ls -al
...
drwxrwxr-x 2 barua barua 4096 Sep  1 22:15 .ssh

# 2. The default permissions are too open. Make it so only this user can
#    read, write, and exec (which for directories means permission to read
#    its contents).
barua@com-srimantabarua-1:~$ chmod 700 ~/.ssh
barua@com-srimantabarua-1:~$ ls -al
...
drwx------ 2 barua barua 4096 Sep  1 22:15 .ssh

# 3. Copy the root user's authorized keys and edit ownership and permissions.
barua@com-srimantabarua-1:~$ sudo cp /root/.ssh/authorized_keys ~/.ssh
barua@com-srimantabarua-1:~$ sudo chown -R barua:barua ~/.ssh/
barua@com-srimantabarua-1:~$ chmod 600 ~/.ssh/authorized_keys

That should be all that’s required. To test whether I can ssh in as barua, I first closed this SSH connection and tried logging in as barua.

barua ~ ssh barua@com-srimantabarua-1
...
barua@com-srimantabarua-1:~$

It worked!

Step 2.3. Configuring firewall

I’ve never used ufw before, but that’s apparently how you set up firewalls in Ubuntu server.

barua@com-srimantabarua-1:~$ sudo ufw app list
Available applications:
  OpenSSH

barua@com-srimantabarua-1:~$ sudo ufw allow OpenSSH
Rules updated
Rules updated (v6)

barua@com-srimantabarua-1:~$ sudo ufw enable
Command may disrupt existing ssh connections. Proceed with operation (y|n)? y
Firewall is active and enabled on system startup

barua@com-srimantabarua-1:~$ sudo ufw status
Status: active

To                         Action      From
--                         ------      ----
OpenSSH                    ALLOW       Anywhere
OpenSSH (v6)               ALLOW       Anywhere (v6)

Step 3. DNS Delegation

Now I had to make sure DNS lookups for srimantabarua.com would resolve to my droplet (on which I would, but still hadn’t) set up my website. I hadn’t worked much with DNS before, so I went through DigitalOcean’s resources for DNS core concepts, and also specifically on how to set up DNS delegation.

First, I went to Networking under the Manage sidebar on the left, and clicked on the Domains tab. Then I entered my new srimantabarua.com domain and clicked Add Domain.

adding_domain

Then I added an A record pointing to my new droplet. A DNS A record maps from a human-readable host name to an IPv4 address. (A AAAA record would map to an IPv6 address, but my droplet only has an IPv4 address). I set the hostname to @ to indicate that I want to map the root domain srimantabarua.com to the droplet. Then I clicked Create Record to create the A record.

adding_a_record

Finally, I had to tell GoDaddy to delegate the srimantabarua.com domain to DigitalOcean’s nameservers. I clicked on my domain, went to Domain on the left sidebar, and clicked Manage DNS near the top right.

godaddy_manage_dns

Then I went to the Nameservers tab and replaced GoDaddy’s default nameservers with DigitalOcean’s nameservers -

change_nameservers

This took some time to propagate, but after it did, I was able to look up my domain with dig from my Mac and see that it was using the DigitalOcean nameservers. So cool!

barua ~ dig +short srimantabarua.com NS
ns2.digitalocean.com.
ns1.digitalocean.com.
ns3.ditigalocean.com.

Step 4. Web server

Now that requests to srimantabarua.com would be routed to my droplet, I needed to spin up a web server on my droplet which would handle those connections. I chose to go with Nginx since it’s quite popular, so I’d have a lot of resources online on how to set it up.

Step 4.1. Installing Nginx

First, of course, I had to install Nginx.

barua@com-srimantabarua-1:~$ sudo apt install nginx

Then, I had to update the firewall to allow HTTPS traffic to port 443. Nginx configures 3 ufw applications we can use. I enabled Nginx Full so we have both HTTP and HTTPS (I’ll close this down later, maybe).

barua@com-srimantabarua-1:~$ sudo ufw app list
Available applications:
  Nginx Full
  Nginx HTTP
  Nginx HTTPS
  OpenSSH

barua@com-srimantabarua-1:~$ sudo ufw allow 'Nginx Full'
Rules updated
Rules updated (v6)

barua@com-srimantabarua-1:~$ sudo ufw status
Status: active

To                         Action      From
--                         ------      ----
OpenSSH                    ALLOW       Anywhere
Nginx Full                 ALLOW       Anywhere
OpenSSH (v6)               ALLOW       Anywhere (v6)
Nginx Full (v6)            ALLOW       Anywhere (v6)

Then, going to srimantabarua.com from my browser, I get the default Nginx page.

nginx_default_page

Step 4.2. Configuring Nginx to serve my site

I created a new directory to serve my site’s content, and transferred ownership to the barua user.

barua@com-srimantabarua-1:~$ sudo mkdir -p /var/www/srimantabarua.com/html
barua@com-srimantabarua-1:~$ sudo chown -R barua:barua /var/www/srimantabarua.com/html

Then I created an Nginx “server block” file for srimantabarua.com by copying default server block.

barua@com-srimantabarua-1:~$ sudo cp /etc/nginx/sites-available/default /etc/nginx/sites-available/srimantabarua.com
barua@com-srimantabarua-1:~$ sudo vim /etc/nginx/sites-available/srimantabarua.com

I edited the server block file to -

Added a symlink from sites-enabled/srimantabarua.com to enable the site.

barua@com-srimantabarua-1:~$ sudo ln -s /etc/nginx/sites-available/srimantabarua.com /etc/nginx/sites-enabled/

Tested the configuration file to check if everything is correct

barua@com-srimantabarua-1:~$ sudo nginx -t

Then restarted Nginx to make sure my configuration took effect.

barua@com-srimantabarua-1:~$ sudo systemctl restart nginx

I put some dummy HTML content in /var/www/srimantabarua.com/html/index.html.

<html>
	<head>
		<title>Welcome to srimantabarua.com</title>
	</head>
	<body>
		<h1>Success! The srimantabarua.com server block is working!</h1>
	</body>
</html>

Then, visiting srimantabarua.com from my web browser, I saw this content!

dummy_content

Step 4.3. Set up TLS/SSL certificate with Let’s Encrypt

So far I was only serving HTTP traffic. I wanted to change that and start only serving HTTPS traffic. But for that, I’d need an SSL certificate from a Certificate Authority (CA). Let’s Encrypt is a CA which provides free SSL certificates via their certbot CLI.

There are instructions on how to install Certbot for Nginx on a Linux system which has snap (which Ubuntu does) here. Following those instructions -

barua@com-srimantabarua-1:/etc/nginx$ sudo snap install --classic certbot
2024-09-02T00:02:37Z INFO Waiting for automatic snapd restart...
certbot 2.11.0 from Certbot Project (certbot-eff✓) installed

barua@com-srimantabarua-1:/etc/nginx$ sudo ln -s /snap/bin/certbot /usr/bin/certbot

barua@com-srimantabarua-1:/etc/nginx$ sudo certbot --nginx -d srimantabarua.com -d www.srimantabarua.com
Saving debug log to /var/log/letsencrypt/letsencrypt.log
...
Successfully deployed certificate for srimantabarua.com to /etc/nginx/sites-enabled/srimantabarua.com
Successfully deployed certificate for www.srimantabarua.com to /etc/nginx/sites-enabled/srimantabarua.com
Congratulations! You have successfully enabled HTTPS on https://srimantabarua.com and https://www.srimantabarua.com

Certbot updated my Nginx config to make http:// traffic redirect to the https:// equivalent.

Reloading the site on my browser, I see that the Not Secure marker went away, indicating my browser is using the HTTPS version.

Step 5. The actual content

In past attempts at setting up a blog, I’ve often gone for super-hard mode and tried writing everything in HTML. As you can guess, that’s a really bad idea. I’d much rather write in Markdown and have the HTML generated for me. That’s what I’m doing this time. I’m looking at Hugo, which is a static site generator.

Of course, the Hugo quickstart guide has us installing themes and stuff, that we don’t need, and which just abstracts away what’s really going on. I found this post which talks about the bare minimum that’s needed to get a site up, which I found quite helpful.

The Hugo documentation is actually quite extensive, and I was able to hack together some HTML templates and some CSS, and arrive at what I have now.

Conclusion

This was actually quite the educational experience. I’m especially happy that I took loads of notes, so I won’t have to re-learn all of this again the next time I’m setting up a blog … shudders (I really hope that doesn’t happen). Now, all I have to do is keep writing regularly, and it’ll all be fine.

References