1. The problem I’m having:
Caddy is used as a drop-in TLS proxy for a web service, which was previously running its own HTTPS server. It is configured to use automatic renewal of certificates, but also provided a custom certificate, so it has a valid one on first start.
For service switchover, the DNS A record is changed from the old server to the new deployment. This works without problems. Caddy picks up the custom cert and it is visible in the web browser.
From the logs, I can see that the automatic cert has been created too. It can be downloaded from the cert storage and checks out.
My question is, what will happen when the custom cert expires? Will Caddy pick up and deliver the new cert on-the-fly?
I have already read the documentation and searched this forum and the web for a conclusive answer. I think the more general questions to this issue are:
- What is the expected/actual behavior of using a global
auto_https ignore_loaded_certs
with a custom cert per site? Does Caddy keep a list of certs per site and switch to another if one expires? - Is there a recommended procedure to use Caddy as a TLS proxy with automatic cert renewal but still have zero downtime when it goes live? I suppose with the DNS challenge Caddy could request a new cert before it is assigned its designated domain name, but this has some downsides I’d like to avoid.
2. Error messages and/or full log output:
Here is part of the full log since the last restart (minus health check messages).
{"level":"info","ts":1723465295.0529082,"logger":"tls.cache.maintenance","msg":"started background certificate maintenance","cache":"0xc00021d100"}
{"level":"info","ts":1723465295.2162435,"logger":"http.auto_https","msg":"enabling automatic HTTP->HTTPS redirects","server_name":"srv0"}
{"level":"info","ts":1723465295.2285855,"logger":"http.log","msg":"server running","name":"remaining_auto_https_redirects","protocols":["h1","h2","h3"]}
{"level":"info","ts":1723465295.2295237,"logger":"http","msg":"enabling HTTP/3 listener","addr":":443"}
{"level":"info","ts":1723465295.2398233,"logger":"http.handlers.reverse_proxy.health_checker.active","msg":"HTTP request failed","host":"localhost:8080","error":"Get \"http://localhost:8080/ping\": dial tcp 127.0.0.1:8080: connect: connection refused"}
{"level":"info","ts":1723465295.2399693,"logger":"http.handlers.reverse_proxy.health_checker.active","msg":"HTTP request failed","host":"localhost:8080","error":"Get \"http://localhost:8080/ping\": dial tcp 127.0.0.1:8080: connect: connection refused"}
{"level":"info","ts":1723465295.2401812,"logger":"http.log","msg":"server running","name":"srv0","protocols":["h1","h2","h3"]}
{"level":"info","ts":1723465295.2402072,"logger":"http","msg":"enabling automatic TLS certificate management","domains":["prod.example.com","test.example.com"]}
{"level":"info","ts":1723465295.3985739,"logger":"tls","msg":"storage cleaning happened too recently; skipping for now","storage":"FileStorage:/data/caddy","instance":"62949b15-1235-4147-89ec-9fe53aa77551","try_again":1723551695.3985674,"try_again_in":86399.9999981}
{"level":"info","ts":1723465295.409549,"logger":"tls.obtain","msg":"acquiring lock","identifier":"prod.example.com"}
{"level":"info","ts":1723465295.4095747,"logger":"tls","msg":"finished cleaning storage units"}
{"level":"info","ts":1723465295.4694626,"logger":"tls.obtain","msg":"lock acquired","identifier":"prod.example.com"}
{"level":"info","ts":1723465295.4697268,"logger":"tls.obtain","msg":"obtaining certificate","identifier":"prod.example.com"}
{"level":"info","ts":1723465295.6137,"logger":"http","msg":"waiting on internal rate limiter","identifiers":["prod.example.com"],"ca":"https://acme-v02.api.letsencrypt.org/directory","account":""}
{"level":"info","ts":1723465295.6137733,"logger":"http","msg":"done waiting on internal rate limiter","identifiers":["prod.example.com"],"ca":"https://acme-v02.api.letsencrypt.org/directory","account":""}
{"level":"info","ts":1723465295.6137993,"logger":"http","msg":"using ACME account","account_id":"https://acme-v02.api.letsencrypt.org/acme/acct/1883892876","account_contact":[]}
{"level":"info","ts":1723465296.5240521,"logger":"http.acme_client","msg":"trying to solve challenge","identifier":"prod.example.com","challenge_type":"tls-alpn-01","ca":"https://acme-v02.api.letsencrypt.org/directory"}
{"level":"error","ts":1723465297.5014439,"logger":"http.acme_client","msg":"challenge failed","identifier":"prod.example.com","challenge_type":"tls-alpn-01","problem":{"type":"urn:ietf:params:acme:error:unauthorized","title":"","detail":"Cannot negotiate ALPN protocol \"acme-tls/1\" for tls-alpn-01 challenge","instance":"","subproblems":[]}}
{"level":"error","ts":1723465297.5016065,"logger":"http.acme_client","msg":"validating authorization","identifier":"prod.example.com","problem":{"type":"urn:ietf:params:acme:error:unauthorized","title":"","detail":"Cannot negotiate ALPN protocol \"acme-tls/1\" for tls-alpn-01 challenge","instance":"","subproblems":[]},"order":"https://acme-v02.api.letsencrypt.org/acme/order/1883892876/295629792376","attempt":1,"max_attempts":3}
{"level":"info","ts":1723465298.900897,"logger":"http.acme_client","msg":"trying to solve challenge","identifier":"prod.example.com","challenge_type":"http-01","ca":"https://acme-v02.api.letsencrypt.org/directory"}
{"level":"error","ts":1723465309.5895202,"logger":"http.acme_client","msg":"challenge failed","identifier":"prod.example.com","challenge_type":"http-01","problem":{"type":"urn:ietf:params:acme:error:connection","title":"","detail":"20.4.144.254: Fetching http://prod.example.com/.well-known/acme-challenge/1KP-Am0zS7_hDzZhTJ-Ho5pfyY0J5hFXqWqcxfg_UFc: Timeout during connect (likely firewall problem)","instance":"","subproblems":[]}}
{"level":"error","ts":1723465309.5909123,"logger":"http.acme_client","msg":"validating authorization","identifier":"prod.example.com","problem":{"type":"urn:ietf:params:acme:error:connection","title":"","detail":"20.4.144.254: Fetching http://prod.example.com/.well-known/acme-challenge/1KP-Am0zS7_hDzZhTJ-Ho5pfyY0J5hFXqWqcxfg_UFc: Timeout during connect (likely firewall problem)","instance":"","subproblems":[]},"order":"https://acme-v02.api.letsencrypt.org/acme/order/1883892876/295629798906","attempt":2,"max_attempts":3}
{"level":"error","ts":1723465309.5910184,"logger":"tls.obtain","msg":"could not get certificate from issuer","identifier":"prod.example.com","issuer":"acme-v02.api.letsencrypt.org-directory","error":"HTTP 400 urn:ietf:params:acme:error:connection - 20.4.144.254: Fetching http://prod.example.com/.well-known/acme-challenge/1KP-Am0zS7_hDzZhTJ-Ho5pfyY0J5hFXqWqcxfg_UFc: Timeout during connect (likely firewall problem)"}
{"level":"error","ts":1723465309.5912375,"logger":"tls.obtain","msg":"will retry","error":"[prod.example.com] Obtain: [prod.example.com] solving challenge: prod.example.com: [prod.example.com] authorization failed: HTTP 400 urn:ietf:params:acme:error:connection - 20.4.144.254: Fetching http://prod.example.com/.well-known/acme-challenge/1KP-Am0zS7_hDzZhTJ-Ho5pfyY0J5hFXqWqcxfg_UFc: Timeout during connect (likely firewall problem) (ca=https://acme-v02.api.letsencrypt.org/directory)","attempt":1,"retrying_in":60,"elapsed":14.121656495,"max_duration":2592000}
{"level":"info","ts":1723465369.6090128,"logger":"tls.obtain","msg":"obtaining certificate","identifier":"prod.example.com"}
{"level":"info","ts":1723465369.7944353,"logger":"http","msg":"using ACME account","account_id":"https://acme-staging-v02.api.letsencrypt.org/acme/acct/158898753","account_contact":[]}
{"level":"info","ts":1723465370.694774,"logger":"http.acme_client","msg":"trying to solve challenge","identifier":"prod.example.com","challenge_type":"http-01","ca":"https://acme-staging-v02.api.letsencrypt.org/directory"}
{"level":"error","ts":1723465381.584563,"logger":"http.acme_client","msg":"challenge failed","identifier":"prod.example.com","challenge_type":"http-01","problem":{"type":"urn:ietf:params:acme:error:connection","title":"","detail":"20.4.144.254: Fetching http://prod.example.com/.well-known/acme-challenge/eYKdSh_P_SZnzRXccVhQTg4JgjIjx-UqoD7uIKzCCiA: Timeout during connect (likely firewall problem)","instance":"","subproblems":[]}}
{"level":"error","ts":1723465381.5846756,"logger":"http.acme_client","msg":"validating authorization","identifier":"prod.example.com","problem":{"type":"urn:ietf:params:acme:error:connection","title":"","detail":"20.4.144.254: Fetching http://prod.example.com/.well-known/acme-challenge/eYKdSh_P_SZnzRXccVhQTg4JgjIjx-UqoD7uIKzCCiA: Timeout during connect (likely firewall problem)","instance":"","subproblems":[]},"order":"https://acme-staging-v02.api.letsencrypt.org/acme/order/158898753/18366061993","attempt":1,"max_attempts":3}
{"level":"info","ts":1723465382.921561,"logger":"http.acme_client","msg":"trying to solve challenge","identifier":"prod.example.com","challenge_type":"tls-alpn-01","ca":"https://acme-staging-v02.api.letsencrypt.org/directory"}
{"level":"error","ts":1723465383.9595618,"logger":"http.acme_client","msg":"challenge failed","identifier":"prod.example.com","challenge_type":"tls-alpn-01","problem":{"type":"urn:ietf:params:acme:error:unauthorized","title":"","detail":"Cannot negotiate ALPN protocol \"acme-tls/1\" for tls-alpn-01 challenge","instance":"","subproblems":[]}}
{"level":"error","ts":1723465383.9597347,"logger":"http.acme_client","msg":"validating authorization","identifier":"prod.example.com","problem":{"type":"urn:ietf:params:acme:error:unauthorized","title":"","detail":"Cannot negotiate ALPN protocol \"acme-tls/1\" for tls-alpn-01 challenge","instance":"","subproblems":[]},"order":"https://acme-staging-v02.api.letsencrypt.org/acme/order/158898753/18366064323","attempt":2,"max_attempts":3}
{"level":"error","ts":1723465383.959792,"logger":"tls.obtain","msg":"could not get certificate from issuer","identifier":"prod.example.com","issuer":"acme-v02.api.letsencrypt.org-directory","error":"HTTP 403 urn:ietf:params:acme:error:unauthorized - Cannot negotiate ALPN protocol \"acme-tls/1\" for tls-alpn-01 challenge"}
{"level":"error","ts":1723465383.961113,"logger":"tls.obtain","msg":"will retry","error":"[prod.example.com] Obtain: [prod.example.com] solving challenge: prod.example.com: [prod.example.com] authorization failed: HTTP 403 urn:ietf:params:acme:error:unauthorized - Cannot negotiate ALPN protocol \"acme-tls/1\" for tls-alpn-01 challenge (ca=https://acme-staging-v02.api.letsencrypt.org/directory)","attempt":2,"retrying_in":120,"elapsed":88.491520814,"max_duration":2592000}
{"level":"info","ts":1723465503.9794903,"logger":"tls.obtain","msg":"obtaining certificate","identifier":"prod.example.com"}
{"level":"info","ts":1723465504.2005625,"logger":"http","msg":"using ACME account","account_id":"https://acme-staging-v02.api.letsencrypt.org/acme/acct/158898753","account_contact":[]}
{"level":"info","ts":1723465504.6667373,"logger":"http.acme_client","msg":"trying to solve challenge","identifier":"prod.example.com","challenge_type":"http-01","ca":"https://acme-staging-v02.api.letsencrypt.org/directory"}
{"level":"error","ts":1723465515.5165007,"logger":"http.acme_client","msg":"challenge failed","identifier":"prod.example.com","challenge_type":"http-01","problem":{"type":"urn:ietf:params:acme:error:connection","title":"","detail":"20.4.144.254: Fetching http://prod.example.com/.well-known/acme-challenge/r8-meEJ96t4OrATyNokiYYtYN-sCf1aqnznLq9IIYEc: Timeout during connect (likely firewall problem)","instance":"","subproblems":[]}}
{"level":"error","ts":1723465515.5166357,"logger":"http.acme_client","msg":"validating authorization","identifier":"prod.example.com","problem":{"type":"urn:ietf:params:acme:error:connection","title":"","detail":"20.4.144.254: Fetching http://prod.example.com/.well-known/acme-challenge/r8-meEJ96t4OrATyNokiYYtYN-sCf1aqnznLq9IIYEc: Timeout during connect (likely firewall problem)","instance":"","subproblems":[]},"order":"https://acme-staging-v02.api.letsencrypt.org/acme/order/158898753/18366090373","attempt":1,"max_attempts":3}
{"level":"info","ts":1723465516.8350718,"logger":"http.acme_client","msg":"trying to solve challenge","identifier":"prod.example.com","challenge_type":"tls-alpn-01","ca":"https://acme-staging-v02.api.letsencrypt.org/directory"}
{"level":"error","ts":1723465517.866599,"logger":"http.acme_client","msg":"challenge failed","identifier":"prod.example.com","challenge_type":"tls-alpn-01","problem":{"type":"urn:ietf:params:acme:error:unauthorized","title":"","detail":"Cannot negotiate ALPN protocol \"acme-tls/1\" for tls-alpn-01 challenge","instance":"","subproblems":[]}}
[...]
{"level":"info","ts":1724357372.7809446,"logger":"tls.obtain","msg":"obtaining certificate","identifier":"prod.example.com"}
{"level":"info","ts":1724357372.9168098,"logger":"http","msg":"using ACME account","account_id":"https://acme-staging-v02.api.letsencrypt.org/acme/acct/158898753","account_contact":[]}
{"level":"info","ts":1724357373.6754532,"logger":"http.acme_client","msg":"trying to solve challenge","identifier":"prod.example.com","challenge_type":"tls-alpn-01","ca":"https://acme-staging-v02.api.letsencrypt.org/directory"}
{"level":"error","ts":1724357374.6854925,"logger":"http.acme_client","msg":"challenge failed","identifier":"prod.example.com","challenge_type":"tls-alpn-01","problem":{"type":"urn:ietf:params:acme:error:unauthorized","title":"","detail":"Cannot negotiate ALPN protocol \"acme-tls/1\" for tls-alpn-01 challenge","instance":"","subproblems":[]}}
{"level":"error","ts":1724357374.6856935,"logger":"http.acme_client","msg":"validating authorization","identifier":"prod.example.com","problem":{"type":"urn:ietf:params:acme:error:unauthorized","title":"","detail":"Cannot negotiate ALPN protocol \"acme-tls/1\" for tls-alpn-01 challenge","instance":"","subproblems":[]},"order":"https://acme-staging-v02.api.letsencrypt.org/acme/order/158898753/18578202803","attempt":1,"max_attempts":3}
{"level":"info","ts":1724357376.038395,"logger":"http.acme_client","msg":"trying to solve challenge","identifier":"prod.example.com","challenge_type":"http-01","ca":"https://acme-staging-v02.api.letsencrypt.org/directory"}
{"level":"error","ts":1724357386.8997538,"logger":"http.acme_client","msg":"challenge failed","identifier":"prod.example.com","challenge_type":"http-01","problem":{"type":"urn:ietf:params:acme:error:connection","title":"","detail":"20.4.247.5: Fetching http://prod.example.com/.well-known/acme-challenge/CU388W6wMlFMQBcmzprGXqtwAPSR4DPXyp3Z6gbcy7s: Timeout during connect (likely firewall problem)","instance":"","subproblems":[]}}
{"level":"error","ts":1724357386.899984,"logger":"http.acme_client","msg":"validating authorization","identifier":"prod.example.com","problem":{"type":"urn:ietf:params:acme:error:connection","title":"","detail":"20.4.247.5: Fetching http://prod.example.com/.well-known/acme-challenge/CU388W6wMlFMQBcmzprGXqtwAPSR4DPXyp3Z6gbcy7s: Timeout during connect (likely firewall problem)","instance":"","subproblems":[]},"order":"https://acme-staging-v02.api.letsencrypt.org/acme/order/158898753/18578203243","attempt":2,"max_attempts":3}
{"level":"error","ts":1724357386.9000409,"logger":"tls.obtain","msg":"could not get certificate from issuer","identifier":"prod.example.com","issuer":"acme-v02.api.letsencrypt.org-directory","error":"HTTP 400 urn:ietf:params:acme:error:connection - 20.4.247.5: Fetching http://prod.example.com/.well-known/acme-challenge/CU388W6wMlFMQBcmzprGXqtwAPSR4DPXyp3Z6gbcy7s: Timeout during connect (likely firewall problem)"}
{"level":"error","ts":1724357386.9001331,"logger":"tls.obtain","msg":"will retry","error":"[prod.example.com] Obtain: [prod.example.com] solving challenge: prod.example.com: [prod.example.com] authorization failed: HTTP 400 urn:ietf:params:acme:error:connection - 20.4.247.5: Fetching http://prod.example.com/.well-known/acme-challenge/CU388W6wMlFMQBcmzprGXqtwAPSR4DPXyp3Z6gbcy7s: Timeout during connect (likely firewall problem) (ca=https://acme-staging-v02.api.letsencrypt.org/directory)","attempt":5,"retrying_in":600,"elapsed":672.013475418,"max_duration":2592000}
{"level":"info","ts":1724357986.9134827,"logger":"tls.obtain","msg":"obtaining certificate","identifier":"prod.example.com"}
{"level":"info","ts":1724357987.0888367,"logger":"http","msg":"using ACME account","account_id":"https://acme-staging-v02.api.letsencrypt.org/acme/acct/158898753","account_contact":[]}
{"level":"info","ts":1724357987.9418023,"logger":"http.acme_client","msg":"trying to solve challenge","identifier":"prod.example.com","challenge_type":"tls-alpn-01","ca":"https://acme-staging-v02.api.letsencrypt.org/directory"}
{"level":"info","ts":1724357988.646631,"logger":"tls","msg":"served key authentication certificate","server_name":"prod.example.com","challenge":"tls-alpn-01","remote":"10.92.0.26:53605","distributed":false}
{"level":"info","ts":1724357989.1863937,"logger":"tls","msg":"served key authentication certificate","server_name":"prod.example.com","challenge":"tls-alpn-01","remote":"10.92.0.24:58715","distributed":false}
{"level":"info","ts":1724357989.2366307,"logger":"tls","msg":"served key authentication certificate","server_name":"prod.example.com","challenge":"tls-alpn-01","remote":"10.92.0.26:53609","distributed":false}
{"level":"info","ts":1724357989.3482773,"logger":"tls","msg":"served key authentication certificate","server_name":"prod.example.com","challenge":"tls-alpn-01","remote":"10.92.0.26:53610","distributed":false}
{"level":"info","ts":1724357989.424147,"logger":"tls","msg":"served key authentication certificate","server_name":"prod.example.com","challenge":"tls-alpn-01","remote":"10.92.0.24:58716","distributed":false}
{"level":"info","ts":1724357989.8467963,"logger":"http.acme_client","msg":"authorization finalized","identifier":"prod.example.com","authz_status":"valid"}
{"level":"info","ts":1724357989.8468966,"logger":"http.acme_client","msg":"validations succeeded; finalizing order","order":"https://acme-staging-v02.api.letsencrypt.org/acme/order/158898753/18578365693"}
{"level":"info","ts":1724357993.528086,"logger":"http.acme_client","msg":"got renewal info","names":["prod.example.com"],"window_start":1729453248.3333333,"window_end":1729626048.3333333,"selected_time":1729513609,"recheck_after":1724379593.5280771,"explanation_url":""}
{"level":"info","ts":1724357993.8590724,"logger":"http.acme_client","msg":"got renewal info","names":["prod.example.com"],"window_start":1729453248.3333333,"window_end":1729626048.3333333,"selected_time":1729508927,"recheck_after":1724379593.8590658,"explanation_url":""}
{"level":"info","ts":1724357993.8591976,"logger":"http.acme_client","msg":"successfully downloaded available certificate chains","count":2,"first_url":"https://acme-staging-v02.api.letsencrypt.org/acme/cert/2bcb230c4e863dc9a768b1d7f6fd2edd657e"}
{"level":"info","ts":1724357993.9236412,"logger":"http","msg":"waiting on internal rate limiter","identifiers":["prod.example.com"],"ca":"https://acme-v02.api.letsencrypt.org/directory","account":""}
{"level":"info","ts":1724357993.9237194,"logger":"http","msg":"done waiting on internal rate limiter","identifiers":["prod.example.com"],"ca":"https://acme-v02.api.letsencrypt.org/directory","account":""}
{"level":"info","ts":1724357993.9237547,"logger":"http","msg":"using ACME account","account_id":"https://acme-v02.api.letsencrypt.org/acme/acct/1883892876","account_contact":[]}
{"level":"info","ts":1724357994.810976,"logger":"http.acme_client","msg":"trying to solve challenge","identifier":"prod.example.com","challenge_type":"tls-alpn-01","ca":"https://acme-v02.api.letsencrypt.org/directory"}
{"level":"info","ts":1724357995.4973617,"logger":"tls","msg":"served key authentication certificate","server_name":"prod.example.com","challenge":"tls-alpn-01","remote":"10.92.0.26:53634","distributed":false}
{"level":"info","ts":1724357996.1374078,"logger":"tls","msg":"served key authentication certificate","server_name":"prod.example.com","challenge":"tls-alpn-01","remote":"10.92.0.26:53637","distributed":false}
{"level":"info","ts":1724357996.2003682,"logger":"tls","msg":"served key authentication certificate","server_name":"prod.example.com","challenge":"tls-alpn-01","remote":"10.92.0.26:53638","distributed":false}
{"level":"info","ts":1724357996.3524294,"logger":"tls","msg":"served key authentication certificate","server_name":"prod.example.com","challenge":"tls-alpn-01","remote":"10.92.0.26:53640","distributed":false}
{"level":"info","ts":1724357996.4743264,"logger":"tls","msg":"served key authentication certificate","server_name":"prod.example.com","challenge":"tls-alpn-01","remote":"10.92.0.26:53642","distributed":false}
{"level":"info","ts":1724357997.0896807,"logger":"http.acme_client","msg":"authorization finalized","identifier":"prod.example.com","authz_status":"valid"}
{"level":"info","ts":1724357997.0898,"logger":"http.acme_client","msg":"validations succeeded; finalizing order","order":"https://acme-v02.api.letsencrypt.org/acme/order/1883892876/298565966576"}
{"level":"info","ts":1724357998.4080057,"logger":"http.acme_client","msg":"got renewal info","names":["prod.example.com"],"window_start":1729453256,"window_end":1729626056,"selected_time":1729480303,"recheck_after":1724379598.4079993,"explanation_url":""}
{"level":"info","ts":1724357998.7498388,"logger":"http.acme_client","msg":"got renewal info","names":["prod.example.com"],"window_start":1729453256,"window_end":1729626056,"selected_time":1729585291,"recheck_after":1724379598.7498305,"explanation_url":""}
{"level":"info","ts":1724357998.7499456,"logger":"http.acme_client","msg":"successfully downloaded available certificate chains","count":2,"first_url":"https://acme-v02.api.letsencrypt.org/acme/cert/042906a14e9d8a413d4aa1ec5c2502287008"}
{"level":"info","ts":1724357998.9449778,"logger":"tls.obtain","msg":"certificate obtained successfully","identifier":"prod.example.com","issuer":"acme-v02.api.letsencrypt.org-directory"}
{"level":"info","ts":1724357998.9457204,"logger":"tls.obtain","msg":"releasing lock","identifier":"prod.example.com"}
3. Caddy version:
v2.8.4 h1:q3pe0wpBj1OcHFZ3n/1nl4V4bxBrYoSoab7rL9BMYNk=
4. How I installed and ran Caddy:
a. System environment:
Caddy and the web service are run from docker images as an Azure container group on Linux.
The container group is managed using Github workflows and Terraform as part of a blue/green deployment strategy.
b. Command:
See dockerfile below.
c. Service/unit/compose file:
The dockerfile to build the Caddy image for deployment:
FROM caddy:2.8-alpine
COPY config/caddy/Caddyfile /etc/caddy/
# add --environ flag for debugging
CMD ["caddy", "run", "--config", "/etc/caddy/Caddyfile", "--adapter", "caddyfile", "--environ"]
d. My complete Caddy config:
The relevant config sections:
{
auto_https ignore_loaded_certs
}
https://prod.example.com,
https://test.example.com {
tls /cert/cert.pem /cert/key.pem
@old_api {
method POST PUT
path /*
}
handle_path /* {
rewrite * /predictions/model
reverse_proxy @old_api http://localhost:8080 {
health_uri /ping
}
}
}