Debugging K8s Ingress Challenges with OpenVSCode Server: 302, 404, 503, and WebSocket Issues
Phase 1: Path Mismatch Causes 404
Initial Ingress configuration routes traffic from /vscode to the backend service:
spec:
rules:
- http:
paths:
- backend:
service:
name: vscode-01
port:
number: 8888
path: /vscode
pathType: Prefix
Accessing /vscode returns a 404. The backend receives a request for /vscode, but expects /—the application has no configurable base path.
Fix: Rewrite the path to root using:
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
Phase 2: 302 Redirect Triggers 503
After path rewriting, the app responds with a 302 redirect to /. The browser follows it, but the Ingress now sees a request for /—a path not defined in any rule—resulting in a 503 Service Unavailable.
Fix: Intercept and rewrite the Location header to preserve the original path prefix:
annotations:
nginx.ingress.kubernetes.io/configuration-snippet: |
more_set_headers "Location: $scheme://$http_host/vscode/";
Phase 3: Static Assets Fail with 503
After resolving the redirect loop, front end assets like /stable-487e0b6eb726a84faf6b1a95c68a092fba078fd1/static/... return 503. Why? The global rewrite-target: / strips all path segments, so these requests never reach the backend with their original paths.
Fix: Define a separate Ingress rule for static assets using ImplementationSpecific path matching:
spec:
rules:
- http:
paths:
- path: /stable-487e0b6eb726a84faf6b1a95c68a092fba078fd1/static/(.*)
pathType: ImplementationSpecific
backend:
service:
name: vscode-01
port:
number: 8888
Phase 4: Cookie Scope Causes 403
Static assets now load, but subsequent requests to /vscode/xxx return 403. Inspection via port-forward and tcpdump reveals missing cookies.
The app sets a cookie with path /, but after the redirect, the browser sends it only for paths under /vscode. Since static assets reside under a completely different path prefix, the cookie is not included.
Fix: Align the entire application’s exposed path to match the static asset prefix. Move the Ingress rule from /vscode to /stable-487e0b6eb726a84faf6b1a95c68a092fba078fd1:
spec:
rules:
- http:
paths:
- path: /stable-487e0b6eb726a84faf6b1a95c68a092fba078fd1/
pathType: ImplementationSpecific
backend:
service:
name: vscode-01
port:
number: 8888
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
nginx.ingress.kubernetes.io/use-regex: "true"
nginx.ingress.kubernetes.io/configuration-snippet: |
more_set_headers "Location: $scheme://$http_host/stable-487e0b6eb726a84faf6b1a95c68a092fba078fd1/";
Now all requests originate from the same base path, and cookies are corrrectly scoped.
Phase 5: WebSocket Connection Drops (1006)
After fixing cookies, the UI loads—but WebSocket connections fail with code 1006 (abnormal closure). Inspection shows the WS endpoint is requested at:
wss://example.com/stable-487e0b6eb726a84faf6b1a95c68a092fba078fd1
But our rule matches only /stable-.../ (with trailing slash). The client omits the trailing slash, so the path doesn’t match.
Fix: Update the path pattern to accept both cases:
spec:
rules:
- http:
paths:
- path: /stable-487e0b6eb726a84faf6b1a95c68a092fba078fd1(/?|$)
pathType: ImplementationSpecific
backend:
service:
name: vscode-01
port:
number: 8888
This pattern matches either a trailing slash or end-of-string, ensuring WebSocket upgrade requests are correctly routed and rewritten to / for the backend.
Final State
With all rule in place, the application is accessible at:
https://example.com/stable-487e0b6eb726a84faf6b1a95c68a092fba078fd1/?tkn=eomdZNpW
Redirects, static assets, cookies, and WebSockets all function as expected. The Ingress now correctly mediates between the application’s rigid path assumptions and external routing requirements.