Writing a Caddy JSON config from scratch

Using JSON can be tedious but has numerous advantages, including the ability to easily generate and consume the structure in almost any programming language, fine-grained control via the API, and unparalleled flexibility that you don’t get with any config adapters. Chances are, if you’re trying to accomplish something that is difficult or complex with a config adapter, there is a more elegant solution in straight JSON.

First, become familiar with Caddy’s JSON structure.

:sparkles: I highly recommend installing an auto-completion helper into your editor. Install the caddy-json-schema plugin and then install the output of caddy json-schema into your editor for a streamlined experience.

An empty config looks like this and is totally valid (but does nothing):

{}

To be useful, you’ll want to start by declaring an “app” module. For example, the http app makes it easy to set up an HTTP server:

{
	"apps": {
		"http": {
			"servers": {
				"myserver": {
					"listen": [":80"]
				}
			}
		}
	}
}

This HTTP server only writes empty responses. To do something useful, create a route:

{
	"apps": {
		"http": {
			"servers": {
				"myserver": {
					"listen": [":80"],
					"routes": [
						{
							"handle": [{
								"handler": "file_server",
								"root": "/var/www"
							}]
						}
					]
				}
			}
		}
	}
}

That serves static files out of the /var/www folder.

To enable automatic HTTPS, all we need to do is specify a hostname at which we are serving the site (notice how we change the port here to the HTTPS port):

{
	"apps": {
		"http": {
			"servers": {
				"myserver": {
					"listen": [":443"],
					"routes": [
						{
							"match": [{"host": ["localhost"]}],
							"handle": [{
								"handler": "file_server",
								"root": "/var/www"
							}]
						}
					]
				}
			}
		}
	}
}

With that, Caddy will generate and renew a certificate for localhost and static files will only be served at that hostname.

That’s about all there is to it!

Bonus tips

  • Building up a config from scratch can be a rewarding experience. But, it’s not always necessary. You can often get “close enough” using an adapter of your choice like the Caddyfile or nginx config and then edit the resulting JSON to accomplish what you need.

  • Using a code editor with IntelliSense (i.e. intelligent code completion) features can be a big help, but especially when writing JSON Caddy configuration you will find caddy-json-schema incredibly useful. See this post for more info: Getting a better experience with JSON/YAML configuration

11 Likes

It would be useful to share JSON schema files right here for all major IDEs, so that we don’t have to install caddy-json-schema, would it be possible?

Another important thing is to plan to implement better error messages on JSON schema validation. I’m currently stuck with an error like this and it is not easy to act upon because it makes me guess instead of giving me exact information about what is wrong and how it can be fixed (marked with bold by me):

caddy_1 | run: loading initial config: loading new config: loading http app module: provision http: server nextjs: setting up route handlers: route 0: loading handler modules: position 0: loading module ‘reverse_proxy’: provision http.handlers.reverse_proxy: loading transport: json: cannot unmarshal string into Go value of type map[string]interface {}

It is better for everyone to generate their own schemas because Caddy plugins extend the JSON config structure, so my schema will not be your schema.

Makes sense, thanks for explaining. So, here are a few ideas:

  1. Make a publicly available URL that serves the schema like e.g. Google Fonts does, where a URL determines which plugins are included into JSON schema.

  2. Because not everyone is using Caddy with plugins (and even when someone does, they can still start plain and add plugins later), it would still be useful to have by-url publicly available JSON schemas for the plain no-plugins version of Caddy.

  3. You can also consider publishing the schemas to the json schema store.

WebStorm can download schemas automatically. I guess other IDEs can do the same. So… after encountering the error, that’s the first thing I intuitively wanted to do - to download the schema and make my IDE use it. But it turned out to be more involving than just feeding a URL to the IDE. So this is a great point to improve the user experience, especially onboarding for those who are new to Caddy.

Can be considered a feature request, or a UX improvement request, or both. Hope it makes sense.

1 Like