On Friday I got the dreaded UptimeRobot email: your site is down. Turns out when you ignore the Oracle Always Free limits changing email, they will shut down your ~~shit~~ site. I decided that I didn't like the structure of my site, and also wanted to try code development using AI, this was as good of a chance as any to learn.
This is mostly here so that I remember what happened... but I don't think it's well written enough to actually help.
The original app lived in a big file, and over time it grew into something harder to manage. I moved it into a package structure under app/, with separate modules for:
That gave a much cleaner flow:
This was a nice improvement in itself, but it also revealed a more important lesson: the server environment has to match the project structure exactly.
I started with Gemini and uploading code files but I didn't like the back and forth, the loop really sucked with copying and pasting. So I just opened VSCode and used whatever default model they had and essentially asked it to refactor my code to whatever is better.
This worked pretty well and I think it does have a better separation, but I understand it less. Since I only update the code like yearly, I think that is ok.
When I deployed the site, the web container kept failing with import errors. At first, the obvious suspect was Python path configuration. But after checking the environment more carefully, it became clear that the deeper issue was that the refactored app/ directory was not actually on the VM in the repository state that was being deployed.
So the runtime was trying to import a package that simply did not exist in the deployed source tree.
This is the kind of problem that is easy to miss because everything can look fine from the local machine. You can have a working Flask app locally, a valid Docker setup, and still end up with a broken deployed container if the files you expect to be there are not actually in the server copy.
In short:
Once the correct files were committed and pushed, pulled to the server, and the image was rebuilt, the app started working again.
Tom is dumb and didn't git add the new folder structure before moving it to the VM.
I also had to sign up for a paid Oracle account now that the limits are lower. You just can't get a VM allocated without a paid account now, even though I remain in the free limits.
The next challenge was the reverse proxy setup. The site runs behind nginx, and nginx sits in front of the Flask application. That means the app itself must work, and the proxy must also be configured to forward traffic correctly.
The main things that matter here are:
A typical working setup looked like this conceptually:
The important detail is that inside Docker Compose, the app is usually reached by service name, such as web, not by a local port on the host machine. That is why proxy_pass http://web:8000; is the correct pattern in many setups.
Once the app was healthy, the next issue was HTTPS. The certificate setup is easy to get wrong if the folders are stale or the challenge path is not served properly.
In practice, the fix was to clear out old Let’s Encrypt state, recreate the cert files, and then restart the stack. The sequence looked roughly like this:
This was a good reminder that a deployment is a stack, not a single service. Even when the Flask app is correct, the surrounding TLS and proxy setup still has to be healthy.
I still hate/do not understand nginx. It seems like caddy might be a good replacement, and it might be my next AI-driven improvement.
AI "successfully" refactored my website, tbd if it is an improvement. It was a lot easier than doing it myself. Still, my own idiocy got in the way of a smooth experience.