Dynamically Adding New Domains With Unique Root using API

1. Caddy version (caddy version):

v2.3.0 h1:fnrqJLa3G5vfxcxmOH/+kJOcunPLhSBnjgIvjXV/QTA=

2. How I run Caddy:

a. System environment:

Unix - Debian

b. Command:

caddy start

c. Service/unit/compose file:

paste full file contents here

d. My complete Caddyfile or JSON config:

ma4b.com {
	root * /home/jimcook/ma4b/builder
	encode zstd gzip
	file_server
	php_fastcgi unix//run/php/php7.3-fpm.sock
}

builder.ma4b.com {
	root * /home/jimcook/ma4b/builder
	encode zstd gzip
	file_server {
		index sb.php
	}
	php_fastcgi unix//run/php/php7.3-fpm.sock
	log {
		output file /home/jimcook/ma4b/logs/builder_access.log
	}
}

web.ma4b.com {
	root * /home/jimcook/ma4b/websites
	encode zstd gzip
	file_server {
		index index.html
	}
	php_fastcgi unix//run/php/php7.3-fpm.sock
	log {
		output file /home/jimcook/ma4b/logs/web_access.log
	}
}

new.ma4b.com {
	root * /home/jimcook/ma4b/websites/x5af/aw13
	encode zstd gzip
	file_server {
		index index.html
	}
	php_fastcgi unix//run/php/php7.3-fpm.sock
	log {
		output file /home/jimcook/ma4b/logs/web_access.log
	}
}

3. The problem I’m having:

(1) I feel like I am missing something as I think what I am trying to do should be simple. I simply want to dynamically add new domains with specific roots to my server using the caddy api and I am having a terrible time trying to figure out how to do it so I think I am not seeing the forest from the trees.

In the caddy file above, the last domain, new.ma4b.com is the pattern I want to add where the domain is anything new and the root will have a unique path. For example, adding a new domain xyz.com and a root path /home/ma4b/websites/a234/b324 . The other entries, encode, file_server, etc… are the same across all new entries.

(2) Is there a way to global those static entries like encode, file_server, etc… without having to specify them each time?

4. Error messages and/or full log output:

No error message… just don’t know where to start.

5. What I already tried:

I looked at the api command and when I have it display the config, it is a convoluted set of parameters and it seems like it would be crazy to have to specify all of those things in the API when it is so simple to add with the caddy file. Am I missing something?

6. Links to relevant resources:

None

It doesn’t quite make sense to use the Caddyfile if you plan on using the API for configuration.

Caddy’s actual config language is JSON, and the Caddyfile is an adapter which outputs JSON. It’s basically a UX layer to make Caddy easier to use for the majority of cases.

You can use the Caddyfile to give you a starting point for your JSON config though, and use the caddy adapt command to get the JSON for your Caddyfile.

In the Caddyfile, yes, you can use snippets:

But this is just glorified copy-paste at the Caddyfile adapter level. There’s no such re-use mechanism in the JSON config.

One approach you can take, which is easier to implement in JSON config (since there’s no real concept of “sites” in JSON, like there is in the Caddyfile, which can be limiting for certain usecases), is to use many host matchers which only change the root path, leaving the rest of the following handles the same. That seems to be the only thing that changes between your sites, if I’m reading correctly.

Another approach you could take, which may work for you, only using the Caddyfile, is to have a wildcard site block which then uses the subdomain as the directory for the site:

*.ma4b.com {
	root * /home/jimcook/ma4b/websites/{labels.2}
	...
}

This would mean for a site like foo.ma4b.com, it would set root to /home/jimcook/ma4b/websites/foo.

For this, you’d need to use On-Demand TLS, or wildcard certificates, and each have different implications.

1 Like

THANK YOU!!!

I was using a Caddyfile to get started and to show what I was trying to do. Your explanation helped me understand where I was not thinking correctly. THANK YOU. Just to be clear, if I wanted to add a new domain, I would need to add all of this:

