Nginx Proxy Manager: Reverse Proxy Setup

Nginx Proxy Manager (NPM) provides a clean web interface for managing reverse proxies and SSL certificates. This article covers deployment, configuration, and integration with Kubernetes services.

Why NPM?

Requirements:

Alternatives Considered:

NPM Advantages:

Architecture

Internet


Home Router (Port Forwarding)


NPM LoadBalancer (192.168.1.202)

   ├─► blog.sortium.fr → homelab-blog.blog.svc.cluster.local:80
   ├─► npm.sortium.fr → localhost:81
   └─► Other services...

Deployment

Kubernetes Manifest

apiVersion: v1
kind: Namespace
metadata:
  name: npm
  labels:
    pod-security.kubernetes.io/enforce: privileged

---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: npm-data
  namespace: npm
spec:
  accessModes:
    - ReadWriteOnce
  storageClassName: local-path
  resources:
    requests:
      storage: 10Gi

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-proxy-manager
  namespace: npm
spec:
  replicas: 1
  template:
    spec:
      containers:
      - name: npm
        image: jc21/nginx-proxy-manager:latest
        ports:
        - containerPort: 80
        - containerPort: 81
        - containerPort: 443
        volumeMounts:
        - name: data
          mountPath: /data
        - name: letsencrypt
          mountPath: /etc/letsencrypt
        env:
        - name: DISABLE_IPV6
          value: "true"
      volumes:
      - name: data
        persistentVolumeClaim:
          claimName: npm-data
      - name: letsencrypt
        persistentVolumeClaim:
          claimName: npm-letsencrypt

---
apiVersion: v1
kind: Service
metadata:
  name: nginx-proxy-manager
  namespace: npm
spec:
  type: LoadBalancer
  ports:
  - name: http
    port: 80
    targetPort: 80
  - name: admin
    port: 81
    targetPort: 81
  - name: https
    port: 443
    targetPort: 443
  selector:
    app: nginx-proxy-manager

Installation Script

#!/bin/bash
# scripts/08-install-npm.sh

echo "========================================"
echo "08 - Installation Nginx Proxy Manager"
echo "========================================"

# Apply manifest
kubectl apply -f kubernetes/networking/npm/npm-deploy.yaml

# Wait for pod
kubectl wait --for=condition=ready pod -l app=nginx-proxy-manager -n npm --timeout=120s

# Get LoadBalancer IP
NPM_IP=$(kubectl get svc -n npm nginx-proxy-manager -o jsonpath='{.status.loadBalancer.ingress[0].ip}')

echo "✅ NPM installé"
echo "🌐 Interface admin: http://${NPM_IP}:81"
echo "   Email: admin@example.com"
echo "   Password: changeme"

Configuration

Initial Setup

  1. Access Admin UI

    • URL: http://192.168.1.202:81
    • Default credentials: admin@example.com / changeme
    • Important: Change password immediately!
  2. Router Configuration

    • Configure port forwarding on home router:
      • Port 80 → 192.168.1.202:80
      • Port 443 → 192.168.1.202:443

Creating Proxy Hosts

Example: Blog Service

  1. Go to Proxy HostsAdd Proxy Host

  2. Details Tab:

    • Domain Names: blog.sortium.fr
    • Scheme: http (important: Kubernetes services use HTTP)
    • Forward Hostname/IP: homelab-blog.blog.svc.cluster.local
    • Forward Port: 80
    • Cache Assets: ✅
    • Block Common Exploits: ✅
    • Websockets Support: ❌ (not needed for static blog)
  3. SSL Tab:

    • SSL Certificate: Request a new SSL Certificate with Let’s Encrypt
    • Force SSL: ✅
    • HTTP/2 Support: ✅
    • HSTS Enabled: ✅
  4. Advanced Tab:

    • Usually empty for simple services
  5. Click Save

Result:

Kubernetes Service Discovery

NPM can access Kubernetes services using DNS:

Format: <service-name>.<namespace>.svc.cluster.local:<port>

Examples:

Common Configurations

Static Site (Blog)

Domain: blog.sortium.fr
Forward to: homelab-blog.blog.svc.cluster.local:80
Scheme: http
SSL: Let's Encrypt

API Service

Domain: api.sortium.fr
Forward to: my-api.default.svc.cluster.local:3000
Scheme: http
SSL: Let's Encrypt
Websockets: ✅ (if needed)

Admin Interface

Domain: npm.sortium.fr
Forward to: localhost:81
Scheme: http
SSL: Let's Encrypt

Multiple Domains

Domain Names: 
  - app1.sortium.fr
  - app1-alias.sortium.fr
Forward to: app1.default.svc.cluster.local:80

SSL Certificate Management

Automatic Let’s Encrypt

