Welcome to Week 1 of the Sysadmin Challenge!

In this task, we deploy a secure and production-ready LEMP stack; that’s Linux + Nginx + MySQL + PHP—with a strong focus on hardening, SSL, and best practices. Whether you're just exploring server management or preparing for real-world deployments, this walkthrough breaks it all down step-by-step.

By the end of this post, you'll learn:

  • How to set up and secure a cloud-hosted Linux server
  • Harden Nginx, MySQL, and PHP for production
  • Deploy SSL with Let’s Encrypt and pass the SSL Labs A+ test
  • Configure a basic firewall
  • Host a simple website with confidence

*Bonus tip: * Always remember to terminate your virtual instances (like AWS EC2) when done to avoid unexpected charges.

Let’s dive in!

🛠️ TASK BREAKDOWN

1. Set up a Linux Server (Ubuntu 24.04)

I used a clean Ubuntu 24.04 VM hosted on the cloud (EC2 on AWS). After launching the instance:

Step-by-Step: Creating an EC2 Instance

  1. Choose AMI: Ubuntu Server 24.04 LTS (x86_64)

Instance Type:
t2.micro (Free Tier eligible)

my t2.micro ec2 instance creation

  1. Key Pair: Create a new key pair (or use existing one). Save your .pem file securely.

Network Settings:

Allow SSH (port 22)

Allow HTTP (port 80)

Allow HTTPS (port 443)

Launch Instance and SSH into your EC2 server
ssh -i your-key.pem ubuntu@your-ec2-public-ip

SSH to my running ec2 instance

Update and upgrade your instance
sudo apt update && sudo apt upgrade -y

Update instance

2. Install & Harden Nginx

Run the following command to install Nginx server. You can also use Apache server.
sudo apt install nginx -y

Active nginx

I created a file named /etc/nginx/snippets/security-headers.conf and added best-practice security headers. Then I included it inside my Nginx server block to globally apply the hardening.

Basic Hardening:
Disabled directory listing
Add headers using this command: sudo nano /etc/nginx/snippets/security-headers.conf

Added security headers in /etc/nginx/snippets/security-headers.conf
add_header X-Frame-Options "SAMEORIGIN";
add_header X-XSS-Protection "1; mode=block";
add_header X-Content-Type-Options "nosniff";
add_header Referrer-Policy "no-referrer-when-downgrade";
add_header Permissions-Policy "geolocation=(), microphone=(), camera=()";
add_header Content-Security-Policy "default-src 'self'; script-src 'self'; object-src 'none';";
Security headers
Test and reload nginx
sudo nginx -t && sudo systemctl reload nginx

Nginx reload

3. Install and Secure MySQL or MariaDB

Install MySQL
sudo apt install mysql-server -y
Run security script
sudo mysql_secure_installation
For MariaDB
sudo apt install -y mariadb-server
Follow the prompts to set up root password and remove anonymous users.

MySQL hardened

4. Install and harden PHP

Install PHP and its modules
sudo apt install php-fpm php-mysql -y
Harden PHP config
sudo nano /etc/php/*/fpm/php.ini # Replace * with PHP version (e.g., 8.1)

Check if the following are applying in your php config:
expose_php = Off
display_errors = Off
disable_functions = exec,passthru,shell_exec,system
cgi.fix_pathinfo = 0

Restart PHP
sudo systemctl restart php*-fpm

5. Configure Nginx for PHP

We will connect Nginx to PHP-FPM
sudo nano /etc/nginx/sites-available/default

Replace server{} block with:
server {
listen 80;
server_name your-domain.com; # Replace with EC2 IP or domain
root /var/www/html;
index index.php index.html;

location / {
    try_files $uri $uri/ =404;
}

location ~ \.php$ {
    include snippets/fastcgi-php.conf;
    fastcgi_pass unix:/var/run/php/php*-fpm.sock;  # * = PHP version
}

location ~ /\.ht {
    deny all;
}

}

Test and reload nginx
sudo nginx -t && sudo systemctl reload nginx

6. Configure UFW firewall

Enable basic firewall to allow only necessary ports
sudo ufw allow OpenSSH
sudo ufw allow 'Nginx Full'
sudo ufw enable

UFW firewall

7. Install Let's Encrypt SSL

After activating the firewall, we are going to secure our site using SSL. We will install Certbot which is a tool that lets us get free SSL certificates for our website.
sudo apt install certbot python3-certbot-nginx -y

We will then create an SSL certificate
sudo certbot --nginx -d your-domain.com ( Replace your-domain.com with your domain name. If you get an error, you can use your public ec2 instance to get a free public domain)

After this, we should see a lock symbol, meaning that our site is secure. we can then test our security headers for our site, and we get a score of A and above, then we are good. Paste your domain name to the following site:

Security Headers scan

Security header scan result

8. Deploy a simple static website

Created a sample HTML page in /var/www/html/index.html using the command
sudo nano /var/www/html/index.html and save.

Simple static webpage

Reload your webpage and you should see an update to the landing page!

My secure site

Challenges Encountered and Possible Solutions

Ubuntu 22.04 Kernel Upgrade Issues

Challenge: I encountered compatibility issues with the latest updates breaking some package dependencies.
Solution: Switched to Ubuntu 24.04, which offered better stability and smoother package handling for this project.

Certbot Failing to Generate SSL Certificate

Challenge: SSL generation via Certbot initially failed due to DNS propagation delays or incorrect domain configuration.
Solution: Ensured my duckdns domain was correctly pointed to my public IP. Waited a few minutes, then retried with:
sudo certbot --nginx -d mydomain.duckdns.org

UFW Not Allowing Nginx Traffic
Challenge: Website wasn’t reachable until firewall rules were corrected.
Solution: Allowed Nginx explicitly:
sudo ufw allow 'Nginx Full'

This project was an eye-opener into real-world web server deployment and hardening. From installing and securing services to implementing proper permission handling and SSL encryption, I walked away with a strong foundational understanding of building secure LEMP stacks on Linux.

This marks my very first blog post (I aim to do better in the second post); if you’ve made it this far, thank you! I’d love to hear your thoughts, questions, or even how you’d approach a similar setup differently. Please feel free to leave a comment below or connect with me!

And to anyone just starting out or feeling stuck: never be afraid to ask for help. Whether from forums, peers, or mentors; every expert was once a beginner.

Let’s keep learning and growing together!