Public Web App Deployment
Claude Code is helping a ton with this refactoring. I am just giving it the idea on what to do, and it's implementing it. Fucking OP.

The main goal of this project is to create a system where I can run multiple services to a single VM using docker compose. Each service can be mapped to a different domain/sub-domain, but since it's the same VM, IP will be the same. I will need a reverse proxy that will take these requests and route to the respective service.

I have something similar on my home server using Caddy as the reverse proxy and TailScale as the "VPN" provider so that I can access the server from outside my house. Even that is not configured I think to my liking, and deserves to be looked at again.

Goal

  • Extensible structure to be able to easily serve multiple applications over HTTPS.
  • SSL Certificate generation should be in-built

Work Log

2025-08-17

Using Claude Code, I got the original personal-bookmark-manager repo updated to have a much more cleaner approach to deploying services. It generated such great output that I was shocked for a few seconds. Just asked it to create the nginx config and some dummy services to test out the implementation and boy oh boy. It created one simple static site as a service (Directly served from nginx) and one nodejs server. Both of these services had amazing landing pages, configured health checks, etc.

Fucking amazing, really.

When I wake up, I'll see if I can spend some time to configure LinkAce or LinkDing as one of the services. I'll use Claude Code only. It's really fun and kinda lets me do other things too.

Morning of 17th

I am now up, and kinda ready to go.
I'll first deploy the new repo as is and bind 2 domains to it through CloudFlare.

Had to make a number of changes in the nginx config to have it run first with HTTP so that LetsEncrypt can provide me the certifications. If I start nginx first only with HTTPS, then because there are no certs, it goes in a crashback loop. Restarts a lot. Hence, to get SSL working, the reverse proxy has to run in HTTP mode first. Once the certificates were provisioned, I got Claude Code to make the SSL versions again and re-deployed with SSL enabled.

And it all.. worked. I've got 2 applications on the same VM served through different sub-domains (https://bookmarks.hamzamoiyadi.dev & https://notes.hamzamoiyadi.dev). I think there's only 1 step remaining and that is to figure out if there's a way to have both https and http versions running at the same time, but the http version should only be accessible when doing the LetsEncrypt stuff.

Claude Code has given a cron statement that i've added the GCP VM.

 0 12 * * * cd /home/hamza.moiyadi/public-webapps && docker compose run --rm certbot renew --quiet && docker compose exec nginx nginx -s reload

This basically means "Every day at 12:00pm, navigate to the /home/... directory, and run the certbot container through docker compose with the command to renew certificates. After that, reload the nginx reverse proxy container". Didn't really like this coz I don't want nginx to reload everyday. Idk, doesn't sit right with me.

Got the edited version here:

0 12 * * * cd /home/hamza.moiyadi/public-webapps && docker compose run --rm certbot renew --quiet --renew-hook "docker compose exec nginx nginx -s reload"

The --renew-hook option on the certbot container runs the command in double quotes ONLY if the certificates are actually renewed.

All that's left now is to check again every few days to see if everything is working fine, and do certificates renew after 90 days or not[1].

We Done 😁

  1. LetsEncrypt certs are valid for upto 90 days. â†Šī¸Ž