Project 01 — Linux / Hosting

Self-Hosted Portfolio
on Raspberry Pi

Setting up a Raspberry Pi 4 as a home web server — installing Linux, configuring Nginx, enabling remote access, and deploying a static site from scratch.

Raspberry Pi 4 Raspberry Pi OS Nginx SSH VNC Linux CLI

Goal

Host this portfolio website directly from a Raspberry Pi on my home network, practising real Linux administration, remote access, and web server configuration along the way.

Environment

  • Raspberry Pi 4 (4 GB)
  • Raspberry Pi OS (64-bit, Lite)
  • Nginx web server
  • SSH for remote terminal access
  • VNC for remote desktop (verified)
  • Windows 11 host on same LAN

Setup process

1
Flashed Raspberry Pi OS

Used Raspberry Pi Imager to write the 64-bit Lite image to a microSD card. Enabled SSH in the imager's advanced options before writing so the Pi was reachable over the network immediately on first boot.

2
Found the Pi on the network

Used ping raspberrypi.local from Windows to confirm it was reachable. Verified the IP in the router's DHCP lease table and set a static reservation so the address doesn't change.

3
Connected via SSH and updated the system

SSHed in with ssh [email protected], ran sudo apt update && sudo apt upgrade -y, changed the default password, and enabled automatic security updates.

4
Installed and configured Nginx

Installed Nginx with sudo apt install nginx -y, confirmed the service started, and tested it by loading the Pi's IP in a browser — default Nginx page confirmed it was serving HTTP correctly.

5
Deployed the site

Copied the portfolio HTML to /var/www/html/. Reloaded Nginx config. Verified the portfolio loaded correctly at http://192.168.1.42.

6
Verified VNC access

Installed RealVNC server, enabled it, and confirmed VNC connectivity from Windows using Test-NetConnection raspberrypi.local -Port 5900.

Commands used

bash — pi@raspberrypi
# Confirm Pi is reachable
ping raspberrypi.local -c 4
Reply from 192.168.1.42: bytes=32 time<1ms TTL=64

# Update system
sudo apt update && sudo apt upgrade -y

# Install web server
sudo apt install nginx -y
sudo systemctl enable nginx
sudo systemctl start nginx

# Check status
sudo systemctl status nginx
● nginx.service - A high performance web server
   Active: active (running) since Mon

# Deploy site files
sudo cp -r ~/portfolio/* /var/www/html/
sudo nginx -t
nginx: configuration file /etc/nginx/nginx.conf test is successful

Screenshots

[ Screenshot: Nginx default page loading from Pi IP ]
[ SSH session connected ]
[ Portfolio loading in browser from Pi ]

What went wrong

Permission denied on /var/www/html/

Copying files without sudo failed. Fixed by prefixing the cp command with sudo and confirming ownership with ls -la /var/www/html/.

Pi hostname not resolving on Windows

ping raspberrypi.local timed out initially. The fix was enabling mDNS on Windows — installing Bonjour Print Services resolved it. Alternatively, using the IP directly always worked.

What I learned

Linux file permissions matter immediately

The first real error I hit was a permissions issue. Learned to check ownership with ls -la and to understand when sudo is needed vs. when it's the wrong tool.

Static IP reservations save headaches

The Pi's DHCP address changed once and broke my SSH shortcut. Setting a reservation in the router is the right first step for any device you plan to access regularly.

systemctl is the go-to for service management

start / stop / enable / status — I used these constantly. Understanding the difference between starting a service now vs. enabling it at boot is fundamental.

Test connectivity at every layer

ping → SSH → HTTP. Verifying each layer separately made it easy to narrow down where a problem lived rather than guessing at the application level first.