Skip to content

Unified Hostname Migration Guide

This guide documents how to migrate a service from *.bogocat.com to *.bogocat.com using the unified hostname architecture.

Prerequisites: Read Unified Hostname Architecture first.

Overview

Migrating a service means changing from separate internal/external hostnames to a single *.bogocat.com hostname that works everywhere via DNS-based routing.

Before: - Internal: radarr.bogocat.com → K8s Ingress - External: radarr.bogocat.com → VPS → K8s Ingress (different provider needed)

After: - Everywhere: radarr.bogocat.com - Internal DNS (OPNsense) → K8s Ingress directly - External DNS (Cloudflare) → VPS → K8s Ingress

Migration Checklist

For each service, complete these steps in order:

Step Location Action
1 K8s Update Ingress manifest
2 K8s Apply manifest
3 Authentik Update provider external_host
4 VPS Add Caddy entry
5 OPNsense Add DNS override
6 Test Verify internal + external access

Step 1: Update K8s Ingress Manifest

Edit the service manifest (e.g., /root/tower-fleet/manifests/arr-stack/{service}.yaml).

Note: For arr-stack services, the actual applications run on VM 100 (10.89.97.50). The K8s manifests define the Ingress + forward auth layer that sits in front of them, not the apps themselves. The manifests contain: - Headless Service + Endpoints pointing to the VM IP - Authentik forward auth configuration - Hostname routing rules

Changes Required

1a. Update ConfigMap headers:

# Before
data:
  X-Forwarded-Host: "{service}.bogocat.com"
  X-Forwarded-Proto: "http"

# After
data:
  X-Forwarded-Host: "{service}.bogocat.com"
  X-Forwarded-Proto: "https"

1b. Update outpost Ingress host:

# Before
spec:
  rules:
    - host: {service}.bogocat.com

# After
spec:
  rules:
    - host: {service}.bogocat.com

1c. Update main Ingress annotations:

# Before
annotations:
  nginx.ingress.kubernetes.io/auth-signin: "http://{service}.bogocat.com/outpost.goauthentik.io/start?rd=$scheme://$http_host$request_uri"

# After - NOTE: hardcode https:// (not $scheme) to handle VPS→K8s HTTP connection
annotations:
  nginx.ingress.kubernetes.io/auth-signin: "https://{service}.bogocat.com/outpost.goauthentik.io/start?rd=https://$http_host$request_uri"

1d. Update main Ingress host:

# Before
spec:
  rules:
    - host: {service}.bogocat.com

# After
spec:
  rules:
    - host: {service}.bogocat.com

1e. Add TLS section to both Ingresses:

# Add to both outpost and main Ingress specs
spec:
  ingressClassName: nginx
  tls:
    - hosts:
        - {service}.bogocat.com
      secretName: wildcard-bogocat-tls
  rules:
    ...

Note: The wildcard-bogocat-tls secret must exist in the service's namespace. Copy from ingress-nginx if needed:

kubectl get secret wildcard-bogocat-tls -n ingress-nginx -o json | \
  jq 'del(.metadata.resourceVersion,.metadata.uid,.metadata.creationTimestamp,.metadata.namespace)' | \
  kubectl apply -n {namespace} -f -

Important: Don't forget to add TLS to all ingresses that use *.bogocat.com hostnames, including shared services like Authentik (auth.bogocat.com). Without TLS, internal access will show certificate warnings.

Example: Complete Diff

 # ConfigMap for auth request headers
 apiVersion: v1
 kind: ConfigMap
 metadata:
   name: sonarr-auth-headers
   namespace: arr-stack
 data:
-  X-Forwarded-Host: "sonarr.bogocat.com"
-  X-Forwarded-Proto: "http"
+  X-Forwarded-Host: "sonarr.bogocat.com"
+  X-Forwarded-Proto: "https"
 ---
 # Ingress for Authentik outpost paths
 spec:
   ingressClassName: nginx
+  tls:
+    - hosts:
+        - sonarr.bogocat.com
+      secretName: wildcard-bogocat-tls
   rules:
-    - host: sonarr.bogocat.com
+    - host: sonarr.bogocat.com
       http:
         paths:
           - path: /outpost.goauthentik.io/
 ---
 # Main app ingress
 metadata:
   annotations:
-    nginx.ingress.kubernetes.io/auth-signin: "http://sonarr.bogocat.com/outpost.goauthentik.io/start?rd=$scheme://$http_host$request_uri"
+    nginx.ingress.kubernetes.io/auth-signin: "https://sonarr.bogocat.com/outpost.goauthentik.io/start?rd=https://$http_host$request_uri"
 spec:
+  tls:
+    - hosts:
+        - sonarr.bogocat.com
+      secretName: wildcard-bogocat-tls
   rules:
-    - host: sonarr.bogocat.com
+    - host: sonarr.bogocat.com

Step 2: Apply K8s Manifest

kubectl apply -f /root/tower-fleet/manifests/arr-stack/{service}.yaml

Verify the ingress updated:

kubectl get ingress -n arr-stack {service}
# Should show HOST as {service}.bogocat.com

Step 3: Update Authentik Provider

  1. Go to https://auth.bogocat.com (or http://auth.bogocat.com)
  2. Navigate to Applications → Providers
  3. Find {service}-proxy provider
  4. Click Edit
  5. Update External host:
