Preparing and hosting a personal blog

Introduction

I wanted to gather my struggle into a blog post while I set up Apache proxy. Firstly, I’d like to clarify why this is needed in the first place. I always wanted to have some kind of domain where I can host my work, my blog and probably an about page, well, about myself. Although I wasn’t sure which platform I should prefer. I could have always preferred Twitter (as always) but I don’t think it exactly fulfills my needs. After some thought process, I just picked Wordpress as my blogging platform. But I never felt comfortable enough to write over there. I keep wanted to have freedom to style, and to program, along with blogging. After all, I am a programmer.

Running into Jekyll was pretty comforting for me as it offered the features I needed. Then I found out it is pretty popular between other developers as well. I also learned that GitHub Pages is powered by Jekyll. At that time, I did not really have to spend more time. This was a suitable platform for me.

Apache proxy

I already have plenty of experience in Apache proxy, just not an expert on it. It is already one of the most popular proxy tools of all. And I just said, why not use it for yourself. It’s nice that other blog/website services abstracts this kind of stuff automatically from you but as I mentioned I do not intend to do just blogging here.

I did not know about the limits of what I what I wanted to do just yet. Addressing and figuring them out were a challenging task by itself. I experienced plenty of non-technical frustration on my end. After all, I decided to start small then expand gradually.

There was several steps of back and forth about setting different versions of proxy configuration. I already expected this will consume some of my time as I was exploring my options, so this is okay. I’d like to clarify some of those steps, and some of my output to leave them as a footprint. This probably will not be useful to anyone directly, but indirectly, it might be good to show how to approach to a problem.

Problem #1: Determine domain name scheme

My main idea was not directly to work with the domain tacalan.com but rather have as many subdomains as I want to have, example: ozan.tacalan.com. Personally, I find it more appealing to have subdomains forming some kind of meaning, like a domain that represents full name, or a domain name which is self explanatory. Another benefit for me, I can also offer more tools, products, demos, experiments and in the end I would have a naming convention that applies to all my subdomains. One downside I see, it might be confusing for anyone else but on the other hand I am not building a commercial product here, so I would say it’s fine.

Approach #1

My initial approach to host tools was to host everything under tools.tacalan.com/app1 style domains. But it apparently become much more challenging task to achieve when it comes to dynamical apps that require backend server to run. Some of the apps I want to host might be designed to work under fixed root path / and in such case I have to cover all the paths of this app in proxy config, or hack the app to make it use relative paths. I did not want to do over engineering simple tasks in the first place.

Consider another app hosted in tools.tacalan.com/app2 is also using fixed path / and both apps want to request /js/dependency.js. This may be a problem if two dependency.js files being referred are different versions and/or are not compatible, or even, it may refer to whole other dependency with the same name. It can easily deviate from being a fun pet project to being an annoying issue.

After I identified this as a growing problem, I switched to approach #2.

Approach #2

