Part C — One-time Hostinger VPS setup
Do this once per VPS — a single Hostinger VPS can host as many separate websites as you like, so you won't need to repeat this for every new site.
Why run websites in Docker containers at all?
You'll meet Docker properly in C3, but it's worth understanding why this guide uses it before you install anything. A container is a self-contained box holding your website plus the exact versions of everything it needs to run — packaged once, then run identically anywhere.
- "It worked on my laptop" stops being a problem. The container that runs on your VPS is built from the exact same instructions as the one you tested locally, so there's no separate "production setup" to get subtly wrong.
- One VPS, many completely separate websites. Each site lives in its own container, isolated from the others. A bug, crash, or security issue in one site can't reach into another — they might as well be on different computers, even though they're sharing the same VPS. This is exactly how you can run a Next.js site, a WordPress site, and a database all on one VPS without them interfering with each other.
- Deploys and rollbacks are simple and predictable. Shipping a change is always the same action — build a new container image, swap it in — and undoing a bad change is the same action in reverse (go back to a previous commit, rebuild). There's no "remembering what I changed by hand on the server" to worry about.
- Automatic recovery. A container is told to always restart itself if
it crashes or the VPS reboots (
restart: unless-stoppedindocker-compose.prod.yml), and Docker can continuously check that your site is actually responding, not just that the process is technically running. - Lighter than a full virtual machine. Containers share the VPS's underlying operating system instead of each needing their own full copy of one, so they start in seconds and leave far more of the VPS's resources free for actually running your sites.
- Plays nicely with a shared reverse proxy. Each container just declares
which domain it wants to answer to (a couple of lines of "labels" in
docker-compose.prod.yml) and Traefik (Part C4) figures out the routing automatically — no manually editing a web server config file by hand every time you add a new site.
C1. Buy a Hostinger VPS plan and note its IP address
- Go to hostinger.com, choose a VPS Hosting plan, and complete the purchase (any of their VPS plans works for this guide — the cheapest tier is fine to start with).
- Log into hPanel (Hostinger's control panel) at hpanel.hostinger.com.
- Go to VPS in the sidebar, click into your server, and note its
IP address — it's shown right on the server's overview page, and
looks like
203.0.113.5. You'll use this constantly throughout this guide.
Underneath the hPanel dashboard, it's a plain Linux computer — everything from here on (SSH, Docker, Traefik) is standard Linux server administration.
C2. Set up a dedicated SSH key (no passwords, no typed usernames, ever)
SSH is how your laptop securely talks to the VPS over the internet — like
a phone line, but for typing commands on a remote computer. An SSH key
is a pair of files: a private one that stays secret on your laptop, and a
public one you give to the VPS. They work like a lock and its matching key —
the VPS only lets in a laptop holding the correct private key. Once this is
set up properly, deploy.sh (Part D5) will be able to connect and run
commands with zero prompts — no password, no typed username, nothing.
Step 1 — Generate a dedicated key pair. In Git Bash, run:
ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519_myvps -N ""
What this does:
-t ed25519picks a modern, strong key type.-f ~/.ssh/id_ed25519_myvpsnames the files. This creates two files:id_ed25519_myvps(the private key — never share this) andid_ed25519_myvps.pub(the public key — safe to share, this is what goes on the VPS).-N ""means "no passphrase." Normally an SSH key asks you to type a passphrase every time it's used, which is more secure for a personal key but would defeat the purpose here —deploy.shneeds to run without you typing anything. This is exactly why you make a separate, dedicated key just for this, instead of reusing your everyday personal key: if this passphrase-less key were ever copied off your laptop, the damage is limited to "can SSH into this one VPS" — not your whole digital identity.
Step 2 — Copy the public key to the VPS. Replace YOUR_VPS_IP with the
real address:
ssh-copy-id -i ~/.ssh/id_ed25519_myvps.pub root@YOUR_VPS_IP
This is the one and only time you'll be asked for the VPS's password —
ssh-copy-id needs it once to install the public key. root is the name
of the all-access administrator account Hostinger gives every VPS by
default. (If ssh-copy-id isn't available, hPanel has an "SSH Keys" section
under your VPS's settings with an "add SSH key" box you can paste the
contents of ~/.ssh/id_ed25519_myvps.pub into instead — same result.)
Step 3 — Add a shortcut so you never type the full command again. Add
this to ~/.ssh/config (create the file if it doesn't exist):
Host myvps
HostName YOUR_VPS_IP
User root
IdentityFile ~/.ssh/id_ed25519_myvps
Now ssh myvps alone connects — no IP address, username, or key path
needed.
Step 4 — Prove it actually needs zero input. Run:
ssh -o BatchMode=yes -o ConnectTimeout=10 myvps "whoami && echo CONNECTED-WITHOUT-A-PASSWORD"
-o BatchMode=yes tells SSH "never prompt for anything — if key-based login
doesn't work, fail immediately instead of hanging on a password prompt."
This is the exact same flag deploy.sh uses, so if this command prints
root and CONNECTED-WITHOUT-A-PASSWORD with no prompt at all, you've
confirmed deploy.sh will be able to connect unattended. If it instead
hangs or asks for a password, something in Steps 1–3 didn't take — redo
Step 2.
C2a. (Optional, recommended) Turn off password login entirely
Right now, the VPS still accepts password logins too — Step 2 above just added a second option. For real security, once you've confirmed Step 4 works, you can tell the VPS to stop accepting passwords altogether, so a stolen or guessed password can never be used to log in — only a matching private key can.
⚠️ Do this carefully, and never skip the safety check below — get it wrong and you can lock yourself out of the VPS entirely.
Safety check first: open a second, separate terminal window and
confirm ssh myvps still connects, and keep that second window open
throughout this step. If something goes wrong with the change below, that
still-open session (or hPanel's browser-based terminal — under your
VPS's page, look for "Browser terminal" — which logs you straight in without
needing SSH at all) is your way back in.
With that safety net open, in your main terminal run:
ssh myvps "sudo sed -i 's/^#*PasswordAuthentication.*/PasswordAuthentication no/' /etc/ssh/sshd_config && sudo systemctl restart sshd"
Then, from a brand new third terminal window (not the safety-net one), test that key-based login still works:
ssh -o BatchMode=yes myvps "echo still works"
If that prints still works, you're done — password login is now fully
disabled, and only your dedicated key can get in. If it fails, use your
still-open safety-net session to undo the change (edit
/etc/ssh/sshd_config back to PasswordAuthentication yes and
sudo systemctl restart sshd again) before closing anything.
C3. Install Docker on the VPS
Docker packages your website — plus everything it needs to run: Node.js, libraries, settings — into a self-contained box called a container, so it runs identically on the VPS as it did on your laptop.
ssh myvps "curl -fsSL https://get.docker.com | sh"
C4. Install Traefik (one reverse proxy for all your sites)
A reverse proxy sits in front of all your websites on the VPS and directs each visitor to the right one, based on which domain name they typed. It also handles HTTPS (the padlock icon in the browser) automatically via a free certificate service called Let's Encrypt. You only need one Traefik running on the VPS, shared by every site you ever deploy there.
Setting Traefik up the first time is a bit fiddly (it needs its own small
config file, and needs permission to see Docker's other containers). The
easiest path is to ask Claude Code to set it up for you, describing that you
want "a Traefik reverse proxy with Let's Encrypt, running with
network_mode: host, so any future site container just needs a few Docker
labels to get routed automatically."
C5. Point your domain at the VPS
Add an A record — a DNS record is the internet's phonebook entry, and
an "A record" is the specific type that maps a domain name to a server's IP
address — pointing yourdomain.com (and www.yourdomain.com) at your VPS's
IP address. This is what makes typing yourdomain.com into a browser
actually reach your VPS.
- If the domain was bought through Hostinger: in hPanel, go to Domains → your domain → DNS / Name Servers → DNS Zone Editor and add the A record there.
- If the domain was bought elsewhere (GoDaddy, Namecheap, etc.): add the A record in that registrar's own DNS settings instead — it still just needs to point at your Hostinger VPS's IP address.
Published