Score:0

Real Client-Ip with Cloudflare, Docker, Traefik and nginx set up as a mail proxy (Client-Ip in PHP script, not in upstream mail server)

id flag

I set nginx as a mail proxy, but i have trouble detecting the real Client-Ip in the php authentication script called by nginx via auth_http.
I am not interested in getting real-IP on the upstream mail server.

This is my stack:

  • Cloudflare manages dns
  • The rest is all handled with Docker

docker-compose.yml:

version: '3.9'

services:
  traefik:
    container_name: traefik
    image: traefik:v2.6.0
    ports:
      - "80:80"
      - "443:443"
      - "465:465"
      - "993:993"
      - "995:995"
      ...
    labels:
      - traefik.enable=true
      - traefik.http.routers.traefik-public-https.tls=true
      ...
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      ...
    command:
      - --providers.docker
      - --providers.docker.exposedbydefault=false
      - --entrypoints.http.address=:80
      - --entrypoints.https.address=:443
      - --entrypoints.entrypoint-nginx-mail-465.address=:465
      - --entrypoints.entrypoint-nginx-mail-993.address=:993
      - --entrypoints.entrypoint-nginx-mail-995.address=:995
      - --entrypoints.entrypoint-forwardedHeaders-trustedIPs.forwardedHeaders.trustedIPs=${TRAEFIK_TRUSTED_IPS}
      ...

  nginx:
    container_name: nginx
    image: nginx:1.21
    volumes:
      - ${PWD}/sys/nginx/vhosts:/etc/nginx/conf.d
      - ${PWD}/sys/nginx/custom.d:/etc/nginx/custom.d
      ...
    labels:
      - traefik.enable=true

      - traefik.tcp.routers.router-nginx-mail-465.entrypoints=entrypoint-nginx-mail-465
      - traefik.tcp.routers.router-nginx-mail-465.rule=HostSNI(`*`)
      - traefik.tcp.routers.router-nginx-mail-465.tls=true
      - traefik.tcp.routers.router-nginx-mail-465.tls.certresolver=le
      - traefik.tcp.routers.router-nginx-mail-465.service=service-nginx-mail-465
      - traefik.tcp.services.service-nginx-mail-465.loadbalancer.server.port=587

      - traefik.tcp.routers.router-nginx-mail-993.entrypoints=entrypoint-nginx-mail-993
      - traefik.tcp.routers.router-nginx-mail-993.rule=HostSNI(`*`)
      - traefik.tcp.routers.router-nginx-mail-993.tls=true
      - traefik.tcp.routers.router-nginx-mail-993.tls.certresolver=le
      - traefik.tcp.routers.router-nginx-mail-993.service=service-nginx-mail-993
      - traefik.tcp.services.service-nginx-mail-993.loadbalancer.server.port=143

      - traefik.tcp.routers.router-nginx-mail-995.entrypoints=entrypoint-nginx-mail-995
      - traefik.tcp.routers.router-nginx-mail-995.rule=HostSNI(`*`)
      - traefik.tcp.routers.router-nginx-mail-995.tls=true
      - traefik.tcp.routers.router-nginx-mail-995.tls.certresolver=le
      - traefik.tcp.routers.router-nginx-mail-995.service=service-nginx-mail-995
      - traefik.tcp.services.service-nginx-mail-995.loadbalancer.server.port=110

      ...
  php-fpm:
    container_name: php-fpm
    image: bitnami/php-fpm:7.4
    userns_mode: 'host'
    labels:
      - traefik.enable=false
    ...

.env:

#https://www.cloudflare.com/ips
# Last updated: April 8, 2021
TRAEFIK_TRUSTED_IPS=173.245.48.0/20,103.21.244.0/22,103.22.200.0/22,103.31.4.0/22,141.101.64.0/18,108.162.192.0/18,190.93.240.0/20,188.114.96.0/20,197.234.240.0/22,198.41.128.0/17,162.158.0.0/15,104.16.0.0/13,104.24.0.0/14,172.64.0.0/13,131.0.72.0/22,2400:cb00::/32,2606:4700::/32,2803:f800::/32,2405:b500::/32,2405:8100::/32,2a06:98c0::/29,2c0f:f248::/32
...

