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).
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.
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.
- An Introduction to DNS Terminology, Components, and Concepts
- Point to DigitalOcean Name Servers From Common Domain Registrars
- How to Create, Edit, and Delete DNS Records
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
.
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.
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.
Then I went to the Nameservers
tab and replaced GoDaddy’s default nameservers with DigitalOcean’s nameservers -
ns1.digitalocean.com
ns2.digitalocean.com
ns3.digitalocean.com
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.
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 -
- Change document
root
from/var/www/html
to/var/www/srimantabarua.com/html
- Change
server_name
from_
tosrimantabarua.com www.srimantabarua.com
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!
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
- An Introduction to DNS Terminology, Components, and Concepts
- Point to DigitalOcean Name Servers From Common Domain Registrars
- How to Create, Edit, and Delete DNS Records
- How To Set Up Nginx Server Blocks (Virtual Hosts) on Ubuntu 16.04
- How To Set Up Let’s Encrypt with Nginx Server Blocks on Ubuntu 16.04
- Really getting started with Hugo: four simple steps
- Hugo Documentation