Documentation
a project

Reverse proxy quick-start

This guide will show you how to get a production-ready reverse proxy with or without HTTPS up and running quickly.

Prerequisites:

  • Basic terminal / command line skills
  • caddy in your PATH
  • A running backend process to proxy to

This tutorial assumes that you have a backend HTTP service running at 127.0.0.1:9000. These commands are for Linux, but the same principles apply to other operating systems.

You can get a simple reverse proxy running without a config file, or you can use a config file for more flexibility and control.

Command line

To start a plaintext HTTP proxy from port 2080 to port 9000 on your machine:

caddy reverse-proxy --from :2080 --to :9000

Then try it:

curl -v 127.0.0.1:2080

The reverse-proxy command is intended for quick and easy reverse proxies. (You can use it in production if your requirements are simple.)

Caddyfile

In the current working directory, create a file called Caddyfile with these contents:

:2080

reverse_proxy :9000

That config file is roughly equivalent to the caddy reverse-proxy command above.

Then, from the same directory, run:

caddy run

Then try your proxy:

curl -v 127.0.0.1:2080

If you change the Caddyfile, make sure to reload Caddy.

This was a simple example. You can do a lot more with the reverse_proxy directive.

HTTPS from client to proxy

Caddy will serve your proxy over HTTPS automatically and by default if it knows the hostname (domain name). The caddy reverse-proxy command will default to localhost if you omit the --from flag, or you can replace the first line of your Caddyfile with the domain name of the proxy.

  • If you use localhost or any domain ending in .localhost, Caddy will use an auto-renewing self-signed certificate. The first time you do this, you may need to enter a password as Caddy attempts to install its CA's root certificate into your trust store.
  • If you use any other domain name, Caddy will attempt to get a publicly-trusted certificate; make sure your DNS records point to your machine and that ports 80 and 443 are open to the public and directed toward Caddy.

If you don't specify a port, Caddy defaults to 443 for HTTPS. In that case you will also need permission to bind to low ports. A couple ways to do this on Linux:

  • Run as root (e.g. sudo -E).
  • Or run sudo setcap cap_net_bind_service=+ep $(which caddy) to give Caddy this specific capability.

Here's the most basic caddy reverse-proxy command that gives you HTTPS:

caddy reverse-proxy --to :9000

Then try it:

curl -v https://localhost

You can customize the hostname using the --from flag:

caddy reverse-proxy --from example.com --to :9000

If you don't have permission to bind to low ports, you can proxy from a higher port:

caddy reverse-proxy --from example.com:8443 --to :9000

If you're using a Caddyfile, simply change the first line to your domain name, for example:

example.com

reverse_proxy :9000

HTTPS from proxy to backend

Caddy can also proxy using HTTPS between itself and the backend if the backend supports TLS. Just use https:// in your backend address:

caddy reverse-proxy --from :2080 --to https://localhost:9000

This requires that the backend's certificate is trusted by the system Caddy is running on. (Caddy doesn't trust self-signed certificates unless explicitly configured to do so.)

Of course, you can do HTTPS on both ends too:

caddy reverse-proxy --from example.com --to https://example.com:9000

This serves HTTPS from client to proxy, and from proxy to backend.

If the hostname you're proxying to is different than the one you're proxying from, you will need to use the --change-host-header flag:

caddy reverse-proxy \
	--from example.com \
	--to https://localhost:9000 \
	--change-host-header

By default, Caddy passes all HTTP headers through unchanged, including Host, and Caddy derives the TLS ServerName from the Host header. The --change-host-header resets the Host header to that of the backend so that the TLS handshake can complete successfully. In the example above, it would be changed from example.com to localhost:9000 (and localhost would be used in the TLS handshake).