Caddy 2 is a whole new code base, written from scratch, to improve on Caddy 1. Caddy 2 is not backwards-compatible with Caddy 1. But don't worry, for most basic setups, not much is different. This guide will help you transition as easily as possible.
This guide won't delve into the new features available -- which are really cool, by the way, you should [learn them](https://caddyserver.com/docs/getting-started) -- the goal here is to just get you up and running on Caddy 2 quickly.
- "Caddy 2" is still just called `caddy`. We may use "Caddy 2" to clarify which version to make the transition less confusing.
- Most users will simply need to replace their `caddy` binary and their updated `Caddyfile` config (after testing that it works).
- It might be best to go into Caddy 2 with no assumptions carried over from Caddy 1.
- You might not be able to perfectly replicate your niche v1 configuration in v2. Usually, there's a good reason for that.
- The command line is no longer used for server configuration.
- Environment variables are no longer needed for configuration.
- The primary way to give Caddy 2 its configuration is through its [API](/docs/api), but the [`caddy` command](/docs/command-line) can also be used.
- You should know that Caddy 2's native configuration language is [JSON](/docs/json/), and the Caddyfile is just another [config adapter](/docs/config-adapters) that converts to JSON for you. Extremely custom/advanced use cases may require JSON, as not every possible configuration can be expressed by the Caddyfile.
- The Caddyfile is mostly the same, but also much more powerful; directives have changed.
## Steps
1. Get familiar with Caddy 2 by doing our [Getting Started](https://caddyserver.com/docs/getting-started) tutorial.
2. Do step 1 if you haven't yet. Seriously -- we can't stress how important it is to at least know how to use Caddy 2. (It's more fun!)
3. Use the guide below to transition your `caddy` command(s).
4. Use the guide below to transition your Caddyfile.
5. Test your new config locally or in staging.
6. Test, test, test again
7. Deploy and have fun!
## HTTPS and ports
Caddy's default port is no longer `:2015`. Caddy 2's default port is `:443` or, if no hostname/IP is known, port `:80`. You can always customize the ports in your config.
Caddy 2's default protocol is [_always_ HTTPS if a hostname or IP is known](/docs/automatic-https#overview). This is different from Caddy 1, where only public-looking domains used HTTPS by default. Now, _every_ site uses HTTPS (unless you disable it by explicitly specifying port `:80` or `http://`).
IP addresses and localhost domains will be issued certificates from a [locally-trusted, embedded CA](/docs/automatic-https#local-https). All other domains will use Let's Encrypt. (This is all configurable.)
The storage structure of certificates and ACME resources has changed. Caddy 2 will probably obtain new certificates for your sites; but if you have a lot of certificates you can migrate them manually if it does not do it for you. See issues [#2955](https://github.com/caddyserver/caddy/issues/2955) and [#3124](https://github.com/caddyserver/caddy/issues/3124) for details.
All command line flags are different. Remove them; all server config now exists within the actual config document (usually Caddyfile or JSON). You will probably find what you need in the [JSON structure](/docs/json/) or in the [Caddyfile global options](/docs/caddyfile/options) to replace most of the command line flags from v1.
A command like `caddy -conf ../Caddyfile` would become `caddy run --config ../Caddyfile`.
As before, if your Caddyfile is in the current folder, Caddy will find and use it automatically; you don't need to use the `--config` flag in that case.
Signals are mostly the same, except USR1 and USR2 are no longer supported. Use the [`caddy reload`](/docs/command-line#caddy-reload) command or the [API](/docs/api) instead to load new configuration.
Running `caddy` without any config used to run a simple file server. The equivalent in Caddy 2 is [`caddy file-server`](/docs/command-line#caddy-file-server).
Environment variables are no longer relevant, except for `HOME` (and, optionally, any `XDG_*` variables you set). The `CADDYPATH` is [replaced by OS conventions](/docs/conventions#file-locations).
## Caddyfile
The [v2 Caddyfile](/docs/caddyfile/concepts) is very similar to what you're already familiar with. The main thing you'll need to do is change your directives.
⚠️ **Be sure to read into the new directives!** Especially if your config is more advanced, there are many nuances to consider. These tips will get you mostly switched over pretty quickly, but please read the full documentation for each directive so you can understand the implications of the upgrade. And of course, always test your configs thoroughly before putting them into production.
- If you are serving static files, you will need to add a [`file_server` directive](/docs/caddyfile/directives/file_server), since Caddy 2 does not assume this by default. Caddy 2 does not sniff MIME by default, either, for security reasons; if a Content-Type is missing you may need to set the header yourself using the [header](/docs/caddyfile/directives/header) directive.
- In v1, you could only filter (or "match") directives by request path. In v2, [request matching](/docs/caddyfile/matchers) is much more powerful. Any v2 directives which add a middleware to the HTTP handler chain or which manipulate the HTTP request/response in any way take advantage of this new matching functionality. [Read more about v2 request matchers.](/docs/caddyfile/matchers) You'll need to know about them to make sense of the v2 Caddyfile.
- Although many [placeholders](/docs/conventions#placeholders) are the same, many have changed, and there are now [many new ones](/docs/modules/http#docs), including [shorthands for the Caddyfile](/docs/caddyfile/concepts#placeholders).
- Caddy 2 logs are all structured, and the default format is JSON. All log levels can simply go to the same log to be processed (but you can customize this if needed).
- Where you matched requests by path prefix in Caddy 1, path matching is now exact by default in Caddy 2. If you want to match a prefix like `/foo/`, you'll need `/foo/*` in Caddy 2.
⚠️ **Just because a v1 directive is missing from this page does not mean v2 can't do it!** Some v1 directives aren't needed, don't translate well, or are fulfilled other ways in v2. For some advanced customization, you may need to drop down to the JSON to get what you want. Explore [our documentation](/docs/caddyfile) to find what you need!
HTTP Basic Authentication is still configured with the [`basicauth`](/docs/caddyfile/directives/basicauth) directive. However, Caddy 2 configuration does not accept plaintext passwords. You must hash them, which the [`caddy hash-password`](/docs/command-line#caddy-hash-password) can help with.
Note that the `fastcgi` directive from v1 did a lot under the hood, including trying files on disk, rewriting requests, and even redirecting. The v2 `php_fastcgi` directive also does these things for you, but the docs give its [expanded form](/docs/caddyfile/directives/php_fastcgi#expanded-form) that you can modify if your requirements are different.
There is no `php` preset needed in v2, since the `php_fastcgi` directive assumes PHP by default. A line such as `php_fastcgi 127.0.0.1:9000 php` will cause the reverse proxy to think that there is a second backend called `php`, leading to connection errors.
Enables access logging; the [`log`](/docs/caddyfile/directives/log) directive can still be used in v2, but all logs are structured, encoded as JSON, by default.
Notable subdirective changes are `header_upstream` and `header_downstream` have become `header_up` and `header_down`, respectively; and load-balancing-related subdirectives are prefixed with `lb_`.
One other significant difference is that the v2 proxy passes all incoming headers thru by default (including the `Host` header) and sets the `X-Forwarded-For` header. In other words, v1's "transparent" mode is basically the default in v2 (but if you need other headers like X-Real-IP you have to set those yourself). You can still override/customize the `Host` header using the `header_up` subdirective.
Websocket proxying "just works" in v2; there is no need to "enable" websockets like in v1.
The `without` subdirective has been removed because [rewrite hacks](#rewrite) are no longer necessary in v2 thanks to improved matcher support.
[Unchanged](/docs/caddyfile/directives/redir), except for a few details about the optional status code argument. Most configs won't need to make any changes.
- **v1:** `redir https://example.com{uri}`
- **v2:** `redir https://example.com{uri}`
### rewrite
The semantics of request rewriting ("internal redirecting") has changed slightly. If you used a so-called "rewrite hack" in v1 as a way to match requests on something other than a simple path prefix, that is completely unnecessary in v2.
The [new `rewrite` directive](/docs/caddyfile/directives/rewrite) is very simple but very powerful, as most of its complexity is handled by [matchers](/docs/caddyfile/matchers) in v2:
Start by removing all rewrite hacks; turn them into [named matchers](/docs/caddyfile/concepts#named-matchers) instead. Evaluate each v1 `rewrite` to see if it's really needed in v2. Hint: A v1 Caddyfile that uses `rewrite` to add a path prefix and then `proxy` with `without` to remove that same prefix is a rewrite hack, and can be eliminated.
You may find the new [`route`](/docs/caddyfile/directives/route) and [`handle`](/docs/caddyfile/directives/handle) directives useful for having greater control over advanced routing logic.
[Unchanged](/docs/caddyfile/directives/root), but if your root path starts with `/`, you'll need to add a `*` matcher token to distinguish it from a [path matcher](/docs/caddyfile/concepts#path-matchers).
The overall syntax of the [`templates`](/docs/caddyfile/directives/templates) directive is unchanged, but the actual template actions/functions are different and much improved. For example, templates are capable of including files, rendering markdown, making internal sub-requests, parsing front matter, and more!
[See the docs](/docs/modules/http.handlers.templates) for details about the new functions.
- **v1:** `templates`
- **v2:** `templates`
### tls
The fundamentals of the [`tls`](/docs/caddyfile/directives/tls) directive have not changed, for example specifying your own cert and key:
- **v1:** `tls cert.pem key.pem`
- **v2:** `tls cert.pem key.pem`
But Caddy's [auto-HTTPS logic](/docs/automatic-https) _has_ changed, so be aware of that!
The cipher suite names have also changed.
A common configuration in Caddy 2 is to use `tls internal` to have it serve a locally-trusted certificate for a dev hostname that isn't `localhost` or an IP address.
If you need a custom service file, base it off of ours. It has been carefully tuned to what it is for good reasons! Be sure to customize yours if needed.
Plugins written for v1 are not automatically compatible with v2. Many v1 plugins are not even needed in v2. On the other hand, v2 is way more easily extensible and flexible than v1!
If you want to write a plugin for Caddy 2, [learn how to write a Caddy module](/docs/extending-caddy).
Caddy 2 does not (yet) have a public build server and interactive download page like v1 did. We're working on it. In the meantime, our [builder tool](https://github.com/caddyserver/xcaddy) may be helpful. It simply automates the instructions in Caddy's [main.go](https://github.com/caddyserver/caddy/blob/v2/cmd/caddy/main.go) file.
If you're struggling to get Caddy working, please take a look through our website for documentation first. Take time to try new things and understand what is going on - v2 is very different from v1 in a lot of ways (but it's also very familiar)!
If you still need assistance, please be a part of [our community](https://caddy.community)! You may find that helping others is the best way to help yourself, too.