Currently using Apache to serve static pages for ~40 different domains, from the same server, with moderate traffic, and, when a pattern is detected in the url the request is rather forwarded to a separate (Java) process (REST) to handle and respond.
The question is will this work with Caddy and if so, is it rather straight forward or very tricky (;.
Yes, Caddy will certainly work well for this. Writing a Caddy config file (Caddyfile) is really easy, I’d like to refer you to the official docs: Caddyfile Concepts — Caddy Documentation
Unlike Apache, you don’t have to have lots of configuration files - just one Caddyfile will do.
Since this is so easy to do with Caddy, I wrote a snippet you could use for each of your sites:
www.your-webapp.com {
handle /your-pattern-for-matching-java-rest-requests/* {
reverse_proxy localhost:3000 # (wherever your Java REST api is listening)
}
handle {
root /var/www/your-static-file-location/
file_server
}
}
This snippet implements two handle directives - the first to route Java REST api requests to your backend and the second, a ‘fallback’ route, to serve static files.
Hi Alex,
This sound great for me to work with now. Thank you.
From my early understanding, JSON config seems more flexible than Caddfile. Is that right?
I do a lot of work with xslt and can generate JSON … endlessly …,
So, although I typically prefer simple, I am willing to consider JSON config. That may well be a mistake, as I am trying to consider medium/long term set up with Caddy. Can Caddyfile be exported to a JSON equivalent?
In the mean time, I can try the Caddyfile first and report here in a little while.
Caddyfile lets you do 99% of everything, but has an easier to use and read syntax. The Caddyfile is an adapter that produces JSON config, and Caddy actually runs on the JSON config. But that’s largely just ran implementation detail.
Yes, with the caddy adapt -p command.
Using JSON config most often makes sense in automated/scripted setups where you plan to use Caddy’s config API to push config changes etc. Otherwise, you should certainly start with the Caddyfile.
can that be something like /abc/def/ghi/, where * is a wild card (protocol, domain, path, suffix, …), or similar?
That must be in the documentation … I need to look it up.
From your suggestion and some reading so far, I could have a Caddyfile like :
{
DEBUG
}
example.com www.example.com {
handle */xml/* {
reverse_proxy localhost:3000 # (wherever your Java REST api is listening)
}
handle {
root /var/www/html/library/hyperlib/com01/
file_server
}
}
In this initial attempt at conversion I left out ports (http/https), aliases, subdomains and log files. How does it seem?
I like the idea of integrated structured logs. currently, with Apache, each domain has its own logs, for access and error.
It can be a single file/database and JSON should work fine. Consumption processing will be through xml, BaseX (XML DB) is an option.
How should I set it up?
For subdomains, can I use a wild card like *.example.com in the site address list (instead of www.example.com in the example) if all subdomains would map to same directory, …?
Since I have about 40 domains to manage and they are not all the same, I am not looking for a structured way to do this. Any help or guidance is appreciated.
I did not find documentation on cross-porting (ex. from Apache). Please tell me if there is.
I am quite sure that snippets and placeholders are handy, but unsure how/when.
For the reverse_proxy, I did not change it yet and I am wondering if I am right in assuming that the token is a url that could correspond to a different computer/IP address?
The good news is that I am looking forward to diving into Caddy. after almost 30 years of Apache …
I still have work to do to setup the server/bridge/firewall, to get Caddy running, but I will, especially with your support.
This isn’t right – inline path matchers must start with /, otherwise you need to use a named matcher.
Seems fine I guess. I’d add a comma between your domains to make it visually stand out more that you have two domains there. But also do you really need www.? Should you just redirect one to the other so you don’t have two identical sites loaded from different subdomains?
Just add the log directive. With no options it writes them to stderr along with the rest of your runtime logs. Or configure it to write to a file. The docs cover all this.
Yes, but then you would need a wildcard cert which means you need to build Caddy with a DNS plugin to solve the ACME DNS challenge. This adds some complexity to your setup.
What do you mean by “structrured” in this case? I don’t understand this point.
Forget everything you know from other servers. Learn Caddy from scratch. The docs have everything you should need.
Yeah, only reach for them when you feel you need them. Depends what you want to do. Snippets can reduce config duplication, placeholders can allow dynamic behaviour (pulling bits of data from the request etc).
You mean the upstream address? Yes it’s the host:port of your upstream app at which Caddy will connect to send the request and get the response.
Here is my current Caddyfile, which I still can’t test bc of the work left to configure the system. I would very much appreciate your comments, especially when pointing my weaknesses, as I will work to fix them.
As for getting a better grip and structuring my setup, what I have done is build an application that reads the site properties and builds the Caddyfile.
The application can also obfuscate domain names and things.
The included Caddyfile is a result example (that takes less than 1/10 of a second to load, compile, obfuscate the config, as well as build the Caddyfile and save it.
It is easier to build, maintain, and evolve.
The domains in the obfuscated version (include here) exactly correspond to the domains I need to manage, only the names have changed.
As you recommended, all www. references are now redirections.
I have used some snippets, to try to ease reading, but now it is all generated anyway … I could have used another (stat), for static file service but the library and folder for the root directory change for each site. My app can handle it easy, but I was wandering how to do this with Caddy snippets.
Thank you for your time and kind support.
Regards.
That’s wrong, there’s no such thing as global. A global options block is a block with nothing in front of it, and must appear at the start. See the docs. Caddyfile Concepts — Caddy Documentation
Snippets don’t go inside the global options block, they’re separate top-level blocks.
You declared the snippet as dynamic, not dyn.
What’s this? That’s not a Caddy directive, not built-in anyway. You didn’t show you were building with plugins.
I am sorry for my mistake with your name.
It must have been too late for me.
I will fix the other mistakes in the Caddyfile (and generator).
I am learning Caddy, enjoying it so far.
When fixed I could include the xml property sheet that provides the parameters for generating the Caddyfile. There is a “static” snippet and it is invoking an inner “snippet” (stat) in the generator and there is probably a bug where I show the wrong name. Sorry for the confusion. Thanks for pointing it out. Similar mis-coding/understanding for the other items you highlighted.
Likewise the redirs for https://site04a.com/, https://site06a.com/, https://site11a.com/, https://site13a.com/, etc…
Every single individual site block that has identical routes to another site block can be combined with its counterparts into one site block with all of the applicable site labels.
Firstly, it can help readability to use commas between site addresses. site18.com, www.site18.com, site19.com, www.site19.com is easier on the eyes in my opinion than site18.com www.site18.com site19.com www.site19.com. This is of course entirely to personal preference and if you prefer it without them, it should function fine.
Secondly, handle serves two main functions: mutual exclusivity with other adjacent handle blocks, and to neatly contain a set of configuration under one matcher. Therefore if you have only one handle in a site block and you are not using it with a matcher, this stucture:
Thanks again as this his truly helping me get a grasp.
You are right about the human readability of adding the commas,
but I may refrain from that, mostly bc parsing is simpler, I process tons of token sequences so I am comfortable, nevertheless, you are right.
I have fixed the redundant “handle” with blank matcher. I am still unsure about the effective scope of “functionally simplified”.
In any case, I do feel much more comfortable with Caddyfile and configuring the Caddy webserver,
As I noted before, I first need to fix the network and firewall config …
I’ll be back.