Reverse proxy to vercel is always redirecting

Pre-emptive: I know, reverse proxying Vercel removes a lot of Vercel’s benefits. I have real-world business reasons for doing this :slightly_smiling_face:

1. Caddy version (caddy version):

v2.3.0 h1:fnrqJLa3G5vfxcxmOH/+kJOcunPLhSBnjgIvjXV/QTA=

2. How I run Caddy:

I run it as a systemd service using the digital ocean marketplace image.

I update the config through the admin API over ssh (root), and use it to create reverse proxy routes for domains/subdomains.

I use the JSON configuration and don’t use a caddyfile.

a. System environment:

Ubuntu 18.04
Systemd caddy-api service

b. Command:

service caddy-api start

(or it’s enabled as a service so it’ll auto start on reboot)

c. Service/unit/compose file:

Systemd service file at:
/lib/systemd/system/caddy-api.service

# caddy-api.service
#
# For using Caddy with its API.
#
# This unit is "durable" in that it will automatically resume
# the last active configuration if the service is restarted.
#
# See https://caddyserver.com/docs/install for instructions.

[Unit]
Description=Caddy
Documentation=https://caddyserver.com/docs/
After=network.target network-online.target
Requires=network-online.target

[Service]
User=caddy
Group=caddy
ExecStart=/usr/bin/caddy run --environ --resume
TimeoutStopSec=5s
LimitNOFILE=1048576
LimitNPROC=512
PrivateTmp=true
ProtectSystem=full
AmbientCapabilities=CAP_NET_BIND_SERVICE

[Install]
WantedBy=multi-user.target

d. My complete Caddyfile or JSON config:

{
    "admin": {
        "disabled": false,
        "listen": "localhost:2019"
    },
    "apps": {
        "http": {
            "servers": {
                "srv0": {
                    "listen": [
                        ":80",
                        ":443"
                    ],
                    "routes": [
                        {
                            "@id": "vhost_781",
                            "handle": [
                                {
                                    "handler": "subroute",
                                    "routes": [
                                        {
                                            "handle": [
                                                {
                                                    "handler": "reverse_proxy",
                                                    "headers": {
                                                        "request": {
                                                            "set": {
                                                                "Host": [
                                                                    "filesharepage.vercel.app"
                                                                ],
                                                                "X-Forwarded-Proto": [
                                                                    "https"
                                                                ]
                                                            }
                                                        }
                                                    },
                                                    "upstreams": [
                                                        {
                                                            "dial": "filesharepage.vercel.app:443"
                                                        }
                                                    ]
                                                }
                                            ]
                                        }
                                    ]
                                }
                            ],
                            "match": [
                                {
                                    "host": [
                                        "t1.fileshare.page"
                                    ]
                                }
                            ],
                            "terminal": true
                        }
                    ]
                }
            }
        },
        "tls": {
            "automation": {
                "on_demand": {
                    "ask": "https://cloud.approximated.app/check-domain"
                }
            }
        }
    },
    "logging": {
        "logs": {
            "default": {
                "level": "DEBUG",
                "writer": {
                    "filename": "caddy_api_log_file",
                    "output": "file"
                }
            }
        }
    }
}

3. The problem I’m having:

I’m trying to get a reverse proxy to work with filesharepage.vercel.app as the upstream target.

My problem with proxying to Vercel specifically is that it’s always returning a redirect (either 308 or 304 depending on browser) to filesharepage.vercel.app instead of a regular response.

My DNS for fileshare.page has an A record for *.fileshare.page pointing at my caddy server, so that’s all setup and working (works with other reverse proxies).

I had thought that originally Vercel was redirecting because I wasn’t upstreaming it to port 443, so naturally it was trying to redirect to the https version. I still think that’s happening but I’m not sure why anymore, because I’m sending it to port 443 as you can see in the config.

Is there something wrong with how I’m setting up my route/reverse proxy here?

If not, any idea why Vercel is redirecting (or how it would even know I’m proxying?).

4. Error messages and/or full log output:

2021/02/22 23:47:59.049 debug   http.handlers.reverse_proxy     upstream roundtrip      
{
   "upstream":"filesharepage.vercel.app:443",
   "request":{
      "remote_addr":"50.98.241.177:3039",
      "proto":"HTTP/2.0",
      "method":"GET",
      "host":"filesharepage.vercel.app",
      "uri":"/",
      "headers":{
         "Accept":[
            "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9"
         ],
         "Sec-Fetch-Mode":[
            "navigate"
         ],
         "Accept-Language":[
            "en-US,en;q=0.9"
         ],
         "Accept-Encoding":[
            "gzip, deflate, br"
         ],
         "X-Forwarded-For":[
            "50.98.241.177"
         ],
         "Referer":[
            "https://approximated-carterbryden.codeanyapp.com/"
         ],
         "Sec-Fetch-Site":[
            "cross-site"
         ],
         "Sec-Fetch-User":[
            "?1"
         ],
         "Cookie":[
            "__stripe_mid=77ed7b4d-00b0-4999-8364-04666c6ab1cb7e506c"
         ],
         "User-Agent":[
            "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.182 Safari/537.36"
         ],
         "Dnt":[
            "1"
         ],
         "X-Forwarded-Proto":[
            "https"
         ],
         "Upgrade-Insecure-Requests":[
            "1"
         ],
         "Sec-Fetch-Dest":[
            "document"
         ]
      },
      "tls":{
         "resumed":false,
         "version":772,
         "cipher_suite":4865,
         "proto":"h2",
         "proto_mutual":true,
         "server_name":"t1.fileshare.page"
      }
   },
   "duration":0.01170214,
   "headers":{
      "Server":[
         "Vercel"
      ],
      "X-Vercel-Id":[
         "sfo1::"
      ],
      "Strict-Transport-Security":[
         "max-age=63072000; includeSubDomains; preload"
      ],
      "Date":[
         "Mon, 22 Feb 2021 23:47:59 GMT"
      ],
      "Content-Length":[
         "168"
      ],
      "Location":[
         "https://filesharepage.vercel.app/"
      ],
      "Cache-Control":[
         "s-maxage=0"
      ],
      "Content-Type":[
         "text/html"
      ]
   },
   "status":308
}

5. What I already tried:

I’ve tried setting the request header for Host to the upstream dial address, as well as the matching host address. Basically I’ve swapped around with every combination I could think of for that.

I’ve set the X-Forwarded-Proto to [“https”] as well.

I’ve tried dialing with no port on the end, with :80 on the end, and with :443 on the end.

I’m not sure what else to do here because it seems like a fairly simple reverse proxy should work here, and I’ve likely just misunderstood or used something wrong.

6. Links to relevant resources:

The target upstream: filesharepage.vercel.app
The subdomain I’m trying to get to reverse proxy to it: t1.fileshare.page
They’re both just test pages as I’m working this out, so don’t mind the rick-roll video :laughing:

Any help at all will be really appreciated!

I think you need to enable “tls” on the proxy transport. You can set it to an empty object.

So like:

"transport": {"protocol": "http", "tls": {}}

That was exactly it. I hadn’t realized there was another TLS config at that level, thanks!

1 Like