diff --git a/api/caddy_manager.py b/api/caddy_manager.py index 4c8a81d..83b9f88 100644 --- a/api/caddy_manager.py +++ b/api/caddy_manager.py @@ -310,7 +310,15 @@ class CaddyManager(BaseServiceManager): service_routes: str, core_routes: str, cert_path: str = _CADDY_INTERNAL_CERT, key_path: str = _CADDY_INTERNAL_KEY) -> str: - """LAN mode: HTTP only + internal-CA TLS, no ACME.""" + """LAN mode: internal-CA TLS on 443, plain HTTP on 80, no ACME. + + The same routes are served on both an HTTPS site (the internal-CA cert) + and an HTTP site. They must be SEPARATE site blocks: a `tls` directive on + an `http://` (port 80) address is rejected by Caddy ("server listening on + [:80] is HTTP, but attempts to configure TLS connection policies"). Both + are needed because the WireGuard server DNATs peer traffic to Caddy on + both 80 and 443. + """ body = [] if service_routes: body.append(self._indent_routes(service_routes)) @@ -325,10 +333,14 @@ class CaddyManager(BaseServiceManager): " auto_https off\n" "}\n" "\n" - f"http://{cell_name}.cell, http://172.20.0.2:80 {{\n" + f"https://{cell_name}.cell {{\n" f" tls {cert_path} {key_path}\n" f"{inner}\n" "}\n" + "\n" + f"http://{cell_name}.cell, http://172.20.0.2:80 {{\n" + f"{inner}\n" + "}\n" ) def _caddyfile_pic_ngo(self, cell_name: str, diff --git a/tests/test_caddy_manager.py b/tests/test_caddy_manager.py index 4e76739..e2eb39c 100644 --- a/tests/test_caddy_manager.py +++ b/tests/test_caddy_manager.py @@ -48,12 +48,16 @@ class TestGenerateCaddyfileLan(unittest.TestCase): self.assertNotIn('acme_email', out) self.assertNotIn('dns pic_ngo', out) self.assertNotIn('dns cloudflare', out) - # Internal-CA TLS pair + # Internal-CA TLS pair, on an HTTPS (443) site — never on an http:// one. self.assertIn('tls /etc/caddy/internal/cert.pem ' '/etc/caddy/internal/key.pem', out) - # Cell hostname plus virtual IP listener - self.assertIn('http://mycell.cell', out) - self.assertIn('http://172.20.0.2:80', out) + self.assertIn('https://mycell.cell {', out) + # Cell hostname plus virtual IP listener on plain HTTP (80) + self.assertIn('http://mycell.cell, http://172.20.0.2:80 {', out) + # The HTTP (:80) block must NOT carry a tls directive — Caddy rejects + # "server listening on [:80] is HTTP, but attempts to configure TLS". + http_block = out.split('http://mycell.cell, http://172.20.0.2:80 {', 1)[1] + self.assertNotIn('tls ', http_block) class TestGenerateCaddyfilePicNgo(unittest.TestCase):