sys/nginx/vhosts/00-main.conf:

server {
    listen [::]:80;
    listen 80;

    server_name localhost;

    root /app/public;

    index index.php;

    location ~ /\. {
        deny all;
    }

    location ~ \.php$ {
        fastcgi_pass php-fpm:9000;
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    }
}

sys/nginx/custom.d/mail.conf:

mail {
    server_name _;
    auth_http localhost:80/proxy.php;
    proxy_pass_error_message on;

    imap_capabilities IMAP4 IMAP4rev1 LOGIN-REFERRALS SASL-IR ENABLE IDLE ID LITERAL+;
    pop3_capabilities CAPA RESP-CODES USER TOP AUTH-RESP-CODE PIPELINING UIDL;
    smtp_capabilities PIPELINING "SIZE ***" ETRN ENHANCEDSTATUSCODES 8BITMIME DSN CHUNKING;
    ...

    server {
        listen 110;
        protocol pop3;
        starttls on;
        auth_http_header X-Auth-Port 110;
        auth_http_header User-Agent "POP3 proxy";
    }

    server {
        listen 143;
        protocol imap;
        starttls on;
        auth_http_header X-Auth-Port 143;
        auth_http_header User-Agent "IMAP proxy";
    }

    server {
        listen 587;
        protocol smtp;
        starttls on;
        auth_http_header X-Auth-Port 587;
        auth_http_header User-Agent "SMTP proxy";
    }
}

getallheaders() inside proxy.php:

array (
  'User-Agent' => 'IMAP proxy',
  'X-Auth-Port' => '143',
  'Client-Ip' => '172.27.0.2',
  'Auth-Login-Attempt' => '1',
  'Auth-Protocol' => 'imap',
  'Auth-Pass' => '***',
  'Auth-User' => '***',
  'Auth-Method' => 'plain',
  'Host' => 'localhost',
  'Content-Length' => '',
  'Content-Type' => '',
)

$_SERVER inside proxy.php:

array (
  'HTTP_USER_AGENT' => 'IMAP proxy',
  'HTTP_X_AUTH_PORT' => '143',
  'HTTP_CLIENT_IP' => '172.27.0.2',
  'HTTP_AUTH_LOGIN_ATTEMPT' => '1',
  'HTTP_AUTH_PROTOCOL' => 'imap',
  'HTTP_AUTH_PASS' => '***',
  'HTTP_AUTH_USER' => '***',
  'HTTP_AUTH_METHOD' => 'plain',
  'HTTP_HOST' => 'localhost',
  'REDIRECT_STATUS' => '200',
  'SERVER_NAME' => 'localhost',
  'SERVER_PORT' => '80',
  'SERVER_ADDR' => '127.0.0.1',
  'REMOTE_PORT' => '49360',
  'REMOTE_ADDR' => '127.0.0.1',
  'SERVER_SOFTWARE' => 'nginx/1.21.3',
  'GATEWAY_INTERFACE' => 'CGI/1.1',
  'REQUEST_SCHEME' => 'http',
  'SERVER_PROTOCOL' => 'HTTP/1.0',
  'DOCUMENT_URI' => '/proxy.php',
  'REQUEST_URI' => '/',
  'SCRIPT_NAME' => '/proxy.php',
  'CONTENT_LENGTH' => '',
  'CONTENT_TYPE' => '',
  'REQUEST_METHOD' => 'GET',
  'QUERY_STRING' => '',
  'FCGI_ROLE' => 'RESPONDER',
  'PHP_SELF' => '/proxy.php',
  ...
)
mangohost

Post an answer

Most people don’t grasp that asking a lot of questions unlocks learning and improves interpersonal bonding. In Alison’s studies, for example, though people could accurately recall how many questions had been asked in their conversations, they didn’t intuit the link between questions and liking. Across four studies, in which participants were engaged in conversations themselves or read transcripts of others’ conversations, people tended not to realize that question asking would influence—or had influenced—the level of amity between the conversationalists.