Skip to content
DevOps AI ToolKit
Newsletter

Kali Linux for DevOps Engineers · Part 15 of 15

Build Your First Kali DevOps Security Lab

Difficulty: Intermediate ~20 min Part 15/15
Series progress15 / 15
Series curriculum (15 lessons)

This is the capstone of the series. Instead of learning one tool at a time, you’ll assemble everything — nmap, dig, curl, openssl, tcpdump, and container networking — into a single, self-contained lab that is yours to break and repair. The goal is not to attack anything. The goal is to build a private, isolated environment where you can practice inspecting and troubleshooting infrastructure without ever touching a system you don’t own.

Every skill in this series is really an infrastructure skill wearing a security label. Discovering hosts is service discovery. Reading TLS handshakes is debugging expired certificates. Capturing packets is diagnosing a connection that “just hangs.” A lab lets you rehearse all of it safely.

What You’re Building

You’ll run a small, closed network on your own machine: a Kali toolbox with the inspection tools, a target web server to inspect, and everything wired onto a private Docker network that can’t reach — and isn’t reached by — the outside world or your real LAN.

                  DEVOPS SECURITY LAB

                    Docker Network
                          |
            +-------------+-------------+
            |                           |
        Kali Linux                  Web Server
        Toolbox                     Container
            |                           |
            +-------------+-------------+
                          |
                     Ubuntu VM

The whole lab lives inside an Ubuntu VM (from Installing Kali in a VM, the same isolation principle applies to any host you dedicate to lab work). Inside that VM, Docker hosts a private bridge network. Two containers attach to it: your Kali toolbox and the target. Because the network is user-defined and internal, the containers can talk to each other by name but nothing leaks toward production.

🔐 Security Note — Isolation is the entire point of a lab. A closed Docker network with no route to your corporate LAN or the internet means a mistake — a wrong IP, an over-broad scan, a fat-fingered flag — stays contained. You get to be curious without being dangerous.

Lab Rules

Read this section before you run a single command. These rules are not bureaucracy; they are the line between practicing engineering and committing a crime.

  1. Only test infrastructure you OWN. Your laptop, your VM, your containers, your home lab.
  2. Only test infrastructure built specifically for the lab. The target container in this lesson exists to be inspected. Public sites, your employer’s staging environment, and “just this one server” do not.
  3. Only test infrastructure you are EXPLICITLY authorized to test — in writing, with a defined scope. Verbal “sure, go ahead” is not authorization.

Everything below runs against lab-web, a container you create yourself. Nothing here points at a system you don’t control, and you should keep it that way.

⛔ Production Warning — Never run scans, packet captures, or probes against production systems, cloud tenants, SaaS providers, or any host you do not own or have written permission to test. Port scanning or capturing traffic on infrastructure you’re not authorized to touch is a violation of computer-misuse law in most jurisdictions and of nearly every cloud provider’s acceptable-use policy — regardless of intent. When in doubt, point it at your lab, not the internet.

Building the Lab

You’ll reuse the container approach from Kali Linux in Docker. If you’re new to Docker itself, the Docker Academy walks through the fundamentals.

1. Create an isolated network

docker network create --internal lab-net

The --internal flag is the safety belt: it creates a bridge network with no external connectivity. Containers on lab-net can reach each other but cannot reach the internet, and the internet cannot reach them. This is exactly the containment the Lab Rules require.

💡 Note — Because --internal blocks outbound access, pull any images you need before attaching containers to lab-net, or attach containers to lab-net as a second network after they’re built. Docker lets a container join multiple networks.

2. Start the target web server

docker run -d --name lab-web --network lab-net nginx:stable

This launches a stock Nginx container named lab-web on the isolated network. It’s an ordinary web server — nothing malicious, nothing special — which makes it a perfect, honest target for inspection.

3. Start your Kali toolbox on the same network

docker run -it --name kali-toolbox --network lab-net kalilinux/kali-rolling bash

Inside that shell, install the inspection tools once:

apt update && apt install -y nmap dnsutils curl openssl tcpdump iproute2 netcat-traditional

