Lesson 1 — Complete Walkthrough

Building a LAMP Server
from Scratch

A no-skip, step-by-step professional guide covering hardware selection through HTTPS virtual hosting — Ubuntu 24.04 · Apache2 · MySQL · PHP

Ubuntu 24.04 LTS Apache 2.4 MySQL 8.x PHP 8.3 Let's Encrypt / Certbot Virtual Hosts

Created: March 2026  ·  Written by Nicole M. Taylor

⚠️
Disclaimer — Software Changes Over Time This guide was written in March 2026 for Ubuntu 24.04 LTS, Apache 2.4, MySQL 8.x, and PHP 8.3. Linux distributions, package managers, and web software are updated frequently — package names, version numbers, configuration file locations, and installer screens may differ from what is shown here. Always verify commands against the official documentation for the version you are installing. Written by Nicole M. Taylor   Contact
01

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+ cores

Any modern x86-64 processor. Intel Core i3/i5 or AMD Ryzen 3/5 are excellent choices.

RAM

Minimum: 2 GB Recommended: 4–8 GB

MySQL in particular benefits greatly from available RAM for query caching and buffer pools.

Storage

Minimum: 20 GB SSD Recommended: 60–120 GB SSD

SSDs dramatically improve MySQL I/O performance. Avoid spinning HDDs for the OS drive if possible.

Network

Minimum: 100 Mbps NIC Recommended: 1 Gbps NIC

A wired Ethernet connection is strongly preferred over Wi-Fi for server stability and consistent latency.

Power Supply

UPS recommended

An Uninterruptible Power Supply (UPS) protects against sudden power loss that can corrupt MySQL databases and the filesystem.

Popular Options

PC / Mini-PC / NUC

Intel 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.

ℹ️
Raspberry Pi Users — Read This First If you choose a Raspberry Pi, use the 64-bit (arm64) Ubuntu Server 24.04 image. Ubuntu on the Raspberry Pi uses cloud-init for its initial networking configuration — this causes problems with setting a local static IP in the traditional way. See Section 3 for the correct approach.

02

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.

ℹ️
Server Edition vs. Desktop Edition Always use the Server edition of Ubuntu for a LAMP server — not the Desktop edition. Server has no graphical interface, uses fewer resources, and gives you full control over exactly what is installed. Everything in this guide is done through the command line (CLI).

Part A — x86-64 PC Installation

What You Will Need

Step 1 — Write the ISO to USB

  1. Download the Ubuntu 24.04 LTS Server ISO from ubuntu.com. The filename will look like ubuntu-24.04-live-server-amd64.iso.
  2. 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.
  3. When flashing is complete, safely eject the USB drive.

Step 2 — Boot From USB

  1. Insert the USB drive into the target PC and power it on.
  2. Enter the BIOS/UEFI boot menu — typically by pressing F2, F10, F12, or Delete immediately on startup. The key varies by manufacturer — watch the screen for a prompt.
  3. Select your USB drive from the boot device list and press Enter.
  4. 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.

  1. Language — Select your language (English is the default) and press Enter.
  2. Keyboard Layout — Select your keyboard layout. Most users in the US select English (US).
  3. Installation Type — Select Ubuntu Server (not the minimized version). Press Enter.
  4. 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.
  5. Proxy — Leave blank unless your network requires a proxy. Press Done.
  6. Ubuntu Archive Mirror — Accept the default mirror. Press Done when the test passes.
  7. Storage Configuration — For most installs, select Use an entire disk. Press Done, then confirm the destructive action warning — this will erase the disk.
  8. Profile Setup — Enter your name, a server hostname (e.g., lampserver), a username, and a strong password. Write the password down.
  9. Ubuntu Pro — Select Skip for now. Press Continue.
  10. SSH Setup — Select Install OpenSSH server and press Space to check it, then Enter. This is essential — it lets you manage the server remotely.
  11. Featured Server Snaps — Do not select anything here. Press Done. All software will be installed manually.
  12. Installation — The installer copies files and installs the system. This takes 5–15 minutes.
  13. 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.

First Boot — Update the SystemBASH
# Always update immediately after a fresh install
sudo apt update && sudo apt upgrade -y

# Reboot if a kernel update was installed
sudo reboot
x86-64 Install Complete Your server is installed and updated. Next: go to Section 3 and set your static IP first. Once that is done, Section 3 will walk you through connecting via SSH so you can copy and paste every remaining command from this webpage directly into your session.

Part B — Raspberry Pi ARM64 Installation

What You Will Need

⚠️
Raspberry Pi 4 USB Boot — Extra Step Required The Pi 4 does not boot from USB 3.0 by default. You must first boot from a microSD card with a special bootloader image, let it update the EEPROM firmware, then power off, remove the SD card, and connect your USB SSD. The Raspberry Pi 5 does not require this step — it supports USB boot natively.

