deploy · tutorial · vps

Localhost to VPS in One Command? Almost

The last mile from laptop to server: a one-time server setup, a settings sync and a deploy that waits for a health check.

A uniformed letter carrier holding a mailbag with a small child inside it, about 1900
A uniformed letter carrier holding a mailbag with a small child inside it, about 1900 · Photo: Unidentified photographer, public domain, via Wikimedia Commons

"Works on my machine" ships nowhere

The app sings on localhost.

Hot reload.

Instant feedback.

All green.

Then deployment Saturday arrives, and the weekend disappears.

Server setup.

Settings typos.

A database that exists only as a file on the laptop.

Monday's standup: "deployment in progress." Translation: the app works in exactly one place on Earth, and it is the laptop in the backpack.

The last mile is solved.

Develop recklessly local.

Ship boringly remote.

Compress the gap to one setup and one command.

The gap, itemized

Gap Localhost Server reality What bridges it
Settings A casual local file Exact production values One sync command
Build Your laptop's chips A Linux server Build once, swap in the result
Database Dev data and seeds Real customer data Separate files, same shape
Process life A dev server you watch An app that restarts itself Set up once by the kit
Hostname and ports localhost:3000 A domain, no open ports A tunnel and a private network

Three details eat the naive weekend.

Transcribed secrets drift on first contact. Retype twelve settings into a server editor and one has a typo. Usually the payment key, found at the first real charge.

Hand-built servers become snowflakes. A box configured from memory is a box nobody can rebuild. A script builds the same server every time, so a dead one is replaceable.

Dev data must never board. Seed users, test orders and fake keys would pollute your production books if the file were copied over. Keep separate files. Move data on purpose.

What to do

Set the server up once.

Run the one-shot setup from your laptop against a fresh Ubuntu server. It creates a non-root user and adds swap space so nothing runs out of memory. It installs the runtime and the web server, closes the firewall to everything but what the app needs, and makes the app restart after a reboot.

It also installs the scheduled housekeeping jobs.

Fresh boxes converge to the same shape. No "this server is special" lore.

Then, every time, sync settings, then deploy.

Run bp secret sync first. The server should hold the production truth before new code arrives.

Then bp deploy.

It checks your code, builds on your laptop, ships the result and swaps it in, with the previous version kept beside it.

It waits for a health check.

If the new version never answers, the old one is put back.

Last, verify from the outside.

Open the public address in a browser, not localhost. Place a test order. Run bp status to confirm the branch, the database size and your latest backup.

That proves the whole chain: DNS, edge, app and database.

First-deploy scorecard

Check The naive Saturday The last-mile setup
Time to live A long day The setup plus a short loop
Settings typos Likely Copied from a file
Dev data in prod Possible Separate files
The second deploy Another Saturday? One command

The setup script is a commitment device. Manual tweaks outside it drift and confuse the next deploy.

Treat servers as replaceable. Built by the script. Rebuilt by it.

Know this first

One command still needs a one-time setup. Manual tweaks outside the setup script drift.

Treat the server as replaceable.

Why BoringPush is the way to do this

From laptop to live in one command.

BoringPush sets up the server once. Then bp secret sync and bp deploy do the rest. The deploy waits for a health check.

Set up once. Ship forever.

FAQ

Does this work from a Windows laptop?

Yes, with WSL. Deploys travel over SSH and the server runs Linux whatever your laptop uses. Run the commands from the Linux side so script line endings stay correct.

What about preview environments per branch?

You can run a second copy of the app on the same server under a staging subdomain. Push to preview, check it, then ship to production. The kit does not do this for you automatically.

How do database changes travel with a deploy?

Production database changes are additive, and an agent cannot run them against production. Seed data never travels. Data moves deliberately, with a snapshot taken first.

Can the setup target hosts other than Hetzner?

Any Ubuntu 22.04 or 24.04 server: Hetzner, DigitalOcean, Linode or spare hardware. Host choice is price shopping, not architecture.

What breaks most often on first deploys?

Settings drift, the sign-in redirect address not matching the live domain, webhooks pointing at test addresses, and DNS patience. All four are documented and none is surprising twice.

When is one-command deploy the wrong goal?

When you run many services with their own lifecycles, such as separate API workers and queues. One-command shipping serves a single app well, and most solo SaaS products are exactly that. Move to orchestration when services multiply, not before.

Keep reading

+ all the boring stuff (analytics, auth, SQLite ↔ Supabase, full marketplace, webhooks)

The Agent-First Shipping Kit

Command from your phone.

Built so autonomous AI agents build what you want without breaking what's already paying you.

$199

Get BoringPush

One-time payment · Lifetime updates · Unlimited projects.

Keep reading