# Mycelium Cloud - Nginx NodePort Secure Website Hosting A complete, production-ready example for deploying a secure, globally accessible website on Mycelium Cloud using Kubernetes NodePort services with enhanced network isolation. This demonstrates **security-first IPv6 web hosting** with standard Kubernetes patterns. ## πŸ“ What This Contains This directory contains everything you need to deploy a secure website with global IPv6 accessibility: - **nginx-nodeport.md** - This comprehensive guide - **nginx-nodeport-deployment.yaml** - Secure deployment configuration - **nginx-nodeport-service.yaml** - NodePort service configuration - **nginx-nodeport-configmaps.yaml** - Website content and nginx configuration - **test-nodeport-ipv6.sh** - IPv6 testing and verification script - **update-content.sh** - Dynamic content update with IPv6 discovery - **compare-approaches.md** - Security and architecture comparison ## πŸš€ Quick Start (3 minutes) ```bash # 1. Deploy the ConfigMaps (content and nginx config) kubectl apply -f nginx-nodeport-configmaps.yaml # 2. Deploy the nginx application kubectl apply -f nginx-nodeport-deployment.yaml # 3. Create the NodePort service kubectl apply -f nginx-nodeport-service.yaml # 4. Wait for deployment to be ready kubectl wait --for=condition=ready pod -l app=nginx-nodeport --timeout=60s # 5. Get IPv6 address of the ACTUAL node where your pod is running POD_NODE=$(kubectl get pods -l app=nginx-nodeport -o jsonpath='{.items[0].spec.nodeName}') NODE_IPV6=$(kubectl get node $POD_NODE -o jsonpath='{range .status.addresses[?(@.type=="InternalIP")]}{.address}{"\n"}{end}' | grep -E '^[0-9a-f]+:[0-9a-f]+:[0-9a-f]+:[0-9a-f]+:[0-9a-f]+:[0-9a-f]+:[0-9a-f]+:[0-9a-f]+$' | head -1) echo "Your website is accessible at: http://[$NODE_IPV6]:30091" echo "NOTE: Pod is running on node: $POD_NODE" # 6. Test the website curl -6 "http://[$NODE_IPV6]:30091/" ``` **Alternative: Use the automated script for IPv6 discovery:** ```bash # Automatically discover IPv6 addresses and update content ./update-content.sh ``` **⚠️ Important: Worker Node vs Master Node Access** Unlike hostNetwork (which can be accessed from any node), NodePort services are **limited to the nodes where your pods are actually running**. Always check: ```bash # Check which node your pod is running on kubectl get pods -l app=nginx-nodeport -o wide # Get the IPv6 of the correct WORKER node (not master) NODE_IPV6=$(kubectl get nodes -l kubernetes.io/role!=master -o jsonpath='{range .items[0].status.addresses[?(@.type=="InternalIP")]}{.address}{"\n"}{end}' | grep -E '^[0-9a-f]+:[0-9a-f]+:[0-9a-f]+:[0-9a-f]+:[0-9a-f]+:[0-9a-f]+:[0-9a-f]+:[0-9a-f]+$' | head -1) ``` **Expected Result:** You'll see a professional website with NodePort security branding and IPv6 address detection. ## πŸ“‹ What You'll Learn - βœ… **Security-First IPv6 Web Hosting** - Enhanced network isolation - βœ… **Standard Kubernetes Service Patterns** - Industry best practices - βœ… **NodePort with External Traffic Policy** - Preserves IPv6 source IP - βœ… **ConfigMap-based Content Management** - Dynamic updates - βœ… **Production nginx Configuration** - Dual-stack (IPv4/IPv6) support - βœ… **Resource Management** - CPU/memory limits and health checks - βœ… **Security Comparison** - Understanding hostNetwork vs standard networking ## πŸ—οΈ Architecture This example uses **separate configuration files** for better organization and security: ### Component Overview ``` β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ Mycelium β”‚ β”‚ NodePort β”‚ β”‚ nginx Pod β”‚ β”‚ IPv6 Network │───▢│ Service │───▢│ (Isolated) β”‚ β”‚ :30090 β”‚ β”‚ :8080 β”‚ β”‚ :8080 β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β–Ό β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ ConfigMaps β”‚ β”‚ β€’ HTML Content β”‚ β”‚ β€’ nginx Config β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` ### Network Flow `IPv6 Client β†’ NodePort:30091 β†’ Service:8080 β†’ Pod:8080 β†’ nginx β†’ HTML Content` ### 🚨 Critical: Worker Node vs Master Node Access **Unlike hostNetwork (accessible from any node), NodePort services are ONLY accessible from the specific worker node where your pod is running.** - **hostNetwork**: Pod has direct host access β†’ accessible from ANY node's IPv6 - **NodePort**: Pod isolated network β†’ accessible ONLY from pod's host node **Always check pod location first:** ```bash # Check where your pod is running kubectl get pods -l app=nginx-nodeport -o wide # Look for the NODE column - this is where you can access your service ``` ### Key Security Improvements - **Pod Isolation**: No `hostNetwork` access, pods run in isolated network namespace - **Standard Service Patterns**: Uses typical Kubernetes service discovery - **External Traffic Policy**: `Local` preserves IPv6 source IP for logging - **Resource Limits**: Prevents resource exhaustion attacks - **Health Checks**: Liveness and readiness probes for reliability ## πŸ“„ Configuration Files ### 1. nginx-nodeport-deployment.yaml **Secure pod deployment without hostNetwork:** ```yaml spec: hostNetwork: false # Key security improvement containers: - name: nginx image: nginx:alpine ports: - containerPort: 8080 # No hostPort needed resources: requests: memory: "64Mi" cpu: "100m" limits: memory: "128Mi" cpu: "200m" livenessProbe: httpGet: path: /health port: 8080 readinessProbe: httpGet: path: /health port: 8080 ``` **What it does:** - Creates 1 pod with nginx and custom website content - Uses **standard pod networking** (no direct host access) - Includes **resource limits** and **health checks** - Uses ConfigMaps for **dynamic content management** - **Dual-stack nginx** (IPv4 + IPv6) configuration ### 2. nginx-nodeport-service.yaml **NodePort service with IPv6 source IP preservation:** ```yaml spec: type: NodePort externalTrafficPolicy: Local # Preserves IPv6 source IP ports: - port: 8080 targetPort: 8080 nodePort: 30091 # External port (avoiding conflict with nginx-mycelium) protocol: TCP ``` **What it does:** - Exposes nginx on **NodePort 30091** (external, avoiding conflicts) - **Preserves IPv6 source IP** for logging and security - Uses **standard Kubernetes service** patterns - Provides **load balancing** across pod replicas (when scaled) ### 3. nginx-nodeport-configmaps.yaml **Content and nginx configuration:** **HTML Content:** Professional website with NodePort security branding **nginx Configuration:** Dual-stack (IPv4/IPv6) with health endpoint ```nginx server { listen 8080; listen [::]:8080 ipv6only=on; # IPv6 support server_name _; location / { root /usr/share/nginx/html; index index.html; } location /health { access_log off; return 200 "healthy\n"; } } ``` ## πŸ” Verification and Testing ### Check pod status ```bash kubectl get pods -l app=nginx-nodeport kubectl describe pod -l app=nginx-nodeport ``` ### Check service configuration ```bash kubectl get svc nginx-nodeport-service -o yaml kubectl get endpoints nginx-nodeport-service ``` ### Test nginx configuration ```bash POD_NAME=$(kubectl get pods -l app=nginx-nodeport -o name | head -1) kubectl exec $POD_NAME -- nginx -t kubectl exec $POD_NAME -- nginx -s reload ``` ### Test health endpoint ```bash POD_NAME=$(kubectl get pods -l app=nginx-nodeport -o name | head -1) kubectl exec $POD_NAME -- curl -s http://localhost:8080/health ``` ### Test website content ```bash # Get node IPv6 address NODE_IPV6=$(kubectl get nodes -o jsonpath='{.items[0].status.addresses[?(@.type=="InternalIP")].address}') # Test from outside the cluster curl -6 "http://[$NODE_IPV6]:30091/" curl -6 "http://[$NODE_IPV6]:30091/health" ``` ### Verify ConfigMaps are mounted ```bash POD_NAME=$(kubectl get pods -l app=nginx-nodeport -o name | head -1) kubectl exec $POD_NAME -- ls -la /usr/share/nginx/html/ kubectl exec $POD_NAME -- cat /usr/share/nginx/html/index.html | head -10 ``` ## πŸ”„ Updating Content ### Update website content ```bash # Create new HTML file cat > new-index.html << 'EOF' Updated Site

