DEV Community

Ifedayo Agboola
Ifedayo Agboola

Posted on

How To Build Your Own Cloud

Lessons 1-3

This post is part of my “Self-Hosting from Scratch” series.

Tired of paying AWS, Render, or Fly.io while juggling multiple projects? I’m documenting how I built my own self-hosting setup, step by step, with all the mistakes, fixes, and lessons learned along the way.

Series roadmap:

  • Lessons 1–3: Hardware, Ubuntu Setup & Security

  • Lesson 4: Docker & Docker Compose

  • Lesson 5: Reverse Proxy with Traefik

  • Lesson 6: Cloudflare Tunnel (public HTTPS without router configs)

  • Lesson 7: Smoke Tests with Whoami

  • Lesson 8: Postgres in Docker (volumes, healthchecks, backups)

  • …and more coming soon

Bookmark this series and follow along. By the end, you’ll be running your own server confidently

End goal for today: you’ll finish with a clean, secure Ubuntu server you can log into from your laptop using SSH keys, with a firewall and automatic security updates. This is the bedrock we’ll reuse for Docker, Traefik, Cloudflare Tunnel, databases, and file storage in later lessons.

I’ll teach this the way I built mine, so you understand why each command exists, when to use it, and how to fix common mistakes without panic.


Roadmap (today & next)

Today (Lessons 1–3):

  1. Hardware choices (home server vs small PC vs VPS)

  2. Install Ubuntu Server (LTS) & first boot

  3. Secure access: SSH keys, firewall, updates

Coming next (in order):

Docker & Compose → Traefik → Cloudflare Tunnel → “whoami” smoke test → Postgres → Prisma → Node/Express API → Cloudflare R2/S3-compatible storage → presigned uploads → observability → clean dev/prod separation.

Throughout the series I’ll also call out real errors we hit (e.g., Traefik 404s from an unhealthy container, Prisma OpenSSL mismatch, S3 CORS quirks) and how we fixed them, so you won’t burn a day like we did.


LESSON 1: Hardware (pick what fits your budget)

The decision tree (plain English)

  • £0–£50: Reuse an old PC or laptop.

    • Pros: free, quick start. Cons: power draw, older disks.
  • £120–£300: Refurbished mini PC (Lenovo Tiny, Dell Micro, Intel NUC).

    • Sweet spot: 16–32 GB RAM, 256+ GB SSD, quiet, low power.
  • £5–£10/mo: VPS (Hetzner/Contabo/Linode).

    • Pros: always-on, public IP. Cons: monthly cost.

Minimum specs for this course

  • CPU: any x86_64 from the last ~10 years

  • RAM: 8 GB (16 GB if you’ll run DB + object storage + search)

  • Disk: 128 GB SSD (NVMe ideal). Start simple (single disk).

  • Network: wired ethernet if possible (Wi-Fi works, but is fussier)

Quality-of-life add-ons (optional)

  • UPS (mini battery) so a power blip won’t corrupt databases.

  • Label the box with its hostname & static IP; you’ll thank yourself later.

Checkpoint: pick your machine. If it’s at home, plug in ethernet. If it’s a VPS, note the provided IP and login.


LESSON 2 — Ubuntu Server (Install & first boot)

We’ll install Ubuntu Server 24.04 LTS because it’s stable and well-supported by Docker.

2.1 Create install media

  1. Download the Ubuntu Server 24.04 LTS ISO.

  2. Flash it to a USB stick with balenaEtcher (or Rufus on Windows).

* Why: it writes the ISO in a bootable format safely.
Enter fullscreen mode Exit fullscreen mode

2.2 BIOS/UEFI boot

  • Plug the USB into your server, power on, press F12 / F2 / DEL / ESC to open the boot menu, choose the USB device.

2.3 The installer (what to pick & why)

  • Keyboard/Language: defaults usually fine.

  • Network: DHCP is OK for now (we’ll use Cloudflare Tunnel later, so no port-forwarding).

  • Storage: “Use entire disk”. LVM optional. Start simple.

  • User: create an admin user (this account gets sudo).

  • OpenSSH: Enable it (lets you log in remotely).

  • Reboot, remove USB.

If you see a hostname prompt, choose something memorable, e.g., blackscript-server or orion.

2.4 First login (locally or over SSH)

On the server screen you’ll see an IP address (e.g., 192.168.1.50).

From your laptop/desktop terminal:

ssh youruser@192.168.1.50
Enter fullscreen mode Exit fullscreen mode
  • ssh opens a secure shell to the server.

  • First time, you’ll be asked to trust a fingerprint → type yes, then your password.

2.5 Update the system (security baseline)

sudo apt update
sudo apt upgrade -y
Enter fullscreen mode Exit fullscreen mode
  • apt update refreshes the package list.

  • apt upgrade -y applies upgrades immediately.

Checkpoint: run hostnamectl (see your hostname) and ip a | grep inet (confirm the IP). If SSH works and updates completed, you’re ready for security hardening.


LESSON 3 — Secure Access (SSH keys, firewall, updates)