Basically take advantage of wildcard certificate and use as many as subdomains you like. But limit this to dynamic apps (described in approach #1) and independent apps. It is probably unnecessary to host every little app in its own domain name. Here is a general layout of domain name scheme:

tacalan.com => redirects to ozan.tacalan.com for the time being
ozan.tacalan.com => personal blog
tools.tacalan.com => host some tools
tools.tacalan.com/app1 => static app1 hosted under same domain
tools.tacalan.com/app2 => static app2 hosted under same domain
app3.tacalan.com => host dynamic app3
app4.tacalan.com => host dynamic app4

Approach #3

For a moment, I just thought why not change the domain name scheme to double wildcard domains, example: *.*.tacalan.com. This way, I could convert domain names as following:

app1.tools.tacalan.com
app3.tools.tacalan.com
app4.tacalan.com

I found out this is not very popular, has its own risks, certification is harder to manage. It also started to feel like this was too much for human eyes. Certbot tool I used, see create certificates section, also was not supporting this type of usage anyway.

# Information from certbot
Additionally, the asterisk can only be substituted by a single label and not by multiple
labels. For example, the name hello.goodbye.example.com will not be covered by a certificate
including only the name *.example.com. It will be covered however, by *.goodbye.example.com.
Note that a wildcard name can not contain multiple asterisks. For example, *.*.example.com
is not valid.

I decided to stick with approach #2 after all.

Problem #2: httpd.conf

There is a certain learning curve to get into understanding about Apache proxy. Some parts are not the way you just assumed, some parts handled totally in different places, debugging and understanding logs are also another important milestone for someone who just wants to get it done. All of these points (and probably more) take more time than you initially estimated (most definitely), especially if you are in my position who wants to test multiple approaches to determine which one suits best for your use case. But good news is that, you end up with a stable, easily copyable configuration for your setup.

Pitfall #1: It’s modular

Apache proxy is modular where you can enable/disable a lot of modules depending on your use case. If you are already familiar which proxy commands you want to use in your configuration, it still may not be obvious which modules should you enable in the first place. Even if you enable that certain module and expect proxy to work, it may depend on another module which puts you in a difficult position to determine if your config is incorrect, or if your modules are missing, or if it relates to something else. My suggestion is try to add config as little as possible at one time, and test to see if it works fine.

Pitfall #2: Only the first match is executed

If you have configurations that overlap with each other (e.g. directories like /directory and /directory/details), Apache proxy starts executing your rules from top to bottom in the file. In case of a match happens, your next matching rule will not be executed. This puts you in a position about how you should define your rules. Answer is from the most detailed to most general. In given example, correct order should be /directory/details and then /directory.

You should also consider modular aspect as described in pitfall #1. Another module/config file may already define the rule you defined. If those are executed first, that might explain why your rule is not executed at all. The entry point for all of these configuration files is httpd.conf file, so you should retrace your steps and check, in which order the configurations are executed, or if any other configurations are included from another file.

Pitfall #3: Preserve modularity

If you want to include multiple configurations, you probably should not put everything into one file like httpd.conf but rather preserve the modular approach of Apache proxy. One of the popular approaches to this is to create another directory next to conf directory (where httpd.conf file is located in) called conf.d and add any number of conf files you want. You can even have more directories inside conf.d. Don’t forget to include all conf files in this directory to your Apache setup though. You can add following to the bottom of httpd.conf file to achieve that.

Include conf.d/*.conf
Include conf.d/**/*.conf

I said to the bottom, this means your configurations are considered the last which is generally okay, in case you want to change any prior rule you can of course do that.

Pitfall #4: Restart on each change

Any change you do in Apache proxy requires a restart to reflect the changes.

Pitfall #5: Enable HTTPS

Setting up my own virtual host with port 443 configuration was simply not enough.

<VirtualHost *:443>
    ServerName ozan.tacalan.com
    SSLEngine on
    SSLCertificateFile server.crt
    SSLCertificateKeyFile server.key
    ...
</VirtualHost>

During my setup from nothing, it was not clear to me to include a line Include conf/extra/httpd-ssl.conf inside httpd.conf file along with enabling required modules. This is not mandatory because you can just copy contents of httpd-ssl.conf to your own config file. But it’s a good practice to borrow default configurations because you might skip some important parts by accident. You might end up a configuration which does not run, or even misconfigured environment potentially leading to more dangerous problems.

See create certificates section to know more about how to create server.crt and server.key files.

Create certificates

Self-signed certificates (not secure):

I usually use following setup to create certificates for my development environment.

# Generate a private key
openssl genpkey -algorithm RSA -out server.key
# Generate a certificate signing request (CSR)
openssl req -new -key server.key -out server.csr
# Generate the self-signed certificate that is valid for one year
openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt

You just need to trust your certificate to work your way around. For a long term local usage to make everything look even nicer, you can create a dummy certificate authority (CA) and mark that CA as trusted in your OS/browser. Then you sign the certificate with that CA. This leads to trusting any certificate signed by that CA automatically.

Sign certificate with trusted CA (secure):

I followed the most straightforward approach here and used certbot tool to create secure certificate from Let’s Encrypt. Certbot is a client that helps users obtain and manage SSL/TLS certificates from Let’s Encrypt, which is a CA that provides free certificates to enable HTTPS on websites. Certbot simplifies the process of obtaining and renewing these certificates. Certbot also supports star certificate (wildcard domain as described before). Here are simplified steps:

# Install certbot and its python Apache addon first
apt install certbot
apt install python3-certbot-apache

# Use additional flags because we typically need to use a DNS-01 challenge, which requires
# us to create a specific TXT DNS record to prove ownership of the domain
certbot -d "tacalan.com,*.tacalan.com" --manual --preferred-challenges dns certonly
# Please deploy a DNS TXT record under the name and value:
...
# Press Enter to Continue
# Please deploy a DNS TXT record under the name and value:
...
# Press Enter to Continue

# (This must be set up in addition to the previous challenges; do not remove,
# replace, or undo the previous challenge tasks yet. Note that you might be
# asked to create multiple distinct TXT records with the same name. This is
# permitted by DNS standards.)

# Before continuing, verify the TXT record has been deployed. Depending on the DNS
# provider, this may take some time, from a few seconds to multiple minutes. You can
# check if it has finished deploying with aid of online tools, such as the Google
# Admin Toolbox: https://toolbox.googleapps.com/apps/dig/#TXT/...
# Look for one or more bolded line(s) below the line ';ANSWER'. It should show the
# value(s) you've just added.
# Press Enter to Continue

# Successfully received certificate.
# NEXT STEPS:
# - This certificate will not be renewed automatically. Autorenewal of --manual
# certificates requires the use of an authentication hook script (--manual-auth-hook)
# but one was not provided. To renew this certificate, repeat this same certbot command
# before the certificate's expiry date.

We just have created a certificate signed by Let’s Encrypt (secure CA) which is valid for 90 days. As you also noticed, it is possible to automate this process via certbot cron job. But for my use case, I did not do it as I am required to use DNS-01 challenge in next time as well. If you have achieved a straightforward way to do it let me know! You can delete TXT DNS records when certificate is created by the way.

Hetzner

I use Hetzner as my hosting platform which I find trustworthy, reliable, and cheap. It has a straightforward portals to manage your configurations. My subscription also offered out of the box Wordpress server which is managed by Hetzner and is accessible using konsoleH panel. When you create a subdomain, you can also create and assign SSL certificate to it. Very convenient, all happens in browser UI. The problem here arose for me, I decided not to use Wordpress and anything that comes with it. I wanted to have full control and have a basic setup.

Problem 3: DNS record management

With Hetzner default configurations, it automatically creates necessary DNS records to resolve your subdomain to Wordpress server which is accessible via konsoleH server. The problem is konsoleH server is a different server with different IP than my own server. It’s probably because it’s a separate setup and allows Hetzner to maintain Wordpress server on your behalf without breaking anything on your own server. But anyway, this was surprising when I first encountered. Thankfully, they also offer DNS management console where you can modify existing DNS records or create your own to resolve correct values. This way, you can by-pass default configurations. Honestly, this was way more simpler than I anticipated. There was no problem and it just worked on first go.

Pitfall #1

If you are changing DNS records frequently in little time, the change may not be reflected to DNS server you use in little time. You might just think you did something wrong and the DNS record is just not working. But in reality DNS server requires to update its own records first to correctly resolve DNS you provided to a value (e.g. IP address). So, rule of thumb: Just wait for a few minutes. It hopefully will just work. Even better, do not change DNS records too often, otherwise you might have to wait minutes/hours to test your changes.

Pitfall #2

Each browser’s behavior may be different when it comes to resolving DNS. Some offer more strict approaches to provide more security, others may just use OS configuration. So it might not be a great idea to debug your DNS problems directly in browsers. Using other helper tools can be more helpful.

Helper tools

Google Dig:

I found Google Dig DNS lookup service superior during my debugging process. Changes were almost always reflected immediately. Most of other DNS lookup services were not really updating their records even after 10-15 minutes. One strange issue about Google Dig is that, it keeps the DNS even after you delete them. My guess is, it relates to TTL (time to live) property of the DNS record. It will not delete or update until TTL is reached because of caching purposes.

nslookup:

Another helper tool I benefited was nslookup. It allows to quickly look up given domain name, change DNS server, change log level for debugging purposes.

nslookup ozan.tacalan.com
nslookup ozan.tacalan.com 8.8.8.8 # Uses given DNS server - which actually helped in my case because browser were not able to resolve at that time due to not synched DNS server

WinSCP:

To be honest, I knew I needed some kind of SFTP client with some UI to fasten things up. Using terminal required a lot of repetitive copy paste work which was annoying after some point, and need I say error prone.

I searched clients based on Windows and once again witnessed the clear gap about how development tools on MacOS is still ahead. But especially in recent years, Windows achieved great improvements and I demand even more, let’s lose the gap! I searched online for some options and even the some appraised clients seemed fishy to me which was annoying. I hope those fishy programs will just disappear and recognized as threats. Anyway coming back to my research, I decided to check Microsoft Store and I find a gem, WinSCP. I decided to use paid version because it seemed good enough and luckily I did not need to think about it again. It is as good as one would expect, I highly recommend it.

Conclusion

This post was a first and an interesting journey for me. For the first time, I set up a blog and host it leveraging my skills and creativity. Every problem I faced led to new discoveries and solutions, creating a cycle of learning without losing my focus. But in the end it was a pleasure from my side, because now I have a running blog, a proxy I can host anything and I can even replicate its logic in professional context from now on. Overall I would say, one should not forget such journey that enhance talents further and open doors to a broader skill set.

Keep on keeping on!