Hardware Recommendations for a Basic LAMP Server
Before installing a single package, you need appropriate hardware. Below are the recommended minimums and comfortable targets for a personal or small-business LAMP server running Ubuntu 24.04 LTS.
CPU
Minimum: 2 cores Recommended: 4+ coresAny modern x86-64 processor. Intel Core i3/i5 or AMD Ryzen 3/5 are excellent choices.
RAM
Minimum: 2 GB Recommended: 4–8 GBMySQL in particular benefits greatly from available RAM for query caching and buffer pools.
Storage
Minimum: 20 GB SSD Recommended: 60–120 GB SSDSSDs dramatically improve MySQL I/O performance. Avoid spinning HDDs for the OS drive if possible.
Network
Minimum: 100 Mbps NIC Recommended: 1 Gbps NICA wired Ethernet connection is strongly preferred over Wi-Fi for server stability and consistent latency.
Power Supply
UPS recommendedAn Uninterruptible Power Supply (UPS) protects against sudden power loss that can corrupt MySQL databases and the filesystem.
Popular Options
PC / Mini-PC / NUCIntel NUC, Beelink Mini-PC, or any repurposed desktop PC are all practical. Raspberry Pi 5 (4 GB+) is recommended for ARM-based builds — it supports USB 3.0 SSD boot natively. The Pi 4 can work but requires an extra bootloader step to enable USB boot and is not recommended for new builds.
Installing Ubuntu 24.04 Server from Scratch
This section covers the complete bare-metal installation of Ubuntu 24.04 LTS Server for both standard x86-64 PCs and ARM64 Raspberry Pi hardware. Follow the path that matches your hardware.
Part A — x86-64 PC Installation
What You Will Need
- A USB flash drive, 4 GB or larger
- The Ubuntu 24.04 LTS Server ISO — download from ubuntu.com/download/server
- A tool to write the ISO to USB: Balena Etcher (Windows/Mac/Linux) or Rufus (Windows only)
- The target PC connected to your router via Ethernet
- A keyboard and monitor connected to the target PC for installation
Step 1 — Write the ISO to USB
- Download the Ubuntu 24.04 LTS Server ISO from ubuntu.com. The filename will look like
ubuntu-24.04-live-server-amd64.iso. - Open Balena Etcher (or Rufus). Select the ISO file, select your USB drive as the target, and click Flash. This will erase everything on the USB drive.
- When flashing is complete, safely eject the USB drive.
Step 2 — Boot From USB
- Insert the USB drive into the target PC and power it on.
- Enter the BIOS/UEFI boot menu — typically by pressing
F2,F10,F12, orDeleteimmediately on startup. The key varies by manufacturer — watch the screen for a prompt. - Select your USB drive from the boot device list and press Enter.
- The Ubuntu installer will load. You will see a GRUB menu — select Try or Install Ubuntu Server and press Enter.
Step 3 — Walk Through the Ubuntu Server Installer
The Ubuntu Server installer is text-based and keyboard-driven. Use the arrow keys to navigate, Space to select checkboxes, and Enter to confirm.
- Language — Select your language (English is the default) and press Enter.
- Keyboard Layout — Select your keyboard layout. Most users in the US select
English (US). - Installation Type — Select Ubuntu Server (not the minimized version). Press Enter.
- Network — The installer will detect your Ethernet interface and attempt DHCP. Leave this as-is for now — you will set the static IP after installation is complete (Section 3). Confirm the interface shows a valid IP and press Done.
- Proxy — Leave blank unless your network requires a proxy. Press Done.
- Ubuntu Archive Mirror — Accept the default mirror. Press Done when the test passes.
- Storage Configuration — For most installs, select Use an entire disk. Press Done, then confirm the destructive action warning — this will erase the disk.
- Profile Setup — Enter your name, a server hostname (e.g.,
lampserver), a username, and a strong password. Write the password down. - Ubuntu Pro — Select Skip for now. Press Continue.
- SSH Setup — Select Install OpenSSH server and press Space to check it, then Enter. This is essential — it lets you manage the server remotely.
- Featured Server Snaps — Do not select anything here. Press Done. All software will be installed manually.
- Installation — The installer copies files and installs the system. This takes 5–15 minutes.
- When installation completes, select Reboot Now. Remove the USB drive when prompted and press Enter.
Step 4 — First Login
After rebooting, log in with the username and password you created during installation. You are now at the Ubuntu Server command line.
# Always update immediately after a fresh install sudo apt update && sudo apt upgrade -y # Reboot if a kernel update was installed sudo reboot
Part B — Raspberry Pi ARM64 Installation
What You Will Need
- Raspberry Pi 4 or Pi 5 (4 GB RAM minimum recommended)
- Storage — choose one:
- microSD card — 16 GB or larger, Class 10 or UHS-I. Works on all Pi models. Fine for testing but slower than SSD for production.
- USB 3.0 SSD — faster and more reliable for a server. Only the Raspberry Pi 5 and newer support native USB boot out of the box. On a Pi 4, you must first update the bootloader EEPROM firmware before USB boot will work.
- The Raspberry Pi Imager tool — free from raspberrypi.com/software
- The Pi connected to your router via Ethernet (not Wi-Fi for a server)
- Optional: keyboard and monitor, or configure SSH headlessly (see below)
Step 1 — Write the Image Using Raspberry Pi Imager
- Download and install Raspberry Pi Imager on your desktop or laptop.
- Insert your microSD card into your computer.
- Open Raspberry Pi Imager. Under Choose Device, select your Pi model.
- Under Choose OS, navigate to: Other general-purpose OS → Ubuntu → Ubuntu Server 24.04 LTS (64-bit). Do not select the Desktop edition.
- Under Choose Storage, select your microSD card.
- Click Next → Edit Settings and configure:
- Hostname — set a name like
lampserver - Username and Password — create your admin user and a strong password
- Enable SSH — check this box and select Use password authentication
- Leave Wi-Fi blank — you will use Ethernet
- Hostname — set a name like
- Click Save, then Yes to apply the settings, then Yes to confirm writing. This erases the card.
- When writing and verification are complete, eject the microSD card safely.
Step 2 — Boot the Raspberry Pi
- Insert the microSD card into the Raspberry Pi.
- Connect the Ethernet cable to your router.
- Connect the power supply. The Pi boots automatically — there is no power button.
- Wait approximately 60–90 seconds for the first boot to complete.
Step 3 — Connect via SSH (Headless)
# Find the Pi's IP from your router's DHCP client list # Or use the hostname (may require mDNS/Avahi) ssh yourusername@lampserver.local # Or connect directly by IP ssh yourusername@192.168.1.XX # Accept the SSH fingerprint prompt by typing: yes
Step 4 — First Update on the Pi
sudo apt update && sudo apt upgrade -y sudo reboot
Setting Up a Static IP Address
A server must have a static (unchanging) local IP address so that your router's port forwarding rules always point to the right machine. Ubuntu 24.04 uses Netplan for network configuration.
cloud-init managing the network. Editing Netplan files directly will be overridden by cloud-init at reboot. You must disable cloud-init networking first. Skipping this step is a very common cause of frustration.
Step 1 — Identify Your Network Interface Name
ip link show # Look for an interface like eth0, ens3, enp3s0, or similar # lo is the loopback — ignore it
Step 2 — Find Your Router's Gateway IP
ip route show # The "default via" line shows your gateway — typically 192.168.1.1
Step 3 — Back Up the Existing Netplan Config
sudo cp /etc/netplan/00-installer-config.yaml \ /etc/netplan/00-installer-config.yaml.bak
Step 4 — Edit the Netplan Configuration File
Replace the contents of your Netplan file. The file name may vary — use ls /etc/netplan/ to see what is present. Substitute eth0 with your actual interface name, and adjust the IP addresses to match your network.
network: version: 2 renderer: networkd ethernets: eth0: # Replace with your interface name dhcp4: no addresses: - 192.168.1.50/24 routes: - to: default via: 192.168.1.1 nameservers: addresses: - 1.1.1.1 - 8.8.8.8
Step 5 — Apply and Verify
# Test the config first (dry run — safe) sudo netplan try # If no errors, apply it permanently sudo netplan apply # Verify the static IP is now active ip addr show eth0 # Test internet connectivity ping -c 4 google.com
Raspberry Pi — Disable cloud-init Networking First
sudo bash -c \ 'echo "network: {config: disabled}" > \ /etc/cloud/cloud.cfg.d/99-disable-network-config.cfg' # Now edit /etc/netplan/ as shown above, then apply: sudo netplan apply # Reboot to confirm the static IP survives a restart sudo reboot
ip addr show and confirm your server shows the static IP you configured. Also confirm you can reach the internet with ping -c 3 google.com.
Now Connect via SSH — Ditch the Server Keyboard for Good
With a confirmed static IP you now have a permanent, reliable address to SSH into. From this point forward you can sit at your regular desktop or laptop, open an SSH session to your server, and copy every command from this webpage and paste it directly into your terminal — no more typing long commands on a server keyboard, no more typos.
sudo apt install -y openssh-server sudo systemctl enable ssh sudo systemctl start ssh sudo systemctl status ssh
Connecting from Windows
Windows 10 and 11 both include a built-in SSH client. Open PowerShell or Command Prompt and run:
# Replace yourusername and IP with your actual values ssh yourusername@192.168.1.50 # First connection: type yes to accept fingerprint # To paste into PowerShell: right-click anywhere in the window
If you prefer a graphical SSH client, PuTTY (free at putty.org) is the most popular option. Enter your server's static IP under Host Name, leave the port as 22, and click Open. To paste in PuTTY: right-click in the terminal window.
Connecting from Linux or macOS
ssh yourusername@192.168.1.50 # Accept fingerprint on first connection: yes # To paste in most Linux terminals: Ctrl+Shift+V # To paste in macOS Terminal: Cmd+V
Router Setup & Port Forwarding
For your server to be reachable from the internet, your router must be configured to forward incoming traffic on the correct ports to your server's local IP address.
Before You Begin
- Know your server's local (LAN) IP address — e.g.,
192.168.1.50 - Log into your router's admin panel — typically at
http://192.168.1.1orhttp://192.168.0.1 - Look for a section called Port Forwarding, Virtual Servers, or NAT
Required Port Forwarding Rules
Rule Protocol Ext Port Int Port Destination ───────────────────────────────────────────────────── HTTP Web TCP 80 80 192.168.1.50 HTTPS Web TCP 443 443 192.168.1.50
Forwarding port 22 allows you to SSH into your server from the internet. This is a significant security risk if left on the default port. If you choose to enable it, strongly consider:
- Changing SSH to a non-standard port (e.g.,
2222) in/etc/ssh/sshd_config - Disabling password-based SSH login and using SSH key pairs only
- Enabling
fail2banto block brute-force attempts
If you only need SSH access from within your home network, do not forward port 22 to the internet at all.
Step-by-Step Port Forwarding
- Log into your router admin panel in your web browser.
- Navigate to the Port Forwarding or Virtual Servers section.
- Create a rule for HTTP: TCP, external port 80, internal port 80, destination IP = your server's static IP.
- Create a rule for HTTPS: TCP, external port 443, internal port 443, same destination IP.
- (Optional) Create a rule for SSH: TCP, external port 22 (or a custom port), internal port 22, same destination IP.
- Save and apply the rules. Some routers require a reboot.
- Verify your public IP address using whatismyip.com — this is the IP your domain name will point to.
Full LAMP Stack Installation
With networking configured, it's time to install the full stack — Apache2, MySQL (not MariaDB), and PHP along with all the recommended modules that make them work together correctly.
Step 1 — Update the System
sudo apt update && sudo apt upgrade -y
Step 2 — Install Apache2
sudo apt install -y apache2 sudo systemctl enable apache2 sudo systemctl start apache2 sudo systemctl status apache2
http://192.168.1.50). You should see the Apache2 Ubuntu Default Page.
Step 3 — Configure UFW Firewall
UFW must be configured before you enable it — enabling UFW with no rules in place will lock you out of SSH immediately.
# Allow HTTP — port 80 sudo ufw allow 80/tcp # Allow HTTPS — port 443 sudo ufw allow 443/tcp # Allow SSH — port 22 # WARNING: If you skip this, enabling UFW will lock you out sudo ufw allow 22/tcp # Now enable the firewall sudo ufw enable # Verify all rules are active sudo ufw status verbose
Status: active Default: deny (incoming), allow (outgoing) To Action From -- ------ ---- 80/tcp ALLOW IN Anywhere 443/tcp ALLOW IN Anywhere 22/tcp ALLOW IN Anywhere
- SSH moved to port 2222:
sudo ufw allow 2222/tcp - Web app on port 8080:
sudo ufw allow 8080/tcp - MySQL from LAN only:
sudo ufw allow from 192.168.1.0/24 to any port 3306
If you move SSH to a custom port, also run sudo ufw delete allow 22/tcp to close the original.
sudo ufw status numbered # List all rules with numbers sudo ufw delete 3 # Delete rule by number sudo ufw delete allow 8080/tcp # Delete rule by name sudo ufw disable # Disable UFW entirely sudo ufw reset # Reset to factory defaults
Step 4 — Install MySQL (Not MariaDB)
apt install mysql-server. To ensure you get Oracle's MySQL, add the official MySQL APT repository first.
# Download the MySQL APT config package wget https://dev.mysql.com/get/mysql-apt-config_0.8.29-1_all.deb # Install it — a dialog will appear # Select "MySQL Server & Cluster" then choose MySQL 8.x sudo dpkg -i mysql-apt-config_0.8.29-1_all.deb sudo apt update sudo apt install -y mysql-server sudo systemctl enable mysql sudo systemctl start mysql sudo systemctl status mysql
Step 5 — Secure MySQL
sudo mysql_secure_installation
- VALIDATE PASSWORD component? —
Y - Password strength level: — Choose
1(Medium) or2(Strong) - Set root password? —
Y— write it down securely - Remove anonymous users? —
Y - Disallow root login remotely? —
Y - Remove test database? —
Y - Reload privilege tables now? —
Y
Step 6 — Create a MySQL Database User
-- Log into MySQL as root sudo mysql -u root -p CREATE DATABASE mywebsite_db; CREATE USER 'webuser'@'localhost' IDENTIFIED BY 'YourStrongPassword123!'; GRANT ALL PRIVILEGES ON mywebsite_db.* TO 'webuser'@'localhost'; FLUSH PRIVILEGES; SELECT user, host FROM mysql.user; EXIT;
Step 7 — Verify MySQL Login as the New User
mysql -u webuser -p SHOW DATABASES; # You should see mywebsite_db listed EXIT;
Step 8 — Install PHP and All Recommended Modules
sudo apt install -y \ php8.3 \ php8.3-mysql \ php8.3-cli \ php8.3-common \ php8.3-curl \ php8.3-gd \ php8.3-intl \ php8.3-mbstring \ php8.3-xml \ php8.3-zip \ php8.3-bcmath \ php8.3-opcache \ libapache2-mod-php8.3 sudo a2enmod php8.3 sudo systemctl restart apache2 php --version
Step 9 — Enable Essential Apache Modules
sudo a2enmod rewrite sudo a2enmod headers sudo a2enmod ssl sudo a2enmod proxy sudo a2enmod proxy_http sudo systemctl restart apache2
Step 10 — Set Correct File Ownership
sudo chown -R www-data:www-data /var/www/html sudo usermod -aG www-data $USER sudo find /var/www/html -type d -exec chmod 755 {} \; sudo find /var/www/html -type f -exec chmod 644 {} \; newgrp www-data
Verifying PHP with phpinfo
The phpinfo() function produces a detailed page showing every PHP setting, loaded module, and environment variable. It's the definitive way to confirm your LAMP stack is wired together correctly.
phpinfo.php file exposes detailed server configuration information to anyone who visits it. Create it, verify your install, then delete it immediately. Never leave this file on a production server.
Step 1 — Create the File
sudo bash -c \ 'echo "<?php phpinfo(); ?>" > /var/www/html/phpinfo.php' sudo chown www-data:www-data /var/www/html/phpinfo.php sudo chmod 644 /var/www/html/phpinfo.php
Step 2 — View the Page in a Browser
Navigate to: http://your-server-ip/phpinfo.php
On the PHP info page, verify the following:
- PHP Version — should show 8.3.x at the top
- Server API — should show
Apache 2.0 Handler(not CLI) - mysqli — confirms PHP can talk to MySQL
- PDO — should show
pdo_mysqlas a driver - Loaded Configuration File — should point to
/etc/php/8.3/apache2/php.ini
Step 3 — Delete the File After Verification
sudo rm /var/www/html/phpinfo.php
Creating Your First Website (HTTP on Port 80)
Apache uses Virtual Host configuration files to serve websites. Each site gets its own config file in /etc/apache2/sites-available/. For this example, assume your domain is example.com. Replace it with your actual domain throughout.
Step 1 — Create the Website Document Root
sudo mkdir -p /var/www/example.com/public_html sudo chown -R www-data:www-data /var/www/example.com sudo chmod -R 755 /var/www/example.com
Step 2 — Create an Index HTML Page
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Success — My LAMP Server</title> </head> <body> <h1>Success! Your LAMP Server is Running.</h1> <p>Apache2, PHP, and MySQL are installed.</p> </body> </html>
sudo nano /var/www/example.com/public_html/index.html # Paste the HTML above, then press Ctrl+X, Y, Enter to save
Step 3 — Create the Virtual Host Configuration File
<VirtualHost *:80> ServerName example.com ServerAlias www.example.com DocumentRoot /var/www/example.com/public_html ServerAdmin webmaster@example.com <Directory /var/www/example.com/public_html> Options -Indexes +FollowSymLinks AllowOverride All Require all granted </Directory> ErrorLog ${APACHE_LOG_DIR}/example.com-error.log CustomLog ${APACHE_LOG_DIR}/example.com-access.log combined </VirtualHost>
Step 4 — Enable the Site and Reload Apache
sudo a2ensite example.com.conf sudo a2dissite 000-default.conf sudo apache2ctl configtest sudo systemctl reload apache2
http://example.com (or your server's IP). Your browser shows your custom HTML page — not the default Apache page. You are now serving a website over HTTP on port 80.
Installing Let's Encrypt with Certbot (HTTPS / Port 443)
Let's Encrypt provides free, trusted SSL/TLS certificates. Before proceeding, your domain's DNS A record must already point to your server's public IP address, and port 80 must be reachable from the internet.
Step 1 — Install Certbot
sudo apt install -y certbot python3-certbot-apache certbot --version
Step 2 — Obtain a Certificate for Your Domain
sudo certbot --apache -d example.com -d www.example.com
- Email address — Enter a valid email for expiry notifications
- Terms of Service — Enter
Ato agree - Redirect HTTP to HTTPS? — Choose
2to enable automatic redirect (recommended)
Step 3 — Verify the HTTPS Configuration
<IfModule mod_ssl.c> <VirtualHost *:443> ServerName example.com DocumentRoot /var/www/example.com/public_html SSLCertificateFile /etc/letsencrypt/live/example.com/fullchain.pem SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem Include /etc/letsencrypt/options-ssl-apache.conf </VirtualHost> </IfModule>
Step 4 — Test Automatic Certificate Renewal
sudo certbot renew --dry-run sudo systemctl status certbot.timer sudo certbot certificates
Apache Virtual Hosts — Multiple Domains on One Server
Apache can serve any number of distinct websites from a single server using Virtual Hosts. In this example, we'll add a second domain: secondsite.com.
Step 1 — Create the Document Root
sudo mkdir -p /var/www/secondsite.com/public_html sudo chown -R www-data:www-data /var/www/secondsite.com sudo chmod -R 755 /var/www/secondsite.com
Step 2 — Create the Virtual Host Config
<VirtualHost *:80> ServerName secondsite.com ServerAlias www.secondsite.com DocumentRoot /var/www/secondsite.com/public_html ServerAdmin webmaster@secondsite.com <Directory /var/www/secondsite.com/public_html> Options -Indexes +FollowSymLinks AllowOverride All Require all granted </Directory> ErrorLog ${APACHE_LOG_DIR}/secondsite.com-error.log CustomLog ${APACHE_LOG_DIR}/secondsite.com-access.log combined </VirtualHost>
sudo a2ensite secondsite.com.conf sudo apache2ctl configtest sudo systemctl reload apache2
Step 3 — Get SSL Certificate for the Second Domain
sudo certbot --apache -d secondsite.com -d www.secondsite.com
sudo a2ensite sitename.conf — Enable a sitesudo a2dissite sitename.conf — Disable a sitels /etc/apache2/sites-enabled/ — List all active sitessudo apache2ctl -S — Show all Virtual Host bindings
Advanced: HTTPS Reverse Proxy Virtual Hosts
A reverse proxy virtual host allows your LAMP server to act as a secure front-door for other services running on your local network. External visitors connect over HTTPS, and Apache silently forwards their requests to a different machine or port inside your network.
Prerequisites
- The
proxy,proxy_http, andheadersApache modules must be enabled (done in Section 5) - A valid SSL certificate for the subdomain must exist (from Section 8)
- The internal service must be running and reachable on its local IP and port
Step 1 — Obtain a Certificate for Your Subdomain
sudo certbot --apache -d app.example.com
Step 2 — Create the Reverse Proxy Virtual Host Config
<IfModule mod_ssl.c> <VirtualHost *:443> ServerName app.example.com ProxyPreserveHost On ProxyPass / http://192.168.1.42:4533/ ProxyPassReverse / http://192.168.1.42:4533/ Header always set Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" SSLCertificateFile /etc/letsencrypt/live/app.example.com/fullchain.pem SSLCertificateKeyFile /etc/letsencrypt/live/app.example.com/privkey.pem Include /etc/letsencrypt/options-ssl-apache.conf </VirtualHost> </IfModule>
Step 3 — Add a Port 80 Redirect
<VirtualHost *:80> ServerName app.example.com Redirect permanent / https://app.example.com/ </VirtualHost>
Step 4 — Enable the Configs and Test
sudo a2ensite app.example.com.conf sudo a2ensite app.example.com-ssl.conf sudo apache2ctl configtest sudo systemctl reload apache2 curl -I https://app.example.com
Setting Up a Second Physical Server as a Subdomain
Now we'll bring a second physical computer online as a separate web server running its own Apache instance, and expose it to the internet through your LAMP server as a subdomain — for example, server2.example.com.
Overview of the Architecture
Internet User
│
▼ (HTTPS — server2.example.com)
[Your LAMP Server — Public IP] ← Port 443
│
│ (HTTP — internal LAN)
▼
[Second Server — 192.168.1.51] ← Port 80
On the Second Server — Install Apache2
sudo apt update && sudo apt install -y apache2 sudo systemctl enable apache2 sudo systemctl start apache2 sudo mkdir -p /var/www/website2/public_html sudo chown -R www-data:www-data /var/www/website2 sudo chmod -R 755 /var/www/website2
On the Second Server — Virtual Host Config
<VirtualHost *:80> ServerName server2.example.com DocumentRoot /var/www/website2/public_html <Directory /var/www/website2/public_html> Options -Indexes +FollowSymLinks AllowOverride All Require all granted </Directory> ErrorLog ${APACHE_LOG_DIR}/website2-error.log CustomLog ${APACHE_LOG_DIR}/website2-access.log combined </VirtualHost>
sudo a2ensite website2.conf sudo a2dissite 000-default.conf sudo apache2ctl configtest sudo systemctl reload apache2
On the DNS — Create the Subdomain Record
Type: A Name: server2 (becomes server2.example.com) Value: YOUR.PUBLIC.IP.ADDRESS TTL: Auto (or 3600)
On the LAMP Server — Reverse Proxy for the Subdomain
sudo certbot --apache -d server2.example.com
<IfModule mod_ssl.c> <VirtualHost *:443> ServerName server2.example.com ProxyPreserveHost On ProxyPass / http://192.168.1.51:80/ ProxyPassReverse / http://192.168.1.51:80/ Header always set Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" SSLCertificateFile /etc/letsencrypt/live/server2.example.com/fullchain.pem SSLCertificateKeyFile /etc/letsencrypt/live/server2.example.com/privkey.pem Include /etc/letsencrypt/options-ssl-apache.conf </VirtualHost> </IfModule>
<VirtualHost *:80> ServerName server2.example.com Redirect permanent / https://server2.example.com/ </VirtualHost>
sudo a2ensite server2.example.com.conf sudo a2ensite server2.example.com-ssl.conf sudo apache2ctl configtest sudo systemctl reload apache2
https://server2.example.com in a browser. You should see the "Website 2" page with a valid padlock — confirming that HTTPS traffic is being handled by your LAMP server and transparently proxied to the second physical server on your LAN.