Caddy reverse proxy setup using Caddyfile on Azure Container Instances does not work

1. Caddy version:

2.6.2

2. How I installed, and run Caddy:

Used the official docker image on azure container instances

a. System environment:

Linux on Azure Container Instances

c. Dockerfile file:

FROM caddy:latest

COPY server/Caddyfile /etc/caddy/Caddyfile

CMD ["caddy", "run", "--config" "/etc/caddy/Caddyfile"]

d. My complete Caddy config:

aifurevproxy.eastus.azurecontainer.io {
    @options {
        method OPTIONS
    }
    header {
        Access-Control-Allow-Origin *
        Access-Control-Allow-Credentials false
        Access-Control-Allow-Methods *
        Access-Control-Allow-Headers *
        defer
    }
    reverse_proxy /records {
        to http://aifutestgroup.eastus.azurecontainer.io:8000
        header_down Access-Control-Allow-Origin *
        header Access-Control-Allow-Methods "GET, OPTIONS"
    }
    reverse_proxy /submit {
        to http://aifutestgroup.eastus.azurecontainer.io:8000
        header_down Access-Control-Allow-Origin *
        header Access-Control-Allow-Methods "POST, OPTIONS"
    }
    reverse_proxy /heartbeat {
        to http://aifutestgroup.eastus.azurecontainer.io:8000
        header_down Access-Control-Allow-Origin *
        header Access-Control-Allow-Methods "GET, OPTIONS"
    }
    respond @options 204
}

3. The problem I’m having:

I have been at it for weeks, trying small changes here and there to see if anything work but nothing has worked so far.

I have a backend Python fastapi server running a few endpoints (/heartbeat, /records, /submit) on port 8000. The URI for the backend container is aifutestgroup.eastus.azurecontainer.io:8000

The website is built by GitHub Pages action automatically - domain is aifu.shantam.io

Caddy runs in its own container (sidecar pattern) and has the URI - aifurevproxy.eastus.azurecontainer.io

How the website works - https://aifu.shantam.io/aifurevproxy
When you click on a country - USA for example - then it makes a call to ..../records?table_name=usa (gbr for Britain and so on). When you enter the details and press submit then it makes a POST request to aifurevproxy.eastus.azurecontainer.io/submit
The javascript request made from the website are https://aifurevproxy.eastus.azurecontainer.io/records?table_name=tableName and https://aifurevproxy.eastus.azurecontainer.io/submit

However neither the records GET request or the Submit POST request works. I get a CORS error in the browser console.

Making http requests from Postman directly to the Python server works.

GitHub Repo folder with all the relevant files - AIFU/server at main · armsp/AIFU · GitHub

Output of curl -vL to the endpoint (does not work)-

❯ curl -vL https://aifurevproxy.eastus.azurecontainer.io/heartbeat
*   Trying 52.186.110.178:443...
* TCP_NODELAY set
* Connected to aifurevproxy.eastus.azurecontainer.io (52.186.110.178) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
*   CAfile: /etc/ssl/certs/ca-certificates.crt
  CApath: /etc/ssl/certs
* TLSv1.3 (OUT), TLS handshake, Client hello (1):

Also does not work -

❯ curl -vL https://aifurevproxy.eastus.azurecontainer.io/records?table_name=usa
*   Trying 52.186.110.178:443...
* TCP_NODELAY set
* Connected to aifurevproxy.eastus.azurecontainer.io (52.186.110.178) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
*   CAfile: /etc/ssl/certs/ca-certificates.crt
  CApath: /etc/ssl/certs
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* Operation timed out after 300579 milliseconds with 0 out of 0 bytes received
* Closing connection 0
curl: (28) Operation timed out after 300579 milliseconds with 0 out of 0 bytes received

The following works (but the https version of the curl request does not…obviously perhaps)-

❯ curl -vL http://aifutestgroup.eastus.azurecontainer.io:8000/heartbeat
*   Trying 20.242.214.191:8000...
* TCP_NODELAY set
* Connected to aifutestgroup.eastus.azurecontainer.io (20.242.214.191) port 8000 (#0)
> GET /heartbeat HTTP/1.1
> Host: aifutestgroup.eastus.azurecontainer.io:8000
> User-Agent: curl/7.68.0
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< date: Sat, 28 Jan 2023 17:16:33 GMT
< server: uvicorn
< content-length: 25
< content-type: application/json
<
* Connection #0 to host aifutestgroup.eastus.azurecontainer.io left intact
{"message":"I am alive!"}

4. Error messages and/or full log output:

Don’t know how to observe these on ACI

Keep in mind that this /records matcher will only match requests to exactly /records and not /records/foo. Path matching is exact in Caddy. You might want to add a * to it to match everything else, like /records*.

You don’t need this, because your Dockerfile will inherit to parent image’s CMD by default.

Since this is all the same backend that you’re proxying to, you can significantly simplify this. You don’t need 3 separate reverse_proxy, you can do the header operations with the header directive, outside of the proxy.

Also, reverse_proxy doesn’t have a header option, it has header_up and header_down.

Well, that’s pretty important to see. You should have a way to see your container’s logs. Caddy logs to stdout.

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