Made with DevXBlog, a free dev blog creator.

The challenges of building a blogging platform

Posted June 25, 2022 by in  Personal projectsTechnology

When I am not working on Vuuh I am building on the side a blogging platform/engine named DevXBlog, which is powering the blog you are currently reading. I did that because I wanted to have a more long-term web-accessible solution for writing my thoughts. In my old blog version, it was mostly a statically generated website with a lot of markdown and custom code at its core. To write something new, I had to power up all my development environment every time (terminal, IDE, browser, etc). It was ok for when I started writing, but after a while it became tedious and was actively discouraging me from writing.

In theory, building a blog engine should be easy: you need a web app where you have users that can create blogs, each blog has posts and pages, and they have to be publicly accessible on a public domain. Nothin' too fancy, right? Wrong!

User management is pain (painfully boring)

The first issue I ran into was the same issue I ran into multiple times: having to implement the basic user management flows. This incuded user sign-up, user login and logout, profile management (changing name, avatar, etc), confirming emails, resetting password. With the help of django-allauth I managed to implement this rather quickly (in under a week), the biggest time sink being implementing the pages for these (the functionality is easy to get, but the default templates provided by the library are plain, unstyled and unsuitable for any web app that people would want to use).

But after a week of boring work, the main features are integrated, working fine and then I could just focus on the other aspects that matter.

Deploying

Another important aspect is the deployment. How will the app run in production? How would the traffic be served to the users? How will my code reach the production environment? These were all questions that needed to be asked and answered before I write any code. Each of those answers will greately impact the overall architecture and tooling of the app.

So I decided to go for a (probably overkill) but more futureproof and familiar way of doing this: containerization + Kubernetes. I have found that Kubernetes abstracts a lot of the moving pieces of a production-ready environment while also being prepared for scaling it horizontally if needed. But the biggest advantage in my opinion of this approach is having the deployment instructions stored as code in the same repository. Having the Deployments, Services and IngressRoutes stored as code means that I can change and improve them incrementally, and at need be able to just move them to another cloud provider if needed. That means no vendor lock in, and the ability to abstract the server from the app. Managing a Kubernetes cluster is challenging, sure, but going for the managed Kubernetes service from Scaleway mitigated that risk to a degree. 

Blogs being publicly accessible

Next challenge was regarding the public accesibility of the user generated blogs. One idea I had was going for a tenancy based implementation, meaning that I would have multiple instances of the same app and the per-blog routing would be done at the infrastructure level. But developing that locally would have been difficult, and it would have made bugs more difficult to investigate and reproduce.

So I went the monolith way: a single app that gets all the requests, and tries to figure out what content to serve based on the requested domain and URL. This was the part that was easy to figure out, and the actual tricky part was making sure the publicly served traffic adheres to the current internet and security standards: is being served over HTTPS.

Serving public traffic over HTTPS means I had to get certificates for each blog I was planning to host, and that means I had to automatically generate them somehow so that they are valid and considered trustworthy by every browser. The solution for this was of course LetsEncrypt.

Managing certificates automatically at scale means multiple things: generating them on demand (when a blog is created or a custom domain is being added for a blog, their certificates need to be created, and also when a certificate is about to expire, it needs to be automatically regenerated and replaced).

By using Kubernetes, I found cert-manager to do exactly this: generate certificates on demand, store then in the cluster and allow Traefik to use them for the appropriate domains. For cases like these, using Kubernetes was a life-saver because there is a lot of tooling readily available, which are also mature, for a lot of these automation cases. 

Theming

Theming was the next problem on my checklist, a problem I am currently still working on. The most important feature all website and blog engines must have is theme support. People usually don't want their website to look the same as other 1000 websites, expecially if they were to pay for it. Wordpress has custom themes, Ghost has custom themes. All of them have support for custom themes. So DevXBlog must have too.

Being a developer, I knew that building a smooth theme development experience was a must. To encourage developers to build themes, and also enable me to build the first few themes myself, I had to create some specialized tooling to make this progress as smooth as possible.

But the app and the blog itself being template based, it means that the users that will develop themes will have to write them in Django's templating language, which also means that in the production environment, these themes would be compiled and executed in the same process as the main web app. That means, that by default, these templates would have access to a lot of information that user-provided code shouldn't have access to, such as the request, some model instances through which you can gain access to the whole database if you craft your templates carefully, being able to perform some denial-of-service by creating some kind of nasty loops, importing other libraries. 

To mitigate these, the soltution was simple in theory, but it was a pain to implement: a custom template renderer that removes the access to all the built-in context variables and just gives some controlled access to some plain Python objects that only exposes the minimal necessary information (eg. the current blog's name, description, favicon, the current post's title, content, meta tags, etc).

Conclusion

I am still working on the theming aspect, and after I finish that I plan to release this update for DevXBlog, and afterwards I'll shift my focus on acquiring users and feedback. At this phase I'll consider the MVP done, even though I don't have yet the payment integrated. But I'll just focus on aquiring users and grow the project.