You now have a Kali toolbox and a target sharing a private network. Everything from here runs inside kali-toolbox, aimed only at lab-web.

The Exercises

Work through these in order. Each one maps to a full lesson from earlier in the series — follow the links when you want the deep dive.

1. Discover your lab server

Confirm the target is reachable and learn its address on the lab network:

getent hosts lab-web
ping -c 3 lab-web

Docker’s embedded DNS resolves the container name lab-web to its IP on lab-net. getent hosts prints that IP; ping confirms the host is alive. Discovery is step one of every real incident: is the thing even up, and where does its name point?

2. Identify listening ports

nmap -sV lab-web

nmap -sV scans lab-web and attempts version detection on any open ports — here you should see TCP 80 open, running Nginx. This is service discovery: confirming what a host is actually exposing versus what you think it exposes. For the full breakdown, see nmap for DevOps.

You can cross-check from the target’s own perspective. Inside lab-web (docker exec -it lab-web bash), list its listening sockets:

ss -tlnp

ss -tlnp shows every TCP socket in the listening state with the owning process — the authoritative, host-side answer to “what’s actually bound here?”

🛠️ DevOps Perspectivenmap tells you what’s exposed from the outside; ss tells you what’s bound from the inside. When those two views disagree, you’ve found a firewall rule, a bind-address bug, or a container port that never got published. That gap is where a huge share of “the service is down” tickets live.

3. Query DNS

dig lab-web

Inside the lab, Docker’s DNS resolves container names. To practice against real, benign public records instead, query a public resolver:

dig @1.1.1.1 example.com A

dig shows you the exact answer a resolver returns, the record type, and the TTL — the ground truth when an app “can’t find” a host. DNS is the number-one cause of mysterious outages; DNS troubleshooting covers the failure modes.

4. Test HTTP

curl -v http://lab-web/

curl -v makes an HTTP request to lab-web and prints the full exchange: request line, request/response headers, status code, and body. You’ll watch the connection open, the GET / go out, and Nginx answer 200 OK. This is how you verify an endpoint’s behavior without a browser guessing on your behalf. See HTTP and API troubleshooting for headers, redirects, and status codes in depth.

5. Inspect TLS

The stock lab-web serves plain HTTP on port 80, so use a benign public endpoint to practice reading a certificate:

echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null | openssl x509 -noout -subject -issuer -dates

openssl s_client performs a full TLS handshake and hands the certificate to openssl x509, which prints the subject, issuer, and — critically — the notBefore/notAfter validity dates. Expired or mismatched certs cause a classic, high-visibility outage; TLS certificate troubleshooting shows how to read the whole chain.

🧪 Try It — For a fully self-contained TLS drill, add a TLS-terminating container to lab-net (for example a second Nginx configured with a self-signed cert) and point openssl s_client at that. You’ll see the self-signed cert fail verification, then learn to read exactly why — the same diagnostic you’ll use on a real expired cert someday.

6. Capture packets

tcpdump -i eth0 -n host lab-web -c 20

tcpdump captures the first 20 packets to or from lab-web on the container’s eth0 interface, with -n skipping name lookups so the output stays readable. Run this in one shell, then trigger traffic from another with curl http://lab-web/, and you’ll see the TCP handshake, the HTTP request, and the response on the wire. When a connection “just hangs,” the packets tell you whether the SYN left, whether anything answered, and where the silence begins. tcpdump for DevOps goes deeper on filters and reading captures.

🔐 Security Note — Packet capture shows you real payloads, which is exactly why it belongs in a lab. Capturing traffic on a network you don’t own can expose other people’s data and is unlawful in most places. On lab-net, the only traffic is yours.

7. Compare expected vs actual exposure

Now put discovery to work. Write down what you expect lab-web to expose — port 80, HTTP, Nginx — then measure it:

nmap -p- lab-web

nmap -p- scans all 65,535 TCP ports so nothing hides above the common range. Compare the result to your expectation. A stock lab-web should show only port 80. If you deliberately publish more (say, an accidental admin port), this scan surfaces the drift. Expected-versus-actual exposure is the core of infrastructure validation and DevSecOps: attack surface is just “ports and services you didn’t mean to leave open.”