Content Updated!

New content deployed at $(date)

EOF # Update ConfigMap kubectl create configmap nginx-nodeport-content \ --from-file=index.html=new-index.html \ --dry-run=client -o yaml | kubectl apply -f - # Reload nginx to pick up changes POD_NAME=$(kubectl get pods -l app=nginx-nodeport -o name | head -1) kubectl exec $POD_NAME -- nginx -s reload echo "βœ… Content updated! Access at: http://[$NODE_IPV6]:30091" ``` ### Update nginx configuration ```bash # Create custom nginx config cat > custom-nginx.conf << 'EOF' server { listen 8080; listen [::]:8080 ipv6only=on; server_name my-site.com; # Custom logging access_log /var/log/nginx/access.log; error_log /var/log/nginx/error.log; location / { root /usr/share/nginx/html; index index.html; try_files $uri $uri/ =404; } location /health { access_log off; return 200 "healthy\n"; } } EOF # Update ConfigMap kubectl create configmap nginx-nodeport-nginx-config \ --from-file=default.conf=custom-nginx.conf \ --dry-run=client -o yaml | kubectl apply -f - # Reload nginx POD_NAME=$(kubectl get pods -l app=nginx-nodeport -o name | head -1) kubectl exec $POD_NAME -- nginx -s reload ``` ## πŸ” Troubleshooting ### Pod won't start ```bash # Check pod status and events kubectl describe pod -l app=nginx-nodeport # Check pod logs kubectl logs -f deployment/nginx-nodeport # Check resource availability kubectl top nodes kubectl describe nodes ``` ### Service not accessible ```bash # Verify service exists and has endpoints kubectl get svc nginx-nodeport-service kubectl get endpoints nginx-nodeport-service # Check if pod is ready kubectl get pods -l app=nginx-nodeport -o wide # Verify NodePort is open netstat -tulpn | grep 30091 ``` ### IPv6 connectivity issues ```bash # Test IPv6 on the node ping6 -c 3 $NODE_IPV6 # Check nginx is listening on IPv6 POD_NAME=$(kubectl get pods -l app=nginx-nodeport -o name | head -1) kubectl exec $POD_NAME -- netstat -tuln | grep 8080 # Verify nginx configuration kubectl exec $POD_NAME -- cat /etc/nginx/conf.d/default.conf ``` ### Performance issues ```bash # Check resource usage kubectl top pods -l app=nginx-nodeport # Check nginx status and connections POD_NAME=$(kubectl get pods -l app=nginx-nodeport -o name | head -1) kubectl exec $POD_NAME -- ps aux | grep nginx kubectl exec $POD_NAME -- netstat -an | grep :8080 | wc -l ``` ## πŸ—‘οΈ Cleanup ```bash # Remove all resources kubectl delete -f nginx-nodeport-deployment.yaml -f nginx-nodeport-service.yaml # Remove ConfigMaps kubectl delete configmap nginx-nodeport-content nginx-nodeport-nginx-config # Verify cleanup kubectl get all -l app=nginx-nodeport # Should return nothing ``` ## πŸ“Š Key Differences from hostNetwork Approach | Feature | hostNetwork (nginx-mycelium) | NodePort (nginx-nodeport) | |---------|------------------------------|---------------------------| | **Security** | ⚠️ Direct host access | βœ… Isolated pod network | | **Network Isolation** | ❌ Uses host interfaces | βœ… Pod namespace isolation | | **Port Conflicts** | ❌ Limited by host ports | βœ… No port conflicts | | **Debugging** | πŸ”„ Host-level tools | βœ… Standard K8s patterns | | **Monitoring** | πŸ”„ Host monitoring | βœ… Pod-level monitoring | | **Scalability** | ❌ Single instance | βœ… Multiple replicas | | **Production Ready** | ⚠️ Demo/POC | βœ… Production patterns | ## πŸ“ˆ Scaling and High Availability ### Scale to multiple replicas ```bash # Scale deployment kubectl scale deployment nginx-nodeport --replicas=3 # Verify scaling kubectl get pods -l app=nginx-nodeport # Check load balancing NODE_IPV6=$(kubectl get nodes -o jsonpath='{.items[0].status.addresses[?(@.type=="InternalIP")].address}') for i in {1..5}; do curl -6 "http://[$NODE_IPV6]:30091/" | grep -o "nginx-nodeport-[a-z0-9]*-[a-z0-9]*" | head -1 done ``` ### Add resource limits for better performance ```yaml # Update deployment with enhanced resources resources: requests: memory: "128Mi" cpu: "200m" limits: memory: "256Mi" cpu: "500m" ``` ## 🎯 Best Practices 1. **Security First**: Always prefer standard pod networking over hostNetwork 2. **Resource Management**: Set appropriate requests and limits 3. **Health Checks**: Use liveness and readiness probes 4. **Monitoring**: Implement proper logging and metrics collection 5. **Updates**: Use rolling updates for zero-downtime deployments 6. **Configuration**: Store configuration in ConfigMaps for flexibility ## πŸ“š Learning Outcomes After completing this example, you understand: - **NodePort Services** - Kubernetes service exposure patterns - **Network Security** - Pod isolation vs hostNetwork trade-offs - **Production Patterns** - Resource management and health checks - **IPv6 Networking** - Dual-stack nginx configuration - **ConfigMap Management** - Dynamic content and configuration updates - **Service Discovery** - Kubernetes service networking - **Load Balancing** - Service-level load distribution ## πŸš€ Next Steps - **Multi-Replica Deployment**: Scale to 3+ replicas for high availability - **LoadBalancer Service**: Move to cloud LoadBalancer for production - **Ingress Controller**: Implement advanced routing and SSL termination - **Monitoring**: Add Prometheus metrics and Grafana dashboards - **SSL/TLS**: Implement HTTPS with Let's Encrypt certificates --- **Success Criteria**: You'll know everything is working when: - βœ… `kubectl get pods` shows nginx-nodeport pod in "Running" status - βœ… `kubectl get svc` shows nginx-nodeport-service with NodePort 30091 - βœ… `curl -6 "http://[$NODE_IPV6]:30091"` returns your secure website - βœ… Website displays "NODEPORT SECURE" and "ENHANCED SECURITY" badges - βœ… `kubectl logs deployment/nginx-nodeport` shows nginx access logs **Access URL**: `http://[NODE-IPV6]:30091` (replace NODE-IPV6 with your node's IPv6 address)