Reverse proxy not passing user IP

1. Caddy version (caddy version):

v2.4.3 h1:Y1FaV2N4WO3rBqxSYA8UZsZTQdN+PwcoOcAiZTM8C0I=

2. How I run Caddy:

Ubuntu 20.04 with systemd. Hosts many websites including Flarum

a. System environment:

Ubuntu 20.04 on systemd

b. Command:

sudo service caddy start

c. Service/unit/compose file:

No clue where the systemd file is

d. My complete Caddyfile or JSON config:

{
        admin off
}
(logging) {
        log {
                output file /var/log/caddy/caddy.log {
                        roll_size 1gb
                        roll_keep 5
                }
        }
}
(errors) {
        handle_errors {
                root * /var/www/internal/errors
                rewrite * /{http.error.status_code}.html
                file_server
        }
}
(php) {
        php_fastcgi unix//run/php/php8.0-fpm.sock
}
www.telesphoreo.me {
        import logging
        redir https://telesphoreo.me{uri}
}
telesphoreo.me {
        import logging
        import errors
        import php
        root * /var/www/telesphoreo.me
        file_server browse
        encode gzip zstd
        respond /assets/ 403
        respond /files/ 403
        respond /files/theme/ 403
        respond /files/theme/fonts/ 403
        respond /files/theme/images/ 403
        respond /uploads/2/6/3/9/26395298/ 403
        respond /uploads/2/6/3/9/26395298/background-images/ 403
        respond /nitrogen/ 403
        respond /wave/ 403
}
db.telesphoreo.me {
        import logging
        import php
        root * /usr/share/phpmyadmin
        file_server
}
i.telesphoreo.me {
        import logging
        import errors
        root * /var/www/i.telesphoreo.me
        file_server
}
forum.telesphoreo.me {
        import logging
        import php
        root * /var/www/forum.telesphoreo.me/public
        file_server
        header /assets {
                +Cache-Control "public, must-revalidate, proxy-revalidate"
                +Cache-Control "max-age=25000"
                Pragma "public"
        }
}
panel.telesphoreo.me {
        import logging
        import php
        root * /var/www/pterodactyl/public
        file_server
        header X-Content-Type-Options nosniff
        header X-XSS-Protection "1; mode=block"
        header X-Robots-Tag none
        header Content-Security-Policy "frame-ancestors 'self'"
        header X-Frame-Options DENY
        header Referrer-Policy same-origin
        request_body {
                max_size 100m
        }
        respond /.ht* 403
}
stevennl2000.telesphoreo.me {
        import logging
        import php
        root * /var/www/snl2000.telesphoreo.me/public
        file_server
        header /assets {
                +Cache-Control "public, must-revalidate, proxy-revalidate"
                +Cache-Control "max-age=25000"
                Pragma "public"
        }
}
stevennl2000.telesphoreo.me:28966 {
        reverse_proxy http://stevennl2000.telesphoreo.me:28900 {
                header_up Host {host}
                header_up X-Real-IP {remote}
                header_up X-Forwarded-For {remote}
                header_up X-Forwarded-Port {server_port}
                header_up X-Forwarded-Proto {scheme}
        }
}
updater.telesphoreo.me {
        import logging
        import errors
        root * /var/www/updater.telesphoreo.me
        file_server browse
}
wiki.stevennl2000.telesphoreo.me {
        import logging
        import errors
        import php
        root * /var/www/wiki.telesphoreo.me
        file_server
}
wiki.telesphoreo.me {
        import logging
        import errors
        import php
        root * /var/www/tfwiki.telesphoreo.me
        file_server
}
packs.smokes-crystal.rocks {
        import logging
        redir https://i.telesphoreo.me{uri}
}
www.smokes-crystal.rocks {
        import logging
        redir https://smokes-crystal.rocks{uri}
}
smokes-crystal.rocks {
        import logging
        import errors
        root * /var/www/smokes-crystal.rocks
        file_server
}

3. The problem I’m having:

So basically I have a Minecraft server that uses NanoHTTPD as a small server. It runs on port 28900. It displays some statistics about the server and pulls files to view. Here’s the thing. Seeing certain things like player punishments is restricted to admins. The way it’s checked is if the admins IP is being used, it will display the page. However, if the IP the user is coming from is not an admin, it will deny them access. The problem is this: “You may not view the punishment list. Your IP, 65.21.153.247, is not registered to an admin on the server.”
This is the IP of the server, not the user IP. It’s not passing the user IP to the server when reverse proxied. I tried adding all the headers back. The way it’s getting the IP is from the default java.net.Socket (socket.getInetAddress().getHostAddress();). I’m not sure what the best way to go is about fixing it. I tried adding all the headers. Looking at the headers, it says it returned 404 and the headers don’t seem to be different for https://stevennl2000.telesphoreo.me:28900/punishments and https://stevennl2000.telesphoreo.me:28966.