🛠️ DevOps Perspective — Bake this comparison into a pipeline and it becomes a guardrail: a scheduled scan of your own environments that alerts when a new port appears. That’s the defensive, authorized use of these tools — continuously checking that reality matches your intended architecture. The validators and Docker Production Readiness Auditor apply the same “verify what you actually shipped” mindset to config.

8. Troubleshoot a deliberately misconfigured service

Break something on purpose, then diagnose it top to bottom. Launch a second target that binds to a non-standard port:

docker run -d --name lab-web-bad --network lab-net -e NGINX_PORT=8081 nginxinc/nginx-unprivileged:stable

Now pretend you’re on call: “the web app is unreachable.” Work the layers you learned:

getent hosts lab-web-bad          # DNS: does the name resolve? (yes)
curl -v http://lab-web-bad/       # HTTP on 80: connection refused
nmap -p 80,8081 lab-web-bad       # ports: 80 closed, 8081 open
curl -v http://lab-web-bad:8081/  # HTTP on 8081: 200 OK

The name resolved, so it’s not DNS. Port 80 refused the connection but 8081 answered — the service is healthy, it’s just listening on the wrong port. That’s a config bug, not an outage. Walking DNS → ports → HTTP in order is the difference between guessing and knowing.

🔎 Troubleshooting Tip — Always diagnose bottom-up through the stack: resolve the name, reach the port, then speak the protocol. Each layer either clears itself or points at the fault. Most “it’s down” incidents are really “it’s up, somewhere I didn’t expect” — and this ordered check finds that in under a minute.

Tearing the Lab Down

When you’re done, remove everything cleanly:

docker rm -f lab-web lab-web-bad kali-toolbox
docker network rm lab-net

Because the lab is disposable, you can rebuild it from these commands any time you want to practice — and you should. Muscle memory on a safe target is what makes you calm on a real incident.

Security Testing Is Infrastructure Mastery

Look back at what you actually did. You resolved names, enumerated ports, spoke HTTP by hand, read a TLS certificate, watched packets on the wire, measured attack surface, and debugged a broken service by layer. Not one of those is a “hacking trick.” Every one is a core DevOps skill — networking, DNS, HTTP, TLS, Linux, and troubleshooting — practiced with sharper tools and a more skeptical eye.

That’s the philosophy of this whole series: the fastest way to understand infrastructure is to learn to inspect and test it. Kali just packages the inspection tools together. Used against systems you own, on a lab you built, they make you a better engineer — one who understands what’s really happening on the network instead of trusting that it’s fine.

Keep the lab around. Add a database container and inspect its port. Put a reverse proxy in front and read the new TLS chain. Break something new each week and diagnose it. Every scenario you rehearse here is one you’ll handle faster in production. And when you’re ready to formalize discovery into a repeatable check, revisit nmap for DevOps and wire it into a pipeline.

What You Learned

  • How to build a safe, isolated lab — an Ubuntu VM running an --internal Docker network with a Kali toolbox and a target web server, fully contained from your real network and the internet.
  • The Lab Rules — only ever test infrastructure you own, that was built for the lab, or that you’re explicitly authorized in writing to test; never point these tools at production.
  • An end-to-end inspection workflow — discover the host, enumerate ports with nmap/ss, resolve DNS with dig, test HTTP with curl, read TLS with openssl s_client, and capture packets with tcpdump.
  • Expected-versus-actual validation — comparing intended exposure to a real scan is how you catch attack-surface drift, the defensive core of DevSecOps.
  • Layered troubleshooting — walking DNS → ports → HTTP in order turns a vague “it’s down” into a precise diagnosis, as proved by the deliberately misconfigured service.
  • The series philosophy — security testing is infrastructure, networking, Linux, and troubleshooting mastery in disguise; the skills that inspect a system are the same ones that keep it running.

Affiliate Disclosure: Some links on this page are affiliate links. If you purchase through one of these links, DevOps AI Toolkit may earn a commission at no additional cost to you. See our affiliate disclosure.

← Back to Kali Linux for DevOps Engineers

Related on DevOps AI Toolkit