NPM handles everything automatically:

  1. Detects new proxy host
  2. Requests certificate from Let’s Encrypt
  3. Validates domain via HTTP-01 challenge
  4. Installs certificate
  5. Auto-renews before expiration

Manual Certificate Upload

For custom certificates:

  1. SSL CertificatesAdd SSL Certificate
  2. Select Custom
  3. Upload certificate files
  4. Assign to proxy hosts

Troubleshooting

Certificate Generation Fails

Problem: Let’s Encrypt validation fails

Causes:

Solution:

# Verify DNS
nslookup blog.sortium.fr
# Should return your public IP

# Verify port forwarding
curl -I http://blog.sortium.fr
# Should return NPM response

# Check NPM logs
kubectl logs -n npm -l app=nginx-proxy-manager | grep -i ssl

404 Errors

Problem: Proxy host returns 404

Causes:

Solution:

# Test service from NPM pod
kubectl exec -n npm $(kubectl get pod -n npm -l app=nginx-proxy-manager -o jsonpath='{.items[0].metadata.name}') -- \
  curl -s http://homelab-blog.blog.svc.cluster.local:80

# Verify service exists
kubectl get svc -n blog homelab-blog

# Check NPM config
kubectl exec -n npm $(kubectl get pod -n npm -l app=nginx-proxy-manager -o jsonpath='{.items[0].metadata.name}') -- \
  cat /data/nginx/proxy_host/1.conf

Scheme Mismatch

Problem: Service returns errors when using HTTPS forward

Cause: Kubernetes services typically use HTTP internally

Solution: Always use http scheme for Kubernetes services:

Forward Scheme: http (not https)
Forward to: service.namespace.svc.cluster.local:80

Backup & Restore

Backup Configuration

# Backup NPM data
kubectl exec -n npm $(kubectl get pod -n npm -l app=nginx-proxy-manager -o jsonpath='{.items[0].metadata.name}') -- \
  tar -czf /tmp/npm-backup.tar.gz /data

# Copy to local
kubectl cp npm/$(kubectl get pod -n npm -l app=nginx-proxy-manager -o jsonpath='{.items[0].metadata.name}'):/tmp/npm-backup.tar.gz \
  ./npm-backup.tar.gz

Restore from Backup

# Copy backup to pod
kubectl cp ./npm-backup.tar.gz \
  npm/$(kubectl get pod -n npm -l app=nginx-proxy-manager -o jsonpath='{.items[0].metadata.name}'):/tmp/npm-backup.tar.gz

# Extract
kubectl exec -n npm $(kubectl get pod -n npm -l app=nginx-proxy-manager -o jsonpath='{.items[0].metadata.name}') -- \
  tar -xzf /tmp/npm-backup.tar.gz -C /

# Restart pod
kubectl rollout restart deployment nginx-proxy-manager -n npm

Performance & Scaling

Resource Limits

resources:
  requests:
    cpu: 100m
    memory: 256Mi
  limits:
    cpu: 1000m
    memory: 1Gi

Caching

Enable caching for static assets:

Multiple Instances

For high availability:

replicas: 2

Requires shared storage (NFS or similar) for /data directory.

Security Considerations

  1. Change Default Password - First thing after installation
  2. Use Strong Passwords - For admin account
  3. Enable 2FA - If available in future versions
  4. Regular Updates - Keep NPM image updated
  5. Firewall Rules - Only expose necessary ports
  6. SSL Everywhere - Force HTTPS for all public services

Integration with Kubernetes

Service Discovery

NPM automatically discovers Kubernetes services via DNS:

Ingress Alternative

Instead of Kubernetes Ingress:

Monitoring

Access Logs

kubectl exec -n npm $(kubectl get pod -n npm -l app=nginx-proxy-manager -o jsonpath='{.items[0].metadata.name}') -- \
  tail -f /data/logs/proxy-host-*_access.log

Error Logs

kubectl exec -n npm $(kubectl get pod -n npm -l app=nginx-proxy-manager -o jsonpath='{.items[0].metadata.name}') -- \
  tail -f /data/logs/proxy-host-*_error.log

Statistics

NPM provides built-in statistics:

Best Practices

  1. Use Descriptive Domain Names - blog.sortium.fr not app1.sortium.fr
  2. Enable SSL Everywhere - Force HTTPS for all public services
  3. Monitor Certificate Expiry - Check renewal status regularly
  4. Backup Regularly - Export configuration periodically
  5. Use Namespaces - Organize proxy hosts logically
  6. Test Before Production - Verify proxy hosts work correctly

Conclusion

NPM provides an excellent solution for managing reverse proxies in a Kubernetes environment. It’s user-friendly, feature-rich, and integrates well with Kubernetes service discovery.

Key Takeaways:


Next: Storage: Local Path vs Longhorn