Step 1 — Write the Image Using Raspberry Pi Imager

  1. Download and install Raspberry Pi Imager on your desktop or laptop.
  2. Insert your microSD card into your computer.
  3. Open Raspberry Pi Imager. Under Choose Device, select your Pi model.
  4. Under Choose OS, navigate to: Other general-purpose OS → Ubuntu → Ubuntu Server 24.04 LTS (64-bit). Do not select the Desktop edition.
  5. Under Choose Storage, select your microSD card.
  6. 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
  7. Click Save, then Yes to apply the settings, then Yes to confirm writing. This erases the card.
  8. When writing and verification are complete, eject the microSD card safely.

Step 2 — Boot the Raspberry Pi

  1. Insert the microSD card into the Raspberry Pi.
  2. Connect the Ethernet cable to your router.
  3. Connect the power supply. The Pi boots automatically — there is no power button.
  4. Wait approximately 60–90 seconds for the first boot to complete.

Step 3 — Connect via SSH (Headless)

Connect to Pi via SSHBASH
# 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

First Boot — Update the SystemBASH
sudo apt update && sudo apt upgrade -y
sudo reboot
⚠️
Raspberry Pi — Disable cloud-init Before Setting Static IP Ubuntu on the Raspberry Pi uses cloud-init to manage networking on first boot. Before you proceed to Section 3 to set a static IP, you must disable cloud-init's network control first — otherwise your static IP settings will be overwritten on every reboot. The exact commands are in Section 3.
ARM64 / Raspberry Pi Install Complete Your Pi is running Ubuntu 24.04 Server. Next: go to Section 3 and set your static IP first (disabling cloud-init networking before you do). Once the static IP is confirmed, Section 3 will walk you through connecting via SSH from Windows or Linux.

03

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.

🚫
Raspberry Pi Users — Important Difference Ubuntu on a Raspberry Pi ships with 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

Find Your InterfaceBASH
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

Find GatewayBASH
ip route show
# The "default via" line shows your gateway — typically 192.168.1.1

Step 3 — Back Up the Existing Netplan Config

BackupBASH
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.

/etc/netplan/00-installer-config.yamlYAML
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
⚠️
YAML is Indentation-Sensitive YAML files use spaces — never tabs — for indentation. Incorrect indentation will cause Netplan to fail silently or throw a parse error. Use exactly 2 spaces per indentation level as shown above.

Step 5 — Apply and Verify

Apply Network ConfigBASH
# 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

Disable cloud-init Network Management (Raspberry Pi)BASH
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
Verification After applying (and rebooting if on Raspberry Pi), run 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.

💡
Make Sure SSH Is Installed on the Server If you selected Install OpenSSH server during the Ubuntu installer you are already done. If you skipped it, go back to the server keyboard one last time and run this:
Install SSH if Not Already PresentBASH
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:

Windows PowerShell or Command PromptBASH
# 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

Linux / macOS TerminalBASH
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
You Are Now Connected via SSH Your server keyboard and monitor can be unplugged. Every command from this point forward can be copied from this webpage and pasted into your SSH session. Continue to Section 4 (Router & Port Forwarding) then Section 5 for the full LAMP stack installation.

04

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

Required Port Forwarding Rules

Port Forwarding RulesTABLE
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
🔐
Optional — SSH Port Forwarding (Port 22)

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 fail2ban to 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

  1. Log into your router admin panel in your web browser.
  2. Navigate to the Port Forwarding or Virtual Servers section.
  3. Create a rule for HTTP: TCP, external port 80, internal port 80, destination IP = your server's static IP.
  4. Create a rule for HTTPS: TCP, external port 443, internal port 443, same destination IP.
  5. (Optional) Create a rule for SSH: TCP, external port 22 (or a custom port), internal port 22, same destination IP.
  6. Save and apply the rules. Some routers require a reboot.
  7. Verify your public IP address using whatismyip.com — this is the IP your domain name will point to.
⚠️
Dynamic IP Addresses Most residential ISPs assign a dynamic public IP — meaning it can change without notice. Solutions include paying your ISP for a static IP, or using a Dynamic DNS (DDNS) service such as DuckDNS or Cloudflare which automatically updates your DNS record whenever your IP changes.

05

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

System UpdateBASH
sudo apt update && sudo apt upgrade -y

Step 2 — Install Apache2

Install Apache2BASH
sudo apt install -y apache2
sudo systemctl enable apache2
sudo systemctl start apache2
sudo systemctl status apache2
ℹ️
Quick Test Open a browser on another device on your network and navigate to your server's local IP (e.g., 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.

🚫
Do Not Enable UFW Before Adding Your Rules Enabling UFW with an empty ruleset blocks all incoming connections including your current SSH session. Add all the rules first, then enable UFW as the final step.
Configure UFW RulesBASH
# 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
Expected UFW Status OutputTEXT
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
⚠️
If You Use Non-Standard Ports — You Must Add Rules for Them Too UFW blocks every port not explicitly allowed. Common examples:
  • 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.