Field Old Value New Value
External host http://{service}.bogocat.com https://{service}.bogocat.com
  1. Click Update

Important: The embedded outpost should already have authentik_host set to https://auth.bogocat.com. If not, see Troubleshooting.


Step 4: Add VPS Caddy Entry

SSH to VPS and edit Caddyfile:

ssh root@5.161.45.147
nano /etc/caddy/Caddyfile

Add entry for the service:

{service}.bogocat.com {
    reverse_proxy 10.89.97.220:80 {
        header_up Host {service}.bogocat.com
        header_up X-Forwarded-Host {service}.bogocat.com
        header_up X-Forwarded-Proto https
    }
}

Validate and reload:

caddy validate --config /etc/caddy/Caddyfile
systemctl reload caddy

Step 5: Add OPNsense DNS Override

  1. Go to OPNsense web UI (https://10.89.97.1)
  2. Navigate to Services → Unbound DNS → Host Overrides
  3. Add new override:
Field Value
Host {service}
Domain bogocat.com
Type A
IP 10.89.97.220
  1. Click Save
  2. Click Apply Changes

Step 6: Test Access

Internal Test (from home network)

# Should resolve to K8s Ingress
nslookup {service}.bogocat.com
# Expected: 10.89.97.220

# Should redirect to Authentik, then to service
curl -sI https://{service}.bogocat.com | head -5

Open browser to https://{service}.bogocat.com: - Should redirect to Authentik login (auth.bogocat.com) - After login, should redirect back to service - Note: May show certificate warning (self-signed) - this is expected without cert-manager

External Test (from mobile network or VPN disabled)

# Should resolve to VPS
nslookup {service}.bogocat.com
# Expected: 5.161.45.147

# Test from external
curl -sI https://{service}.bogocat.com | head -5

Open browser (on mobile network or with VPN off): - Should redirect to Authentik login (auth.bogocat.com) - After login, should redirect back to service


Service Reference

arr-stack Services (VM 100 at 10.89.97.50)

Service Port Authentik Group
Sonarr 8989 arr-admins
Radarr 7878 arr-admins
Lidarr 8686 arr-admins
Prowlarr 9696 arr-admins
Bazarr 6767 arr-admins
SABnzbd 8080 arr-admins
Deluge 8112 arr-admins
Jellyseerr 5056 arr-users
Overseerr 5055 arr-users

Other Services

Service Backend Port Notes
Jellyfin LXC 113 (10.89.97.97) 8096 Native auth, no forward auth
Home Portal K8s - OAuth, not forward auth

Troubleshooting

Redirect Loop (ERR_TOO_MANY_REDIRECTS)

Symptom: Browser shows "redirected you too many times"

Causes:

  1. HTTP/HTTPS mismatch in auth-signin URL
  2. Check: Is auth-signin using $scheme which evaluates to http?
  3. Fix: Hardcode https:// in the auth-signin annotation

  4. X-Forwarded-Proto not set to https

  5. Check: ConfigMap has X-Forwarded-Proto: "https"?
  6. Fix: Update ConfigMap and re-apply

  7. Authentik provider external_host mismatch

  8. Check: Does provider external_host match the ingress hostname?
  9. Fix: Update provider to https://{service}.bogocat.com

Outpost Redirects to auth.bogocat.com

Symptom: After clicking login, URL shows auth.bogocat.com instead of auth.bogocat.com

Cause: Embedded outpost authentik_host is set to internal URL

Fix: Update embedded outpost configuration via Django shell:

kubectl exec -it -n authentik deploy/authentik-server -- ak shell
from authentik.outposts.models import Outpost
outpost = Outpost.objects.get(name="authentik Embedded Outpost")
config = outpost.config
config['authentik_host'] = 'https://auth.bogocat.com'
outpost.config = config
outpost.save()
print("Updated. Restart may be needed.")

Then restart Authentik:

kubectl rollout restart deployment -n authentik authentik-server

502 Bad Gateway

Symptom: Caddy returns 502

Checks: 1. VPS can reach K8s Ingress: ping 10.89.97.220 from VPS 2. WireGuard tunnel is up: wg show on VPS 3. Ingress exists: kubectl get ingress -n arr-stack {service} 4. Host header matches: Caddy header_up Host must match Ingress host

503 Service Unavailable

Symptom: K8s Ingress returns 503

Checks: 1. Endpoints exist: kubectl get endpoints -n arr-stack {service}-external 2. Backend reachable: curl http://10.89.97.50:{PORT} from Proxmox host 3. Service running on VM 100

Certificate Warning (Internal)

Symptom: Browser shows "Your connection is not private" when accessing internally

Cause: No TLS certificate configured for internal access (nginx-ingress serves default cert)

Workarounds: - Click "Advanced" → "Proceed to site" - Set up cert-manager with Let's Encrypt (future improvement) - Access via HTTP internally (less secure)


Cleanup (Optional)

After confirming the new hostname works, you can optionally remove the old *.bogocat.com ingress:

# Check old ingress still exists
kubectl get ingress -n arr-stack {service} -o yaml | grep "host:"

# If only the new hostname exists, you're done
# If old hostname exists as separate ingress, delete it:
kubectl delete ingress -n arr-stack {service}-internal  # if named separately

Recommendation: Keep *.bogocat.com ingresses for 1-2 weeks as fallback before removing.