4. Error messages and/or full log output:

*   Trying 65.21.153.247...
* TCP_NODELAY set
* Connected to stevennl2000.telesphoreo.me (65.21.153.247) port 28966 (#0)
* schannel: SSL/TLS connection with stevennl2000.telesphoreo.me port 28966 (step 1/3)
* schannel: checking server certificate revocation
* schannel: sending initial handshake data: sending 192 bytes...
* schannel: sent initial handshake data: sent 192 bytes
* schannel: SSL/TLS connection with stevennl2000.telesphoreo.me port 28966 (step 2/3)
* schannel: failed to receive handshake, need more data
* schannel: SSL/TLS connection with stevennl2000.telesphoreo.me port 28966 (step 2/3)
* schannel: encrypted data got 4096
* schannel: encrypted data buffer: offset 4096 length 4096
* schannel: encrypted data length: 180
* schannel: encrypted data buffer: offset 180 length 4096
* schannel: received incomplete message, need more data
* schannel: SSL/TLS connection with stevennl2000.telesphoreo.me port 28966 (step 2/3)
* schannel: encrypted data got 465
* schannel: encrypted data buffer: offset 645 length 4096
* schannel: sending next handshake data: sending 93 bytes...
* schannel: SSL/TLS connection with stevennl2000.telesphoreo.me port 28966 (step 2/3)
* schannel: encrypted data got 195
* schannel: encrypted data buffer: offset 195 length 4096
* schannel: SSL/TLS handshake complete
* schannel: SSL/TLS connection with stevennl2000.telesphoreo.me port 28966 (step 3/3)
* schannel: stored credential handle in session cache
> GET /punishments HTTP/1.1
> Host: stevennl2000.telesphoreo.me:28966
> User-Agent: curl/7.55.1
> Accept: */*
>
* schannel: client wants to read 102400 bytes
* schannel: encdata_buffer resized 103424
* schannel: encrypted data buffer: offset 0 length 103424
* schannel: encrypted data got 260
* schannel: encrypted data buffer: offset 260 length 103424
* schannel: decrypted data length: 231
* schannel: decrypted data added: 231
* schannel: decrypted data cached: offset 231 length 102400
* schannel: encrypted data buffer: offset 0 length 103424
* schannel: decrypted data buffer: offset 231 length 102400
* schannel: schannel_recv cleanup
* schannel: decrypted data returned 231
* schannel: decrypted data buffer: offset 0 length 102400
< HTTP/1.1 404 Not Found
< Content-Length: 106
< Content-Type: text/plain
< Date: Sun, 27 Jun 2021 22:15:59 GMT
< Server: Caddy
<
You may not view the punishment list. Your IP, 65.21.153.247, is not registered to an admin on the server.* Connection #0 to host stevennl2000.telesphoreo.me left intact

5. What I already tried:

I tried looking at previous solutions. One person added all the headers that Caddy doesn’t keep when reverse proxying. This didn’t work. The only other thing I can think of is to add a special header and have the code check the special header for the Host IP. I know that it’s possible for the host IP to exist as I’ve seen it when (accidently) setting it as a response header. The request headers for the headers don’t appear to be there when I check it from Inspect > Network > Headers though. Not sure what I’m doing wrong?

6. Links to relevant resources:

http://stevennl2000.telesphoreo.me:28900/index
https://stevennl2000.telesphoreo.me:28900/index

Instead of all these individual responds, you can just use a named path matcher to get them all at once (note the \ for continuing on new lines, effectively escapes the newline):

@denied path /assets/ \
	/files/ /files/theme/ /files/theme/fonts/ /files/theme/images/ \
	/uploads/2/6/3/9/26395298/ /uploads/2/6/3/9/26395298/background-images/ \
	/nitrogen/ /wave
respond @denied 403

By the way, /assets will only match requests to exactly /assets and not /assets/foo and so on. Make sure to use a * here if you need it to.

Remove all these lines. They’re not useful (and probably harmful in this case). Caddy will warn about this on startup (as of v2.4.0). See reverse_proxy (Caddyfile directive) — Caddy Documentation

Make sure that your upstream app looks at the X-Forwarded-For header for the original client’s IP. It needs to look there in case a reverse proxy is placed in front of it.

1 Like

This topic was automatically closed after 30 days. New replies are no longer allowed.