A TLS-enabled chat service demonstrated in two environments:
- a Dockerized workflow (automated scripted demo + interactive clients), and
- a Mininet VM workflow (multi-host lab topology with CA-signed certs).
The project shows practical TLS, basic routing, health checks, graceful shutdown, and reproducible demos on Windows (PowerShell), Git Bash / WSL, and a Linux VM running Mininet.
SecureNexusNetwork/
├─ dockerized_version/
│ ├─ chat_server_secure.py # TLS server with clean idle shutdown
│ ├─ chat_client_secure.py # Interactive TLS client
│ ├─ scripted_client_secure.py # Scripted TLS client (demo automation)
│ ├─ certificate_generation_docker.py# CA + server certs (container-friendly)
│ ├─ Dockerfile
│ ├─ docker-compose.yml
│ ├─ entrypoint.sh # ROLE=server|client|client-scripted
│ ├─ tmux_interactive.sh # Split-pane interactive (tmux) helper
│ └─ scripts/
│ ├─ client1_messages.txt # Demo script for client1
│ └─ client2_messages.txt # Demo script for client2
│
├─ oracle_vm_mininet_version/
│ ├─ legacy_network.py # Mininet topology + auto-launch Xterms
│ ├─ certificate_generation.py # CA-signed server certificate (VM)
│ ├─ chat_server.py # Mininet server (group chat)
│ ├─ chat_client.py # Mininet client
│ ├─ server-key.pem / server.csr / server-cert.pem
│
├─ Network Diagram.png # High-level diagram (reference)
└─ changes_to_legacy_network.txt # What changed & why (Mininet)
- TLS for all clients using a project-local CA; the server presents a cert and clients verify with
cafile. - SAN/SNI alignment: the Docker cert is issued for
chat_server(plus loopback) so TLS hostname validation works. - Clean shutdown on idle: the server keeps track of connected clients and exits when all clients disconnect (opt-in).
- Health check-friendly: the server tolerates short probes (e.g., connect-and-close) without crashing; probes can be logged at DEBUG.
cert_gencontainer producesca.crt,server.crt,server.keymounted into all services via thecertsvolume.chat_serverstarts on0.0.0.0:12000, advertises readiness when listening, and (optionally) exits when idle.- Scripted clients (
client1_demo,client2_demo) replay messages fromscripts/*.txt, then saybyeand exit. r1watchdog tracks the server port; once the server stops listening,r1exits sodocker compose upends cleanly.
- Three routers and four hosts across two /24 LANs with two /30 point-to-point links; static routes ensure end-to-end reachability.
legacy_network.pybuilds the topology, assigns IPs/routes, and launches Xterm windows: one TLS server + three clients.certificate_generation.pyintegrates with the lab CA to produce a CA-signed server certificate and updates/etc/hosts.- Steps and grading criteria align with the Subnet Addressing + TLS brief (CST 311 Programming Assignment 4).
This mode runs: generate certs → start server → run two scripted TLS clients → everything exits with code 0.
cd .\dockerized_version
docker compose down -v --remove-orphans
docker compose up --buildcd dockerized_version
docker compose down -v --remove-orphans
docker compose up --buildExpected run:
cert_gencreates/certs/{ca.crt,ca.key,server.crt,server.key,server.csr}then exits.chat_serverbecomes healthy, clients connect, exchange scripted lines, saybye, and disconnect.- Server prints “No active clients remain; initiating shutdown.”, then exits.
r1detects the closed port and exits → compose run ends cleanly.
Tip: To end the whole stack precisely when the server exits:
docker compose up --build --abort-on-container-exit --exit-code-from chat_server
Run one server and two interactive clients (each in its own terminal). Type messages freely; type bye to disconnect.
Terminal 1 — server (detached):
cd .\dockerized_version
docker compose up --build -d chat_serverTerminal 2 — client #1 (interactive):
cd .\dockerized_version
docker compose run --rm -it client1Terminal 3 — client #2 (interactive):
cd .\dockerized_version
docker compose run --rm -it client2cd dockerized_version
docker compose up --build -d chat_server
docker compose run --rm -it client1
docker compose run --rm -it client2Shutdown:
docker compose down -vThe helper script opens a tmux session with panes for server logs + two interactive clients.
cd dockerized_version
chmod +x tmux_interactive.sh
./tmux_interactive.shRequirements: tmux available in your shell (WSL/Ubuntu: sudo apt-get install tmux). Close via Ctrl+b, : then kill-session, or exit clients and stop logs pane.
- Volume:
certs(shared CA + server materials). - Networks:
net_a,net_b(demo routing contexts), plusdefault.
cert_gen(Debian slim): runs OpenSSL to create a local CA and server cert, writes to/certs, exits.chat_server(Python 3.11 slim): TLS server listening on0.0.0.0:12000with healthcheck and optional idle shutdown.client1_demo/client2_demo: scripted secure clients replayingscripts/*.txt.client1/client2(interactive aliases): runchat_client_secure.py.r1(Alpine): simple watchdog that polls the server port; exits when the port closes so the entire compose run ends.
The server’s healthcheck performs a 1-second TLS handshake against 127.0.0.1:12000. When healthy, clients begin. (The minimal probe can generate harmless TLS EOF logs because it’s a bare test connection on a TLS port.)
-
Server container
ROLE=serverHOST=0.0.0.0PORT=12000SHUTDOWN_WHEN_IDLE=1(optional) → adds--shutdown-when-idleso the server terminates after the last client disconnects.
-
Scripted clients
ROLE=client-scriptedSERVER_HOST=chat_serverPORT=12000SCRIPT=scripts/client{N}_messages.txt
- TLS server using
ssl.SSLContext(PROTOCOL_TLS_SERVER) - Loads
/certs/server.crtand/certs/server.key(signed by/certs/ca.crt). - Line protocol: line-delimited UTF-8.
- Echoes with a
server:prefix and does a clean shutdown when receivingbye. - When started with
--shutdown-when-idle, the server tracks active clients and exits once none remain.
Server CLI
python chat_server_secure.py
--host 0.0.0.0
--port 12000
--certfile /certs/server.crt
--keyfile /certs/server.key
--cafile /certs/ca.crt
[--shutdown-when-idle]
- Interactive TLS client using
cafileto validate the server. - Prompts for a username, then sends/receives lines; type
byeto disconnect.
Client CLI
python chat_client_secure.py
--server chat_server
--port 12000
--cafile /certs/ca.crt
- Connects via TLS and replays lines from a script file (with optional delays and retry logic).
- Used by the automated demo to guarantee deterministic logs.
-
Generates a local CA and a server cert signed by that CA.
-
Honors env vars
CERT_OUT(default/certs),SERVER_CN(defaultserver), andDAYS(default 365). -
The compose service writes:
ca.crt,ca.keyserver.key,server.csr,server.crt
- Integrates with the lab’s CA (e.g.,
/etc/ssl/demoCA) to issue a lab-trusted server cert. - Updates
/etc/hostswith the chosen hostname and IP, generates key/CSR, and issues a CA-signed certificate.
- A Mininet VM (Ubuntu-based), Python 3.x, OpenSSL, and Xterm (for GUI terminals).
- For Xterm windows, ensure X forwarding / desktop is available in the VM.
Copy the entire oracle_vm_mininet_version/ directory into the VM (e.g., ~/secure-nexus/).
~/secure-nexus/oracle_vm_mininet_version/
legacy_network.py
certificate_generation.py
chat_server.py
chat_client.py
(server-key.pem/server.csr/server-cert.pem if you’ve pre-generated)
cd ~/secure-nexus/oracle_vm_mininet_version
sudo -E python3 certificate_generation.pyThis writes/refreshes server-key.pem, server.csr, server-cert.pem, and updates /etc/hosts for the server hostname.
cd ~/secure-nexus/oracle_vm_mininet_version
sudo -E python3 legacy_network.py-
The topology (3 routers, 2 LANs, 2 P2P links) is built.
-
Static routes are configured on routers so all hosts reach one another (
pingallsucceeds). -
Xterm windows auto-start:
- One for the server (on the designated host)
- Three for clients (on three other hosts)
-
Chat among the three clients; type
byeto disconnect from any client.
If you prefer the pure Mininet CLI instead of Xterms, you can run:
mininet> hX python3 /path/to/chat_server.py mininet> hY python3 /path/to/chat_client.py mininet> hZ python3 /path/to/chat_client.pywhere
hXis the server host andhY/hZare client hosts.
sudo mn -c- Compose keeps tailing logs even though the server exited: ensure the
r1watchdog is present (it exits when the server port closes). Alternatively, run with--abort-on-container-exit --exit-code-from chat_server. - TLS EOF or handshake errors at startup: health probes or port polling may connect and immediately close on a TLS port; these are expected and harmless.
- Clients connect before server is healthy: rely on
depends_on: condition: service_healthyfor demo clients, or start the server first in interactive sessions. - Windows line endings: if a shell script misbehaves, convert to LF (e.g.,
dos2unix tmux_interactive.sh). - Xterms don’t appear in Mininet: verify X support in the VM (desktop session or X forwarding). Use the Mininet CLI fallback if needed.
- Graceful idle shutdown: the server tracks live client handlers; after both scripted clients say
bye, the server initiates shutdown and exits with code 0 so CI-friendly runs complete cleanly. - Port watchdog (
r1): a tiny Alpine container thatnc -zpolls the server port; once it closes,r1prints a notice and exits → the wholedocker compose upreturns. - Health check over TLS: a local Python snippet inside the compose healthcheck verifies a TLS handshake to
127.0.0.1:12000. This avoids race conditions without needing sleeps. - Two environments, one story: the Docker demo mirrors the Mininet lab’s goals—TLS, routing exposure, and repeatable workflows. The Mininet brief’s guidance on IP addressing, static routes, and deliverables informed the VM instructions.