commit ee5828a54e365ce7603734a68935a7c56886515b Author: D Stephenson Date: Tue May 5 20:07:37 2026 +0000 Initial commit diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..d6d4eae --- /dev/null +++ b/Dockerfile @@ -0,0 +1,30 @@ +# ============================================================ +# Dockerfile — WWTP Extreme Switch TLS 1.0 Proxy +# +# Uses Debian Bullseye (OpenSSL 1.1.1) instead of Alpine 3.18 +# (OpenSSL 3.x) because OpenSSL 1.1.1 supports TLS 1.0 natively +# without requiring legacy provider hacks. +# ============================================================ + +FROM debian:bullseye-slim + +# Install stunnel — Debian Bullseye ships OpenSSL 1.1.1 which +# supports TLS 1.0 out of the box. No legacy provider needed. +RUN apt-get update && \ + apt-get install -y --no-install-recommends stunnel4 && \ + rm -rf /var/lib/apt/lists/* + +# Lower the OpenSSL minimum protocol to TLS 1.0 +# Bullseye's default is TLSv1.2 — we override it here +RUN sed -i 's/MinProtocol = TLSv1.2/MinProtocol = TLSv1/' /etc/ssl/openssl.cnf && \ + sed -i 's/CipherString = DEFAULT@SECLEVEL=2/CipherString = DEFAULT@SECLEVEL=1/' /etc/ssl/openssl.cnf + +# Copy stunnel config into image +COPY stunnel.conf /etc/stunnel/stunnel.conf + +# Expose all 20 switch proxy ports (4500-4519) +EXPOSE 4500 4501 4502 4503 4504 4505 4506 4507 4508 4509 \ + 4510 4511 4512 4513 4514 4515 4516 4517 4518 4519 + +# stunnel4 on Debian uses a wrapper script — call it directly +CMD ["stunnel4", "/etc/stunnel/stunnel.conf"] diff --git a/README.md b/README.md new file mode 100644 index 0000000..270d715 --- /dev/null +++ b/README.md @@ -0,0 +1,112 @@ +# WWTP Extreme Switch TLS Proxy +## stunnel Docker Container — Deployment Guide + +### What This Does +Allows modern browsers (TLS 1.2/1.3) to reach Extreme switches +running firmware 1.01.02.0005 (TLS 1.0 only) via a stunnel proxy. + +``` +Browser (TLS 1.2/1.3) + ↓ +stunnel container on 192.168.16.130 + ↓ +Switch (TLS 1.0) on 10.214.0.x +``` + +--- + +### Step 1 — Prepare the switches via SSH +Each switch needs HTTPS enabled before the proxy will work. +SSH into each switch and run: + +``` +enable +configure +http secure-server +save configuration +``` + +> wwtp-gate-sw01 (10.214.0.112) is already done and confirmed working. + +--- + +### Step 2 — Build the Docker image on the Portainer host + +Copy the three files (Dockerfile, stunnel.conf, docker-compose.yml) +to the same directory on your Portainer host, then build: + +```bash +cd /path/to/stunnel-wwtp +docker build -t stunnel-wwtp:latest . +``` + +--- + +### Step 3 — Deploy via Portainer + +1. Open Portainer → **Stacks** → **Add Stack** +2. Name it: `stunnel-wwtp` +3. Paste the contents of `docker-compose.yml` into the editor +4. Click **Deploy the stack** + +--- + +### Step 4 — Access a switch in your browser + +Use: `https://192.168.16.130:` + +| Port | Switch | Location | +|-------|-----------------|-----------------| +| 4500 | wwtp-offc-sw01 | Plant Office | +| 4501 | wwtp-srvr-sw01 | Server Room | +| 4502 | wwtp-ecb1-sw01 | Elec Ctrl Bldg 1 | +| 4503 | wwtp-head-sw01 | Head Works | +| 4504 | wwtp-ecb2-sw01 | Elec Ctrl Bldg 2 | +| 4505 | wwtp-ags1-sw01 | AGS Tank 1 | +| 4506 | wwtp-ags2-sw01 | AGS Tank 2 | +| 4507 | wwtp-ags3-sw01 | AGS Tank 3 | +| 4508 | wwtp-coag-sw01 | Coag & Buffer | +| 4509 | wwtp-reuse-sw01 | Reuse | +| 4510 | wwtp-ecb3-sw01 | Elec Ctrl Bldg 3 | +| 4511 | wwtp-yard-sw01 | Yard Drain | +| 4512 | wwtp-gate-sw01 | Gate ✅ TESTED | +| 4513 | wwtp-ecb1-sw02 | Elec Ctrl Bldg 1 | +| 4514 | wwtp-ecb2-sw02 | Elec Ctrl Bldg 2 | +| 4515 | wwtp-uv-sw01 | UV | +| 4516 | wwtp-fitr-sw01 | Filters | +| 4517 | wwtp-crn-sw01 | Crane Room | +| 4518 | wwtp-bst-sw01 | Beast | +| 4519 | wwtp-ecb3-sw02 | Elec Ctrl Bldg 3 | + +> Your browser will warn about an invalid/self-signed certificate. +> Click through the warning — this is expected with old switch firmware. + +--- + +### Troubleshooting + +**Browser shows "connection refused"** +→ The switch doesn't have `http secure-server` enabled yet. +→ SSH to the switch and run the commands in Step 1. + +**Browser shows "connection timed out"** +→ The switch is offline or unreachable. + +**stunnel container won't start** +→ Check Portainer logs for the container. +→ Verify the image was built: `docker images | grep stunnel-wwtp` + +**Test a specific switch from the host CLI:** +```bash +curl -k https://192.168.16.130:4512 # should return HTML from gate switch +``` + +--- + +### Notes +- `network_mode: host` is required so the container inherits the + host's routing table and can reach the 10.214.0.x subnet. +- `verify = 0` in stunnel.conf disables certificate validation — + necessary because switch certs are self-signed and likely expired. +- `sslVersion = TLSv1` forces TLS 1.0 on the switch-facing side only. + Your browser still connects to stunnel using modern TLS. diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..c3c18c0 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,46 @@ +# ============================================================ +# docker-compose.yml — WWTP Extreme Switch TLS 1.0 Proxy +# Deploy via Portainer → Stacks → Add Stack → paste this file +# ============================================================ +# +# Port reference (4400 + last octet of switch IP): +# :4500 → 10.214.0.100 wwtp-offc-sw01 Plant Office +# :4501 → 10.214.0.101 wwtp-srvr-sw01 Server Room +# :4502 → 10.214.0.102 wwtp-ecb1-sw01 Elec Ctrl Bldg 1 +# :4503 → 10.214.0.103 wwtp-head-sw01 Head Works +# :4504 → 10.214.0.104 wwtp-ecb2-sw01 Elec Ctrl Bldg 2 +# :4505 → 10.214.0.105 wwtp-ags1-sw01 AGS Tank 1 +# :4506 → 10.214.0.106 wwtp-ags2-sw01 AGS Tank 2 +# :4507 → 10.214.0.107 wwtp-ags3-sw01 AGS Tank 3 +# :4508 → 10.214.0.108 wwtp-coag-sw01 Coag & Buffer +# :4509 → 10.214.0.109 wwtp-reuse-sw01 Reuse +# :4510 → 10.214.0.110 wwtp-ecb3-sw01 Elec Ctrl Bldg 3 +# :4511 → 10.214.0.111 wwtp-yard-sw01 Yard Drain +# :4512 → 10.214.0.112 wwtp-gate-sw01 Gate ← TESTED/WORKING +# :4513 → 10.214.0.113 wwtp-ecb1-sw02 Elec Ctrl Bldg 1 +# :4514 → 10.214.0.114 wwtp-ecb2-sw02 Elec Ctrl Bldg 2 +# :4515 → 10.214.0.115 wwtp-uv-sw01 UV +# :4516 → 10.214.0.116 wwtp-fitr-sw01 Filters +# :4517 → 10.214.0.117 wwtp-crn-sw01 Crane Room +# :4518 → 10.214.0.118 wwtp-bst-sw01 Beast +# :4519 → 10.214.0.119 wwtp-ecb3-sw02 Elec Ctrl Bldg 3 +# +# Browser usage: https://192.168.16.130: +# Accept the self-signed cert warning in your browser +# ============================================================ + +version: "3.8" + +services: + stunnel-wwtp: + image: stunnel-wwtp:latest + container_name: stunnel-wwtp + restart: always + network_mode: host + # network_mode: host is used so stunnel can reach the + # 10.214.0.x switch subnet via the host's routing table. + # Without this, the container would be NAT'd and unable + # to route to the switches. + ports: [] + # Ports are bound directly via host networking above — + # no explicit port mapping needed here. diff --git a/stunnel.conf b/stunnel.conf new file mode 100644 index 0000000..ced2039 --- /dev/null +++ b/stunnel.conf @@ -0,0 +1,108 @@ +foreground = yes +pid = /tmp/stunnel.pid +socket = l:TCP_NODELAY=1 +socket = r:TCP_NODELAY=1 +verify = 0 +sslVersionMin = TLSv1 +sslVersionMax = TLSv1 +ciphers = DEFAULT:@SECLEVEL=0 + +[wwtp-offc-sw01] +client = yes +accept = 0.0.0.0:4500 +connect = 10.214.0.100:443 + +[wwtp-srvr-sw01] +client = yes +accept = 0.0.0.0:4501 +connect = 10.214.0.101:443 + +[wwtp-ecb1-sw01] +client = yes +accept = 0.0.0.0:4502 +connect = 10.214.0.102:443 + +[wwtp-head-sw01] +client = yes +accept = 0.0.0.0:4503 +connect = 10.214.0.103:443 + +[wwtp-ecb2-sw01] +client = yes +accept = 0.0.0.0:4504 +connect = 10.214.0.104:443 + +[wwtp-ags1-sw01] +client = yes +accept = 0.0.0.0:4505 +connect = 10.214.0.105:443 + +[wwtp-ags2-sw01] +client = yes +accept = 0.0.0.0:4506 +connect = 10.214.0.106:443 + +[wwtp-ags3-sw01] +client = yes +accept = 0.0.0.0:4507 +connect = 10.214.0.107:443 + +[wwtp-coag-sw01] +client = yes +accept = 0.0.0.0:4508 +connect = 10.214.0.108:443 + +[wwtp-reuse-sw01] +client = yes +accept = 0.0.0.0:4509 +connect = 10.214.0.109:443 + +[wwtp-ecb3-sw01] +client = yes +accept = 0.0.0.0:4510 +connect = 10.214.0.110:443 + +[wwtp-yard-sw01] +client = yes +accept = 0.0.0.0:4511 +connect = 10.214.0.111:443 + +[wwtp-gate-sw01] +client = yes +accept = 0.0.0.0:4512 +connect = 10.214.0.112:443 + +[wwtp-ecb1-sw02] +client = yes +accept = 0.0.0.0:4513 +connect = 10.214.0.113:443 + +[wwtp-ecb2-sw02] +client = yes +accept = 0.0.0.0:4514 +connect = 10.214.0.114:443 + +[wwtp-uv-sw01] +client = yes +accept = 0.0.0.0:4515 +connect = 10.214.0.115:443 + +[wwtp-fitr-sw01] +client = yes +accept = 0.0.0.0:4516 +connect = 10.214.0.116:443 + +[wwtp-crn-sw01] +client = yes +accept = 0.0.0.0:4517 +connect = 10.214.0.117:443 + +[wwtp-bst-sw01] +client = yes +accept = 0.0.0.0:4518 +connect = 10.214.0.118:443 + +[wwtp-ecb3-sw02] +client = yes +accept = 0.0.0.0:4519 +connect = 10.214.0.119:443