Header 1

ioan

ioan biticu's website

nginx-proxy limit connections to cloudflare

Here is how to limit the ips that can connect to your nginx-proxy container

The IPs are available on Cloudflare's website and they rarely change.

What I'm going to show below works as of Sep 28, 2023.

File: ./conf/cloudflare-ip.conf

# Cloudflare IP configuration (http level)
geo $realip_remote_addr $cloudflare_ip {
    default 0;
    
    # IPv4 ranges
    173.245.48.0/20 1;
    103.21.244.0/22 1;
    103.22.200.0/22 1;
    103.31.4.0/22 1;
    141.101.64.0/18 1;
    108.162.192.0/18 1;
    190.93.240.0/20 1;
    188.114.96.0/20 1;
    197.234.240.0/22 1;
    198.41.128.0/17 1;
    162.158.0.0/15 1;
    104.16.0.0/13 1;
    104.24.0.0/14 1;
    172.64.0.0/13 1;
    131.0.72.0/22 1;
    
    # IPv6 ranges
    2400:cb00::/32 1;
    2606:4700::/32 1;
    2803:f800::/32 1;
    2405:b500::/32 1;
    2405:8100::/32 1;
    2a06:98c0::/29 1;
    2c0f:f248::/32 1;
}

map $cloudflare_ip $allowed_ip {
    0 0;
    1 1;
}

File: ./conf/cloudflare.conf

# Cloudflare IP ranges
# IPv4
set_real_ip_from 173.245.48.0/20;
set_real_ip_from 103.21.244.0/22;
set_real_ip_from 103.22.200.0/22;
set_real_ip_from 103.31.4.0/22;
set_real_ip_from 141.101.64.0/18;
set_real_ip_from 108.162.192.0/18;
set_real_ip_from 190.93.240.0/20;
set_real_ip_from 188.114.96.0/20;
set_real_ip_from 197.234.240.0/22;
set_real_ip_from 198.41.128.0/17;
set_real_ip_from 162.158.0.0/15;
set_real_ip_from 104.16.0.0/13;
set_real_ip_from 104.24.0.0/14;
set_real_ip_from 172.64.0.0/13;
set_real_ip_from 131.0.72.0/22;

# IPv6
set_real_ip_from 2400:cb00::/32;
set_real_ip_from 2606:4700::/32;
set_real_ip_from 2803:f800::/32;
set_real_ip_from 2405:b500::/32;
set_real_ip_from 2405:8100::/32;
set_real_ip_from 2a06:98c0::/29;
set_real_ip_from 2c0f:f248::/32;

# Use CF-Connecting-IP header
real_ip_header CF-Connecting-IP;

File: ./vhost.d/default

# Block access if not from Cloudflare
if ($cloudflare_ip = 0) {
    return 403 "Access denied: Direct IP access not allowed";
}

File: docker-compose.yml

  nginx-proxy:
    image: nginxproxy/nginx-proxy:alpine
    container_name: nginx-proxy
    ports:
      - "80:80"
      - "443:443"
      - "443:443/udp"
    volumes:
      - /var/run/docker.sock:/tmp/docker.sock:ro
      - ./conf/cloudflare.conf:/etc/nginx/conf.d/cloudflare.conf:ro
      - ./conf/cloudflare-ip.conf:/etc/nginx/conf.d/cloudflare-ip.conf:ro
      - ./vhost.d/default:/etc/nginx/vhost.d/default:ro
      - certs:/etc/nginx/certs
      - vhost2:/etc/nginx/vhost.d
      - html:/usr/share/nginx/html
    environment: # for debugging purposes, feel free to remove
    - |
      LOG_FORMAT=$${remote_addr} - $${remote_user} [$${time_local}] 
      "$${request}" $${status} $${body_bytes_sent} 
      "$${http_referer}" "$${http_user_agent}"
      CF-IP:$${http_cf_connecting_ip} 
      Cloudflare:$${cloudflare_ip}
    restart: always
    networks:
      - proxy-network
    labels:
      - "com.github.jrcs.letsencrypt_nginx_proxy_companion.nginx_proxy=true"