{"id":403,"date":"2026-03-17T19:44:56","date_gmt":"2026-03-17T19:44:56","guid":{"rendered":"https:\/\/www.anfamily.cloud\/home\/?page_id=403"},"modified":"2026-03-17T19:44:59","modified_gmt":"2026-03-17T19:44:59","slug":"lamp-server-setup-complete-guide","status":"publish","type":"page","link":"https:\/\/www.anfamily.cloud\/home\/index.php\/lamp-server-setup-complete-guide\/","title":{"rendered":"LAMP Server Setup \u2014 Complete Guide"},"content":{"rendered":"\n<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n<meta charset=\"UTF-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n<title>LAMP Server Setup \u2014 Complete Guide<\/title>\n<link href=\"https:\/\/fonts.googleapis.com\/css2?family=IBM+Plex+Mono:wght@400;600&#038;family=IBM+Plex+Sans:ital,wght@0,300;0,400;0,600;0,700;1,400&#038;display=swap\" rel=\"stylesheet\">\n<style>\n  :root {\n    --bg: #f7f9fc;\n    --surface: #ffffff;\n    --surface2: #eef2f9;\n    --border: #d0daea;\n    --blue-dark: #0d2a6e;\n    --blue-mid: #1a56db;\n    --blue-light: #3b82f6;\n    --blue-pale: #dbeafe;\n    --accent: #0ea5e9;\n    --accent2: #06b6d4;\n    --warn: #f59e0b;\n    --warn-bg: #fffbeb;\n    --warn-border: #fcd34d;\n    --danger: #dc2626;\n    --danger-bg: #fef2f2;\n    --danger-border: #fca5a5;\n    --success: #16a34a;\n    --success-bg: #f0fdf4;\n    --success-border: #86efac;\n    --text: #0f172a;\n    --text-muted: #475569;\n    --text-light: #94a3b8;\n    --code-bg: #0f1729;\n    --code-text: #e2e8f0;\n    --font-body: 'IBM Plex Sans', sans-serif;\n    --font-mono: 'IBM Plex Mono', monospace;\n    --radius: 8px;\n    --shadow: 0 1px 3px rgba(13,42,110,0.08), 0 4px 16px rgba(13,42,110,0.06);\n    --shadow-lg: 0 4px 24px rgba(13,42,110,0.12);\n  }\n\n  *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; min-width: 0; }\n\n  html { scroll-behavior: smooth; overflow-x: hidden; max-width: 100%; }\n\n  body {\n    font-family: var(--font-body);\n    background: var(--bg);\n    color: var(--text);\n    font-size: 16px;\n    line-height: 1.7;\n    overflow-x: hidden;\n    max-width: 100%;\n  }\n\n  \/* \u2500\u2500 HEADER \u2500\u2500 *\/\n  header {\n    background: linear-gradient(135deg, var(--blue-dark) 0%, #1a3a8f 60%, #1e50c8 100%);\n    color: #fff;\n    padding: 3rem 1.5rem 2.5rem;\n    text-align: center;\n    position: relative;\n    overflow: hidden;\n  }\n  header::before {\n    content: '';\n    position: absolute;\n    inset: 0;\n    background: repeating-linear-gradient(90deg, rgba(255,255,255,0.03) 0px, rgba(255,255,255,0.03) 1px, transparent 1px, transparent 80px);\n    pointer-events: none;\n  }\n  header .badge {\n    display: inline-block;\n    background: rgba(255,255,255,0.12);\n    border: 1px solid rgba(255,255,255,0.2);\n    color: #bfdbfe;\n    font-size: 0.75rem;\n    font-weight: 600;\n    letter-spacing: 0.1em;\n    text-transform: uppercase;\n    padding: 0.3rem 0.9rem;\n    border-radius: 999px;\n    margin-bottom: 1rem;\n  }\n  header h1 {\n    font-size: clamp(1.5rem, 6vw, 3rem);\n    font-weight: 700;\n    letter-spacing: -0.02em;\n    line-height: 1.15;\n    margin-bottom: 0.75rem;\n    word-break: break-word;\n  }\n  header h1 span { color: #93c5fd; }\n  header p.subtitle {\n    color: #bfdbfe;\n    font-size: clamp(0.88rem, 2vw, 1.1rem);\n    max-width: 680px;\n    margin: 0 auto 1.5rem;\n    font-weight: 300;\n  }\n  .stack-badges {\n    display: flex;\n    flex-wrap: wrap;\n    justify-content: center;\n    gap: 0.5rem;\n    margin-top: 1rem;\n  }\n  .stack-badge {\n    background: rgba(255,255,255,0.1);\n    border: 1px solid rgba(255,255,255,0.15);\n    color: #e0f2fe;\n    font-family: var(--font-mono);\n    font-size: 0.78rem;\n    padding: 0.3rem 0.8rem;\n    border-radius: var(--radius);\n  }\n\n  \/* \u2500\u2500 DISCLAIMER \u2500\u2500 *\/\n  .disclaimer-wrap {\n    background: #fffbeb;\n    border-top: 4px solid #f59e0b;\n    border-bottom: 4px solid #f59e0b;\n    padding: 1rem 1.25rem;\n    overflow-x: hidden;\n    width: 100%;\n  }\n  .disclaimer-inner {\n    max-width: 900px;\n    margin: 0 auto;\n    display: flex;\n    align-items: flex-start;\n    gap: 0.75rem;\n    text-align: left;\n    font-size: 0.88rem;\n    color: #78350f;\n    line-height: 1.6;\n  }\n  .disclaimer-icon { font-size: 1.4rem; flex-shrink: 0; }\n\n  \/* \u2500\u2500 TOC \u2500\u2500 *\/\n  nav.toc {\n    background: var(--surface);\n    border: 1px solid var(--border);\n    border-radius: var(--radius);\n    padding: 1.5rem;\n    margin: 2rem auto;\n    max-width: 900px;\n    box-shadow: var(--shadow);\n  }\n  nav.toc h2 {\n    font-size: 0.75rem;\n    font-weight: 700;\n    letter-spacing: 0.12em;\n    text-transform: uppercase;\n    color: var(--blue-mid);\n    margin-bottom: 1rem;\n    border-bottom: 2px solid var(--blue-pale);\n    padding-bottom: 0.5rem;\n  }\n  nav.toc ol {\n    list-style: none;\n    counter-reset: toc;\n    display: grid;\n    grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));\n    gap: 0.3rem 1.5rem;\n  }\n  nav.toc li { counter-increment: toc; }\n  nav.toc a {\n    display: flex;\n    align-items: baseline;\n    gap: 0.5rem;\n    color: var(--blue-mid);\n    text-decoration: none;\n    font-size: 0.9rem;\n    padding: 0.25rem 0;\n    transition: color 0.15s;\n  }\n  nav.toc a::before {\n    content: counter(toc, decimal-leading-zero);\n    font-family: var(--font-mono);\n    font-size: 0.72rem;\n    color: var(--accent);\n    font-weight: 600;\n    flex-shrink: 0;\n  }\n  nav.toc a:hover { color: var(--blue-dark); }\n\n  \/* \u2500\u2500 MAIN LAYOUT \u2500\u2500 *\/\n  main { max-width: 900px; margin: 0 auto; padding: 0 1.25rem 4rem; }\n\n  \/* \u2500\u2500 SECTIONS \u2500\u2500 *\/\n  .lesson-section { margin-bottom: 3.5rem; }\n  .section-header {\n    display: flex;\n    align-items: center;\n    gap: 1rem;\n    margin-bottom: 1.5rem;\n    padding-bottom: 0.75rem;\n    border-bottom: 2px solid var(--blue-pale);\n  }\n  .section-number {\n    display: flex;\n    align-items: center;\n    justify-content: center;\n    width: 2.5rem;\n    height: 2.5rem;\n    border-radius: 50%;\n    background: linear-gradient(135deg, var(--blue-dark), var(--blue-mid));\n    color: white;\n    font-family: var(--font-mono);\n    font-weight: 600;\n    font-size: 0.9rem;\n    flex-shrink: 0;\n    box-shadow: 0 2px 8px rgba(26,86,219,0.35);\n  }\n  .section-header h2 {\n    font-size: clamp(1rem, 2.5vw, 1.4rem);\n    font-weight: 700;\n    color: var(--blue-dark);\n    letter-spacing: -0.01em;\n    line-height: 1.25;\n  }\n\n  p { margin-bottom: 1rem; color: var(--text); }\n  p:last-child { margin-bottom: 0; }\n\n  h3 {\n    font-size: 1.05rem;\n    font-weight: 700;\n    color: var(--blue-dark);\n    margin: 1.75rem 0 0.75rem;\n    display: flex;\n    align-items: center;\n    gap: 0.5rem;\n  }\n  h3::before {\n    content: '';\n    display: inline-block;\n    width: 3px;\n    height: 1.1em;\n    background: var(--accent);\n    border-radius: 2px;\n    flex-shrink: 0;\n  }\n  h4 { font-size: 0.95rem; font-weight: 600; color: var(--text); margin: 1.25rem 0 0.5rem; }\n  ul, ol { padding-left: 1.5rem; margin-bottom: 1rem; }\n  li { margin-bottom: 0.3rem; }\n\n  \/* \u2500\u2500 CALLOUT BOXES \u2500\u2500 *\/\n  .callout {\n    border-radius: var(--radius);\n    padding: 1rem 1.25rem;\n    margin: 1.25rem 0;\n    display: flex;\n    gap: 0.85rem;\n    align-items: flex-start;\n    font-size: 0.92rem;\n  }\n  .callout-icon { font-size: 1.1rem; flex-shrink: 0; margin-top: 0.1rem; }\n  .callout-body { flex: 1; min-width: 0; }\n  .callout-body strong { display: block; margin-bottom: 0.25rem; }\n  .callout.warn { background: var(--warn-bg); border: 1px solid var(--warn-border); color: #78350f; }\n  .callout.warn strong { color: #92400e; }\n  .callout.danger { background: var(--danger-bg); border: 1px solid var(--danger-border); color: #7f1d1d; }\n  .callout.danger strong { color: #991b1b; }\n  .callout.info { background: var(--blue-pale); border: 1px solid #93c5fd; color: #1e3a5f; }\n  .callout.info strong { color: var(--blue-dark); }\n  .callout.success { background: var(--success-bg); border: 1px solid var(--success-border); color: #14532d; }\n  .callout.success strong { color: #166534; }\n  .callout.optional { background: #f5f3ff; border: 1px solid #c4b5fd; color: #3b0764; }\n  .callout.optional strong { color: #4c1d95; }\n\n  \/* \u2500\u2500 CODE BLOCKS \u2500\u2500 *\/\n  .code-wrap {\n    margin: 1.25rem 0;\n    border-radius: var(--radius);\n    overflow: hidden;\n    box-shadow: var(--shadow-lg);\n    border: 1px solid #1e2d4e;\n    width: 100%;\n    max-width: 100%;\n  }\n  .code-label {\n    background: #1a2540;\n    color: #64748b;\n    font-family: var(--font-mono);\n    font-size: 0.7rem;\n    font-weight: 600;\n    letter-spacing: 0.08em;\n    text-transform: uppercase;\n    padding: 0.45rem 1rem;\n    display: flex;\n    align-items: center;\n    gap: 0.5rem;\n    border-bottom: 1px solid #1e2d4e;\n  }\n  .code-label .dots { display: flex; gap: 5px; }\n  .code-label .dot { width: 10px; height: 10px; border-radius: 50%; }\n  .dot-r { background: #ff5f56; }\n  .dot-y { background: #ffbd2e; }\n  .dot-g { background: #27c93f; }\n  .code-label .lang { margin-left: auto; color: #475569; }\n\n  pre {\n    background: var(--code-bg);\n    color: #e2e8f0;\n    margin: 0;\n    padding: 1.25rem;\n    overflow-x: auto;\n    font-family: var(--font-mono);\n    font-size: clamp(0.65rem, 2vw, 0.82rem);\n    line-height: 1.7;\n    -webkit-overflow-scrolling: touch;\n    white-space: pre;\n    word-break: normal;\n    max-width: 100%;\n  }\n\n  \/* Syntax highlighting *\/\n  .kw  { color: #e879f9; }\n  .cm  { color: #94a3b8; font-style: italic; }\n  .str { color: #6ee7b7; }\n  .num { color: #fdba74; }\n  .fn  { color: #ffffff; font-weight: 600; }\n  .fl  { color: #f9a8d4; }\n  .pt  { color: #fde68a; }\n  .op  { color: #cbd5e1; }\n  .va  { color: #7dd3fc; }\n  .ht  { color: #ffffff; font-weight: 700; }\n  .ky  { color: #c4b5fd; }\n  .vl  { color: #86efac; }\n\n  code.inline {\n    font-family: var(--font-mono);\n    background: var(--surface2);\n    color: var(--blue-dark);\n    border: 1px solid var(--border);\n    padding: 0.1em 0.4em;\n    border-radius: 4px;\n    font-size: 0.85em;\n    white-space: nowrap;\n  }\n\n  \/* \u2500\u2500 HARDWARE GRID \u2500\u2500 *\/\n  .hw-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); gap: 1rem; margin: 1.25rem 0; }\n  .hw-card { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); padding: 1rem; box-shadow: var(--shadow); }\n  .hw-card h4 { color: var(--blue-mid); font-size: 0.8rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.06em; margin: 0 0 0.5rem; }\n  .hw-card p { font-size: 0.88rem; margin: 0; color: var(--text-muted); }\n  .hw-card .spec { font-family: var(--font-mono); color: var(--text); font-size: 0.82rem; font-weight: 600; margin-bottom: 0.15rem; display: block; }\n\n  \/* \u2500\u2500 STEP BLOCKS \u2500\u2500 *\/\n  .steps { counter-reset: step; list-style: none; padding: 0; }\n  .steps li { counter-increment: step; display: flex; gap: 1rem; margin-bottom: 1.5rem; align-items: flex-start; }\n  .steps li::before {\n    content: counter(step);\n    display: flex;\n    align-items: center;\n    justify-content: center;\n    min-width: 1.75rem;\n    height: 1.75rem;\n    border-radius: 50%;\n    background: var(--blue-pale);\n    color: var(--blue-dark);\n    font-family: var(--font-mono);\n    font-weight: 700;\n    font-size: 0.78rem;\n    flex-shrink: 0;\n    margin-top: 0.15rem;\n    border: 2px solid #93c5fd;\n  }\n  .steps li > div { flex: 1; min-width: 0; }\n\n  \/* \u2500\u2500 DIVIDER \u2500\u2500 *\/\n  hr.section-divider { border: none; height: 1px; background: linear-gradient(to right, transparent, var(--border), transparent); margin: 3rem 0; }\n\n  \/* \u2500\u2500 FOOTER \u2500\u2500 *\/\n  footer { background: var(--blue-dark); color: #ffffff; text-align: center; padding: 2rem 1.5rem; font-size: 0.85rem; margin-top: 3rem; }\n  footer strong { color: #ffffff; }\n\n  \/* \u2500\u2500 RESPONSIVE \u2500\u2500 *\/\n  @media (max-width: 600px) {\n    nav.toc ol { grid-template-columns: 1fr; }\n    .hw-grid { grid-template-columns: 1fr; }\n    .code-label .lang { display: none; }\n    .code-label { font-size: 0.62rem; padding: 0.4rem 0.75rem; }\n    pre { font-size: 0.68rem; padding: 0.85rem 0.75rem; line-height: 1.6; }\n    main { padding: 0 1rem 3rem; }\n    nav.toc { margin: 1rem; padding: 1rem; }\n    header { padding: 2rem 1rem 1.75rem; }\n    code.inline { font-size: 0.78em; white-space: normal; word-break: break-all; }\n    .callout { padding: 0.85rem 1rem; font-size: 0.87rem; }\n    .steps li { gap: 0.65rem; }\n  }\n\n  @media (max-width: 400px) {\n    pre { font-size: 0.62rem; padding: 0.7rem 0.6rem; }\n    header h1 { font-size: 1.3rem; }\n  }\n<\/style>\n<\/head>\n<body>\n\n<header>\n  <div class=\"badge\">Lesson 1 \u2014 Complete Walkthrough<\/div>\n  <h1>Building a <span>LAMP Server<\/span><br>from Scratch<\/h1>\n  <p class=\"subtitle\">A no-skip, step-by-step professional guide covering hardware selection through HTTPS virtual hosting \u2014 Ubuntu 24.04 \u00b7 Apache2 \u00b7 MySQL \u00b7 PHP<\/p>\n  <div class=\"stack-badges\">\n    <span class=\"stack-badge\">Ubuntu 24.04 LTS<\/span>\n    <span class=\"stack-badge\">Apache 2.4<\/span>\n    <span class=\"stack-badge\">MySQL 8.x<\/span>\n    <span class=\"stack-badge\">PHP 8.3<\/span>\n    <span class=\"stack-badge\">Let&#8217;s Encrypt \/ Certbot<\/span>\n    <span class=\"stack-badge\">Virtual Hosts<\/span>\n  <\/div>\n  <p style=\"margin-top:1.25rem; font-size:0.8rem; color:rgba(255,255,255,0.4);\">Created: March 2026 &nbsp;&middot;&nbsp; Written by Nicole M. Taylor<\/p>\n<\/header>\n\n<div class=\"disclaimer-wrap\">\n  <div class=\"disclaimer-inner\">\n    <span class=\"disclaimer-icon\">\u26a0\ufe0f<\/span>\n    <div>\n      <strong style=\"display:block; margin-bottom:0.25rem; color:#92400e; font-size:0.95rem;\">Disclaimer \u2014 Software Changes Over Time<\/strong>\n      This guide was written in <strong>March 2026<\/strong> 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 \u2014 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.\n      <span style=\"display:block; margin-top:0.5rem;\">Written by <strong>Nicole M. Taylor<\/strong>\n        &nbsp;<a href=\"mailto:nicolemtaylor1972@gmail.com\" title=\"Contact Nicole M. Taylor\" style=\"color:#92400e; text-decoration:none; display:inline-flex; align-items:center; gap:0.25rem; vertical-align:middle;\">\n          <svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" style=\"vertical-align:middle;\"><rect x=\"2\" y=\"4\" width=\"20\" height=\"16\" rx=\"2\"\/><path d=\"m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7\"\/><\/svg>\n          <span style=\"font-size:0.82rem; border-bottom:1px dotted #92400e;\">Contact<\/span>\n        <\/a>\n      <\/span>\n    <\/div>\n  <\/div>\n<\/div>\n\n<nav class=\"toc\">\n  <h2>Table of Contents<\/h2>\n  <ol>\n    <li><a href=\"#s1\">Hardware Recommendations<\/a><\/li>\n    <li><a href=\"#s2\">Installing Ubuntu 24.04 Server (x86-64 &amp; ARM64)<\/a><\/li>\n    <li><a href=\"#s3\">Static IP Address Setup<\/a><\/li>\n    <li><a href=\"#s4\">Router &amp; Port Forwarding<\/a><\/li>\n    <li><a href=\"#s5\">Full LAMP Stack Installation<\/a><\/li>\n    <li><a href=\"#s6\">Verifying PHP with phpinfo<\/a><\/li>\n    <li><a href=\"#s7\">Creating Your First Website (HTTP)<\/a><\/li>\n    <li><a href=\"#s8\">Let&#8217;s Encrypt &amp; HTTPS with Certbot<\/a><\/li>\n    <li><a href=\"#s9\">Apache Virtual Hosts (Multi-Domain)<\/a><\/li>\n    <li><a href=\"#s10\">Advanced: Reverse Proxy Virtual Hosts (HTTPS)<\/a><\/li>\n    <li><a href=\"#s11\">Adding a Second Server as a Subdomain<\/a><\/li>\n  <\/ol>\n<\/nav>\n\n<main>\n\n<!-- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 SECTION 1 -->\n<section class=\"lesson-section\" id=\"s1\">\n  <div class=\"section-header\">\n    <div class=\"section-number\">01<\/div>\n    <h2>Hardware Recommendations for a Basic LAMP Server<\/h2>\n  <\/div>\n  <p>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.<\/p>\n  <div class=\"hw-grid\">\n    <div class=\"hw-card\">\n      <h4>CPU<\/h4>\n      <span class=\"spec\">Minimum: 2 cores<\/span>\n      <span class=\"spec\">Recommended: 4+ cores<\/span>\n      <p>Any modern x86-64 processor. Intel Core i3\/i5 or AMD Ryzen 3\/5 are excellent choices.<\/p>\n    <\/div>\n    <div class=\"hw-card\">\n      <h4>RAM<\/h4>\n      <span class=\"spec\">Minimum: 2 GB<\/span>\n      <span class=\"spec\">Recommended: 4\u20138 GB<\/span>\n      <p>MySQL in particular benefits greatly from available RAM for query caching and buffer pools.<\/p>\n    <\/div>\n    <div class=\"hw-card\">\n      <h4>Storage<\/h4>\n      <span class=\"spec\">Minimum: 20 GB SSD<\/span>\n      <span class=\"spec\">Recommended: 60\u2013120 GB SSD<\/span>\n      <p>SSDs dramatically improve MySQL I\/O performance. Avoid spinning HDDs for the OS drive if possible.<\/p>\n    <\/div>\n    <div class=\"hw-card\">\n      <h4>Network<\/h4>\n      <span class=\"spec\">Minimum: 100 Mbps NIC<\/span>\n      <span class=\"spec\">Recommended: 1 Gbps NIC<\/span>\n      <p>A wired Ethernet connection is strongly preferred over Wi-Fi for server stability and consistent latency.<\/p>\n    <\/div>\n    <div class=\"hw-card\">\n      <h4>Power Supply<\/h4>\n      <span class=\"spec\">UPS recommended<\/span>\n      <p>An Uninterruptible Power Supply (UPS) protects against sudden power loss that can corrupt MySQL databases and the filesystem.<\/p>\n    <\/div>\n    <div class=\"hw-card\">\n      <h4>Popular Options<\/h4>\n      <span class=\"spec\">PC \/ Mini-PC \/ NUC<\/span>\n      <p>Intel NUC, Beelink Mini-PC, or any repurposed desktop PC are all practical. <strong>Raspberry Pi 5 (4 GB+) is recommended<\/strong> for ARM-based builds \u2014 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.<\/p>\n    <\/div>\n  <\/div>\n  <div class=\"callout info\">\n    <span class=\"callout-icon\">\u2139\ufe0f<\/span>\n    <div class=\"callout-body\">\n      <strong>Raspberry Pi Users \u2014 Read This First<\/strong>\n      If you choose a Raspberry Pi, use the <strong>64-bit (arm64) Ubuntu Server 24.04 image<\/strong>. Ubuntu on the Raspberry Pi uses <em>cloud-init<\/em> for its initial networking configuration \u2014 this causes problems with setting a local static IP in the traditional way. See Section 3 for the correct approach.\n    <\/div>\n  <\/div>\n<\/section>\n\n<hr class=\"section-divider\">\n\n<!-- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 SECTION 2 -->\n<section class=\"lesson-section\" id=\"s2\">\n  <div class=\"section-header\">\n    <div class=\"section-number\">02<\/div>\n    <h2>Installing Ubuntu 24.04 Server from Scratch<\/h2>\n  <\/div>\n  <p>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.<\/p>\n  <div class=\"callout info\">\n    <span class=\"callout-icon\">\u2139\ufe0f<\/span>\n    <div class=\"callout-body\">\n      <strong>Server Edition vs. Desktop Edition<\/strong>\n      Always use the <strong>Server<\/strong> edition of Ubuntu for a LAMP server \u2014 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).\n    <\/div>\n  <\/div>\n\n  <h3>Part A \u2014 x86-64 PC Installation<\/h3>\n  <h4>What You Will Need<\/h4>\n  <ul>\n    <li>A USB flash drive, 4 GB or larger<\/li>\n    <li>The Ubuntu 24.04 LTS Server ISO \u2014 download from <strong>ubuntu.com\/download\/server<\/strong><\/li>\n    <li>A tool to write the ISO to USB: <strong>Balena Etcher<\/strong> (Windows\/Mac\/Linux) or <strong>Rufus<\/strong> (Windows only)<\/li>\n    <li>The target PC connected to your router via Ethernet<\/li>\n    <li>A keyboard and monitor connected to the target PC for installation<\/li>\n  <\/ul>\n\n  <h4>Step 1 \u2014 Write the ISO to USB<\/h4>\n  <ol class=\"steps\">\n    <li><div>Download the Ubuntu 24.04 LTS Server ISO from ubuntu.com. The filename will look like <code class=\"inline\">ubuntu-24.04-live-server-amd64.iso<\/code>.<\/div><\/li>\n    <li><div>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.<\/div><\/li>\n    <li><div>When flashing is complete, safely eject the USB drive.<\/div><\/li>\n  <\/ol>\n\n  <h4>Step 2 \u2014 Boot From USB<\/h4>\n  <ol class=\"steps\">\n    <li><div>Insert the USB drive into the target PC and power it on.<\/div><\/li>\n    <li><div>Enter the BIOS\/UEFI boot menu \u2014 typically by pressing <code class=\"inline\">F2<\/code>, <code class=\"inline\">F10<\/code>, <code class=\"inline\">F12<\/code>, or <code class=\"inline\">Delete<\/code> immediately on startup. The key varies by manufacturer \u2014 watch the screen for a prompt.<\/div><\/li>\n    <li><div>Select your USB drive from the boot device list and press Enter.<\/div><\/li>\n    <li><div>The Ubuntu installer will load. You will see a GRUB menu \u2014 select <strong>Try or Install Ubuntu Server<\/strong> and press Enter.<\/div><\/li>\n  <\/ol>\n\n  <h4>Step 3 \u2014 Walk Through the Ubuntu Server Installer<\/h4>\n  <p>The Ubuntu Server installer is text-based and keyboard-driven. Use the arrow keys to navigate, Space to select checkboxes, and Enter to confirm.<\/p>\n  <ol class=\"steps\">\n    <li><div><strong>Language<\/strong> \u2014 Select your language (English is the default) and press Enter.<\/div><\/li>\n    <li><div><strong>Keyboard Layout<\/strong> \u2014 Select your keyboard layout. Most users in the US select <code class=\"inline\">English (US)<\/code>.<\/div><\/li>\n    <li><div><strong>Installation Type<\/strong> \u2014 Select <strong>Ubuntu Server<\/strong> (not the minimized version). Press Enter.<\/div><\/li>\n    <li><div><strong>Network<\/strong> \u2014 The installer will detect your Ethernet interface and attempt DHCP. Leave this as-is for now \u2014 you will set the static IP after installation is complete (Section 3). Confirm the interface shows a valid IP and press Done.<\/div><\/li>\n    <li><div><strong>Proxy<\/strong> \u2014 Leave blank unless your network requires a proxy. Press Done.<\/div><\/li>\n    <li><div><strong>Ubuntu Archive Mirror<\/strong> \u2014 Accept the default mirror. Press Done when the test passes.<\/div><\/li>\n    <li><div><strong>Storage Configuration<\/strong> \u2014 For most installs, select <strong>Use an entire disk<\/strong>. Press Done, then confirm the destructive action warning \u2014 this will erase the disk.<\/div><\/li>\n    <li><div><strong>Profile Setup<\/strong> \u2014 Enter your name, a server hostname (e.g., <code class=\"inline\">lampserver<\/code>), a username, and a strong password. Write the password down.<\/div><\/li>\n    <li><div><strong>Ubuntu Pro<\/strong> \u2014 Select <strong>Skip for now<\/strong>. Press Continue.<\/div><\/li>\n    <li><div><strong>SSH Setup<\/strong> \u2014 Select <strong>Install OpenSSH server<\/strong> and press Space to check it, then Enter. This is essential \u2014 it lets you manage the server remotely.<\/div><\/li>\n    <li><div><strong>Featured Server Snaps<\/strong> \u2014 Do not select anything here. Press Done. All software will be installed manually.<\/div><\/li>\n    <li><div><strong>Installation<\/strong> \u2014 The installer copies files and installs the system. This takes 5\u201315 minutes.<\/div><\/li>\n    <li><div>When installation completes, select <strong>Reboot Now<\/strong>. Remove the USB drive when prompted and press Enter.<\/div><\/li>\n  <\/ol>\n\n  <h4>Step 4 \u2014 First Login<\/h4>\n  <p>After rebooting, log in with the username and password you created during installation. You are now at the Ubuntu Server command line.<\/p>\n  <div class=\"code-wrap\">\n    <div class=\"code-label\"><div class=\"dots\"><div class=\"dot dot-r\"><\/div><div class=\"dot dot-y\"><\/div><div class=\"dot dot-g\"><\/div><\/div>First Boot \u2014 Update the System<span class=\"lang\">BASH<\/span><\/div>\n    <pre><span class=\"cm\"># Always update immediately after a fresh install<\/span>\n<span class=\"fn\">sudo<\/span> apt update <span class=\"op\">&amp;&amp;<\/span> <span class=\"fn\">sudo<\/span> apt upgrade <span class=\"fl\">-y<\/span>\n\n<span class=\"cm\"># Reboot if a kernel update was installed<\/span>\n<span class=\"fn\">sudo<\/span> reboot<\/pre>\n  <\/div>\n\n  <div class=\"callout success\">\n    <span class=\"callout-icon\">\u2705<\/span>\n    <div class=\"callout-body\">\n      <strong>x86-64 Install Complete<\/strong>\n      Your server is installed and updated. <strong>Next: go to Section 3 and set your static IP first.<\/strong> 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.\n    <\/div>\n  <\/div>\n\n  <hr style=\"border:none; border-top: 1px dashed var(--border); margin: 2rem 0;\">\n\n  <h3>Part B \u2014 Raspberry Pi ARM64 Installation<\/h3>\n  <h4>What You Will Need<\/h4>\n  <ul>\n    <li>Raspberry Pi 4 or Pi 5 (4 GB RAM minimum recommended)<\/li>\n    <li><strong>Storage \u2014 choose one:<\/strong>\n      <ul style=\"margin-top:0.4rem\">\n        <li><strong>microSD card<\/strong> \u2014 16 GB or larger, Class 10 or UHS-I. Works on all Pi models. Fine for testing but slower than SSD for production.<\/li>\n        <li><strong>USB 3.0 SSD<\/strong> \u2014 faster and more reliable for a server. <strong>Only the Raspberry Pi 5 and newer support native USB boot out of the box.<\/strong> On a Pi 4, you must first update the bootloader EEPROM firmware before USB boot will work.<\/li>\n      <\/ul>\n    <\/li>\n    <li>The <strong>Raspberry Pi Imager<\/strong> tool \u2014 free from <strong>raspberrypi.com\/software<\/strong><\/li>\n    <li>The Pi connected to your router via Ethernet (not Wi-Fi for a server)<\/li>\n    <li>Optional: keyboard and monitor, or configure SSH headlessly (see below)<\/li>\n  <\/ul>\n\n  <div class=\"callout warn\">\n    <span class=\"callout-icon\">\u26a0\ufe0f<\/span>\n    <div class=\"callout-body\">\n      <strong>Raspberry Pi 4 USB Boot \u2014 Extra Step Required<\/strong>\n      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 <strong>Raspberry Pi 5 does not require this step<\/strong> \u2014 it supports USB boot natively.\n    <\/div>\n  <\/div>\n\n  <h4>Step 1 \u2014 Write the Image Using Raspberry Pi Imager<\/h4>\n  <ol class=\"steps\">\n    <li><div>Download and install <strong>Raspberry Pi Imager<\/strong> on your desktop or laptop.<\/div><\/li>\n    <li><div>Insert your microSD card into your computer.<\/div><\/li>\n    <li><div>Open Raspberry Pi Imager. Under <strong>Choose Device<\/strong>, select your Pi model.<\/div><\/li>\n    <li><div>Under <strong>Choose OS<\/strong>, navigate to: <strong>Other general-purpose OS \u2192 Ubuntu \u2192 Ubuntu Server 24.04 LTS (64-bit)<\/strong>. Do not select the Desktop edition.<\/div><\/li>\n    <li><div>Under <strong>Choose Storage<\/strong>, select your microSD card.<\/div><\/li>\n    <li><div>Click <strong>Next \u2192 Edit Settings<\/strong> and configure:\n      <ul style=\"margin-top:0.5rem\">\n        <li><strong>Hostname<\/strong> \u2014 set a name like <code class=\"inline\">lampserver<\/code><\/li>\n        <li><strong>Username and Password<\/strong> \u2014 create your admin user and a strong password<\/li>\n        <li><strong>Enable SSH<\/strong> \u2014 check this box and select <em>Use password authentication<\/em><\/li>\n        <li>Leave Wi-Fi blank \u2014 you will use Ethernet<\/li>\n      <\/ul>\n    <\/div><\/li>\n    <li><div>Click <strong>Save<\/strong>, then <strong>Yes<\/strong> to apply the settings, then <strong>Yes<\/strong> to confirm writing. This erases the card.<\/div><\/li>\n    <li><div>When writing and verification are complete, eject the microSD card safely.<\/div><\/li>\n  <\/ol>\n\n  <h4>Step 2 \u2014 Boot the Raspberry Pi<\/h4>\n  <ol class=\"steps\">\n    <li><div>Insert the microSD card into the Raspberry Pi.<\/div><\/li>\n    <li><div>Connect the Ethernet cable to your router.<\/div><\/li>\n    <li><div>Connect the power supply. The Pi boots automatically \u2014 there is no power button.<\/div><\/li>\n    <li><div>Wait approximately 60\u201390 seconds for the first boot to complete.<\/div><\/li>\n  <\/ol>\n\n  <h4>Step 3 \u2014 Connect via SSH (Headless)<\/h4>\n  <div class=\"code-wrap\">\n    <div class=\"code-label\"><div class=\"dots\"><div class=\"dot dot-r\"><\/div><div class=\"dot dot-y\"><\/div><div class=\"dot dot-g\"><\/div><\/div>Connect to Pi via SSH<span class=\"lang\">BASH<\/span><\/div>\n    <pre><span class=\"cm\"># Find the Pi's IP from your router's DHCP client list<\/span>\n<span class=\"cm\"># Or use the hostname (may require mDNS\/Avahi)<\/span>\n<span class=\"fn\">ssh<\/span> yourusername@lampserver.local\n\n<span class=\"cm\"># Or connect directly by IP<\/span>\n<span class=\"fn\">ssh<\/span> yourusername@192.168.1.XX\n\n<span class=\"cm\"># Accept the SSH fingerprint prompt by typing: yes<\/span><\/pre>\n  <\/div>\n\n  <h4>Step 4 \u2014 First Update on the Pi<\/h4>\n  <div class=\"code-wrap\">\n    <div class=\"code-label\"><div class=\"dots\"><div class=\"dot dot-r\"><\/div><div class=\"dot dot-y\"><\/div><div class=\"dot dot-g\"><\/div><\/div>First Boot \u2014 Update the System<span class=\"lang\">BASH<\/span><\/div>\n    <pre><span class=\"fn\">sudo<\/span> apt update <span class=\"op\">&amp;&amp;<\/span> <span class=\"fn\">sudo<\/span> apt upgrade <span class=\"fl\">-y<\/span>\n<span class=\"fn\">sudo<\/span> reboot<\/pre>\n  <\/div>\n\n  <div class=\"callout warn\">\n    <span class=\"callout-icon\">\u26a0\ufe0f<\/span>\n    <div class=\"callout-body\">\n      <strong>Raspberry Pi \u2014 Disable cloud-init Before Setting Static IP<\/strong>\n      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 <strong>must<\/strong> disable cloud-init&#8217;s network control first \u2014 otherwise your static IP settings will be overwritten on every reboot. The exact commands are in Section 3.\n    <\/div>\n  <\/div>\n\n  <div class=\"callout success\">\n    <span class=\"callout-icon\">\u2705<\/span>\n    <div class=\"callout-body\">\n      <strong>ARM64 \/ Raspberry Pi Install Complete<\/strong>\n      Your Pi is running Ubuntu 24.04 Server. <strong>Next: go to Section 3 and set your static IP first<\/strong> (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.\n    <\/div>\n  <\/div>\n<\/section>\n\n<hr class=\"section-divider\">\n\n<!-- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 SECTION 3 -->\n<section class=\"lesson-section\" id=\"s3\">\n  <div class=\"section-header\">\n    <div class=\"section-number\">03<\/div>\n    <h2>Setting Up a Static IP Address<\/h2>\n  <\/div>\n  <p>A server must have a static (unchanging) local IP address so that your router&#8217;s port forwarding rules always point to the right machine. Ubuntu 24.04 uses <strong>Netplan<\/strong> for network configuration.<\/p>\n  <div class=\"callout danger\">\n    <span class=\"callout-icon\">\ud83d\udeab<\/span>\n    <div class=\"callout-body\">\n      <strong>Raspberry Pi Users \u2014 Important Difference<\/strong>\n      Ubuntu on a Raspberry Pi ships with <code class=\"inline\">cloud-init<\/code> managing the network. Editing Netplan files directly will be overridden by cloud-init at reboot. You must disable cloud-init networking <em>first<\/em>. Skipping this step is a very common cause of frustration.\n    <\/div>\n  <\/div>\n\n  <h3>Step 1 \u2014 Identify Your Network Interface Name<\/h3>\n  <div class=\"code-wrap\">\n    <div class=\"code-label\"><div class=\"dots\"><div class=\"dot dot-r\"><\/div><div class=\"dot dot-y\"><\/div><div class=\"dot dot-g\"><\/div><\/div>Find Your Interface<span class=\"lang\">BASH<\/span><\/div>\n    <pre><span class=\"fn\">ip<\/span> <span class=\"fl\">link show<\/span>\n<span class=\"cm\"># Look for an interface like eth0, ens3, enp3s0, or similar<\/span>\n<span class=\"cm\"># lo is the loopback \u2014 ignore it<\/span><\/pre>\n  <\/div>\n\n  <h3>Step 2 \u2014 Find Your Router&#8217;s Gateway IP<\/h3>\n  <div class=\"code-wrap\">\n    <div class=\"code-label\"><div class=\"dots\"><div class=\"dot dot-r\"><\/div><div class=\"dot dot-y\"><\/div><div class=\"dot dot-g\"><\/div><\/div>Find Gateway<span class=\"lang\">BASH<\/span><\/div>\n    <pre><span class=\"fn\">ip<\/span> route show\n<span class=\"cm\"># The \"default via\" line shows your gateway \u2014 typically 192.168.1.1<\/span><\/pre>\n  <\/div>\n\n  <h3>Step 3 \u2014 Back Up the Existing Netplan Config<\/h3>\n  <div class=\"code-wrap\">\n    <div class=\"code-label\"><div class=\"dots\"><div class=\"dot dot-r\"><\/div><div class=\"dot dot-y\"><\/div><div class=\"dot dot-g\"><\/div><\/div>Backup<span class=\"lang\">BASH<\/span><\/div>\n    <pre><span class=\"fn\">sudo<\/span> cp <span class=\"pt\">\/etc\/netplan\/00-installer-config.yaml<\/span> \\\n         <span class=\"pt\">\/etc\/netplan\/00-installer-config.yaml.bak<\/span><\/pre>\n  <\/div>\n\n  <h3>Step 4 \u2014 Edit the Netplan Configuration File<\/h3>\n  <p>Replace the contents of your Netplan file. The file name may vary \u2014 use <code class=\"inline\">ls \/etc\/netplan\/<\/code> to see what is present. Substitute <code class=\"inline\">eth0<\/code> with your actual interface name, and adjust the IP addresses to match your network.<\/p>\n  <div class=\"code-wrap\">\n    <div class=\"code-label\"><div class=\"dots\"><div class=\"dot dot-r\"><\/div><div class=\"dot dot-y\"><\/div><div class=\"dot dot-g\"><\/div><\/div>\/etc\/netplan\/00-installer-config.yaml<span class=\"lang\">YAML<\/span><\/div>\n    <pre><span class=\"ky\">network<\/span><span class=\"op\">:<\/span>\n  <span class=\"ky\">version<\/span><span class=\"op\">:<\/span> <span class=\"num\">2<\/span>\n  <span class=\"ky\">renderer<\/span><span class=\"op\">:<\/span> <span class=\"vl\">networkd<\/span>\n  <span class=\"ky\">ethernets<\/span><span class=\"op\">:<\/span>\n    <span class=\"ky\">eth0<\/span><span class=\"op\">:<\/span>             <span class=\"cm\"># Replace with your interface name<\/span>\n      <span class=\"ky\">dhcp4<\/span><span class=\"op\">:<\/span> <span class=\"vl\">no<\/span>\n      <span class=\"ky\">addresses<\/span><span class=\"op\">:<\/span>\n        <span class=\"op\">-<\/span> <span class=\"vl\">192.168.1.50\/24<\/span>\n      <span class=\"ky\">routes<\/span><span class=\"op\">:<\/span>\n        <span class=\"op\">-<\/span> <span class=\"ky\">to<\/span><span class=\"op\">:<\/span> <span class=\"vl\">default<\/span>\n          <span class=\"ky\">via<\/span><span class=\"op\">:<\/span> <span class=\"vl\">192.168.1.1<\/span>\n      <span class=\"ky\">nameservers<\/span><span class=\"op\">:<\/span>\n        <span class=\"ky\">addresses<\/span><span class=\"op\">:<\/span>\n          <span class=\"op\">-<\/span> <span class=\"vl\">1.1.1.1<\/span>\n          <span class=\"op\">-<\/span> <span class=\"vl\">8.8.8.8<\/span><\/pre>\n  <\/div>\n\n  <div class=\"callout warn\">\n    <span class=\"callout-icon\">\u26a0\ufe0f<\/span>\n    <div class=\"callout-body\">\n      <strong>YAML is Indentation-Sensitive<\/strong>\n      YAML files use spaces \u2014 never tabs \u2014 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.\n    <\/div>\n  <\/div>\n\n  <h3>Step 5 \u2014 Apply and Verify<\/h3>\n  <div class=\"code-wrap\">\n    <div class=\"code-label\"><div class=\"dots\"><div class=\"dot dot-r\"><\/div><div class=\"dot dot-y\"><\/div><div class=\"dot dot-g\"><\/div><\/div>Apply Network Config<span class=\"lang\">BASH<\/span><\/div>\n    <pre><span class=\"cm\"># Test the config first (dry run \u2014 safe)<\/span>\n<span class=\"fn\">sudo<\/span> netplan try\n\n<span class=\"cm\"># If no errors, apply it permanently<\/span>\n<span class=\"fn\">sudo<\/span> netplan apply\n\n<span class=\"cm\"># Verify the static IP is now active<\/span>\n<span class=\"fn\">ip<\/span> addr show eth0\n\n<span class=\"cm\"># Test internet connectivity<\/span>\n<span class=\"fn\">ping<\/span> <span class=\"fl\">-c 4<\/span> google.com<\/pre>\n  <\/div>\n\n  <h3>Raspberry Pi \u2014 Disable cloud-init Networking First<\/h3>\n  <div class=\"code-wrap\">\n    <div class=\"code-label\"><div class=\"dots\"><div class=\"dot dot-r\"><\/div><div class=\"dot dot-y\"><\/div><div class=\"dot dot-g\"><\/div><\/div>Disable cloud-init Network Management (Raspberry Pi)<span class=\"lang\">BASH<\/span><\/div>\n    <pre><span class=\"fn\">sudo<\/span> bash <span class=\"fl\">-c<\/span> \\\n  <span class=\"str\">'echo \"network: {config: disabled}\" &gt; \\\n  \/etc\/cloud\/cloud.cfg.d\/99-disable-network-config.cfg'<\/span>\n\n<span class=\"cm\"># Now edit \/etc\/netplan\/ as shown above, then apply:<\/span>\n<span class=\"fn\">sudo<\/span> netplan apply\n\n<span class=\"cm\"># Reboot to confirm the static IP survives a restart<\/span>\n<span class=\"fn\">sudo<\/span> reboot<\/pre>\n  <\/div>\n\n  <div class=\"callout success\">\n    <span class=\"callout-icon\">\u2705<\/span>\n    <div class=\"callout-body\">\n      <strong>Verification<\/strong>\n      After applying (and rebooting if on Raspberry Pi), run <code class=\"inline\">ip addr show<\/code> and confirm your server shows the static IP you configured. Also confirm you can reach the internet with <code class=\"inline\">ping -c 3 google.com<\/code>.\n    <\/div>\n  <\/div>\n\n  <h3>Now Connect via SSH \u2014 Ditch the Server Keyboard for Good<\/h3>\n  <p>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 <strong>copy every command from this webpage and paste it directly into your terminal<\/strong> \u2014 no more typing long commands on a server keyboard, no more typos.<\/p>\n\n  <div class=\"callout info\">\n    <span class=\"callout-icon\">\ud83d\udca1<\/span>\n    <div class=\"callout-body\">\n      <strong>Make Sure SSH Is Installed on the Server<\/strong>\n      If you selected <strong>Install OpenSSH server<\/strong> during the Ubuntu installer you are already done. If you skipped it, go back to the server keyboard one last time and run this:\n    <\/div>\n  <\/div>\n\n  <div class=\"code-wrap\">\n    <div class=\"code-label\"><div class=\"dots\"><div class=\"dot dot-r\"><\/div><div class=\"dot dot-y\"><\/div><div class=\"dot dot-g\"><\/div><\/div>Install SSH if Not Already Present<span class=\"lang\">BASH<\/span><\/div>\n    <pre><span class=\"fn\">sudo<\/span> apt install <span class=\"fl\">-y<\/span> openssh-server\n<span class=\"fn\">sudo<\/span> systemctl enable ssh\n<span class=\"fn\">sudo<\/span> systemctl start ssh\n<span class=\"fn\">sudo<\/span> systemctl status ssh<\/pre>\n  <\/div>\n\n  <h4>Connecting from Windows<\/h4>\n  <p>Windows 10 and 11 both include a built-in SSH client. Open <strong>PowerShell<\/strong> or <strong>Command Prompt<\/strong> and run:<\/p>\n  <div class=\"code-wrap\">\n    <div class=\"code-label\"><div class=\"dots\"><div class=\"dot dot-r\"><\/div><div class=\"dot dot-y\"><\/div><div class=\"dot dot-g\"><\/div><\/div>Windows PowerShell or Command Prompt<span class=\"lang\">BASH<\/span><\/div>\n    <pre><span class=\"cm\"># Replace yourusername and IP with your actual values<\/span>\nssh yourusername@192.168.1.50\n\n<span class=\"cm\"># First connection: type yes to accept fingerprint<\/span>\n<span class=\"cm\"># To paste into PowerShell: right-click anywhere in the window<\/span><\/pre>\n  <\/div>\n  <p>If you prefer a graphical SSH client, <strong>PuTTY<\/strong> (free at putty.org) is the most popular option. Enter your server&#8217;s static IP under Host Name, leave the port as 22, and click Open. To paste in PuTTY: right-click in the terminal window.<\/p>\n\n  <h4>Connecting from Linux or macOS<\/h4>\n  <div class=\"code-wrap\">\n    <div class=\"code-label\"><div class=\"dots\"><div class=\"dot dot-r\"><\/div><div class=\"dot dot-y\"><\/div><div class=\"dot dot-g\"><\/div><\/div>Linux \/ macOS Terminal<span class=\"lang\">BASH<\/span><\/div>\n    <pre><span class=\"fn\">ssh<\/span> yourusername@192.168.1.50\n\n<span class=\"cm\"># Accept fingerprint on first connection: yes<\/span>\n<span class=\"cm\"># To paste in most Linux terminals:  Ctrl+Shift+V<\/span>\n<span class=\"cm\"># To paste in macOS Terminal:        Cmd+V<\/span><\/pre>\n  <\/div>\n\n  <div class=\"callout success\">\n    <span class=\"callout-icon\">\u2705<\/span>\n    <div class=\"callout-body\">\n      <strong>You Are Now Connected via SSH<\/strong>\n      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 &amp; Port Forwarding) then Section 5 for the full LAMP stack installation.\n    <\/div>\n  <\/div>\n<\/section>\n\n<hr class=\"section-divider\">\n\n<!-- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 SECTION 4 -->\n<section class=\"lesson-section\" id=\"s4\">\n  <div class=\"section-header\">\n    <div class=\"section-number\">04<\/div>\n    <h2>Router Setup &amp; Port Forwarding<\/h2>\n  <\/div>\n  <p>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&#8217;s local IP address.<\/p>\n\n  <h3>Before You Begin<\/h3>\n  <ul>\n    <li>Know your server&#8217;s local (LAN) IP address \u2014 e.g., <code class=\"inline\">192.168.1.50<\/code><\/li>\n    <li>Log into your router&#8217;s admin panel \u2014 typically at <code class=\"inline\">http:\/\/192.168.1.1<\/code> or <code class=\"inline\">http:\/\/192.168.0.1<\/code><\/li>\n    <li>Look for a section called <strong>Port Forwarding<\/strong>, <strong>Virtual Servers<\/strong>, or <strong>NAT<\/strong><\/li>\n  <\/ul>\n\n  <h3>Required Port Forwarding Rules<\/h3>\n  <div class=\"code-wrap\">\n    <div class=\"code-label\"><div class=\"dots\"><div class=\"dot dot-r\"><\/div><div class=\"dot dot-y\"><\/div><div class=\"dot dot-g\"><\/div><\/div>Port Forwarding Rules<span class=\"lang\">TABLE<\/span><\/div>\n    <pre><span class=\"ht\">Rule         Protocol  Ext Port  Int Port  Destination<\/span>\n<span class=\"op\">\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500<\/span>\n<span class=\"vl\">HTTP Web     TCP       80        80        192.168.1.50<\/span>\n<span class=\"vl\">HTTPS Web    TCP       443       443       192.168.1.50<\/span><\/pre>\n  <\/div>\n\n  <div class=\"callout optional\">\n    <span class=\"callout-icon\">\ud83d\udd10<\/span>\n    <div class=\"callout-body\">\n      <strong>Optional \u2014 SSH Port Forwarding (Port 22)<\/strong>\n      <p>Forwarding port 22 allows you to SSH into your server from the internet. <em>This is a significant security risk if left on the default port.<\/em> If you choose to enable it, strongly consider:<\/p>\n      <ul>\n        <li>Changing SSH to a non-standard port (e.g., <code class=\"inline\">2222<\/code>) in <code class=\"inline\">\/etc\/ssh\/sshd_config<\/code><\/li>\n        <li>Disabling password-based SSH login and using SSH key pairs only<\/li>\n        <li>Enabling <code class=\"inline\">fail2ban<\/code> to block brute-force attempts<\/li>\n      <\/ul>\n      <p style=\"margin-top:0.5rem\">If you only need SSH access from within your home network, <strong>do not forward port 22 to the internet at all<\/strong>.<\/p>\n    <\/div>\n  <\/div>\n\n  <h3>Step-by-Step Port Forwarding<\/h3>\n  <ol class=\"steps\">\n    <li><div>Log into your router admin panel in your web browser.<\/div><\/li>\n    <li><div>Navigate to the <strong>Port Forwarding<\/strong> or <strong>Virtual Servers<\/strong> section.<\/div><\/li>\n    <li><div>Create a rule for <strong>HTTP<\/strong>: TCP, external port 80, internal port 80, destination IP = your server&#8217;s static IP.<\/div><\/li>\n    <li><div>Create a rule for <strong>HTTPS<\/strong>: TCP, external port 443, internal port 443, same destination IP.<\/div><\/li>\n    <li><div>(Optional) Create a rule for <strong>SSH<\/strong>: TCP, external port 22 (or a custom port), internal port 22, same destination IP.<\/div><\/li>\n    <li><div>Save and apply the rules. Some routers require a reboot.<\/div><\/li>\n    <li><div>Verify your public IP address using <a href=\"https:\/\/whatismyip.com\" style=\"color:var(--blue-mid)\">whatismyip.com<\/a> \u2014 this is the IP your domain name will point to.<\/div><\/li>\n  <\/ol>\n\n  <div class=\"callout warn\">\n    <span class=\"callout-icon\">\u26a0\ufe0f<\/span>\n    <div class=\"callout-body\">\n      <strong>Dynamic IP Addresses<\/strong>\n      Most residential ISPs assign a <em>dynamic<\/em> public IP \u2014 meaning it can change without notice. Solutions include paying your ISP for a static IP, or using a Dynamic DNS (DDNS) service such as <strong>DuckDNS<\/strong> or <strong>Cloudflare<\/strong> which automatically updates your DNS record whenever your IP changes.\n    <\/div>\n  <\/div>\n<\/section>\n\n<hr class=\"section-divider\">\n\n<!-- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 SECTION 5 -->\n<section class=\"lesson-section\" id=\"s5\">\n  <div class=\"section-header\">\n    <div class=\"section-number\">05<\/div>\n    <h2>Full LAMP Stack Installation<\/h2>\n  <\/div>\n  <p>With networking configured, it&#8217;s time to install the full stack \u2014 Apache2, MySQL (not MariaDB), and PHP along with all the recommended modules that make them work together correctly.<\/p>\n\n  <h3>Step 1 \u2014 Update the System<\/h3>\n  <div class=\"code-wrap\">\n    <div class=\"code-label\"><div class=\"dots\"><div class=\"dot dot-r\"><\/div><div class=\"dot dot-y\"><\/div><div class=\"dot dot-g\"><\/div><\/div>System Update<span class=\"lang\">BASH<\/span><\/div>\n    <pre><span class=\"fn\">sudo<\/span> apt update <span class=\"op\">&amp;&amp;<\/span> <span class=\"fn\">sudo<\/span> apt upgrade <span class=\"fl\">-y<\/span><\/pre>\n  <\/div>\n\n  <h3>Step 2 \u2014 Install Apache2<\/h3>\n  <div class=\"code-wrap\">\n    <div class=\"code-label\"><div class=\"dots\"><div class=\"dot dot-r\"><\/div><div class=\"dot dot-y\"><\/div><div class=\"dot dot-g\"><\/div><\/div>Install Apache2<span class=\"lang\">BASH<\/span><\/div>\n    <pre><span class=\"fn\">sudo<\/span> apt install <span class=\"fl\">-y<\/span> apache2\n<span class=\"fn\">sudo<\/span> systemctl enable apache2\n<span class=\"fn\">sudo<\/span> systemctl start apache2\n<span class=\"fn\">sudo<\/span> systemctl status apache2<\/pre>\n  <\/div>\n  <div class=\"callout info\">\n    <span class=\"callout-icon\">\u2139\ufe0f<\/span>\n    <div class=\"callout-body\">\n      <strong>Quick Test<\/strong>\n      Open a browser on another device on your network and navigate to your server&#8217;s local IP (e.g., <code class=\"inline\">http:\/\/192.168.1.50<\/code>). You should see the <strong>Apache2 Ubuntu Default Page<\/strong>.\n    <\/div>\n  <\/div>\n\n  <h3>Step 3 \u2014 Configure UFW Firewall<\/h3>\n  <p>UFW must be configured <em>before<\/em> you enable it \u2014 enabling UFW with no rules in place will lock you out of SSH immediately.<\/p>\n  <div class=\"callout danger\">\n    <span class=\"callout-icon\">\ud83d\udeab<\/span>\n    <div class=\"callout-body\">\n      <strong>Do Not Enable UFW Before Adding Your Rules<\/strong>\n      Enabling UFW with an empty ruleset blocks <em>all<\/em> incoming connections including your current SSH session. Add all the rules first, then enable UFW as the final step.\n    <\/div>\n  <\/div>\n\n  <div class=\"code-wrap\">\n    <div class=\"code-label\"><div class=\"dots\"><div class=\"dot dot-r\"><\/div><div class=\"dot dot-y\"><\/div><div class=\"dot dot-g\"><\/div><\/div>Configure UFW Rules<span class=\"lang\">BASH<\/span><\/div>\n    <pre><span class=\"cm\"># Allow HTTP \u2014 port 80<\/span>\n<span class=\"fn\">sudo<\/span> ufw allow 80\/tcp\n\n<span class=\"cm\"># Allow HTTPS \u2014 port 443<\/span>\n<span class=\"fn\">sudo<\/span> ufw allow 443\/tcp\n\n<span class=\"cm\"># Allow SSH \u2014 port 22<\/span>\n<span class=\"cm\"># WARNING: If you skip this, enabling UFW will lock you out<\/span>\n<span class=\"fn\">sudo<\/span> ufw allow 22\/tcp\n\n<span class=\"cm\"># Now enable the firewall<\/span>\n<span class=\"fn\">sudo<\/span> ufw enable\n\n<span class=\"cm\"># Verify all rules are active<\/span>\n<span class=\"fn\">sudo<\/span> ufw status verbose<\/pre>\n  <\/div>\n\n  <div class=\"code-wrap\">\n    <div class=\"code-label\"><div class=\"dots\"><div class=\"dot dot-r\"><\/div><div class=\"dot dot-y\"><\/div><div class=\"dot dot-g\"><\/div><\/div>Expected UFW Status Output<span class=\"lang\">TEXT<\/span><\/div>\n    <pre>Status: active\nDefault: deny (incoming), allow (outgoing)\n\nTo          Action    From\n--          ------    ----\n80\/tcp      ALLOW IN  Anywhere\n443\/tcp     ALLOW IN  Anywhere\n22\/tcp      ALLOW IN  Anywhere<\/pre>\n  <\/div>\n\n  <div class=\"callout warn\">\n    <span class=\"callout-icon\">\u26a0\ufe0f<\/span>\n    <div class=\"callout-body\">\n      <strong>If You Use Non-Standard Ports \u2014 You Must Add Rules for Them Too<\/strong>\n      UFW blocks every port not explicitly allowed. Common examples:\n      <ul style=\"margin-top:0.5rem\">\n        <li>SSH moved to port 2222: <code class=\"inline\">sudo ufw allow 2222\/tcp<\/code><\/li>\n        <li>Web app on port 8080: <code class=\"inline\">sudo ufw allow 8080\/tcp<\/code><\/li>\n        <li>MySQL from LAN only: <code class=\"inline\">sudo ufw allow from 192.168.1.0\/24 to any port 3306<\/code><\/li>\n      <\/ul>\n      <p style=\"margin-top:0.5rem\">If you move SSH to a custom port, also run <code class=\"inline\">sudo ufw delete allow 22\/tcp<\/code> to close the original.<\/p>\n    <\/div>\n  <\/div>\n\n  <div class=\"code-wrap\">\n    <div class=\"code-label\"><div class=\"dots\"><div class=\"dot dot-r\"><\/div><div class=\"dot dot-y\"><\/div><div class=\"dot dot-g\"><\/div><\/div>UFW Management Reference<span class=\"lang\">BASH<\/span><\/div>\n    <pre><span class=\"fn\">sudo<\/span> ufw status numbered       <span class=\"cm\"># List all rules with numbers<\/span>\n<span class=\"fn\">sudo<\/span> ufw delete <span class=\"num\">3<\/span>              <span class=\"cm\"># Delete rule by number<\/span>\n<span class=\"fn\">sudo<\/span> ufw delete allow 8080\/tcp <span class=\"cm\"># Delete rule by name<\/span>\n<span class=\"fn\">sudo<\/span> ufw disable               <span class=\"cm\"># Disable UFW entirely<\/span>\n<span class=\"fn\">sudo<\/span> ufw reset                 <span class=\"cm\"># Reset to factory defaults<\/span><\/pre>\n  <\/div>\n\n  <h3>Step 4 \u2014 Install MySQL (Not MariaDB)<\/h3>\n  <div class=\"callout warn\">\n    <span class=\"callout-icon\">\u26a0\ufe0f<\/span>\n    <div class=\"callout-body\">\n      <strong>MySQL vs. MariaDB<\/strong>\n      Ubuntu&#8217;s default repositories may install MariaDB when you run <code class=\"inline\">apt install mysql-server<\/code>. To ensure you get <strong>Oracle&#8217;s MySQL<\/strong>, add the official MySQL APT repository first.\n    <\/div>\n  <\/div>\n\n  <div class=\"code-wrap\">\n    <div class=\"code-label\"><div class=\"dots\"><div class=\"dot dot-r\"><\/div><div class=\"dot dot-y\"><\/div><div class=\"dot dot-g\"><\/div><\/div>Add Official MySQL Repository<span class=\"lang\">BASH<\/span><\/div>\n    <pre><span class=\"cm\"># Download the MySQL APT config package<\/span>\n<span class=\"fn\">wget<\/span> https:\/\/dev.mysql.com\/get\/mysql-apt-config_0.8.29-1_all.deb\n\n<span class=\"cm\"># Install it \u2014 a dialog will appear<\/span>\n<span class=\"cm\"># Select \"MySQL Server &amp; Cluster\" then choose MySQL 8.x<\/span>\n<span class=\"fn\">sudo<\/span> dpkg <span class=\"fl\">-i<\/span> mysql-apt-config_0.8.29-1_all.deb\n\n<span class=\"fn\">sudo<\/span> apt update\n<span class=\"fn\">sudo<\/span> apt install <span class=\"fl\">-y<\/span> mysql-server\n<span class=\"fn\">sudo<\/span> systemctl enable mysql\n<span class=\"fn\">sudo<\/span> systemctl start mysql\n<span class=\"fn\">sudo<\/span> systemctl status mysql<\/pre>\n  <\/div>\n\n  <h3>Step 5 \u2014 Secure MySQL<\/h3>\n  <div class=\"code-wrap\">\n    <div class=\"code-label\"><div class=\"dots\"><div class=\"dot dot-r\"><\/div><div class=\"dot dot-y\"><\/div><div class=\"dot dot-g\"><\/div><\/div>Secure MySQL Installation<span class=\"lang\">BASH<\/span><\/div>\n    <pre><span class=\"fn\">sudo<\/span> mysql_secure_installation<\/pre>\n  <\/div>\n  <ul>\n    <li><strong>VALIDATE PASSWORD component?<\/strong> \u2014 <code class=\"inline\">Y<\/code><\/li>\n    <li><strong>Password strength level:<\/strong> \u2014 Choose <code class=\"inline\">1<\/code> (Medium) or <code class=\"inline\">2<\/code> (Strong)<\/li>\n    <li><strong>Set root password?<\/strong> \u2014 <code class=\"inline\">Y<\/code> \u2014 write it down securely<\/li>\n    <li><strong>Remove anonymous users?<\/strong> \u2014 <code class=\"inline\">Y<\/code><\/li>\n    <li><strong>Disallow root login remotely?<\/strong> \u2014 <code class=\"inline\">Y<\/code><\/li>\n    <li><strong>Remove test database?<\/strong> \u2014 <code class=\"inline\">Y<\/code><\/li>\n    <li><strong>Reload privilege tables now?<\/strong> \u2014 <code class=\"inline\">Y<\/code><\/li>\n  <\/ul>\n\n  <h3>Step 6 \u2014 Create a MySQL Database User<\/h3>\n  <div class=\"code-wrap\">\n    <div class=\"code-label\"><div class=\"dots\"><div class=\"dot dot-r\"><\/div><div class=\"dot dot-y\"><\/div><div class=\"dot dot-g\"><\/div><\/div>Create Database User<span class=\"lang\">SQL<\/span><\/div>\n    <pre><span class=\"cm\">-- Log into MySQL as root<\/span>\n<span class=\"fn\">sudo<\/span> mysql <span class=\"fl\">-u<\/span> root <span class=\"fl\">-p<\/span>\n\n<span class=\"kw\">CREATE DATABASE<\/span> mywebsite_db;\n<span class=\"kw\">CREATE USER<\/span> <span class=\"str\">'webuser'<\/span>@<span class=\"str\">'localhost'<\/span>\n  <span class=\"kw\">IDENTIFIED BY<\/span> <span class=\"str\">'YourStrongPassword123!'<\/span>;\n<span class=\"kw\">GRANT ALL PRIVILEGES ON<\/span> mywebsite_db.<span class=\"op\">*<\/span>\n  <span class=\"kw\">TO<\/span> <span class=\"str\">'webuser'<\/span>@<span class=\"str\">'localhost'<\/span>;\n<span class=\"kw\">FLUSH PRIVILEGES<\/span>;\n<span class=\"kw\">SELECT<\/span> user, host <span class=\"kw\">FROM<\/span> mysql.user;\n<span class=\"kw\">EXIT<\/span>;<\/pre>\n  <\/div>\n\n  <h3>Step 7 \u2014 Verify MySQL Login as the New User<\/h3>\n  <div class=\"code-wrap\">\n    <div class=\"code-label\"><div class=\"dots\"><div class=\"dot dot-r\"><\/div><div class=\"dot dot-y\"><\/div><div class=\"dot dot-g\"><\/div><\/div>Test User Login<span class=\"lang\">BASH<\/span><\/div>\n    <pre><span class=\"fn\">mysql<\/span> <span class=\"fl\">-u<\/span> webuser <span class=\"fl\">-p<\/span>\n<span class=\"kw\">SHOW DATABASES<\/span>;\n<span class=\"cm\"># You should see mywebsite_db listed<\/span>\n<span class=\"kw\">EXIT<\/span>;<\/pre>\n  <\/div>\n\n  <h3>Step 8 \u2014 Install PHP and All Recommended Modules<\/h3>\n  <div class=\"code-wrap\">\n    <div class=\"code-label\"><div class=\"dots\"><div class=\"dot dot-r\"><\/div><div class=\"dot dot-y\"><\/div><div class=\"dot dot-g\"><\/div><\/div>Install PHP 8.3 and Modules<span class=\"lang\">BASH<\/span><\/div>\n    <pre><span class=\"fn\">sudo<\/span> apt install <span class=\"fl\">-y<\/span> \\\n  php8.3 \\\n  php8.3-mysql \\\n  php8.3-cli \\\n  php8.3-common \\\n  php8.3-curl \\\n  php8.3-gd \\\n  php8.3-intl \\\n  php8.3-mbstring \\\n  php8.3-xml \\\n  php8.3-zip \\\n  php8.3-bcmath \\\n  php8.3-opcache \\\n  libapache2-mod-php8.3\n\n<span class=\"fn\">sudo<\/span> a2enmod php8.3\n<span class=\"fn\">sudo<\/span> systemctl restart apache2\n<span class=\"fn\">php<\/span> <span class=\"fl\">--version<\/span><\/pre>\n  <\/div>\n\n  <h3>Step 9 \u2014 Enable Essential Apache Modules<\/h3>\n  <div class=\"code-wrap\">\n    <div class=\"code-label\"><div class=\"dots\"><div class=\"dot dot-r\"><\/div><div class=\"dot dot-y\"><\/div><div class=\"dot dot-g\"><\/div><\/div>Enable Apache Modules<span class=\"lang\">BASH<\/span><\/div>\n    <pre><span class=\"fn\">sudo<\/span> a2enmod rewrite\n<span class=\"fn\">sudo<\/span> a2enmod headers\n<span class=\"fn\">sudo<\/span> a2enmod ssl\n<span class=\"fn\">sudo<\/span> a2enmod proxy\n<span class=\"fn\">sudo<\/span> a2enmod proxy_http\n<span class=\"fn\">sudo<\/span> systemctl restart apache2<\/pre>\n  <\/div>\n\n  <h3>Step 10 \u2014 Set Correct File Ownership<\/h3>\n  <div class=\"code-wrap\">\n    <div class=\"code-label\"><div class=\"dots\"><div class=\"dot dot-r\"><\/div><div class=\"dot dot-y\"><\/div><div class=\"dot dot-g\"><\/div><\/div>File Ownership &amp; Permissions<span class=\"lang\">BASH<\/span><\/div>\n    <pre><span class=\"fn\">sudo<\/span> chown <span class=\"fl\">-R<\/span> www-data:www-data <span class=\"pt\">\/var\/www\/html<\/span>\n<span class=\"fn\">sudo<\/span> usermod <span class=\"fl\">-aG<\/span> www-data <span class=\"va\">$USER<\/span>\n<span class=\"fn\">sudo<\/span> find <span class=\"pt\">\/var\/www\/html<\/span> <span class=\"fl\">-type<\/span> d <span class=\"fl\">-exec<\/span> chmod 755 <span class=\"op\">{}<\/span> \\;\n<span class=\"fn\">sudo<\/span> find <span class=\"pt\">\/var\/www\/html<\/span> <span class=\"fl\">-type<\/span> f <span class=\"fl\">-exec<\/span> chmod 644 <span class=\"op\">{}<\/span> \\;\n<span class=\"fn\">newgrp<\/span> www-data<\/pre>\n  <\/div>\n<\/section>\n\n<hr class=\"section-divider\">\n\n<!-- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 SECTION 6 -->\n<section class=\"lesson-section\" id=\"s6\">\n  <div class=\"section-header\">\n    <div class=\"section-number\">06<\/div>\n    <h2>Verifying PHP with phpinfo<\/h2>\n  <\/div>\n  <p>The <code class=\"inline\">phpinfo()<\/code> function produces a detailed page showing every PHP setting, loaded module, and environment variable. It&#8217;s the definitive way to confirm your LAMP stack is wired together correctly.<\/p>\n  <div class=\"callout danger\">\n    <span class=\"callout-icon\">\ud83d\udeab<\/span>\n    <div class=\"callout-body\">\n      <strong>Security Warning \u2014 Delete This File After Testing<\/strong>\n      The <code class=\"inline\">phpinfo.php<\/code> file exposes detailed server configuration information to anyone who visits it. Create it, verify your install, then <strong>delete it immediately<\/strong>. Never leave this file on a production server.\n    <\/div>\n  <\/div>\n\n  <h3>Step 1 \u2014 Create the File<\/h3>\n  <div class=\"code-wrap\">\n    <div class=\"code-label\"><div class=\"dots\"><div class=\"dot dot-r\"><\/div><div class=\"dot dot-y\"><\/div><div class=\"dot dot-g\"><\/div><\/div>Create phpinfo.php<span class=\"lang\">BASH<\/span><\/div>\n    <pre><span class=\"fn\">sudo<\/span> bash <span class=\"fl\">-c<\/span> \\\n  <span class=\"str\">'echo \"&lt;?php phpinfo(); ?&gt;\" &gt; \/var\/www\/html\/phpinfo.php'<\/span>\n<span class=\"fn\">sudo<\/span> chown www-data:www-data <span class=\"pt\">\/var\/www\/html\/phpinfo.php<\/span>\n<span class=\"fn\">sudo<\/span> chmod 644 <span class=\"pt\">\/var\/www\/html\/phpinfo.php<\/span><\/pre>\n  <\/div>\n\n  <h3>Step 2 \u2014 View the Page in a Browser<\/h3>\n  <p>Navigate to: <code class=\"inline\">http:\/\/your-server-ip\/phpinfo.php<\/code><\/p>\n  <p>On the PHP info page, verify the following:<\/p>\n  <ul>\n    <li><strong>PHP Version<\/strong> \u2014 should show 8.3.x at the top<\/li>\n    <li><strong>Server API<\/strong> \u2014 should show <code class=\"inline\">Apache 2.0 Handler<\/code> (not CLI)<\/li>\n    <li><strong>mysqli<\/strong> \u2014 confirms PHP can talk to MySQL<\/li>\n    <li><strong>PDO<\/strong> \u2014 should show <code class=\"inline\">pdo_mysql<\/code> as a driver<\/li>\n    <li><strong>Loaded Configuration File<\/strong> \u2014 should point to <code class=\"inline\">\/etc\/php\/8.3\/apache2\/php.ini<\/code><\/li>\n  <\/ul>\n\n  <h3>Step 3 \u2014 Delete the File After Verification<\/h3>\n  <div class=\"code-wrap\">\n    <div class=\"code-label\"><div class=\"dots\"><div class=\"dot dot-r\"><\/div><div class=\"dot dot-y\"><\/div><div class=\"dot dot-g\"><\/div><\/div>Delete phpinfo.php<span class=\"lang\">BASH<\/span><\/div>\n    <pre><span class=\"fn\">sudo<\/span> rm <span class=\"pt\">\/var\/www\/html\/phpinfo.php<\/span><\/pre>\n  <\/div>\n<\/section>\n\n<hr class=\"section-divider\">\n\n<!-- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 SECTION 7 -->\n<section class=\"lesson-section\" id=\"s7\">\n  <div class=\"section-header\">\n    <div class=\"section-number\">07<\/div>\n    <h2>Creating Your First Website (HTTP on Port 80)<\/h2>\n  <\/div>\n  <p>Apache uses <strong>Virtual Host<\/strong> configuration files to serve websites. Each site gets its own config file in <code class=\"inline\">\/etc\/apache2\/sites-available\/<\/code>. For this example, assume your domain is <code class=\"inline\">example.com<\/code>. Replace it with your actual domain throughout.<\/p>\n\n  <h3>Step 1 \u2014 Create the Website Document Root<\/h3>\n  <div class=\"code-wrap\">\n    <div class=\"code-label\"><div class=\"dots\"><div class=\"dot dot-r\"><\/div><div class=\"dot dot-y\"><\/div><div class=\"dot dot-g\"><\/div><\/div>Create Web Root Directory<span class=\"lang\">BASH<\/span><\/div>\n    <pre><span class=\"fn\">sudo<\/span> mkdir <span class=\"fl\">-p<\/span> <span class=\"pt\">\/var\/www\/example.com\/public_html<\/span>\n<span class=\"fn\">sudo<\/span> chown <span class=\"fl\">-R<\/span> www-data:www-data <span class=\"pt\">\/var\/www\/example.com<\/span>\n<span class=\"fn\">sudo<\/span> chmod <span class=\"fl\">-R<\/span> 755 <span class=\"pt\">\/var\/www\/example.com<\/span><\/pre>\n  <\/div>\n\n  <h3>Step 2 \u2014 Create an Index HTML Page<\/h3>\n  <div class=\"code-wrap\">\n    <div class=\"code-label\"><div class=\"dots\"><div class=\"dot dot-r\"><\/div><div class=\"dot dot-y\"><\/div><div class=\"dot dot-g\"><\/div><\/div>\/var\/www\/example.com\/public_html\/index.html<span class=\"lang\">HTML<\/span><\/div>\n    <pre><span class=\"kw\">&lt;!DOCTYPE html&gt;<\/span>\n<span class=\"kw\">&lt;html<\/span> <span class=\"fl\">lang=<\/span><span class=\"str\">\"en\"<\/span><span class=\"kw\">&gt;<\/span>\n<span class=\"kw\">&lt;head&gt;<\/span>\n    <span class=\"kw\">&lt;meta<\/span> <span class=\"fl\">charset=<\/span><span class=\"str\">\"UTF-8\"<\/span><span class=\"kw\">&gt;<\/span>\n    <span class=\"kw\">&lt;title&gt;<\/span>Success \u2014 My LAMP Server<span class=\"kw\">&lt;\/title&gt;<\/span>\n<span class=\"kw\">&lt;\/head&gt;<\/span>\n<span class=\"kw\">&lt;body&gt;<\/span>\n    <span class=\"kw\">&lt;h1&gt;<\/span>Success! Your LAMP Server is Running.<span class=\"kw\">&lt;\/h1&gt;<\/span>\n    <span class=\"kw\">&lt;p&gt;<\/span>Apache2, PHP, and MySQL are installed.<span class=\"kw\">&lt;\/p&gt;<\/span>\n<span class=\"kw\">&lt;\/body&gt;<\/span>\n<span class=\"kw\">&lt;\/html&gt;<\/span><\/pre>\n  <\/div>\n  <div class=\"code-wrap\">\n    <div class=\"code-label\"><div class=\"dots\"><div class=\"dot dot-r\"><\/div><div class=\"dot dot-y\"><\/div><div class=\"dot dot-g\"><\/div><\/div>Write the Index File<span class=\"lang\">BASH<\/span><\/div>\n    <pre><span class=\"fn\">sudo<\/span> nano <span class=\"pt\">\/var\/www\/example.com\/public_html\/index.html<\/span>\n<span class=\"cm\"># Paste the HTML above, then press Ctrl+X, Y, Enter to save<\/span><\/pre>\n  <\/div>\n\n  <h3>Step 3 \u2014 Create the Virtual Host Configuration File<\/h3>\n  <div class=\"code-wrap\">\n    <div class=\"code-label\"><div class=\"dots\"><div class=\"dot dot-r\"><\/div><div class=\"dot dot-y\"><\/div><div class=\"dot dot-g\"><\/div><\/div>\/etc\/apache2\/sites-available\/example.com.conf<span class=\"lang\">APACHE<\/span><\/div>\n    <pre><span class=\"kw\">&lt;VirtualHost<\/span> <span class=\"vl\">*:80<\/span><span class=\"kw\">&gt;<\/span>\n    <span class=\"ky\">ServerName<\/span>    <span class=\"vl\">example.com<\/span>\n    <span class=\"ky\">ServerAlias<\/span>   <span class=\"vl\">www.example.com<\/span>\n    <span class=\"ky\">DocumentRoot<\/span>  <span class=\"pt\">\/var\/www\/example.com\/public_html<\/span>\n    <span class=\"ky\">ServerAdmin<\/span>   <span class=\"vl\">webmaster@example.com<\/span>\n\n    <span class=\"kw\">&lt;Directory<\/span> <span class=\"pt\">\/var\/www\/example.com\/public_html<\/span><span class=\"kw\">&gt;<\/span>\n        <span class=\"ky\">Options<\/span>       <span class=\"vl\">-Indexes +FollowSymLinks<\/span>\n        <span class=\"ky\">AllowOverride<\/span> <span class=\"vl\">All<\/span>\n        <span class=\"ky\">Require<\/span>       <span class=\"vl\">all granted<\/span>\n    <span class=\"kw\">&lt;\/Directory&gt;<\/span>\n\n    <span class=\"ky\">ErrorLog<\/span>  <span class=\"pt\">${APACHE_LOG_DIR}\/example.com-error.log<\/span>\n    <span class=\"ky\">CustomLog<\/span> <span class=\"pt\">${APACHE_LOG_DIR}\/example.com-access.log<\/span> <span class=\"vl\">combined<\/span>\n<span class=\"kw\">&lt;\/VirtualHost&gt;<\/span><\/pre>\n  <\/div>\n\n  <h3>Step 4 \u2014 Enable the Site and Reload Apache<\/h3>\n  <div class=\"code-wrap\">\n    <div class=\"code-label\"><div class=\"dots\"><div class=\"dot dot-r\"><\/div><div class=\"dot dot-y\"><\/div><div class=\"dot dot-g\"><\/div><\/div>Enable Site<span class=\"lang\">BASH<\/span><\/div>\n    <pre><span class=\"fn\">sudo<\/span> a2ensite example.com.conf\n<span class=\"fn\">sudo<\/span> a2dissite 000-default.conf\n<span class=\"fn\">sudo<\/span> apache2ctl configtest\n<span class=\"fn\">sudo<\/span> systemctl reload apache2<\/pre>\n  <\/div>\n\n  <div class=\"callout success\">\n    <span class=\"callout-icon\">\u2705<\/span>\n    <div class=\"callout-body\">\n      <strong>Success Check<\/strong>\n      Navigate to <code class=\"inline\">http:\/\/example.com<\/code> (or your server&#8217;s IP). Your browser shows your custom HTML page \u2014 not the default Apache page. You are now serving a website over HTTP on port 80.\n    <\/div>\n  <\/div>\n<\/section>\n\n<hr class=\"section-divider\">\n\n<!-- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 SECTION 8 -->\n<section class=\"lesson-section\" id=\"s8\">\n  <div class=\"section-header\">\n    <div class=\"section-number\">08<\/div>\n    <h2>Installing Let&#8217;s Encrypt with Certbot (HTTPS \/ Port 443)<\/h2>\n  <\/div>\n  <p>Let&#8217;s Encrypt provides free, trusted SSL\/TLS certificates. Before proceeding, your domain&#8217;s DNS A record must already point to your server&#8217;s public IP address, and port 80 must be reachable from the internet.<\/p>\n\n  <div class=\"callout warn\">\n    <span class=\"callout-icon\">\u26a0\ufe0f<\/span>\n    <div class=\"callout-body\">\n      <strong>DNS Must Resolve First<\/strong>\n      Certbot verifies domain ownership by making an HTTP request to your server from the internet. If your domain&#8217;s DNS is not yet pointing to your public IP \u2014 or if port 80 is blocked \u2014 certificate issuance will fail. Verify DNS propagation first using <a href=\"https:\/\/dnschecker.org\" style=\"color:#92400e\">dnschecker.org<\/a>.\n    <\/div>\n  <\/div>\n\n  <h3>Step 1 \u2014 Install Certbot<\/h3>\n  <div class=\"code-wrap\">\n    <div class=\"code-label\"><div class=\"dots\"><div class=\"dot dot-r\"><\/div><div class=\"dot dot-y\"><\/div><div class=\"dot dot-g\"><\/div><\/div>Install Certbot<span class=\"lang\">BASH<\/span><\/div>\n    <pre><span class=\"fn\">sudo<\/span> apt install <span class=\"fl\">-y<\/span> certbot python3-certbot-apache\n<span class=\"fn\">certbot<\/span> <span class=\"fl\">--version<\/span><\/pre>\n  <\/div>\n\n  <h3>Step 2 \u2014 Obtain a Certificate for Your Domain<\/h3>\n  <div class=\"code-wrap\">\n    <div class=\"code-label\"><div class=\"dots\"><div class=\"dot dot-r\"><\/div><div class=\"dot dot-y\"><\/div><div class=\"dot dot-g\"><\/div><\/div>Request SSL Certificate<span class=\"lang\">BASH<\/span><\/div>\n    <pre><span class=\"fn\">sudo<\/span> certbot <span class=\"fl\">--apache<\/span> <span class=\"fl\">-d<\/span> example.com <span class=\"fl\">-d<\/span> www.example.com<\/pre>\n  <\/div>\n  <ul>\n    <li><strong>Email address<\/strong> \u2014 Enter a valid email for expiry notifications<\/li>\n    <li><strong>Terms of Service<\/strong> \u2014 Enter <code class=\"inline\">A<\/code> to agree<\/li>\n    <li><strong>Redirect HTTP to HTTPS?<\/strong> \u2014 Choose <code class=\"inline\">2<\/code> to enable automatic redirect (recommended)<\/li>\n  <\/ul>\n\n  <h3>Step 3 \u2014 Verify the HTTPS Configuration<\/h3>\n  <div class=\"code-wrap\">\n    <div class=\"code-label\"><div class=\"dots\"><div class=\"dot dot-r\"><\/div><div class=\"dot dot-y\"><\/div><div class=\"dot dot-g\"><\/div><\/div>\/etc\/apache2\/sites-available\/example.com-le-ssl.conf<span class=\"lang\">APACHE<\/span><\/div>\n    <pre><span class=\"kw\">&lt;IfModule<\/span> <span class=\"vl\">mod_ssl.c<\/span><span class=\"kw\">&gt;<\/span>\n<span class=\"kw\">&lt;VirtualHost<\/span> <span class=\"vl\">*:443<\/span><span class=\"kw\">&gt;<\/span>\n    <span class=\"ky\">ServerName<\/span>    <span class=\"vl\">example.com<\/span>\n    <span class=\"ky\">DocumentRoot<\/span>  <span class=\"pt\">\/var\/www\/example.com\/public_html<\/span>\n\n    <span class=\"ky\">SSLCertificateFile<\/span>\n      <span class=\"pt\">\/etc\/letsencrypt\/live\/example.com\/fullchain.pem<\/span>\n    <span class=\"ky\">SSLCertificateKeyFile<\/span>\n      <span class=\"pt\">\/etc\/letsencrypt\/live\/example.com\/privkey.pem<\/span>\n    <span class=\"ky\">Include<\/span>\n      <span class=\"pt\">\/etc\/letsencrypt\/options-ssl-apache.conf<\/span>\n<span class=\"kw\">&lt;\/VirtualHost&gt;<\/span>\n<span class=\"kw\">&lt;\/IfModule&gt;<\/span><\/pre>\n  <\/div>\n\n  <h3>Step 4 \u2014 Test Automatic Certificate Renewal<\/h3>\n  <div class=\"code-wrap\">\n    <div class=\"code-label\"><div class=\"dots\"><div class=\"dot dot-r\"><\/div><div class=\"dot dot-y\"><\/div><div class=\"dot dot-g\"><\/div><\/div>Test Auto-Renewal<span class=\"lang\">BASH<\/span><\/div>\n    <pre><span class=\"fn\">sudo<\/span> certbot renew <span class=\"fl\">--dry-run<\/span>\n<span class=\"fn\">sudo<\/span> systemctl status certbot.timer\n<span class=\"fn\">sudo<\/span> certbot certificates<\/pre>\n  <\/div>\n\n  <div class=\"callout success\">\n    <span class=\"callout-icon\">\u2705<\/span>\n    <div class=\"callout-body\">\n      <strong>Success Check<\/strong>\n      The dry run completes without errors. Your site loads over HTTPS with a valid padlock. HTTP traffic automatically redirects to HTTPS.\n    <\/div>\n  <\/div>\n<\/section>\n\n<hr class=\"section-divider\">\n\n<!-- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 SECTION 9 -->\n<section class=\"lesson-section\" id=\"s9\">\n  <div class=\"section-header\">\n    <div class=\"section-number\">09<\/div>\n    <h2>Apache Virtual Hosts \u2014 Multiple Domains on One Server<\/h2>\n  <\/div>\n  <p>Apache can serve any number of distinct websites from a single server using <strong>Virtual Hosts<\/strong>. In this example, we&#8217;ll add a second domain: <code class=\"inline\">secondsite.com<\/code>.<\/p>\n\n  <h3>Step 1 \u2014 Create the Document Root<\/h3>\n  <div class=\"code-wrap\">\n    <div class=\"code-label\"><div class=\"dots\"><div class=\"dot dot-r\"><\/div><div class=\"dot dot-y\"><\/div><div class=\"dot dot-g\"><\/div><\/div>Create Second Site Directory<span class=\"lang\">BASH<\/span><\/div>\n    <pre><span class=\"fn\">sudo<\/span> mkdir <span class=\"fl\">-p<\/span> <span class=\"pt\">\/var\/www\/secondsite.com\/public_html<\/span>\n<span class=\"fn\">sudo<\/span> chown <span class=\"fl\">-R<\/span> www-data:www-data <span class=\"pt\">\/var\/www\/secondsite.com<\/span>\n<span class=\"fn\">sudo<\/span> chmod <span class=\"fl\">-R<\/span> 755 <span class=\"pt\">\/var\/www\/secondsite.com<\/span><\/pre>\n  <\/div>\n\n  <h3>Step 2 \u2014 Create the Virtual Host Config<\/h3>\n  <div class=\"code-wrap\">\n    <div class=\"code-label\"><div class=\"dots\"><div class=\"dot dot-r\"><\/div><div class=\"dot dot-y\"><\/div><div class=\"dot dot-g\"><\/div><\/div>\/etc\/apache2\/sites-available\/secondsite.com.conf<span class=\"lang\">APACHE<\/span><\/div>\n    <pre><span class=\"kw\">&lt;VirtualHost<\/span> <span class=\"vl\">*:80<\/span><span class=\"kw\">&gt;<\/span>\n    <span class=\"ky\">ServerName<\/span>    <span class=\"vl\">secondsite.com<\/span>\n    <span class=\"ky\">ServerAlias<\/span>   <span class=\"vl\">www.secondsite.com<\/span>\n    <span class=\"ky\">DocumentRoot<\/span>  <span class=\"pt\">\/var\/www\/secondsite.com\/public_html<\/span>\n    <span class=\"ky\">ServerAdmin<\/span>   <span class=\"vl\">webmaster@secondsite.com<\/span>\n\n    <span class=\"kw\">&lt;Directory<\/span> <span class=\"pt\">\/var\/www\/secondsite.com\/public_html<\/span><span class=\"kw\">&gt;<\/span>\n        <span class=\"ky\">Options<\/span>       <span class=\"vl\">-Indexes +FollowSymLinks<\/span>\n        <span class=\"ky\">AllowOverride<\/span> <span class=\"vl\">All<\/span>\n        <span class=\"ky\">Require<\/span>       <span class=\"vl\">all granted<\/span>\n    <span class=\"kw\">&lt;\/Directory&gt;<\/span>\n\n    <span class=\"ky\">ErrorLog<\/span>  <span class=\"pt\">${APACHE_LOG_DIR}\/secondsite.com-error.log<\/span>\n    <span class=\"ky\">CustomLog<\/span> <span class=\"pt\">${APACHE_LOG_DIR}\/secondsite.com-access.log<\/span> <span class=\"vl\">combined<\/span>\n<span class=\"kw\">&lt;\/VirtualHost&gt;<\/span><\/pre>\n  <\/div>\n\n  <div class=\"code-wrap\">\n    <div class=\"code-label\"><div class=\"dots\"><div class=\"dot dot-r\"><\/div><div class=\"dot dot-y\"><\/div><div class=\"dot dot-g\"><\/div><\/div>Enable Second Site<span class=\"lang\">BASH<\/span><\/div>\n    <pre><span class=\"fn\">sudo<\/span> a2ensite secondsite.com.conf\n<span class=\"fn\">sudo<\/span> apache2ctl configtest\n<span class=\"fn\">sudo<\/span> systemctl reload apache2<\/pre>\n  <\/div>\n\n  <h3>Step 3 \u2014 Get SSL Certificate for the Second Domain<\/h3>\n  <div class=\"code-wrap\">\n    <div class=\"code-label\"><div class=\"dots\"><div class=\"dot dot-r\"><\/div><div class=\"dot dot-y\"><\/div><div class=\"dot dot-g\"><\/div><\/div>Issue Certificate for Second Domain<span class=\"lang\">BASH<\/span><\/div>\n    <pre><span class=\"fn\">sudo<\/span> certbot <span class=\"fl\">--apache<\/span> <span class=\"fl\">-d<\/span> secondsite.com <span class=\"fl\">-d<\/span> www.secondsite.com<\/pre>\n  <\/div>\n\n  <div class=\"callout info\">\n    <span class=\"callout-icon\">\u2139\ufe0f<\/span>\n    <div class=\"callout-body\">\n      <strong>Useful Management Commands<\/strong><br>\n      <code class=\"inline\">sudo a2ensite sitename.conf<\/code> \u2014 Enable a site<br>\n      <code class=\"inline\">sudo a2dissite sitename.conf<\/code> \u2014 Disable a site<br>\n      <code class=\"inline\">ls \/etc\/apache2\/sites-enabled\/<\/code> \u2014 List all active sites<br>\n      <code class=\"inline\">sudo apache2ctl -S<\/code> \u2014 Show all Virtual Host bindings\n    <\/div>\n  <\/div>\n<\/section>\n\n<hr class=\"section-divider\">\n\n<!-- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 SECTION 10 -->\n<section class=\"lesson-section\" id=\"s10\">\n  <div class=\"section-header\">\n    <div class=\"section-number\">10<\/div>\n    <h2>Advanced: HTTPS Reverse Proxy Virtual Hosts<\/h2>\n  <\/div>\n  <p>A <strong>reverse proxy<\/strong> 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.<\/p>\n\n  <h3>Prerequisites<\/h3>\n  <ul>\n    <li>The <code class=\"inline\">proxy<\/code>, <code class=\"inline\">proxy_http<\/code>, and <code class=\"inline\">headers<\/code> Apache modules must be enabled (done in Section 5)<\/li>\n    <li>A valid SSL certificate for the subdomain must exist (from Section 8)<\/li>\n    <li>The internal service must be running and reachable on its local IP and port<\/li>\n  <\/ul>\n\n  <h3>Step 1 \u2014 Obtain a Certificate for Your Subdomain<\/h3>\n  <div class=\"code-wrap\">\n    <div class=\"code-label\"><div class=\"dots\"><div class=\"dot dot-r\"><\/div><div class=\"dot dot-y\"><\/div><div class=\"dot dot-g\"><\/div><\/div>Issue Certificate for Subdomain<span class=\"lang\">BASH<\/span><\/div>\n    <pre><span class=\"fn\">sudo<\/span> certbot <span class=\"fl\">--apache<\/span> <span class=\"fl\">-d<\/span> app.example.com<\/pre>\n  <\/div>\n\n  <h3>Step 2 \u2014 Create the Reverse Proxy Virtual Host Config<\/h3>\n  <div class=\"code-wrap\">\n    <div class=\"code-label\"><div class=\"dots\"><div class=\"dot dot-r\"><\/div><div class=\"dot dot-y\"><\/div><div class=\"dot dot-g\"><\/div><\/div>\/etc\/apache2\/sites-available\/app.example.com-ssl.conf<span class=\"lang\">APACHE<\/span><\/div>\n    <pre><span class=\"kw\">&lt;IfModule<\/span> <span class=\"vl\">mod_ssl.c<\/span><span class=\"kw\">&gt;<\/span>\n<span class=\"kw\">&lt;VirtualHost<\/span> <span class=\"vl\">*:443<\/span><span class=\"kw\">&gt;<\/span>\n    <span class=\"ky\">ServerName<\/span>        <span class=\"vl\">app.example.com<\/span>\n\n    <span class=\"ky\">ProxyPreserveHost<\/span> <span class=\"vl\">On<\/span>\n    <span class=\"ky\">ProxyPass<\/span>         <span class=\"vl\">\/ http:\/\/192.168.1.42:4533\/<\/span>\n    <span class=\"ky\">ProxyPassReverse<\/span>  <span class=\"vl\">\/ http:\/\/192.168.1.42:4533\/<\/span>\n\n    <span class=\"ky\">Header always set<\/span>\n      <span class=\"vl\">Strict-Transport-Security<\/span>\n      <span class=\"str\">\"max-age=63072000; includeSubDomains; preload\"<\/span>\n\n    <span class=\"ky\">SSLCertificateFile<\/span>\n      <span class=\"pt\">\/etc\/letsencrypt\/live\/app.example.com\/fullchain.pem<\/span>\n    <span class=\"ky\">SSLCertificateKeyFile<\/span>\n      <span class=\"pt\">\/etc\/letsencrypt\/live\/app.example.com\/privkey.pem<\/span>\n    <span class=\"ky\">Include<\/span>\n      <span class=\"pt\">\/etc\/letsencrypt\/options-ssl-apache.conf<\/span>\n<span class=\"kw\">&lt;\/VirtualHost&gt;<\/span>\n<span class=\"kw\">&lt;\/IfModule&gt;<\/span><\/pre>\n  <\/div>\n\n  <h3>Step 3 \u2014 Add a Port 80 Redirect<\/h3>\n  <div class=\"code-wrap\">\n    <div class=\"code-label\"><div class=\"dots\"><div class=\"dot dot-r\"><\/div><div class=\"dot dot-y\"><\/div><div class=\"dot dot-g\"><\/div><\/div>\/etc\/apache2\/sites-available\/app.example.com.conf<span class=\"lang\">APACHE<\/span><\/div>\n    <pre><span class=\"kw\">&lt;VirtualHost<\/span> <span class=\"vl\">*:80<\/span><span class=\"kw\">&gt;<\/span>\n    <span class=\"ky\">ServerName<\/span> <span class=\"vl\">app.example.com<\/span>\n    <span class=\"ky\">Redirect<\/span>   <span class=\"vl\">permanent \/ https:\/\/app.example.com\/<\/span>\n<span class=\"kw\">&lt;\/VirtualHost&gt;<\/span><\/pre>\n  <\/div>\n\n  <h3>Step 4 \u2014 Enable the Configs and Test<\/h3>\n  <div class=\"code-wrap\">\n    <div class=\"code-label\"><div class=\"dots\"><div class=\"dot dot-r\"><\/div><div class=\"dot dot-y\"><\/div><div class=\"dot dot-g\"><\/div><\/div>Enable Reverse Proxy Sites<span class=\"lang\">BASH<\/span><\/div>\n    <pre><span class=\"fn\">sudo<\/span> a2ensite app.example.com.conf\n<span class=\"fn\">sudo<\/span> a2ensite app.example.com-ssl.conf\n<span class=\"fn\">sudo<\/span> apache2ctl configtest\n<span class=\"fn\">sudo<\/span> systemctl reload apache2\n<span class=\"fn\">curl<\/span> <span class=\"fl\">-I<\/span> https:\/\/app.example.com<\/pre>\n  <\/div>\n<\/section>\n\n<hr class=\"section-divider\">\n\n<!-- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 SECTION 11 -->\n<section class=\"lesson-section\" id=\"s11\">\n  <div class=\"section-header\">\n    <div class=\"section-number\">11<\/div>\n    <h2>Setting Up a Second Physical Server as a Subdomain<\/h2>\n  <\/div>\n  <p>Now we&#8217;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 \u2014 for example, <code class=\"inline\">server2.example.com<\/code>.<\/p>\n\n  <h3>Overview of the Architecture<\/h3>\n  <div class=\"code-wrap\">\n    <div class=\"code-label\"><div class=\"dots\"><div class=\"dot dot-r\"><\/div><div class=\"dot dot-y\"><\/div><div class=\"dot dot-g\"><\/div><\/div>Traffic Flow<span class=\"lang\">TEXT<\/span><\/div>\n    <pre>Internet User\n     \u2502\n     \u25bc  (HTTPS \u2014 server2.example.com)\n[Your LAMP Server \u2014 Public IP]   \u2190 Port 443\n     \u2502\n     \u2502  (HTTP \u2014 internal LAN)\n     \u25bc\n[Second Server \u2014 192.168.1.51]   \u2190 Port 80<\/pre>\n  <\/div>\n\n  <h3>On the Second Server \u2014 Install Apache2<\/h3>\n  <div class=\"code-wrap\">\n    <div class=\"code-label\"><div class=\"dots\"><div class=\"dot dot-r\"><\/div><div class=\"dot dot-y\"><\/div><div class=\"dot dot-g\"><\/div><\/div>Second Server \u2014 Install Apache<span class=\"lang\">BASH<\/span><\/div>\n    <pre><span class=\"fn\">sudo<\/span> apt update <span class=\"op\">&amp;&amp;<\/span> <span class=\"fn\">sudo<\/span> apt install <span class=\"fl\">-y<\/span> apache2\n<span class=\"fn\">sudo<\/span> systemctl enable apache2\n<span class=\"fn\">sudo<\/span> systemctl start apache2\n\n<span class=\"fn\">sudo<\/span> mkdir <span class=\"fl\">-p<\/span> <span class=\"pt\">\/var\/www\/website2\/public_html<\/span>\n<span class=\"fn\">sudo<\/span> chown <span class=\"fl\">-R<\/span> www-data:www-data <span class=\"pt\">\/var\/www\/website2<\/span>\n<span class=\"fn\">sudo<\/span> chmod <span class=\"fl\">-R<\/span> 755 <span class=\"pt\">\/var\/www\/website2<\/span><\/pre>\n  <\/div>\n\n  <h3>On the Second Server \u2014 Virtual Host Config<\/h3>\n  <div class=\"code-wrap\">\n    <div class=\"code-label\"><div class=\"dots\"><div class=\"dot dot-r\"><\/div><div class=\"dot dot-y\"><\/div><div class=\"dot dot-g\"><\/div><\/div>\/etc\/apache2\/sites-available\/website2.conf<span class=\"lang\">APACHE<\/span><\/div>\n    <pre><span class=\"kw\">&lt;VirtualHost<\/span> <span class=\"vl\">*:80<\/span><span class=\"kw\">&gt;<\/span>\n    <span class=\"ky\">ServerName<\/span>    <span class=\"vl\">server2.example.com<\/span>\n    <span class=\"ky\">DocumentRoot<\/span>  <span class=\"pt\">\/var\/www\/website2\/public_html<\/span>\n\n    <span class=\"kw\">&lt;Directory<\/span> <span class=\"pt\">\/var\/www\/website2\/public_html<\/span><span class=\"kw\">&gt;<\/span>\n        <span class=\"ky\">Options<\/span>       <span class=\"vl\">-Indexes +FollowSymLinks<\/span>\n        <span class=\"ky\">AllowOverride<\/span> <span class=\"vl\">All<\/span>\n        <span class=\"ky\">Require<\/span>       <span class=\"vl\">all granted<\/span>\n    <span class=\"kw\">&lt;\/Directory&gt;<\/span>\n\n    <span class=\"ky\">ErrorLog<\/span>  <span class=\"pt\">${APACHE_LOG_DIR}\/website2-error.log<\/span>\n    <span class=\"ky\">CustomLog<\/span> <span class=\"pt\">${APACHE_LOG_DIR}\/website2-access.log<\/span> <span class=\"vl\">combined<\/span>\n<span class=\"kw\">&lt;\/VirtualHost&gt;<\/span><\/pre>\n  <\/div>\n\n  <div class=\"code-wrap\">\n    <div class=\"code-label\"><div class=\"dots\"><div class=\"dot dot-r\"><\/div><div class=\"dot dot-y\"><\/div><div class=\"dot dot-g\"><\/div><\/div>Enable on Second Server<span class=\"lang\">BASH<\/span><\/div>\n    <pre><span class=\"fn\">sudo<\/span> a2ensite website2.conf\n<span class=\"fn\">sudo<\/span> a2dissite 000-default.conf\n<span class=\"fn\">sudo<\/span> apache2ctl configtest\n<span class=\"fn\">sudo<\/span> systemctl reload apache2<\/pre>\n  <\/div>\n\n  <h3>On the DNS \u2014 Create the Subdomain Record<\/h3>\n  <div class=\"code-wrap\">\n    <div class=\"code-label\"><div class=\"dots\"><div class=\"dot dot-r\"><\/div><div class=\"dot dot-y\"><\/div><div class=\"dot dot-g\"><\/div><\/div>DNS Record<span class=\"lang\">TEXT<\/span><\/div>\n    <pre>Type:    A\nName:    server2   (becomes server2.example.com)\nValue:   YOUR.PUBLIC.IP.ADDRESS\nTTL:     Auto (or 3600)<\/pre>\n  <\/div>\n\n  <h3>On the LAMP Server \u2014 Reverse Proxy for the Subdomain<\/h3>\n  <div class=\"code-wrap\">\n    <div class=\"code-label\"><div class=\"dots\"><div class=\"dot dot-r\"><\/div><div class=\"dot dot-y\"><\/div><div class=\"dot dot-g\"><\/div><\/div>Issue Certificate (LAMP Server)<span class=\"lang\">BASH<\/span><\/div>\n    <pre><span class=\"fn\">sudo<\/span> certbot <span class=\"fl\">--apache<\/span> <span class=\"fl\">-d<\/span> server2.example.com<\/pre>\n  <\/div>\n\n  <div class=\"code-wrap\">\n    <div class=\"code-label\"><div class=\"dots\"><div class=\"dot dot-r\"><\/div><div class=\"dot dot-y\"><\/div><div class=\"dot dot-g\"><\/div><\/div>server2.example.com-ssl.conf (LAMP Server)<span class=\"lang\">APACHE<\/span><\/div>\n    <pre><span class=\"kw\">&lt;IfModule<\/span> <span class=\"vl\">mod_ssl.c<\/span><span class=\"kw\">&gt;<\/span>\n<span class=\"kw\">&lt;VirtualHost<\/span> <span class=\"vl\">*:443<\/span><span class=\"kw\">&gt;<\/span>\n    <span class=\"ky\">ServerName<\/span>        <span class=\"vl\">server2.example.com<\/span>\n    <span class=\"ky\">ProxyPreserveHost<\/span> <span class=\"vl\">On<\/span>\n    <span class=\"ky\">ProxyPass<\/span>         <span class=\"vl\">\/ http:\/\/192.168.1.51:80\/<\/span>\n    <span class=\"ky\">ProxyPassReverse<\/span>  <span class=\"vl\">\/ http:\/\/192.168.1.51:80\/<\/span>\n\n    <span class=\"ky\">Header always set<\/span>\n      <span class=\"vl\">Strict-Transport-Security<\/span>\n      <span class=\"str\">\"max-age=63072000; includeSubDomains; preload\"<\/span>\n\n    <span class=\"ky\">SSLCertificateFile<\/span>\n      <span class=\"pt\">\/etc\/letsencrypt\/live\/server2.example.com\/fullchain.pem<\/span>\n    <span class=\"ky\">SSLCertificateKeyFile<\/span>\n      <span class=\"pt\">\/etc\/letsencrypt\/live\/server2.example.com\/privkey.pem<\/span>\n    <span class=\"ky\">Include<\/span>\n      <span class=\"pt\">\/etc\/letsencrypt\/options-ssl-apache.conf<\/span>\n<span class=\"kw\">&lt;\/VirtualHost&gt;<\/span>\n<span class=\"kw\">&lt;\/IfModule&gt;<\/span><\/pre>\n  <\/div>\n\n  <div class=\"code-wrap\">\n    <div class=\"code-label\"><div class=\"dots\"><div class=\"dot dot-r\"><\/div><div class=\"dot dot-y\"><\/div><div class=\"dot dot-g\"><\/div><\/div>server2.example.com.conf (LAMP Server)<span class=\"lang\">APACHE<\/span><\/div>\n    <pre><span class=\"kw\">&lt;VirtualHost<\/span> <span class=\"vl\">*:80<\/span><span class=\"kw\">&gt;<\/span>\n    <span class=\"ky\">ServerName<\/span> <span class=\"vl\">server2.example.com<\/span>\n    <span class=\"ky\">Redirect<\/span>   <span class=\"vl\">permanent \/ https:\/\/server2.example.com\/<\/span>\n<span class=\"kw\">&lt;\/VirtualHost&gt;<\/span><\/pre>\n  <\/div>\n\n  <div class=\"code-wrap\">\n    <div class=\"code-label\"><div class=\"dots\"><div class=\"dot dot-r\"><\/div><div class=\"dot dot-y\"><\/div><div class=\"dot dot-g\"><\/div><\/div>Enable and Reload on LAMP Server<span class=\"lang\">BASH<\/span><\/div>\n    <pre><span class=\"fn\">sudo<\/span> a2ensite server2.example.com.conf\n<span class=\"fn\">sudo<\/span> a2ensite server2.example.com-ssl.conf\n<span class=\"fn\">sudo<\/span> apache2ctl configtest\n<span class=\"fn\">sudo<\/span> systemctl reload apache2<\/pre>\n  <\/div>\n\n  <div class=\"callout success\">\n    <span class=\"callout-icon\">\u2705<\/span>\n    <div class=\"callout-body\">\n      <strong>Final Verification<\/strong>\n      Visit <code class=\"inline\">https:\/\/server2.example.com<\/code> in a browser. You should see the &#8220;Website 2&#8221; page with a valid padlock \u2014 confirming that HTTPS traffic is being handled by your LAMP server and transparently proxied to the second physical server on your LAN.\n    <\/div>\n  <\/div>\n\n  <div class=\"callout info\">\n    <span class=\"callout-icon\">\ud83d\udca1<\/span>\n    <div class=\"callout-body\">\n      <strong>What&#8217;s Coming Next \u2014 File Permissions Deep Dive<\/strong>\n      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.\n    <\/div>\n  <\/div>\n<\/section>\n\n<\/main>\n\n<footer>\n  <div style=\"max-width:900px; margin:0 auto; padding:0 1.25rem;\">\n    <p style=\"font-size:1rem; font-weight:700; color:#ffffff; margin-bottom:0.5rem;\">LAMP Server Setup &mdash; Lesson 1<\/p>\n    <p style=\"color:#ffffff; margin-bottom:0.25rem;\">Ubuntu 24.04 LTS &middot; Apache 2.4 &middot; MySQL 8.x &middot; PHP 8.3 &middot; Let&#39;s Encrypt<\/p>\n    <p style=\"color:#ffffff; margin-top:1rem;\">\n      Written by <strong style=\"color:#ffffff;\">Nicole M. Taylor<\/strong>\n      &nbsp;\n      <a href=\"mailto:nicolemtaylor1972@gmail.com\" title=\"Contact Nicole M. Taylor\" style=\"color:#93c5fd; text-decoration:none; display:inline-flex; align-items:center; gap:0.3rem; vertical-align:middle;\">\n        <svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" style=\"vertical-align:middle;\"><rect x=\"2\" y=\"4\" width=\"20\" height=\"16\" rx=\"2\"\/><path d=\"m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7\"\/><\/svg>\n        <span style=\"font-size:0.8rem; color:#93c5fd;\">Contact<\/span>\n      <\/a>\n    <\/p>\n    <p style=\"color:#94a3b8; font-size:0.78rem; margin-top:0.75rem;\">Created: March 2026 &nbsp;&middot;&nbsp; Always test in a non-production environment first. Keep your system updated. Back up before making major changes.<\/p>\n  <\/div>\n<\/footer>\n\n<\/body>\n<\/html>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n","protected":false},"excerpt":{"rendered":"<p>LAMP Server Setup \u2014 Complete Guide Lesson 1 \u2014 Complete Walkthrough Building a LAMP Serverfrom Scratch A no-skip, step-by-step professional guide covering hardware selection through HTTPS virtual hosting \u2014 Ubuntu 24.04 \u00b7 Apache2 \u00b7 MySQL \u00b7 PHP Ubuntu 24.04 LTS Apache 2.4 MySQL 8.x PHP 8.3 Let&#8217;s Encrypt \/ Certbot Virtual Hosts Created: March 2026 [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"footnotes":""},"class_list":["post-403","page","type-page","status-publish","hentry"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.6 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>LAMP Server Setup \u2014 Complete Guide - A &amp; N Family Professional Business Services<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.anfamily.cloud\/home\/index.php\/lamp-server-setup-complete-guide\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"LAMP Server Setup \u2014 Complete Guide - A &amp; N Family Professional Business Services\" \/>\n<meta property=\"og:description\" content=\"LAMP Server Setup \u2014 Complete Guide Lesson 1 \u2014 Complete Walkthrough Building a LAMP Serverfrom Scratch A no-skip, step-by-step professional guide covering hardware selection through HTTPS virtual hosting \u2014 Ubuntu 24.04 \u00b7 Apache2 \u00b7 MySQL \u00b7 PHP Ubuntu 24.04 LTS Apache 2.4 MySQL 8.x PHP 8.3 Let&#8217;s Encrypt \/ Certbot Virtual Hosts Created: March 2026 [&hellip;]\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.anfamily.cloud\/home\/index.php\/lamp-server-setup-complete-guide\/\" \/>\n<meta property=\"og:site_name\" content=\"A &amp; N Family Professional Business Services\" \/>\n<meta property=\"article:modified_time\" content=\"2026-03-17T19:44:59+00:00\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data1\" content=\"16 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/www.anfamily.cloud\\\/home\\\/index.php\\\/lamp-server-setup-complete-guide\\\/\",\"url\":\"https:\\\/\\\/www.anfamily.cloud\\\/home\\\/index.php\\\/lamp-server-setup-complete-guide\\\/\",\"name\":\"LAMP Server Setup \u2014 Complete Guide - A &amp; N Family Professional Business Services\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.anfamily.cloud\\\/home\\\/#website\"},\"datePublished\":\"2026-03-17T19:44:56+00:00\",\"dateModified\":\"2026-03-17T19:44:59+00:00\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/www.anfamily.cloud\\\/home\\\/index.php\\\/lamp-server-setup-complete-guide\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/www.anfamily.cloud\\\/home\\\/index.php\\\/lamp-server-setup-complete-guide\\\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/www.anfamily.cloud\\\/home\\\/index.php\\\/lamp-server-setup-complete-guide\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/www.anfamily.cloud\\\/home\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"LAMP Server Setup \u2014 Complete Guide\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/www.anfamily.cloud\\\/home\\\/#website\",\"url\":\"https:\\\/\\\/www.anfamily.cloud\\\/home\\\/\",\"name\":\"AnFamily Professional Services\",\"description\":\"Providing Quality Service Since 2021\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/www.anfamily.cloud\\\/home\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"LAMP Server Setup \u2014 Complete Guide - A &amp; N Family Professional Business Services","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.anfamily.cloud\/home\/index.php\/lamp-server-setup-complete-guide\/","og_locale":"en_US","og_type":"article","og_title":"LAMP Server Setup \u2014 Complete Guide - A &amp; N Family Professional Business Services","og_description":"LAMP Server Setup \u2014 Complete Guide Lesson 1 \u2014 Complete Walkthrough Building a LAMP Serverfrom Scratch A no-skip, step-by-step professional guide covering hardware selection through HTTPS virtual hosting \u2014 Ubuntu 24.04 \u00b7 Apache2 \u00b7 MySQL \u00b7 PHP Ubuntu 24.04 LTS Apache 2.4 MySQL 8.x PHP 8.3 Let&#8217;s Encrypt \/ Certbot Virtual Hosts Created: March 2026 [&hellip;]","og_url":"https:\/\/www.anfamily.cloud\/home\/index.php\/lamp-server-setup-complete-guide\/","og_site_name":"A &amp; N Family Professional Business Services","article_modified_time":"2026-03-17T19:44:59+00:00","twitter_card":"summary_large_image","twitter_misc":{"Est. reading time":"16 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/www.anfamily.cloud\/home\/index.php\/lamp-server-setup-complete-guide\/","url":"https:\/\/www.anfamily.cloud\/home\/index.php\/lamp-server-setup-complete-guide\/","name":"LAMP Server Setup \u2014 Complete Guide - A &amp; N Family Professional Business Services","isPartOf":{"@id":"https:\/\/www.anfamily.cloud\/home\/#website"},"datePublished":"2026-03-17T19:44:56+00:00","dateModified":"2026-03-17T19:44:59+00:00","breadcrumb":{"@id":"https:\/\/www.anfamily.cloud\/home\/index.php\/lamp-server-setup-complete-guide\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.anfamily.cloud\/home\/index.php\/lamp-server-setup-complete-guide\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/www.anfamily.cloud\/home\/index.php\/lamp-server-setup-complete-guide\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.anfamily.cloud\/home\/"},{"@type":"ListItem","position":2,"name":"LAMP Server Setup \u2014 Complete Guide"}]},{"@type":"WebSite","@id":"https:\/\/www.anfamily.cloud\/home\/#website","url":"https:\/\/www.anfamily.cloud\/home\/","name":"AnFamily Professional Services","description":"Providing Quality Service Since 2021","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.anfamily.cloud\/home\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"}]}},"_links":{"self":[{"href":"https:\/\/www.anfamily.cloud\/home\/index.php\/wp-json\/wp\/v2\/pages\/403","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.anfamily.cloud\/home\/index.php\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/www.anfamily.cloud\/home\/index.php\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/www.anfamily.cloud\/home\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.anfamily.cloud\/home\/index.php\/wp-json\/wp\/v2\/comments?post=403"}],"version-history":[{"count":3,"href":"https:\/\/www.anfamily.cloud\/home\/index.php\/wp-json\/wp\/v2\/pages\/403\/revisions"}],"predecessor-version":[{"id":406,"href":"https:\/\/www.anfamily.cloud\/home\/index.php\/wp-json\/wp\/v2\/pages\/403\/revisions\/406"}],"wp:attachment":[{"href":"https:\/\/www.anfamily.cloud\/home\/index.php\/wp-json\/wp\/v2\/media?parent=403"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}