{"handle":[{"handler":"subroute","routes":[{"handle":[{"handler":"vars","root":"/home/jimcook/ma4b/websites/test/new"},{"encodings":{"gzip":{},"zstd":{}},"handler":"encode"}]},{"handle":[{"handler":"static_response","headers":{"Location":["{http.request.uri.path}/"]},"status_code":308}],"match":[{"file":{"try_files":["{http.request.uri.path}/index.php"]},"not":[{"path":["*/"]}]}]},{"handle":[{"handler":"rewrite","uri":"{http.matchers.file.relative}"}],"match":[{"file":{"split_path":[".php"],"try_files":["{http.request.uri.path}","{http.request.uri.path}/index.php","index.php"]}}]},{"handle":[{"handler":"reverse_proxy","transport":{"protocol":"fastcgi","split_path":[".php"]},"upstreams":[{"dial":"unix//run/php/php7.3-fpm.sock"}]}],"match":[{"path":["*.php"]}]},{"handle":[{"handler":"file_server","hide":["./Caddyfile"],"index_names":["index.html"]}]}]}],"match":[{"host":["new.ma4b.com"]}],"terminal":true}

and not something smaller that only has a root and a host specified.

The @id feature will come in handy for easily removing and updating entries as needed.

The *.ma4b.com idea, may come in handy and be useful. Could I do something like:

* {
  root * /home/jimcook/ma4b/websites/{labels}
 }

for for a website xxx.com the directory would be /home/jimcook/ma4b/websites/xxx.com ?

You would need to use {host} in that case, {labels} is not a valid placeholder.

When I use “host”:"*" in the api, I get a browser error when navigating to the site. Like the server isn’t recogizing the url.

{"@id":"*","handle":[{"handler":"subroute","routes":[{"handle":[{"handler":"vars","root":"/home/jimcook/ma4b/websites/{host}"},{"encodings":{"gzip":{},"zstd":{}},"handler":"encode"}]},{"handle":[{"handler":"static_response","headers":{"Location":["{http.request.uri.path}/"]},"status_code":308}],"match":[{"file":{"try_files":["{http.request.uri.path}/index.php"]},"not":[{"path":["*/"]}]}]},{"handle":[{"handler":"rewrite","uri":"{http.matchers.file.relative}"}],"match":[{"file":{"split_path":[".php"],"try_files":["{http.request.uri.path}","{http.request.uri.path}/index.php","index.php"]}}]},{"handle":[{"handler":"reverse_proxy","transport":{"protocol":"fastcgi","split_path":[".php"]},"upstreams":[{"dial":"unix//run/php/php7.3-fpm.sock"}]}],"match":[{"path":["*.php"]}]},{"handle":[{"handler":"file_server","hide":["./Caddyfile"]}]}]}],"match":[{"host":["*"]}],"terminal":true}

When I use “host”:“new.ma4b.com” for the host, the {host} seems to be empty as it takes me to the directory above.

{"@id":"new.ma4b.com","handle":[{"handler":"subroute","routes":[{"handle":[{"handler":"vars","root":"/home/jimcook/ma4b/websites/{host}"},{"encodings":{"gzip":{},"zstd":{}},"handler":"encode"}]},{"handle":[{"handler":"static_response","headers":{"Location":["{http.request.uri.path}/"]},"status_code":308}],"match":[{"file":{"try_files":["{http.request.uri.path}/index.php"]},"not":[{"path":["*/"]}]}]},{"handle":[{"handler":"rewrite","uri":"{http.matchers.file.relative}"}],"match":[{"file":{"split_path":[".php"],"try_files":["{http.request.uri.path}","{http.request.uri.path}/index.php","index.php"]}}]},{"handle":[{"handler":"reverse_proxy","transport":{"protocol":"fastcgi","split_path":[".php"]},"upstreams":[{"dial":"unix//run/php/php7.3-fpm.sock"}]}],"match":[{"path":["*.php"]}]},{"handle":[{"handler":"file_server","hide":["./Caddyfile"]}]}]}],"match":[{"host":["new.ma4b.com"]}],"terminal":true}

{host} is a Caddyfile placeholder shortcut, as explained in the link above.

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