Web Server
Raspberry Pi Projects
Project 1 — Setting up a Raspberry Pi as a Web Server
What You Will Need
Step 1 — Update Your Pi
Always start with a full system update. This ensures you are installing the latest versions of all packages and avoids dependency conflicts later.
pi@raspberrypi:~$ sudo apt update && sudo apt upgrade -y Hit:1 http://archive.raspberrypi.com/debian bookworm InRelease Get:2 http://deb.debian.org/debian bookworm InRelease [151 kB] ... Reading package lists... Done Building dependency tree... Done
This may take a few minutes. Once complete, reboot to ensure all updates take effect:
pi@raspberrypi:~$ sudo reboot
Wait about 30 seconds then SSH back in before continuing.
Step 2 — Install Apache
Apache is the world's most widely used web server. It handles incoming HTTP/HTTPS requests and serves your web pages.
pi@raspberrypi:~$ sudo apt install -y apache2 Reading package lists... Done ... Setting up apache2 (2.4.57-2+deb12u2) ... Enabling module mpm_event. ...
Verify Apache is running
pi@raspberrypi:~$ sudo systemctl status apache2 ● apache2.service - The Apache HTTP Server Loaded: loaded (/lib/systemd/system/apache2.service; enabled) Active: active (running) since Wed 2026-06-11 09:14:33 BST; 22s ago
Now test it from a browser on the same network. Find your Pi's local IP address:
pi@raspberrypi:~$ hostname -I 192.168.1.42
Open a browser and visit http://192.168.1.42. You should see the Apache default page — "It works!"
Enable Apache to start on boot
pi@raspberrypi:~$ sudo systemctl enable apache2 Synchronizing state of apache2.service...
Step 3 — Install PHP
PHP is the server-side scripting language used by WordPress, phpMyAdmin, and most dynamic websites.
pi@raspberrypi:~$ sudo apt install -y php libapache2-mod-php php-mysql php-curl php-gd php-mbstring php-xml php-zip Reading package lists... Done ... Setting up php8.2 (8.2.20-1~deb12u1) ...
Verify PHP is working
Create a test PHP file in Apache's web root:
pi@raspberrypi:~$ echo '<?php phpinfo(); ?>' | sudo tee /var/www/html/info.php
Visit http://192.168.1.42/info.php in your browser. You should see the PHP information page showing your PHP version and configuration.
sudo rm /var/www/html/info.php
Step 4 — Install MariaDB
MariaDB is a fast, open-source relational database (a drop-in replacement for MySQL) used by WordPress and most web applications.
pi@raspberrypi:~$ sudo apt install -y mariadb-server Reading package lists... Done ... Setting up mariadb-server (1:10.11.6-0+deb12u1) ...
Secure the installation
Run the security script to set a root password, remove test databases, and disable remote root login:
pi@raspberrypi:~$ sudo mysql_secure_installation Enter current password for root (enter for none): [press Enter] Switch to unix_socket authentication [Y/n]: n Change the root password? [Y/n]: Y New password: [enter a strong password] Re-enter new password: [repeat password] Remove anonymous users? [Y/n]: Y Disallow root login remotely? [Y/n]: Y Remove test database and access to it? [Y/n]: Y Reload privilege tables now? [Y/n]: Y All done!
Create a database and user for your website
Rather than using the root account for your website, create a dedicated database user:
pi@raspberrypi:~$ sudo mysql -u root -p MariaDB [(none)]> CREATE DATABASE mywebsite_db; MariaDB [(none)]> CREATE USER 'webuser'@'localhost' IDENTIFIED BY 'StrongPassword123!'; MariaDB [(none)]> GRANT ALL PRIVILEGES ON mywebsite_db.* TO 'webuser'@'localhost'; MariaDB [(none)]> FLUSH PRIVILEGES; MariaDB [(none)]> EXIT;
Step 5 — Configure a Virtual Host
A virtual host tells Apache which folder to serve for a given domain name. This allows you to host multiple websites on the same Pi.
Create the website directory
pi@raspberrypi:~$ sudo mkdir -p /var/www/mywebsite pi@raspberrypi:~$ sudo chown -R $USER:$USER /var/www/mywebsite pi@raspberrypi:~$ sudo chmod -R 755 /var/www/mywebsite
Create a test index page
pi@raspberrypi:~$ nano /var/www/mywebsite/index.html
Paste in a simple page:
<html> <head><title>My Pi Web Server</title></head> <body> <h1>Hello from my Raspberry Pi! 🍓</h1> </body> </html>
Create the virtual host config file
pi@raspberrypi:~$ sudo nano /etc/apache2/sites-available/mywebsite.conf
<VirtualHost *:80> ServerName yourdomain.com ServerAlias www.yourdomain.com DocumentRoot /var/www/mywebsite ErrorLog ${APACHE_LOG_DIR}/mywebsite-error.log CustomLog ${APACHE_LOG_DIR}/mywebsite-access.log combined <Directory /var/www/mywebsite> AllowOverride All Require all granted </Directory> </VirtualHost>
Enable the site and reload Apache
pi@raspberrypi:~$ sudo a2ensite mywebsite.conf pi@raspberrypi:~$ sudo a2dissite 000-default.conf # disable the default page pi@raspberrypi:~$ sudo a2enmod rewrite # enable mod_rewrite (needed for WordPress etc.) pi@raspberrypi:~$ sudo systemctl reload apache2
Step 6 — Set Up a Static Local IP
Before making your Pi accessible from the internet, give it a fixed local IP address so your port forwarding rules don't break when it reboots.
The easiest approach is to assign a DHCP reservation in your router — find your Pi's MAC address and tell the router to always give it the same IP. Look for "DHCP reservation" or "Static DHCP" in your router settings.
Alternatively, set a static IP on the Pi itself:
pi@raspberrypi:~$ sudo nano /etc/dhcpcd.conf
Add these lines at the bottom (adjust to match your network):
interface eth0 static ip_address=192.168.1.42/24 static routers=192.168.1.1 static domain_name_servers=8.8.8.8 8.8.4.4
pi@raspberrypi:~$ sudo reboot
Step 7 — Port Forwarding and Domain Setup
To make your web server reachable from the internet, you need to forward ports 80 (HTTP) and 443 (HTTPS) from your router to your Pi's local IP address.
Set up port forwarding on your router
- Log in to your router admin panel (usually
192.168.1.1or192.168.0.1) - Find the Port Forwarding section (sometimes under "NAT" or "Virtual Server")
- Add two rules:
| Service | External Port | Internal Port | Protocol | Internal IP |
|---|---|---|---|---|
| HTTP | 80 | 80 | TCP | 192.168.1.42 |
| HTTPS | 443 | 443 | TCP | 192.168.1.42 |
Point your domain to your Pi
Log in to your domain registrar (or DuckDNS/No-IP) and create an A record pointing your domain to your home's public IP address. Find your public IP at api.ipify.org:
pi@raspberrypi:~$ curl https://api.ipify.org 203.0.113.42
Step 8 — Enable SSL with Let's Encrypt
Let's Encrypt provides free, automatically renewed SSL certificates. Certbot is the tool that handles the whole process.
pi@raspberrypi:~$ sudo apt install -y certbot python3-certbot-apache
pi@raspberrypi:~$ sudo certbot --apache -d yourdomain.com -d www.yourdomain.com Saving debug log to /var/log/letsencrypt/letsencrypt.log Enter email address (used for urgent renewal and security notices): your@email.com Please read the Terms of Service at https://letsencrypt.org/documents/LE-SA-v1.4-April-3-2024.pdf Do you agree? [Y]es/[N]o: Y Would you like to share your email address? [Y]es/[N]o: N Requesting a certificate for yourdomain.com and www.yourdomain.com ... Congratulations! You have successfully enabled HTTPS on https://yourdomain.com
Certbot automatically updates your Apache virtual host config to use HTTPS and sets up a cron job to renew the certificate before it expires (certificates last 90 days). Test the auto-renewal:
pi@raspberrypi:~$ sudo certbot renew --dry-run ... Congratulations, all simulated renewals succeeded: /etc/letsencrypt/live/yourdomain.com/fullchain.pem (success)
Step 9 — Final Checks
Run through this checklist to confirm everything is working correctly:
- Visit
http://yourdomain.com— does your website load? - Visit
https://yourdomain.com— does the padlock appear in the browser? - Visit
http://yourdomain.com— are you automatically redirected to HTTPS? (Certbot configures this by default) - Check Apache error logs for any warnings:
sudo tail -f /var/log/apache2/mywebsite-error.log - Verify MariaDB is running:
sudo systemctl status mariadb - Reboot and check that Apache and MariaDB both restart automatically
Troubleshooting Common Problems
sudo ss -tlnp | grep :80 and stop it, or change Apache's port. This often happens if Nginx was previously installed.sudo chown -R www-data:www-data /var/www/mywebsitesudo chmod -R 755 /var/www/mywebsiteAlso check your virtual host config has
Require all granted inside the Directory block.sudo a2enmod php8.2sudo systemctl restart apache2Replace
php8.2 with your installed version (check with php --version).sudo mysql -u root -pALTER USER 'webuser'@'localhost' IDENTIFIED BY 'NewPassword';FLUSH PRIVILEGES;mpm_event to mpm_prefork for better PHP compatibility, or use PHP-FPM for better performance. Also consider adding swap space on the Pi if you have less than 2 GB RAM: sudo dphys-swapfile swapoff, edit /etc/dphys-swapfile and set CONF_SWAPSIZE=1024, then sudo dphys-swapfile setup && sudo dphys-swapfile swapon.sudo cat /var/log/letsencrypt/letsencrypt.log. Force a renewal manually: sudo certbot renew --force-renewal.Optional Extras
Install phpMyAdmin (database web interface)
pi@raspberrypi:~$ sudo apt install -y phpmyadmin Web server to reconfigure automatically: apache2 Configure database for phpmyadmin with dbconfig-common? Yes
Access it at https://yourdomain.com/phpmyadmin.
Install WordPress
pi@raspberrypi:~$ cd /tmp pi@raspberrypi:/tmp$ wget https://wordpress.org/latest.tar.gz pi@raspberrypi:/tmp$ tar -xzf latest.tar.gz pi@raspberrypi:/tmp$ sudo cp -r wordpress/* /var/www/mywebsite/ pi@raspberrypi:/tmp$ sudo chown -R www-data:www-data /var/www/mywebsite/
Then visit your domain in a browser and follow the WordPress setup wizard. Use the database name, username, and password you created in Step 4.
Quick Reference
| Task | Command |
|---|---|
| Start Apache | sudo systemctl start apache2 |
| Stop Apache | sudo systemctl stop apache2 |
| Reload Apache config | sudo systemctl reload apache2 |
| Test Apache config | sudo apache2ctl configtest |
| View Apache error log | sudo tail -f /var/log/apache2/error.log |
| View Apache access log | sudo tail -f /var/log/apache2/access.log |
| Enable a site | sudo a2ensite sitename.conf |
| Disable a site | sudo a2dissite sitename.conf |
| Enable a module | sudo a2enmod modulename |
| Renew SSL certificate | sudo certbot renew |
| Check cert expiry | sudo certbot certificates |
| Log in to MariaDB | sudo mysql -u root -p |
| Web root directory | /var/www/mywebsite/ |
| Apache config directory | /etc/apache2/sites-available/ |