Lab: Setting up Nginx on Ubuntu (Static, PHP, ASP.NET, TLS)

0. General Information

Learning goals

By the end of this lab you will be able to:

  • Install and start Nginx on a fresh Ubuntu Server VM
  • Serve a static website (HTML/CSS/JS)**
  • Serve a PHP-based website using php-fpm
  • Serve an ASP.NET website via reverse proxy to a .NET application
  • Secure a virtual host with TLS using a self-signed certificate
  • Explain in theory how Let’s Encrypt would be used in a real public setup

1. Prerequisites

  • You have a fresh Ubuntu Server VM (no GUI needed).
  • You can log in via console or SSH as a user with sudo privileges.
  • The VM has internet access for installing packages.

Protocol requirement:
For every step in this lab, write in your protocol:

  • The commands you executed
  • A short explanation of what you did and why
  • Any error messages and how you fixed them
  • Screenshots or copy-pasted outputs where useful

2. Basic System Setup

Update & tools:

sudo apt update
sudo apt upgrade -y
sudo apt install -y curl nano unzip

3. Install and Test Nginx

Install:

sudo apt install -y nginx

Check service:

systemctl status nginx

Test:

curl http://localhost/

4. Virtual Host for Static Files (HTTP)

4.1 Add to client hosts file

<VIRTUAL_MACHINE_IP>   static.local

On Windows the hosts file can be found under: C:\Windows\System32\Drivers\etc

4.2 Create directory and sample static site

sudo mkdir -p /var/www/static.local/public
sudo chown -R $USER:$USER /var/www/static.local

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Static Site Test</title>
    <link rel="stylesheet" href="style.css">
    <script src="script.js" defer></script>
</head>
<body>
    <h1>Hello from Nginx static site!</h1>
    <p>This page is served as a static file.</p>
    <p>Time loaded: <span id="time"></span></p>
</body>
</html>

style.css

body { font-family: Arial, sans-serif; }
h1   { text-align: center; }

script.js

document.addEventListener("DOMContentLoaded", () => {
  const span = document.getElementById("time");
  span.textContent = new Date().toLocaleString();
});

4.3 Nginx configuration

Create:

sudo nano /etc/nginx/sites-available/static.local

Content:

server {
    listen 80;
    server_name static.local;
 
    root /var/www/static.local/public;
 
    location / {
        try_files $uri $uri/ =404;
    }
}

Enable:

sudo ln -s /etc/nginx/sites-available/static.local /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx

5. Virtual Host for PHP

5.1 Install PHP-FPM

sudo apt install -y php-fpm php-cli

5.2 Sample PHP site

sudo mkdir -p /var/www/php.local/public
sudo chown -R $USER:$USER /var/www/php.local

index.php

<!DOCTYPE html>
<html>
<body>
<h1>PHP is working!</h1>
<p>Current time: <?php echo date('Y-m-d H:i:s'); ?></p>
<p>PHP version: <?php echo phpversion(); ?></p>
</body>
</html>

5.3 Nginx config for PHP

Add hosts entry:

<VIRTUAL_MACHINE_IP>   php.local

Config:

server {
    listen 80;
    server_name php.local;
 
    root /var/www/php.local/public;
    index index.php index.html;
 
    location / {
        try_files $uri $uri/ /index.php;
    }
 
    location ~ \.php$ {
        include snippets/fastcgi-php.conf;
        fastcgi_pass unix:/run/php/php8.3-fpm.sock;
    }
}

6. Virtual Host for ASP.NET (Reverse Proxy)

6.1 Install .NET

sudo apt update
sudo apt install -y dotnet-sdk-8.0

6.2 Create minimal ASP.NET app

mkdir -p ~/aspnet-site
cd ~/aspnet-site
dotnet new web -o WebApp1
cd WebApp1
dotnet run --urls http://localhost:5000

Test:

curl http://localhost:5000

6.3 Nginx reverse proxy config

Hosts entry:

<VIRTUAL_MACHINE_IP>   aspnet.local

Config:

server {
    listen 80;
    server_name aspnet.local;
 
    location / {
        proxy_pass http://localhost:5000;
        proxy_http_version 1.1;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

7. TLS with a Self-Signed Certificate

7.1 Create certificate

sudo mkdir -p /etc/ssl/private
sudo openssl req -x509 -nodes -days 365   -newkey rsa:2048   -keyout /etc/ssl/private/static.local.key   -out /etc/ssl/certs/static.local.crt

Use CN = static.local.

7.2 Nginx HTTPS config

server {
    listen 80;
    server_name static.local;
    return 301 https://$host$request_uri;
}
 
server {
    listen 443 ssl;
    server_name static.local;
 
    ssl_certificate /etc/ssl/certs/static.local.crt;
    ssl_certificate_key /etc/ssl/private/static.local.key;
 
    root /var/www/static.local/public;
 
    location / {
        try_files $uri $uri/ =404;
    }
}

8. Optional: Let’s Encrypt Theory

  • Uses the ACME protocol
  • Proves domain control via HTTP-01, DNS-01, or TLS-ALPN-01
  • Works with Certbot to automate issuing & renewal
  • Requires a public DNS name and publicly reachable server

Example (NOT executed in lab):

sudo apt install certbot python3-certbot-nginx
sudo certbot --nginx -d example.com -d www.example.com

9. Protocol Checklist

  • Static site setup (with sample HTML, CSS, JS)
  • PHP site setup
  • ASP.NET reverse proxy
  • Self-signed TLS
  • Let’s Encrypt explanation
  • Screenshots or curl outputs where useful