Issue with simultaneous caddy config updates via API

1. Caddy version (caddy version):

2.2.0

2. How I run Caddy:

a. System environment:

Docker

b. Command:

docker run -it -p 2019:2019 -p 80:80 --env-file .env mycaddy

c. Service/unit/compose file:

FROM caddy:2.2.0-builder AS builder

COPY ./caddy-proxyprotocol/ /usr/local/go/src/caddy-proxyprotocol
RUN xcaddy build \
    --with caddy-proxyprotocol
FROM caddy:2.2.0
COPY --from=builder /usr/bin/caddy /usr/bin/caddy

COPY config/caddy.json /etc/caddy/caddy.json

CMD ["caddy", "run", "-config", "/etc/caddy/caddy.json"]

3. The problem I’m having:

I am facing issues with dynamic config updates using admin API’s.

For instance, I am triggering these two simultaneous requests:

  1. “method”: “PUT”, “host”: “localhost:2019”, “uri”: “/config/apps/http/servers/srv0/routes/0”
  2. “method”: “PATCH”, “host”: “localhost:2019”, “uri”: “/id/domain.com”,

Assume @id” : “domain.com is present at /config/apps/http/servers/srv0/routes/0

The issue is while making updates via API using @id mechanism, there is an internalRedir which implies that there is no global lock acquired for the whole operation. The path returned by the Config index for “id” provided might be no longer valid when the redirect request is served since the config could have been changed by some other request.

I guess the same is happening in my case as well.

4. What I already tried:

In my case I have to support “multiple domains and their subdomains” rules which can be edited dynamically at any times.
So structure for my config is like below with subdomain blocks structured inside parent blocks.

{
  "@id": "sahil1.me",
  "handle": [
      {
          "handler": "subroute",
          "routes": [
              {
                  "@id": "S_sahil1.me",
                  "handle": [
                      {
                          "handler": "subroute",
                          "routes": [
                              {
                                  "handle": [
                                      {
                                          "handler": "http_cache"
                                      },
                                      {
                                          "handler": "reverse_proxy",
                                          "upstreams": [
                                              {
                                                  "dial": "13.127.152.23:80"
                                              }
                                          ]
                                      }
                                  ],
                                  "match": [
                                      {
                                          "host": [
                                              "sahil1.me"
                                          ]
                                      }
                                  ],
                                  "terminal": true
                              }
                          ]
                      }
                  ],
                  "match": [
                      {
                          "host": [
                              "*.sahil1.me",
                              "*.*.sahil1.me",
                              "*.*.*.sahil1.me",
                              "sahil1.me"
                          ]
                      }
                  ],
                  "terminal": true
              }
          ]
      }
  ],
  "match": [
      {
          "host": [
              "*.sahil1.me",
              "*.*.sahil1.me",
              "*.*.*.sahil1.me",
              "sahil1.me"
          ]
      }
  ],
  "terminal": true
},

The above described issue leads to foreign subdomain block in a given parent domain block.

One way around is I just issue sequential updates by acquiring global lock because for now I acquire lock for a specific domain before issuing updates. But i don’t feel like doing that considering the number of requests i might receive.

You lost me here. What is internalRedir exactly? What global lock are you talking about? And what exactly is the “operation”?

So this is the internalRedir : caddy/admin.go at bd17eb205d6ac464c64eb888a6f4b57445b6c59c · caddyserver/caddy · GitHub
which is used while handleConfigByID

By global lock i meant since update API for @id works in two phases

  1. reading raw path for the “id” value
  2. applying config updates for the raw path.

So there is a possibility of config update by other API in between these steps which implies for no blocking of other requests till the process is complete.

My operations involve adding/updating new domain/subdomain blocks. To achieve these i use a combination of PUT,PATCH and POST requests.

PATCH → when a given subdomain block exists and i have to update it
PUT → when i have to add a new parent domain block in routes array or when i have to add a new subdomain block at a given index inside an existing parent domain block.
POST → when i have add a subdomain block at the end of an existing parent domain block

Hi @matt, Any updates on this? What should be the intended flow for API updates using @id mechanism?

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