Five lessons from running our own platform in production

OwnSites is the platform our customers' websites run on. It builds the sites, hosts them on their own domains and handles their forms, bookings and blogs. Running it ourselves, every day, has taught us more than any architecture diagram. Here are five lessons we now build into every app.
1. Right-size the server before it hurts
For a while the platform ran on a small cloud server. Everything worked, until the load started climbing well past what the machine could handle and free memory dropped close to zero. Nothing had failed yet, but one more spike could have taken every hosted site down with it.
We moved to a larger server, added swap space as a safety margin and set up a weekly report on memory, CPU and disk. The change took a few minutes of downtime and roughly doubled a small monthly bill. Lesson: watch the numbers before your customers notice them.
2. Never stack heavy jobs on one small machine
Once, a deploy ran at the same time as a heavy one-off job on the same server. Several copies of the app started at once, the server ran short of memory and the container system itself stopped responding. Every hosted site was unreachable until it was restarted.
Now we check that nothing else is running before we deploy, and we keep heavy one-off work out of deploy windows. Lesson: on a small machine, one thing at a time.
3. Keep slow work off the request
Our blog generator once made three AI calls while the person who clicked "Generate" waited: writing the post, tagging it and creating its image. The image alone took most of a minute. Together they took about 53 seconds, uncomfortably close to the server's 60-second limit for a single request, and on the live server the browser was left waiting on an answer that never came.
We moved image generation and tagging into background jobs. The post now appears in seconds and the image follows. Lesson: never put more than one slow call between a click and its response.
4. Serve images from one shared CDN
Images used to be streamed through the app itself, which meant every photo on every customer site took up the same workers that answer page requests. We put one shared content delivery network in front of the images for every site. Image requests stopped tying up the workers that answer page requests, and the app now serves an image only when the CDN doesn't already have it.
Lesson: let the app do app work, and let a CDN do what it is built for.
5. Check real customer sites, before and after every deploy
A health check that says "the app is up" is not the same as "every customer's site loads". Before and after each deploy we load the home page of every customer domain we host, along with its robots file and sitemap, and a deploy isn't done until every one answers.
Lesson: test what your customers see, not what your server reports.
What this means for your app
None of these lessons needed an enormous system. They needed attention: watching the right numbers, doing one risky thing at a time and testing from the customer's side. That is the habit we bring to every app we build and run.