# 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'
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)