Loading
October 26, 2026

AmirHesamTech

Raspberry Pi, homelab, Linux and automation — projects and practical guides

Two monitors showing the Raspberry Pi OS desktop, with the Raspberry Pi 4 that runs this website between them

This website doesn’t live with a hosting company. It runs on a Raspberry Pi 4 sitting on a shelf in my home. Here is the real setup: the hardware, every piece of software in the stack, how it stays online when I’m not watching it, and the mistakes that taught me the most.

The hardware

  • Raspberry Pi 4 Model B with 8 GB of memory. Four cores, and plenty of RAM for WordPress, a database and a cache at the same time.
  • A 128 GB portable SSD over USB as the system drive. The Pi boots from it instead of a microSD card. A database makes a constant stream of small writes, and SD cards are neither built for that nor fast at it.
  • A second 128 GB USB drive just for backups. Keeping backups on a separate drive means one dead drive can’t take the site and its backups down together.

It isn’t working hard. When I checked while writing this, the load average was about 0.4 — less than half of one core busy — and the CPU was at 47 °C.

Raspberry Pi 4 fitted with a tower cooler and fan, with a Samsung USB stick plugged into a USB port
The Raspberry Pi 4 that runs this site, fitted with a tower cooler and fan. The Samsung USB stick at the front holds the weekly backups.

The software stack

Layer What runs Why it’s there
Operating system Raspberry Pi OS, 64-bit (based on Debian 13) The official OS, with regular security updates
Web server Apache 2.4 with PHP 8.4 Serves WordPress
Database MariaDB 11.8 Stores posts, pages, users and settings
Object cache Redis 8 Keeps frequent database lookups in memory
Page cache WP Super Cache Hands visitors who aren’t signed in a ready-made page instead of rebuilding it each time
Front door Cloudflare Tunnel Puts the site on the internet without opening ports on my router; Cloudflare also caches images, CSS and scripts
Remote access Tailscale Lets me reach the Pi over SSH from anywhere without exposing SSH to the internet
Firewall ufw Blocks everything that isn’t explicitly allowed
Scheduled jobs cron Weekly backups, plus WordPress’s scheduled tasks every minute
Self-repair A watchdog on a systemd timer Checks the site every five minutes and restarts what has stopped

Why a Cloudflare Tunnel instead of port forwarding

The usual way to host from home is to forward ports 80 and 443 on your router to the server. I didn’t want to do that. With a tunnel, a small program on the Pi (cloudflared) opens an outgoing connection to Cloudflare, and visitors reach the site through Cloudflare. Nothing on my home network accepts connections from the internet, my home IP address isn’t published, HTTPS certificates are handled for me, and it works even if your internet provider won’t give you a public IP address.

Advertisement

The trade-off is honest: if my internet or the Pi goes down, Cloudflare has nothing to connect to, and visitors would normally see a Cloudflare error page. To soften that, I added a small Cloudflare Worker that catches those errors and shows a “back shortly” page that retries on its own every 30 seconds. It doesn’t stop an outage, but it’s a much better experience than an error code.

If you want to try the same idea on your own desk, my DuckDNS and Nginx Proxy Manager project shows another way to get free HTTPS for a home server.

How it stays online when I’m not watching

The watchdog. Every five minutes a small script checks that Apache, MariaDB, Redis and the tunnel are running and restarts any that have stopped. It also loads the WordPress login page: if that returns a server error twice in a row, it restarts Apache — or the database, if the error is a database connection problem. It stops after three restarts of the same service in an hour, so a real fault can’t turn into an endless restart loop, and it sends a notification to my phone every time it acts.

Backups. Every Sunday at 3 a.m. a script copies the site files, the database and the configuration to the backup drive, and keeps eight weeks of copies. If the drive isn’t plugged in, it skips the run instead of filling up the system drive. My guide to automating backups covers the same idea for your own files.

A real scheduler. WordPress’s built-in scheduler only runs when somebody visits a page, which is unreliable on a small site. I switched it off, and a timer on the Pi now calls WordPress’s scheduler every minute instead.

What went wrong (and what I changed)

1. My own browser slowed the site down

The Pi has a desktop, and I left Chromium open on it. When the site felt slow, I found the browser using around 250% CPU — two and a half of the four cores — while the website fought over what was left. Lesson: a server is not a desktop. Nothing heavy runs on it now.

2. One open tab made thousands of requests

The site has a small visitor counter that checks in while a page is open. It had no idle limit, so a single forgotten tab sent about 4,300 requests in a day. It now stops after five minutes of inactivity.

3. Most of my traffic was bots

When I finally sorted the logs, about 91% of all requests were junk: bots hammering WordPress’s old XML-RPC endpoint and the login page. XML-RPC is now blocked completely, and repeated failed logins get locked out. If you run WordPress anywhere, turn on two-factor authentication and use a password manager — the bots never stop trying.

