PS. Have you seen Caddy's on-line config API? https://caddyserver.com/docs/api
PS. Have you seen Caddy's on-line config API? https://caddyserver.com/docs/api
When people say "production", they mean things like "QoS for a shared-multitenant system, in the presence of customers with really badly tuned and spiky request workloads, whose traffic you must nevertheless mostly accept."
> QoS for a shared-multitenant system, in the presence of customers with really badly tuned and spiky request workloads, whose traffic you must nevertheless mostly accept.
Yah, we see that sometimes. Caddy usually handles it fine, sometimes with a bit of massaging the config.
It would be great if you would like to finish the work on this project and make it part of the Caddy default distribution.
Honestly I do not understand how people run high-traffic sites without rate limiting. [D]DOS attacks and other misuse (e.g. spambots etc.) are daily issues on the internet, do you just ignore that?
https://news.ycombinator.com/item?id=31439457
Appreciative of all the work regarding caddy, but the rate limiting seems to be chicken and egg, as few people seem to be willing to test it out in order for it to be accepted into core, and people are unwilling to test it out, because it's not in core.
It's also a blocker for me, so nginx wins by force of inertia.
I keep telling people "tens of thousands" when I probably should be saying "hundreds of thousands"...
How do you know how many requests are silently lost?
I would like to read more about how reliability is actually measured on high-traffic sites.
1) Nginx configs are (from my experience) easier to template (in our Nomad & Consul cluster architecture) 2) From what I could gather, Nginx is more stable and performant 3) I don’t trust Caddy’s codebase security. It simply has too many dependencies, and Go makes it very easy to get into dependency hell
Honestly if 3) wouldn’t be an issue, and stability from 2) would be proven, I would probably give Caddy a try in production.
I host some stuff at home and moving from nginx to Caddy v1 was a huge breath of fresh air. V2 made the product extremely good.
I tried a bit to use the API to automate my deployments (which are, again, home deployments) but it stopped to make sense when i discovered that Caddy has the ability to read config files via wildcards.
Pro tip: Did you know you can use any config format you want to configure Caddy [1]? So if templating the Caddyfile is hard for you, use something else! You can use YAML, TOML, or even NGINX configs.
On 2, that's been pretty well debunked at this point. Caddy is written in Go, and is only a very thin wrapper over the Go standard library, which heartily powers much of Cloudflare's, Netflix's, and Google's infrastructure. Plus you gain memory safety and are exempt from a whole class of vulnerabilities with Caddy. We've seen numerous instances where Caddy has kept sites up while nginx let other sites go down, due to Caddy's resilience in the face of certificate problems, for example.
On 3, sure, I can understand that -- but this is true of any open source project. And it IS open source, so you can "own" your own code base. You're in control. And actually, Go's module proxy protects Go projects more than most C projects. Caddy's extensible architecture means that you can add all the features you need without bloating the code base.
I think the ACME integration in Caddy was a really smart move, it's great to see some competition.
To be fair, that was several years ago. But can you explain the logic behind that decision?
I use it with ansible for 18 months with no issue
> dns.providers.azure wraps the provider implementation as a Caddy module.
Well great what does the provider implementation do? It’s the same for all DNS and not so useful if I’m coming from Apache or Nginx. At least explain what I’ll be able to do with this module.
From http.handlers.push:
> http.handlers.push is a middleware for manipulating the request body.
That’s a bit generic - any examples? There’s a lot of ways to modify the request body so what can I do with this?
There are 2 http.authentication.providers.jwt - both unofficial and both with 0 documentation. There has to be some standards here, why link to blank docs from your site?
All-in-all it just feels meh. I like to read docs that’ll give me the technical ins and outs of every function with some examples ideally.
Microsoft does a decent job of this as does Postgres (and others but these two come to mind immediately). Envoy is pretty nice here too and Nginx close.
Re "http.handlers.push", fair point, that one's lacking/misleading. But this is a feature that was just added to satisfy a specific need, then fell by the wayside. Mostly because now Chrome is removing support for Server Push, so we'll need to deprecate this feature, in favor of HTTP 103 Early Hints which is the effective replacement for it.
Also, in general, we tend to spend more effort on maintaining the Caddyfile docs than the JSON docs, because the large majority of users use the Caddyfile. See https://caddyserver.com/docs/caddyfile/directives/push for the push handler, complete with examples.
Re "http.authentication.providers.jwt", well again, I think that's an issue with the module's maintainer not sufficiently using godoc comments. The maintainer registered the module under two different module paths (renamed repo) so it caused a duplicate. We'll need to manually remove the duplicate from the database, I think. It might be because there's conflicting ones that no docs are shown (cause the backend which serves the API docs is confused, I dunno, it's a bug clearly, will need to dig deeper).
Useful for example for staging environments, whitelisted from certain ips, but allowing access via user-name/password from other IPs and/or the Internet.
@needsAuth not remote_ip private_ranges
basicauth @needsAuth {
user pass
}
This uses a named matcher[0] `@needsAuth` with the `not` and `remote_ip` matchers, to match all public IP ranges (change `private_ranges` to a list of CIDRs if you prefer), then applies that request matcher to the `basicauth` handler[1], and pass in user/pass pairs to it (passwords are bcrypt hashed).If the user fails authentication, then they won't be able to get in, as you'd expect. But users inside your allowed IP ranges will get through without basicauth.
[0]: https://caddyserver.com/docs/caddyfile/matchers
[1]: https://caddyserver.com/docs/caddyfile/directives/basicauth
log_format main '$remote_addr - - [$time_local] "$request" '
'$status $body_bytes_sent "$host" '
'"$http_user_agent" $http_content_length $request_time '
'"$resp_body" *$connection $connection_requests';
server {
set $resp_body "";
location ~ "^/api/v1/...$" {
# Append response to resp_body until it reaches max_len.
# - ngx.arg[1] is input chunk.
# - ngx.arg[2] is eof flag (response is done).
# - ngx.ctx.resp_body holds partial result between calls
# - ngx.var.resp_body holds final result.
# From:
# - https://gist.github.com/morhekil/1ff0e902ed4de2adcb7a
# - https://github.com/openresty/lua-nginx-module/
body_filter_by_lua_block {
local max_len = 256
local resp_body = (ngx.ctx.resp_body or "")
if string.len(resp_body) <= max_len then
resp_body = resp_body .. string.sub(ngx.arg[1], 1, max_len)
ngx.ctx.resp_body = string.sub(resp_body, 1, max_len)
end
if ngx.arg[2] then
ngx.var.resp_body = ngx.ctx.resp_body
end
}
}
But there are many scenarios where being able to extend the HTTP server via Lua is more convenient than writing a plugin I would think?I've also used Lua in the past with haproxy and with Redis. It's a powerful, performant, light-weight, and flexible escape hatch/extension mechanism.
Well, Caddy is written in Go, so it's only natural to write a plugin in Go. Statically compiled into your binary. We provide a tool called `xcaddy` which is used to produce builds of Caddy with any plugins you need. You just need Go installed on your system to run it, no other dependencies.
The reason why Lua is used for OpenResty is because writing plugins in C is... not fun.
You can absolutely do what you described with an HTTP handler module in Caddy. You'd just wrap the req.Body with a reader that watches the bytes as they're copied through the stream, and when you see the part you want to log, you do that.
We have a replace-response plugin which takes a similar approach, except it manipulates the response as it's being streamed back to the client. https://github.com/caddyserver/replace-response The whole plugin is just one file of Go code.