diff --git a/README.md b/README.md
index 5482817..7ac72ac 100644
--- a/README.md
+++ b/README.md
@@ -5,6 +5,7 @@
+
# BrokenOps
diff --git a/labs/nginx-broken/cloud-init.yaml b/labs/nginx-broken/cloud-init.yaml
index b4bad6f..274045b 100644
--- a/labs/nginx-broken/cloud-init.yaml
+++ b/labs/nginx-broken/cloud-init.yaml
@@ -1,8 +1,16 @@
#cloud-config
packages:
- nginx
+ - policycoreutils
+ - selinux-utils
+ - policycoreutils-python-utils
+ - auditd
runcmd:
- # Intentional break: configure nginx to listen on invalid port to break it
- - sed -i 's/listen 80 default_server;/listen 80808 default_server;/' /etc/nginx/sites-available/default
+ # Intentional break: move nginx to 8080, but do not allow SELinux http_port_t on 8080.
+ - sed -i 's/listen 80 default_server;/listen 8080 default_server;/' /etc/nginx/sites-available/default
+ - sed -i 's/listen \[::\]:80 default_server;/listen [::]:8080 default_server;/' /etc/nginx/sites-available/default
+ - systemctl enable --now auditd || true
+ - setenforce 1 || true
+ - semanage port -d -t http_port_t -p tcp 8080 || true
- systemctl restart nginx || true
diff --git a/labs/nginx-broken/lab.yaml b/labs/nginx-broken/lab.yaml
index 7867bec..cbc052f 100644
--- a/labs/nginx-broken/lab.yaml
+++ b/labs/nginx-broken/lab.yaml
@@ -1,6 +1,6 @@
id: nginx-broken
-name: Nginx Service Down
+name: SELinux Denies Nginx on Custom Port
category: linux
difficulty: beginner
@@ -17,18 +17,18 @@ vm:
cloud_init: cloud-init.yaml
verify_script: verify.sh
exposed_ports:
- - 80
+ - 8080
verify: verify.sh
description:
- summary: "Nginx is not running after reboot"
- story: "A server reboot caused nginx to stop."
+ summary: "Nginx runs but app is unreachable on port 8080"
+ story: "Nginx was moved to port 8080, but SELinux policy was never updated."
objectives:
- - Start nginx
- - Enable service on boot
- - Confirm HTTP response
+ - Investigate SELinux denials for nginx
+ - Map TCP port 8080 to http_port_t
+ - Confirm HTTP response on port 8080
tags:
- - systemd
+ - selinux
- nginx
diff --git a/labs/nginx-broken/question.md b/labs/nginx-broken/question.md
index c290fa6..45a2526 100644
--- a/labs/nginx-broken/question.md
+++ b/labs/nginx-broken/question.md
@@ -1,13 +1,19 @@
### Scenario
-You have just joined a new company as a junior sysadmin. A developer frantically messages you:
-> "Hey! The main Nginx web server is completely down on our internal staging box. The service won't start at all after I accidentally rebooted it! I need to test my new frontend right now, can you please fix it?"
+Nginx was reconfigured to use port **8080** on a host where SELinux is expected to remain enforcing.
+The service appears configured, but the app is unreachable.
### Objective
-Investigate why the `nginx` service is failing to start on this machine, fix the root cause, and ensure the service is running.
-Once running, the web server should be accessible via the **"Open Port 80"** button in the top navigation bar. When clicked, it should display the default Nginx welcome page.
+Find and fix the SELinux policy issue preventing HTTP service on the custom port while keeping SELinux enforcing.
+
+When solved:
+- Nginx should run on **port 8080**
+- SELinux should allow HTTP traffic on 8080 (`http_port_t` mapping)
+- The **"Open Port 8080"** button should load the Nginx default page
### Useful Commands
- `systemctl status nginx`
- `journalctl -xeu nginx.service`
+- `ausearch -m avc -ts recent`
+- `semanage port -l | grep http_port_t`
diff --git a/labs/nginx-broken/solution.md b/labs/nginx-broken/solution.md
index 8d3590c..4931174 100644
--- a/labs/nginx-broken/solution.md
+++ b/labs/nginx-broken/solution.md
@@ -1,42 +1,40 @@
### The Issue
-The developer or someone else accidentally configured Nginx to listen on a port that it doesn't have permission to bind to, or they made a syntax error in the configuration file!
+Nginx was moved to TCP port `8080`, but SELinux policy did not allow HTTP services on that port.
+So nginx fails to bind when SELinux is enforcing.
### Step-by-Step Fix
-1. **Check the service status to get a hint:**
+1. **Check nginx status and logs:**
```bash
systemctl status nginx
+ journalctl -xeu nginx.service
```
- You should see it failing.
-2. **Test the Nginx configuration for syntax errors:**
+2. **Check SELinux denials:**
```bash
- sudo nginx -t
+ ausearch -m avc -ts recent
```
- This will pinpoint exactly which file and line number contains the bad configuration. You'll likely see an error pointing to `/etc/nginx/sites-available/default` trying to listen on port `80808` or a typo like `lissten 80`.
-3. **Fix the configuration file:**
- Open the file with your favorite editor:
+3. **Confirm the custom port is not mapped to `http_port_t`:**
```bash
- sudo nano /etc/nginx/sites-available/default
- ```
- Find the incorrect line and fix it back to listening on a standard port like `80`:
- ```nginx
- server {
- listen 80 default_server;
- listen [::]:80 default_server;
- # ...
- }
+ semanage port -l | grep http_port_t
```
-4. **Restart the Nginx service:**
+4. **Map TCP 8080 for HTTP services:**
```bash
- sudo systemctl restart nginx
+ sudo semanage port -a -t http_port_t -p tcp 8080
+ ```
+ If it already exists with a different type, modify it instead:
+ ```bash
+ sudo semanage port -m -t http_port_t -p tcp 8080
```
-5. **Verify it's running:**
+5. **Restart nginx and verify:**
```bash
- systemctl status nginx
+ sudo systemctl restart nginx
+ ss -tuln | grep ':8080 '
+ curl -I http://127.0.0.1:8080
```
- It should now say **active (running)**. You've solved the lab!
+
+You have solved the lab once nginx is reachable on port `8080` with SELinux still enforcing.
diff --git a/labs/nginx-broken/solution.sh b/labs/nginx-broken/solution.sh
new file mode 100755
index 0000000..f7ee0bf
--- /dev/null
+++ b/labs/nginx-broken/solution.sh
@@ -0,0 +1,13 @@
+#!/bin/bash
+set -e
+
+# Keep nginx on custom port 8080
+sed -i 's/listen 80 default_server;/listen 8080 default_server;/' /etc/nginx/sites-available/default || true
+sed -i 's/listen \[::\]:80 default_server;/listen [::]:8080 default_server;/' /etc/nginx/sites-available/default || true
+
+# Ensure SELinux allows HTTP traffic on tcp/8080
+if ! semanage port -l | awk '/^http_port_t/ && /(^|[^0-9])8080([^0-9]|$)/ {found=1} END {exit found?0:1}'; then
+ semanage port -a -t http_port_t -p tcp 8080 || semanage port -m -t http_port_t -p tcp 8080
+fi
+
+systemctl restart nginx
diff --git a/labs/nginx-broken/verify.sh b/labs/nginx-broken/verify.sh
old mode 100644
new mode 100755
index acf7136..0a9a379
--- a/labs/nginx-broken/verify.sh
+++ b/labs/nginx-broken/verify.sh
@@ -3,16 +3,30 @@
# Check if nginx service is active
systemctl is-active --quiet nginx
if [ $? -ne 0 ]; then
- echo "FAILURE: The nginx service is not running."
+ echo "FAILURE: nginx service is not running."
exit 1
fi
-# Check if it's actually listening on port 80
-ss -tuln | grep ":80 " > /dev/null
+# Check if nginx is listening on port 8080
+ss -tuln | grep ':8080 ' > /dev/null
if [ $? -ne 0 ]; then
- echo "FAILURE: Nginx is running, but it's not listening on port 80!"
+ echo "FAILURE: nginx is not listening on port 8080."
exit 1
fi
-echo "SUCCESS: Nginx is running and listening on port 80!"
+# Check SELinux port context mapping for HTTP on 8080
+semanage port -l | awk '/^http_port_t/ && /(^|[^0-9])8080([^0-9]|$)/ {found=1} END {exit found?0:1}'
+if [ $? -ne 0 ]; then
+ echo "FAILURE: SELinux is not allowing HTTP service on tcp/8080 (http_port_t mapping missing)."
+ exit 1
+fi
+
+# Check HTTP response over localhost
+curl -sSf http://127.0.0.1:8080 > /dev/null
+if [ $? -ne 0 ]; then
+ echo "FAILURE: nginx is running on 8080 but HTTP request failed."
+ exit 1
+fi
+
+echo "SUCCESS: nginx is serving on 8080 and SELinux http_port_t mapping is set for tcp/8080."
exit 0
diff --git a/workflow_status.svg b/workflow_status.svg
index 5f2e518..82843e6 100644
--- a/workflow_status.svg
+++ b/workflow_status.svg
@@ -11,31 +11,47 @@
Workflow Execution Report
-Commit: a0dc113 • Triggered: 2026-06-05 13:28:35
+Commit: 11f2d59 • Triggered: 2026-06-05 14:23:50
-
-Remove Solutions on Main
-2026-06-05 13:28:19 • trigger: push
+
+CI Verify Labs
+2026-06-05 14:23:38 • trigger: pull_request
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-SUCCESS (6s)
+FAILURE (154s)
-CI Verify Labs
-2026-06-05 12:25:41 • prev trigger: pull_request
+Remove Solutions on Main
+2026-06-05 13:28:19 • prev trigger: push
-SUCCESS (Last: 122s)
+SUCCESS (Last: 6s)
Generate and Embed Banner