Your new data center is a Dell tower from 2017. It lives under the office manager's desk, next to a space heater, on the same power strip as a mini-fridge. The label on the front says "DO NOT TURN OFF" in three kinds of tape. This is where the inventory app you just built is going to live, because the client's insurance paperwork says their data does not leave the building.
Welcome to on-prem. For a certain kind of FDE engagement, docker deployment on premise client server hardware is not a retro curiosity. It is the job.
Here is the direct answer. You deploy onsite with a boring, self-contained stack: Docker Compose, a handful of containers, named volumes, automatic restarts, and a backup routine you have actually tested. Updates go out as tagged images, never "latest," and every deploy has a rollback path. The goal is a system so dull that the client's biggest crisis is forgetting it exists.
Why on-prem still happens
The reasons are usually legitimate, even when they arrive wearing a tinfoil hat. A clinic with cautious counsel reading HIPAA-adjacent requirements. A manufacturer whose floor has one network drop and a firewall policy from a previous decade. A company whose biggest customer contract says data stays in the building. Sometimes it is simply that the owner got burned by a SaaS price hike and wants to own the box.
Your job is not to win the cloud argument. Their risk call is their risk call. Your job is to make the onsite option boring and safe, which is a genuinely different skill from deploying to a managed platform, and it builds on the FDE stack essentials you would use anywhere else.
Docker deployment on premise client server: the boring stack that works
The architecture that survives onsite is the one you can explain on a napkin. One docker-compose.yml, one .env file, three containers if you can hold the line: app, database, reverse proxy. Named volumes for data, restart: unless-stopped on everything, and logs that rotate so the disk does not fill up in month seven. Postgres is the default database for a reason, and why Postgres runs half these onsite boxes makes the case better than I can here.
Add one outside observer. A five-dollar uptime check hitting the app over the client's network, paging your phone when it stops answering, is the difference between a maintenance task and a trust event. A dead app that texts you at 2am gets fixed before anyone notices. A dead app the client discovers during Monday morning receiving gets remembered at renewal time.
Keep it to three containers
Every container you add is a thing that can fail in a building where you do not work. Redis for a five-user internal tool is not architecture, it is decoration. If a service is not pulling its weight, fold it into the app and move on.
The backup is the product
Nightly database dumps to a second disk, plus a weekly copy onto a USB drive someone takes home, plus, and this is the part everyone skips, a restore drill every quarter. A backup you have never restored is a rumor. Schedule the drill, time it, and write the steps on a laminated card taped to the server. The card has saved more engagements than any framework.
Updates without a horror story
Updates are where onsite deployments go to die, so design the ritual before you need it. If you have network access, SSH in, pull the new tagged image, run a compose up, watch the logs for five minutes, done. Every image gets a version tag, and the previous tag stays on the box so rollback is one command, not a prayer.
Air-gapped sites get the USB treatment: export the image on your machine, carry it in, load it, update the compose file, restart. Test the whole loop on your own hardware first, because discovering a missing architecture build while standing in a server closet is a special kind of afternoon. The schedule matters too: quarterly or monthly visits, agreed in writing, so "the system broke six weeks ago and nobody called" never happens. Write the update steps into the same laminated runbook as the restore steps, and leave a copy with the office manager, who is, whether anyone admits it or not, your site reliability engineer.
Security on hardware you don't control
You cannot harden a building, but you can harden the box. Ask for full-disk encryption and say why in plain language: if the tower walks away, the data does not. Bind the app to the LAN only, with the firewall blocking everything else. Run the app under a service account with exactly the permissions it needs. Set up auth that fits how the client actually works, and sorting out auth for internal tools covers the options without the enterprise theater.
Also plan for physics. Power cuts happen in buildings with space heaters on shared circuits. Docker's restart policies handle the reboot; your job is making sure the database comes back clean and the app does not need a human to remember a startup order. A cheap UPS with a USB monitoring cable is a $150 insurance policy that pays for itself the first time the mini-fridge wins the argument with the breaker.
When to refuse on-prem
Sometimes the honest answer is no. If the client cannot commit to a restore drill, they are not buying software, they are buying a future incident with your name on it. If the site loses power or network weekly, no compose file will save you. And if the tool serves five casual users, a $20 cloud VPS with managed backups beats a heroic onsite rig every time.
Say it early and say it kindly. The engagements that go wrong are rarely the hard ones. They are the ones where everyone agreed to pretend the constraints were smaller than they were. Refusing a bad fit costs you one invoice; accepting it costs you your weekends and eventually your reputation.
Done right, the dusty server under the desk is not a compromise. It is a competitive advantage: a system the client owns, that nobody can sunset, that hums along while the SaaS world raises prices around it. Just label the power strip. Onsite builds often start when a spreadsheet or shared tool finally collapses, and the Airtable escape that triggers an on-prem build is the usual origin story.