I like how the author didn’t try to be overly clever with it. They could’ve used Docker to install and isolate dependencies, Caddy or Traefik to serve the site and manage SSL automatically, maybe even k3s to run a mini cluster for HA, Tailscale to avoid manual port forwarding, Terraform for future auto-provisioning without hassle, or Ansible to prepare the machine and all that jazz.<p>Instead, they took the simplest possible route that works: installing the web server on bare metal, serving plain HTML and CSS, and using direct port forwarding via the router. This was a delightful read.
> Step 5: Getting an HTTPS Certificate<p>If you’re using Apache2 you might also want to look at mod_md, not just certbot: <a href="https://httpd.apache.org/docs/2.4/mod/mod_md.html" rel="nofollow">https://httpd.apache.org/docs/2.4/mod/mod_md.html</a><p>Also, if you want to minimize the amount of JS, then just drop jQuery and use fetch, it’s reasonably pleasant too: <a href="https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API" rel="nofollow">https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API</a><p>Lovely article!
I had set one (Pi 3B+)up to do both a website as well as a public service announcement slideshow display for a local Community TV. Used PHP/CMSimple for the site and wrote a custom slider.<p>Things I learned:<p>- set the pi to reboot on poweroff<p>- Given this was TV used the AV output on the PI displaying in NTSC 4:3 (to support customers with older TVs), so had to be aware of overscan margins<p>- Added a startup script to start chromium in kiosk mode and open the slider page for the show side. worked 95% of the time, if not just power off then on.<p>- part of the troubleshooting was just unplug and replug - but SD cards will choke on too many power cycles, so instead of SD use a USB->SATA cable and a regular spinning rust HDD - slower but VERY reliable, the journaling file system can recover after power-outage.<p>- Get the right USB->SATA cable, USB-3 models seem to be more responsive and the PI can boot from them, there are some are too slow and the Pi will fail to boot.<p>- Slider had it's own login page (outside of CMSimple) to remotely manage the slideshow.<p>- Also changed the SSH Port to something uncommon to thwart bad guys.
I did something similar in 2016 <a href="https://www.e-tinkers.com/2016/11/hosting-wordpress-on-raspberry-pi-a-complete-approach/" rel="nofollow">https://www.e-tinkers.com/2016/11/hosting-wordpress-on-raspb...</a>. Instead of having Apache, I use Nginx. Instead of serving webpage from SD card, I setup a 512MB hard disk except booting still done via the SD card. The site is still running on a Raspberry Pi 3 till this day from my living room.
Very cool, very accessibly written. Thanks for sharing.<p>Curious how you handle your router’s public IP changing as (I believe?) this is pretty common depending on the ISP, no?
Surpised he does not have a step for a assigning a permanent address for the local network. He mentions it but skips it like it's not needed. a lot of routers like those from att do not allow port forwarding to addresses that have finite lease times.
Great article—thanks for sharing! I did something similar nine years ago with a Raspberry Pi 3 Model B. It stayed online for nearly a decade until it went offline at the end of 2024, following Google's decision to sunset my OnHub router.<p>Initially, I used it as a CUPS server to turn a non-networked Brother printer (HL-2240) into a wireless printer after Google discontinued Google Cloud Print.<p>The printing project was a lot of fun and inspired me to dive into another challenge: self-hosting. Along the way, I learned a great deal about Apache, SSL certificates, security, and just how fragile SD cards can be!<p>The print server still works well, though I’ve since downsized to a Raspberry Pi Zero W.
This is a wonderful project and an even more wonderful write-up, I wish I came across more in this tone! I'll just add to anyone following in these footsteps: be careful what <i>type</i> of website you host on your Pi. Self-hosting is great, but if you expose services on your home network to the internet, expect people to try to hack you. What type of site you host will either make this very hard or very easy. The difference between compromising a VPS and compromising your home web server is now they have access to your actual LAN. Cloudflare has a pretty good WAF on the free tier, look at it as another learning opportunity.
Regarding private keys and computers going in for repairs...<p>I know it's not strictly best practice but store your private key in your password manager. That way if the worst happens you aren't up a creek...
To the OP:<p>Make sure you have updated firmware to latest, plus added active protection against the following known vulnerabilities.<p><a href="https://nvd.nist.gov/vuln/search/results?form_type=Basic&results_type=overview&query=R6020&search_type=all&isCpeNameSearch=false" rel="nofollow">https://nvd.nist.gov/vuln/search/results?form_type=Basic&res...</a>
I really enjoyed this but at the same time find it completely perplexing - I can't place where the author is coming from - they are either really good at explaining things from the point of view of someone who knows almost nothing about this stuff or they genuinely started this without knowing most of it. I'm not sure which would be more impressive.
I use Kamal[1] to host all my side projects on a Raspberry Pi. It works for more than just Rails apps.<p>I’ve tried a few other approaches in the past and this seems like the simplest, given a familiarity with git.<p>[1] <a href="https://kamal-deploy.org/" rel="nofollow">https://kamal-deploy.org/</a>
Hey, if one is only using apache and serving static files, is there any security issue one needs to be in the lookout? I was surprised fail2ban was the only thing installed there and it seems reliably working.
Any DDoS protection? Doesn't really matter with a small personal site, but I run a few solo production apps and they get hit multiple times a month by >100k rps DDoS attacks.
Nice description, very helpful, thanks. IFAIK there’s a mixup between the words „permanent“ vs „temporary“ in the fail2ban section, you may want to check that.