Self-hosted cloud infrastructure v4

Self-hosted cloud infrastructure v4
Photo by Taylor Vick / Unsplash

I've been working steadily towards replacing conventional big-tech services like Google Drive, Photos, etc. with open-source self-hosted alternatives for around 3 years now. Why? The better question is, why not? From going beyond the storage limits and subscription-based payment model for each useful service – to having more control over your data along with various custom configurations and workflows, are only possible with self-hosted approaches.

However, it's both complicated to setup and maintain as well as requires you to have your own hardware (or rent a VPS). For me, I just like doing things myself, as it allows me to develop my skills and learn new things. I have a multi-server configuration which uses a cheap VPS with a dedicated IP address as a proxy server and an old laptop running the heavier services with more private data at home, more on that later.


v4?

The current version is the 4th iteration of my cloud, the first version was a very simple all-in-one Nextcloud Docker container, launched directly with docker run. The second version moved everything to Docker Compose, while adding an Nginx reverse-proxy which also served my old portfolio, which was a static site.

The third version was the first step towards proper standardization and security, as well as adding more useful services. It used Dashy for the dashboard, added Authelia for authentication and access control and Ghost for my portfolio site, a mailserver, and various new services like Immich (Google Photos alternative), Seafile (Google Drive alternative), Caddy (as both reverse-proxy and for serving sites), etc. This still had it's pain points and flaws which caused me to eventually work towards the current implementation. By this time, I was renting an expensive VPS which also made it economically nonviable.


Changes and improvements in v4

This iteration focused on various quality-of-life improvements and security considerations for services with open API endpoints (for client applications). I replaced Caddy as my reverse-proxy from the last version with Traefik, which allowed me to have a much more flexible setup after getting past the initial learning curve.

I put the resource-heavy services like Immich and Kasm Workspaces as well as private services like Vaultwarden on my home server, and made it accessible through Tailscale – a mesh VPN which utilizes Wireguard behind-the-scenes. By default, Tailscale uses their own control servers for configuration and device management. I added Headscale (open-source Tailscale control server) as a replacement since I'm going the self-hosted route anyway.

The VPS and home server communicate over the internal Tailscale network. This makes it easier to access the services on the home server without having to deal with various complications, such as getting a dedicated IP address from my ISP, setting up port forwarding, etc. This also allowed me to limit access to all the services which had companion client apps behind Tailscale, making them publicly inaccessible and reducing the entrypoints.

Below is the general architecture of cloud v4:

Account provisioning was moved to lldap – an LDAP server, which integrates authentication with Authelia. Previously I just used Authelia's built-in SQLite DB for this purpose, which made it difficult to modify passwords or add new users. Authelia handles authentication for the majority of the services through Open ID Connect (OIDC), effectively functioning as a Single Sign On (SSO) similar to "Sign in with Google", but for my self-hosted services. I also enabled the TOTP 2FA provider which improves overall security for authentication.

The heavy lifting of all this complex network configuration was handled by Traefik, which is my preferred reverse-proxy because of the sheer number of configuration options and flexibility it provides.

Traefik allows me to easily define endpoints, by defining service:port and the subdomain it's to be served on, Traefik automatically performs the routing and even enables zero configuration HTTPS. I have a rate limit defined to limit load on the services and forwardAuth middlewares which includes Authelia and a Crowdsec bouncer for dealing with malicious traffic. Crowdsec is an open-source and participative security solution which offers crowdsourced protection against malicious IPs, and essentially acts as a smarter Fail2ban as well.

Another addition to this iteration is the Grafana-Prometheus observability stack, which allows me to monitor and setup alerts for my servers. The alerts are delivered through Gotify – a lightweight notification server along with client apps to send push notifications. The data collection is handled by various services like CAdvisor, Node Exporter, etc.

The final addition was service uptime monitoring and reporting with Uptime Kuma, an open-source uptime monitor which integrates with Docker and offers various service monitoring and notification options. Whenever any service goes down, I'm immediately notified through Gotify.


Conclusion

Self-hosting is complicated – it requires constant learning and monitoring. Server maintenance has varying levels of difficulty. It can be as simple as pulling a new image and restarting a container. It can also be increasingly convoluted, like a package update causing networking issues and nothing appearing out-of-the-ordinary on a surface level glance.

Self-hosting my own cloud infrastructure helped me learn many new things, from advanced networking concepts to integrating various services to form a coherent authentication and authorization subsystem.

Overall, it's the quality-of-life improvements that make it worthwhile. It might be something small like aggregating the various blogs I read in one place and notifying me when a new post is published, or something which significantly affects browsing the internet – such as DNS level tracker and ad-blocking.

Thank you for reading!