# NPM Configuration for Docker Registry (registry.directlx.dev) ## Overview This guide configures Nginx Proxy Manager to proxy `registry.directlx.dev` to the backend Docker registry at `192.168.200.200:5000` with HTTPS/SSL termination. ## Prerequisites - ✅ DNS configured: registry.directlx.dev → 192.168.200.71 - ✅ NPM running at 192.168.200.71 - ✅ Docker registry running at 192.168.200.200:5000 - ⚠️ NPM admin access required ## Step-by-Step Configuration ### 1. Access NPM Admin Panel ```bash # Open in browser http://192.168.200.71:81/ # Default credentials (if first time): # Email: admin@example.com # Password: changeme ``` ### 2. Create Proxy Host Navigate to: **Hosts** → **Proxy Hosts** → **Add Proxy Host** #### Details Tab **Domain Names:** ``` registry.directlx.dev ``` **Scheme:** `http` **Forward Hostname / IP:** `192.168.200.200` **Forward Port:** `5000` **Options:** - ☐ Cache Assets - ☑ Block Common Exploits - ☑ Websockets Support (for Docker registry v2 API) - ☐ Access List #### SSL Tab **SSL Certificate:** - Select existing Let's Encrypt certificate for `*.directlx.dev`, OR - Request New SSL Certificate: - ☑ Force SSL - ☑ HTTP/2 Support - ☑ HSTS Enabled - ☑ HSTS Subdomains - Email: `your-email@example.com` - ☑ I Agree to the Let's Encrypt Terms of Service **Note:** If using wildcard certificate, ensure DNS challenge is configured. #### Advanced Tab (IMPORTANT for Docker Registry) Add the following custom Nginx configuration: ```nginx # Docker Registry v2 API requires specific headers proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; # Increase timeouts for large image pushes proxy_connect_timeout 300; proxy_send_timeout 300; proxy_read_timeout 300; send_timeout 300; # Disable buffering for chunked uploads proxy_request_buffering off; # Allow large body sizes for Docker images (5GB max) client_max_body_size 5120M; # Disable access log for registry (too verbose) access_log off; ``` ### 3. Save and Test Click **Save** to create the proxy host. ### 4. Verify Configuration #### Test DNS Resolution ```bash nslookup registry.directlx.dev # Should return: 192.168.200.71 ``` #### Test HTTPS Access ```bash curl -I https://registry.directlx.dev/v2/ # Expected: HTTP/2 200 ``` #### Test Docker Registry API ```bash # List repositories curl -s https://registry.directlx.dev/v2/_catalog | jq '.' # Expected output: # { # "repositories": [ # "atm-incident-backend", # "hiveops-incident", # ... # ] # } ``` #### Test Docker Pull ```bash docker pull registry.directlx.dev/hiveops-incident:latest ``` ## Troubleshooting ### 502 Bad Gateway **Cause:** NPM can't reach backend registry **Check backend is running:** ```bash ansible docker -m shell -a "docker ps | grep registry" ansible docker -m shell -a "curl -I http://localhost:5000/v2/" ``` **Check firewall:** ```bash ansible docker -m shell -a "ufw status" -b ``` ### SSL Certificate Error **Cause:** Let's Encrypt can't verify domain **Solution:** 1. Ensure port 80/443 are open on NPM server 2. Verify DNS propagation: `nslookup registry.directlx.dev` 3. Check NPM logs: **Tools** → **Error Logs** ### 413 Request Entity Too Large **Cause:** `client_max_body_size` too small **Solution:** Add to Advanced tab: ```nginx client_max_body_size 5120M; ``` ### Connection Timeout on Large Pushes **Cause:** Timeout values too low **Solution:** Add to Advanced tab: ```nginx proxy_connect_timeout 300; proxy_send_timeout 300; proxy_read_timeout 300; send_timeout 300; ``` ### Docker Push Hangs **Cause:** Request buffering enabled **Solution:** Add to Advanced tab: ```nginx proxy_request_buffering off; ``` ## Docker Client Configuration ### No Additional Configuration Required With HTTPS enabled, Docker will work without insecure registry configuration: ```bash # Just works! docker pull registry.directlx.dev/my-image:latest docker push registry.directlx.dev/my-image:latest ``` ### Legacy HTTP Configuration (NOT RECOMMENDED) If you need HTTP-only access (not recommended): Edit `/etc/docker/daemon.json`: ```json { "insecure-registries": ["registry.directlx.dev"] } ``` Restart Docker: ```bash sudo systemctl restart docker ``` ## Testing the Complete Setup ### 1. Tag and Push Test Image ```bash # Pull a small test image docker pull alpine:latest # Tag for your registry docker tag alpine:latest registry.directlx.dev/test-alpine:latest # Push to registry docker push registry.directlx.dev/test-alpine:latest ``` ### 2. Verify Upload ```bash # Check repository exists curl -s https://registry.directlx.dev/v2/_catalog | jq '.repositories[] | select(. == "test-alpine")' # Check tags curl -s https://registry.directlx.dev/v2/test-alpine/tags/list | jq '.' ``` ### 3. Pull from Another Machine ```bash # Remove local image docker rmi registry.directlx.dev/test-alpine:latest # Pull from registry docker pull registry.directlx.dev/test-alpine:latest # Verify docker images | grep test-alpine ``` ### 4. Cleanup ```bash # Remove test image from local docker rmi alpine:latest registry.directlx.dev/test-alpine:latest ``` ## NPM Configuration Summary | Setting | Value | |---------|-------| | Domain | registry.directlx.dev | | Scheme | http | | Forward Host | 192.168.200.200 | | Forward Port | 5000 | | SSL | Enabled (Let's Encrypt) | | Force SSL | Yes | | HTTP/2 | Yes | | HSTS | Yes | | Max Body Size | 5120M | | Timeouts | 300s | ## Security Considerations ### ✅ Implemented - HTTPS/TLS encryption (via Let's Encrypt) - SSL certificate validation - Block common exploits enabled - Large body size limits (prevents DoS) - Access logging disabled (prevents log spam) ### ⚠️ Not Implemented (Consider for Production) - Authentication (Docker registry supports basic auth, tokens, OAuth) - Access lists (NPM can restrict by IP/network) - Rate limiting (prevent abuse) - Image scanning (vulnerability detection) - Content trust (signed images) ### Authentication Setup (Optional) To add basic authentication to the registry: 1. Generate htpasswd file on docker server: ```bash ansible docker -m shell -a "docker run --rm --entrypoint htpasswd httpd:alpine -Bbn username password > /opt/docker-registry/auth/htpasswd" ``` 2. Update registry configuration to use auth: ```yaml auth: htpasswd: realm: Registry Realm path: /auth/htpasswd ``` 3. Restart registry container 4. Docker login: ```bash docker login registry.directlx.dev ``` ## Related Documentation - [Docker Registry DNS Configuration](DOCKER-REGISTRY-DNS.md) - [Local DNS Configuration](LOCAL-DNS-CONFIGURATION.md) - [SSL Offloading Fix](SSL-OFFLOADING-FIX.md) ## Maintenance ### Update SSL Certificate Certificates auto-renew via Let's Encrypt. To force renewal: 1. NPM Admin → **SSL Certificates** 2. Find `registry.directlx.dev` certificate 3. Click **...** → **Renew Certificate** ### Monitor Logs ```bash # NPM access logs (if enabled) ansible npm -m shell -a "tail -f /data/logs/proxy-host-*.log" # NPM error logs ansible npm -m shell -a "tail -f /data/logs/error.log" # Registry logs ansible docker -m shell -a "docker logs -f registry" -b ``` ### Backup Configuration ```bash # Backup NPM database ansible npm -m shell -a "sqlite3 /data/database.sqlite .dump > /tmp/npm-backup.sql" # Download backup ansible npm -m fetch -a "src=/tmp/npm-backup.sql dest=./backups/" ``` --- **Created**: 2026-02-14 **Last Updated**: 2026-02-14 **Author**: DirectLX Infrastructure Team