4. A hidden folder was publicly readable

My web server rules were in the wrong order. A rule that serves any real file on disk ran before the rule meant to block hidden folders, so a folder that should have been private could be downloaded by anyone who knew its name. The fix was simple: block hidden files and folders first, then everything else. The lesson is the useful part — after changing server rules, test from outside with curl exactly as a stranger would, instead of assuming the rule works.

5. The pages were heavier than they looked

Measuring the homepage showed that 84% of it was code written straight into the page, which browsers and Cloudflare couldn’t cache. Moving that code into separate, cacheable files took the homepage from 587 KB to 218 KB. Converting the images to WebP took the image library from 77 MB to 10 MB.

6. Cloudflare remembers “not found”

Cloudflare caches error pages too. When I tested it, a file that was missing for a moment had its “not found” answer cached at the edge — so even after the file is back, visitors can keep getting the old “not found” until that cache is cleared. Now, after any fix, I clear the Cloudflare cache as well as the site’s own.

7. Caching pages for signed-in members

For a while the page cache also stored pages for members who were signed in. They started seeing old versions of their own pages — stale coin balances and the same welcome message again and again. The cache now only serves visitors who aren’t signed in.

Would I do it again?

Yes, for a personal site. The running costs are small — the electricity for a low-power board and the domain name — and this one machine has taught me a lot about Linux, caching and security. But be honest with yourself about the downsides:

  • Home outages are site outages. A power cut or an internet problem takes the site offline. The maintenance page makes it look better; it doesn’t prevent it.
  • You’re the system administrator. Updates, security, backups and fixing things at odd hours are all on you.
  • One machine is a single point of failure. Good backups matter more than anything else on this list.

If a site earns money for a business and downtime is expensive, a managed host is the safer choice. If you want to learn, a Raspberry Pi is a great teacher. If your home connection is the weak link, start with my guide to fixing a slow internet connection and the one on setting up a reliable home network.

Frequently asked questions

Can a Raspberry Pi 4 really run a WordPress site?

For a small site, yes — this one runs on a Pi 4 with 8 GB. Page caching does most of the heavy lifting: most visitors get a ready-made page, so PHP and the database only work when something changes.

Do I have to open ports on my router?

Not with a Cloudflare Tunnel. The Pi connects out to Cloudflare, so nothing on your network has to accept incoming connections.

SD card or SSD?

I boot from a USB SSD. It’s faster and much better suited to a database’s constant small writes than a microSD card.

What happens when my internet goes down?

The site goes offline until the connection comes back. A Cloudflare Worker shows visitors a “back shortly” page and retries automatically, and the watchdog restarts anything on the Pi that didn’t come back by itself.

How do you back it up?

A weekly script copies the files, the database and the configuration to a separate USB drive and keeps eight weeks of copies. Test a restore at least once — a backup you’ve never restored is a guess.

Want to see the other things I run at home? Here’s what I’m working on, or browse all the guides.

Advertisement

65 Posts

SDET and QA engineer. I build Raspberry Pi servers, a Proxmox homelab and automations, and share how on TikTok and Instagram (@techwithamirh3sam).

View All Posts

You Missed

REWARDS 🔰 LV1 0🪙 ❯
🔰
Recruit
Guest Operative
Level1
XP0 / 100
💬 Need help?
coins0
Streak0 days · best 0
📋 Daily missions
↻ Resets daily at midnight
Rank ladder
How to earn
✓ Welcome bonus for joining — +200 🪙 & +100 XP (one-time)
✓ Daily check-in (streak bonus) — +20 XP & +12–24 🪙 (more 🪙 the longer your streak)
✓ Spin the daily wheel — +10 to +150 🪙 (free, once a day)
✓ Daily missions — check-in +15 🪙/+10 XP · daily spin +15 🪙/+10 XP
✓ Finish ALL daily missions — +30 🪙 & +20 XP bonus
✓ Level up — +25 🪙 every new level
✓ Achievements — first sign-in +50 🪙 · Lv5 +75 · Lv10 +150 · Lv25 +300 · 7-day streak +100 · 30-day +250 · collector +100 · subscriber +50
✓ Complete your profile (name, bio, photo) — up to +55 XP (one-time)
✓ Subscribe to the newsletter — +250 🪙 (one-time)
Coins and XP are just for fun: they have no cash value and can't be exchanged for money or prizes. You never earn them for viewing or clicking ads, or for how many pages or articles you open.
🛒 Token Shop0 🪙
🛍️ Shop0items
🎒 Inventory0items

🎡 Daily Spin

One free spin every day — pure bonus coins!
🪙
💬Need help?