We’ll get you to a place where you log in with a key (not a password), a firewall protects the box, and security updates auto-apply.

⚠️ Safety tip: keep one SSH session open while you change settings. If you misconfigure, you still have a lifeline.

3.1 Generate an SSH key (on your laptop)

If you don’t have one already:

ssh-keygen -t ed25519 -C "you@example.com"
Enter fullscreen mode Exit fullscreen mode

What it does:

  • Creates a keypair in ~/.ssh/ (id_ed25519 + id_ed25519.pub).

  • -t ed25519 is a modern, secure key type.

  • -C adds a label so you recognize it later.

  • Set a passphrase when prompted (local theft protection).

3.2 Copy your key to the server

Still on your laptop:

ssh-copy-id youruser@192.168.1.50
Enter fullscreen mode Exit fullscreen mode

What it does:

  • Appends your public key to the server’s ~/.ssh/authorized_keys.

  • After this, your key can log in without typing the server password every time.

If ssh-copy-id isn’t available, you can copy manually:

cat ~/.ssh/id_ed25519.pub | ssh youruser@192.168.1.50 "mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys"

3.3 Test key login

Close your SSH session and reconnect:

ssh youruser@192.168.1.50
Enter fullscreen mode Exit fullscreen mode

If it logs you in without asking the server password (it may ask your key passphrase), you’re good.

3.4 Enable & configure the firewall (UFW)

sudo ufw allow OpenSSH
sudo ufw enable
sudo ufw status
Enter fullscreen mode Exit fullscreen mode
  • allow OpenSSH opens port 22 so you don’t lock yourself out.

  • enable turns the firewall on.

  • status shows allowed rules.

Later, when we run Traefik, we’ll open HTTP (80). With Cloudflare Tunnel you often don’t need to open public ports at all, but we’ll cover both patterns.

3.5 Harden SSH (disable password & root logins)

sudo nano /etc/ssh/sshd_config
Enter fullscreen mode Exit fullscreen mode

Find/set:

PasswordAuthentication no
PermitRootLogin no
Enter fullscreen mode Exit fullscreen mode

Save and restart SSH:

sudo systemctl restart ssh
Enter fullscreen mode Exit fullscreen mode

Why:

  • Password logins are bruteforced on the public internet. Keys are safer.

  • Root login disabled reduces blast radius.

Recovery if you lock yourself out:

  • Use the console/KVM/monitor+keyboard to revert PasswordAuthentication yes temporarily.

  • Or re-enable via cloud provider console.

    Always keep one SSH window open while testing changes.

3.6 Automatic security updates

sudo apt install -y unattended-upgrades
sudo dpkg-reconfigure -plow unattended-upgrades
Enter fullscreen mode Exit fullscreen mode
  • Installs a service that applies security updates automatically.

  • The reconfigure step enables it persistently.

You can inspect logs in /var/log/unattended-upgrades/.


Bonus safety nets (optional but nice)

A. Create a friendly SSH alias on your laptop

Add to ~/.ssh/config:

Host home-server
  HostName 192.168.1.50
  User youruser
  IdentityFile ~/.ssh/id_ed25519
Enter fullscreen mode Exit fullscreen mode

Now you can do ssh home-server.

B. Timezone & NTP (useful for logs)

sudo timedatectl set-timezone Europe/London
timedatectl
Enter fullscreen mode Exit fullscreen mode

C. Basic fail2ban (blocks repeated auth failures. Handy if you expose SSH)

sudo apt install -y fail2ban
Enter fullscreen mode Exit fullscreen mode

Defaults are sensible; we can tune later if you open SSH to the world.


“What can go wrong?” (real mistakes we’ve made)

  • Locked myself out of SSH.

    I disabled password logins before confirming key auth worked.

    Fix: Console in, set PasswordAuthentication yes, restart ssh, copy key correctly, then disable again.

  • UFW dropped my SSH.

    I enabled UFW without allowing OpenSSH first.

    Fix: Console in, sudo ufw allow OpenSSH, sudo ufw enable.

  • No network after reboot.

    Router changed IP via DHCP.

    Fix: Check the screen/ip a for the new IP. Later we’ll set a DHCP reservation or a static IP.

Bigger errors we’ll meet later (and solve):

  • Traefik 404s because the backend container was unhealthy (our healthcheck hit a non-existent /healthz).

  • Prisma OpenSSL mismatch (client built for openssl-1.1.x but runtime had 3.0.x). We fixed it by setting binaryTargets = ["native","debian-openssl-3.0.x"] and generating in the build image.

  • S3 CORS headaches on MinIO; we worked around by injecting CORS at Traefik.

    You’ll see those fixes in context when we reach those lessons.


Recap (what you achieved today)

  • Picked sensible hardware that won’t wreck your wallet.

  • Installed Ubuntu Server 24.04 LTS the right way (with SSH).

  • Logged in from your laptop, enabled a firewall, switched to key-based auth, and turned on automatic security updates.

This is the foundation. With this done, everything else (Docker, Traefik, tunnels, DBs) becomes straightforward and repeatable.

Top comments (0)