UFW Management ReferenceBASH
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)

⚠️
MySQL vs. MariaDB Ubuntu's default repositories may install MariaDB when you run apt install mysql-server. To ensure you get Oracle's MySQL, add the official MySQL APT repository first.
Add Official MySQL RepositoryBASH
# 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

Secure MySQL InstallationBASH
sudo mysql_secure_installation

Step 6 — Create a MySQL Database User

Create Database UserSQL
-- 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

Test User LoginBASH
mysql -u webuser -p
SHOW DATABASES;
# You should see mywebsite_db listed
EXIT;

Step 8 — Install PHP and All Recommended Modules

Install PHP 8.3 and ModulesBASH
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

Enable Apache ModulesBASH
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

File Ownership & PermissionsBASH
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

06

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.

🚫
Security Warning — Delete This File After Testing The 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

Create phpinfo.phpBASH
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:

Step 3 — Delete the File After Verification

Delete phpinfo.phpBASH
sudo rm /var/www/html/phpinfo.php

07

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

Create Web Root DirectoryBASH
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

/var/www/example.com/public_html/index.htmlHTML
<!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>
Write the Index FileBASH
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

/etc/apache2/sites-available/example.com.confAPACHE
<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

Enable SiteBASH
sudo a2ensite example.com.conf
sudo a2dissite 000-default.conf
sudo apache2ctl configtest
sudo systemctl reload apache2
Success Check Navigate to 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.

08

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.

⚠️
DNS Must Resolve First Certbot verifies domain ownership by making an HTTP request to your server from the internet. If your domain's DNS is not yet pointing to your public IP — or if port 80 is blocked — certificate issuance will fail. Verify DNS propagation first using dnschecker.org.

Step 1 — Install Certbot

Install CertbotBASH
sudo apt install -y certbot python3-certbot-apache
certbot --version

Step 2 — Obtain a Certificate for Your Domain

Request SSL CertificateBASH
sudo certbot --apache -d example.com -d www.example.com

Step 3 — Verify the HTTPS Configuration

/etc/apache2/sites-available/example.com-le-ssl.confAPACHE
<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

Test Auto-RenewalBASH
sudo certbot renew --dry-run
sudo systemctl status certbot.timer
sudo certbot certificates
Success Check The dry run completes without errors. Your site loads over HTTPS with a valid padlock. HTTP traffic automatically redirects to HTTPS.

09

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

Create Second Site DirectoryBASH
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

/etc/apache2/sites-available/secondsite.com.confAPACHE
<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>
Enable Second SiteBASH
sudo a2ensite secondsite.com.conf
sudo apache2ctl configtest
sudo systemctl reload apache2

Step 3 — Get SSL Certificate for the Second Domain

Issue Certificate for Second DomainBASH
sudo certbot --apache -d secondsite.com -d www.secondsite.com
ℹ️
Useful Management Commands
sudo a2ensite sitename.conf — Enable a site
sudo a2dissite sitename.conf — Disable a site
ls /etc/apache2/sites-enabled/ — List all active sites
sudo apache2ctl -S — Show all Virtual Host bindings

10

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

Step 1 — Obtain a Certificate for Your Subdomain

Issue Certificate for SubdomainBASH
sudo certbot --apache -d app.example.com

Step 2 — Create the Reverse Proxy Virtual Host Config

/etc/apache2/sites-available/app.example.com-ssl.confAPACHE
<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

/etc/apache2/sites-available/app.example.com.confAPACHE
<VirtualHost *:80>
    ServerName app.example.com
    Redirect   permanent / https://app.example.com/
</VirtualHost>

Step 4 — Enable the Configs and Test

Enable Reverse Proxy SitesBASH
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

11

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

Traffic FlowTEXT
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

Second Server — Install ApacheBASH
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

/etc/apache2/sites-available/website2.confAPACHE
<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>
Enable on Second ServerBASH
sudo a2ensite website2.conf
sudo a2dissite 000-default.conf
sudo apache2ctl configtest
sudo systemctl reload apache2

On the DNS — Create the Subdomain Record

DNS RecordTEXT
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

Issue Certificate (LAMP Server)BASH
sudo certbot --apache -d server2.example.com
server2.example.com-ssl.conf (LAMP Server)APACHE
<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>
server2.example.com.conf (LAMP Server)APACHE
<VirtualHost *:80>
    ServerName server2.example.com
    Redirect   permanent / https://server2.example.com/
</VirtualHost>
Enable and Reload on LAMP ServerBASH
sudo a2ensite server2.example.com.conf
sudo a2ensite server2.example.com-ssl.conf
sudo apache2ctl configtest
sudo systemctl reload apache2
Final Verification Visit 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.
💡
What's Coming Next — File Permissions Deep Dive A dedicated Lesson 2 will cover Linux file permission levels in depth: understanding octal notation, setuid/setgid bits, sticky bits, ACLs, and best practices for securing your web directories beyond the basics covered here.