# Use Caddy instead of NGINX as your reverse proxy

**URL:** https://meta.discourse.org/t/use-caddy-instead-of-nginx-as-your-reverse-proxy/54716
**Category:** Self-Hosting
**Tags:** how-to
**Created:** [December 23, 2016, 4:35pm UTC](https://meta.discourse.org/t/use-caddy-instead-of-nginx-as-your-reverse-proxy/54716 "2016-12-23T16:35:50Z")
**Posts on this page:** 20
**Page:** 1

<div class="post-metadata">

### Author: ![Discourse](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/discourse/32/148734_2.png) [@Discourse](https://meta.discourse.org/u/Discourse)
#### Post date: [December 23, 2016, 4:35pm UTC](https://meta.discourse.org/t/use-caddy-instead-of-nginx-as-your-reverse-proxy/54716/1 "2016-12-23T16:35:50Z")

</div>

![](https://global.discourse-cdn.com/meta/original/3X/2/9/29084cf4e1415d32ef08723b318e3030d719c9cb.png)

Here are some notes about how I got my test Discourse instance running with [Caddy Server](https://caddyserver.com/).

Cool stuff about Caddy:

- They [use Discourse](https://caddy.community/) 😄

- [Free SSL](https://caddyserver.com/docs/automatic-https) with Let’s Encrypt

- HTTP2 and [QUIC](https://www.chromium.org/quic) out of the box

- Easier to configure than nginx

Cons:

- Not as battle tested as apache, nginx and cia.

## How To

### Preparing Discourse

First, you need to apply this changes to your `app.yml`:

```bash
templates:
  - "templates/postgres.template.yml"
  - "templates/redis.template.yml"
  - "templates/web.template.yml"
  - "templates/web.ratelimited.template.yml"
  - "templates/web.socketed.template.yml" # <<<----- THIS IS NEW

## Leave these two commented out
# - "templates/web.ssl.template.yml"
# - "templates/web.letsencrypt.ssl.template.yml"

## Leave these two commented out 
expose:
# - "8080:80" # http
# - "443:443" # https

env:
  ## This should be commented out
  #LETSENCRYPT_ACCOUNT_EMAIL: mymail@gmail.com
  ## This is required to avoid mixed content warnings when behind a reverse proxy
  DISCOURSE_FORCE_HTTPS: true

```

### Preparing Caddy

In the spirit of Discourse, let’s put Caddy in a Docker image too 🐳

First prepare with:

```plaintext
mkdir -p /var/caddy/data /var/caddy/config
nano /var/caddy/Caddyfile

```

Add the following to the Caddyfile (using Caddy v2 syntax):

```bash
{
  email MYEMAILHERE@gmail.com
}

forum.example.com { # your domain here
  reverse_proxy unix//sock/nginx.http.sock
}

```

Save and exit.

### Let’s test

Now you need to rebuild Discourse:

```bash
cd /var/discourse
./launcher rebuild app

```

And then run Caddy:

```bash
docker run -d \
    -v /var/caddy/Caddyfile:/etc/caddy/Caddyfile \
    -v /var/caddy/data:/data \
    -v /var/caddy/config:/config \
    -v /var/discourse/shared/standalone:/sock \
    -p 80:80 -p 443:443 \
    -p 443:443/udp \
    --restart=always \
    --name caddy \
    caddy:latest

```

After all, your forum should be avaliable at your domain, using SSL + HTTP2 + QUIC. You can’t more hipster than that.

> Last edited by @pacharanero 2026-04-19T13:38:22Z
> 
> > **Check document**
> >
> > Perform check on document:

---

<div class="post-metadata">

### Author: ![mholt](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/mholt/32/120935_2.png) [@mholt](https://meta.discourse.org/u/mholt)
#### Post date: [December 23, 2016, 7:32pm UTC](https://meta.discourse.org/t/use-caddy-instead-of-nginx-as-your-reverse-proxy/54716/2 "2016-12-23T19:32:11Z")

</div>

I run Caddy’s Discourse forums with this Caddyfile and no container:

```plaintext
forum.caddyserver.com

timeouts off
proxy / localhost:8080 {
	transparent
}

```

I just set up Discourse ([with one easy tweak](https://github.com/caddyserver/examples/tree/master/discourse)) and ran Caddy on the host machine.

^ This setup _has_ been tested, and I can confirm it has been running with no glitches for months.

---

<div class="post-metadata">

### Author: ![Whitestrake](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/whitestrake/32/59617_2.png) [@Whitestrake](https://meta.discourse.org/u/Whitestrake)
#### Post date: [December 23, 2016, 9:36pm UTC](https://meta.discourse.org/t/use-caddy-instead-of-nginx-as-your-reverse-proxy/54716/3 "2016-12-23T21:36:54Z")

</div>

I like how you’ve proxied to the socket and left the ports unexposed.

Neat little guide that one can use as a guideline to easily incorporate their Discourse installation to an existing Caddy proxy, too. Cheers!

---

<div class="post-metadata">

### Author: ![RoldanLT](https://avatars.discourse-cdn.com/v4/letter/r/da6949/32.png) [@RoldanLT](https://meta.discourse.org/u/RoldanLT)
#### Post date: [June 5, 2017, 8:16pm UTC](https://meta.discourse.org/t/use-caddy-instead-of-nginx-as-your-reverse-proxy/54716/4 "2017-06-05T20:16:30Z")

</div>

> [@Falco](#):
>
> They use Discourse 😄

But using nginx, as I can see now.

---

<div class="post-metadata">

### Author: ![Falco](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/falco/32/179432_2.png) [@Falco](https://meta.discourse.org/u/Falco)
#### Post date: [June 5, 2017, 8:46pm UTC](https://meta.discourse.org/t/use-caddy-instead-of-nginx-as-your-reverse-proxy/54716/5 "2017-06-05T20:46:47Z")

</div>

> [@RoldanLT](#):
>
> > [@Falco](#):
> >
> > They use Discourse 😄
> 
> But using nginx, as I can see now.

Well, I have more than 1 Discourse install with Caddy in the front, but I didn’t bother to replace the `server` header and it still shows nginx. Can be the same. Or they are just using the simple Discourse install and have no need to run a reverse proxy at all in the front.

---

<div class="post-metadata">

### Author: ![pfaffman](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/pfaffman/32/120154_2.png) [@pfaffman](https://meta.discourse.org/u/pfaffman)
#### Post date: [June 5, 2017, 9:18pm UTC](https://meta.discourse.org/t/use-caddy-instead-of-nginx-as-your-reverse-proxy/54716/6 "2017-06-05T21:18:02Z")

</div>

My Discourse sites behind Caddy show nginx as the server too. I guess that `transparent` setting might make Caddy, uh, transparent.

---

<div class="post-metadata">

### Author: ![mholt](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/mholt/32/120935_2.png) [@mholt](https://meta.discourse.org/u/mholt)
#### Post date: [June 14, 2017, 2:55pm UTC](https://meta.discourse.org/t/use-caddy-instead-of-nginx-as-your-reverse-proxy/54716/7 "2017-06-14T14:55:44Z")

</div>

That might be a bug from a recent change, it didn’t used to do that. 🤔

---

<div class="post-metadata">

### Author: ![honggian](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/honggian/32/237166_2.png) [@honggian](https://meta.discourse.org/u/honggian)
#### Post date: [September 8, 2017, 7:16pm UTC](https://meta.discourse.org/t/use-caddy-instead-of-nginx-as-your-reverse-proxy/54716/8 "2017-09-08T19:16:03Z")

</div>

Dear @Falco

Thank you so much for your posting.

I would like to install discourse using caddy condition, but I was confused with your docker command.

I never heard about the caddy, so I follow the digital ocean document

> **[How To Host a Website with Caddy on Ubuntu 16.04 | DigitalOcean](https://www.digitalocean.com/community/tutorials/how-to-host-a-website-with-caddy-on-ubuntu-16-04)**
>
> Caddy is a web server that was created with ease of use in mind. It’s become a common choice for developers who want to quickly r…

My question is, in the current server situation, Should I change the path  
from etc/Caddyfile to /etc/caddy/Caddyfile?

```
docker run -d \
    -v /var/caddy/Caddyfile:/etc/Caddyfile \
    -v /var/caddy:/root/.caddy \
    -v /var/discourse/shared/standalone:/sock \
    -p 80:80 -p 443:443 \
    -p 80:80/udp -p 443:443/udp \
    --restart=always \
    --name caddy \
    --entrypoint "/usr/local/bin/caddy" \
    abiosoft/caddy -quic -email MYEMAILHERE@gmail.com -agree --conf /etc/Caddyfile --log stdout

```

Sincerely

---

<div class="post-metadata">

### Author: ![tachibanalolo](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/tachibanalolo/32/233762_2.png) [@tachibanalolo](https://meta.discourse.org/u/tachibanalolo)
#### Post date: [December 2, 2021, 9:23am UTC](https://meta.discourse.org/t/use-caddy-instead-of-nginx-as-your-reverse-proxy/54716/9 "2021-12-02T09:23:13Z")

</div>

> [@Falco](#):
>
> `unix:/sock/nginx.http.sock`

This not work on my server. For me, I used:

```plaintext
unix:/var/discourse/shared/standalone/nginx.http.sock

```

And this is for caddy v1. For caddy v2, please use:

```plaintext
unix//var/discourse/shared/standalone/nginx.http.sock

```

Just replace “:” to “/”.

---

<div class="post-metadata">

### Author: ![Falco](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/falco/32/179432_2.png) [@Falco](https://meta.discourse.org/u/Falco)
#### Post date: [December 2, 2021, 1:55pm UTC](https://meta.discourse.org/t/use-caddy-instead-of-nginx-as-your-reverse-proxy/54716/10 "2021-12-02T13:55:40Z")

</div>

That path works if you are following the guide in the OP and running Caddy in docker and mounting the volumes as specified. If you are not following the guide, there will be different paths, yes.

---

<div class="post-metadata">

### Author: ![RPaladin](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/rpaladin/32/280255_2.png) [@RPaladin](https://meta.discourse.org/u/RPaladin)
#### Post date: [July 22, 2022, 9:56pm UTC](https://meta.discourse.org/t/use-caddy-instead-of-nginx-as-your-reverse-proxy/54716/12 "2022-07-22T21:56:59Z")

</div>

> [@Falco](#):
>
> They [use Discourse](https://forum.caddyserver.com/) 😄

Their forum domain and subdomain are now named under [this](https://caddy.community/).

---

<div class="post-metadata">

### Author: ![ARHAEEM](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/arhaeem/32/310459_2.png) [@ARHAEEM](https://meta.discourse.org/u/ARHAEEM)
#### Post date: [June 10, 2023, 10:30pm UTC](https://meta.discourse.org/t/use-caddy-instead-of-nginx-as-your-reverse-proxy/54716/13 "2023-06-10T22:30:30Z")

</div>

Sorry for bumping old threads, I’m trying to make Caddy work with Discourse. In your Caddy configuration, you use “proxy”, but when I use it, it says that there is a syntax error and that it’s not valid. Hasn’t “proxy” now been changed to “reverse\_proxy”?

here’s my config:

```plaintext
forum.example.com {
    reverse_proxy / unix//var/discourse/shared/standalone/nginx.http.sock {
        transparent
    }
}

```

---

<div class="post-metadata">

### Author: ![pfaffman](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/pfaffman/32/120154_2.png) [@pfaffman](https://meta.discourse.org/u/pfaffman)
#### Post date: [June 11, 2023, 11:40am UTC](https://meta.discourse.org/t/use-caddy-instead-of-nginx-as-your-reverse-proxy/54716/14 "2023-06-11T11:40:53Z")

</div>

> [@ARHAEEM](#):
>
> Hasn’t “proxy” now been changed to “reverse\_proxy”?

I think so. Did you try it?

---

<div class="post-metadata">

### Author: ![bananaman](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/bananaman/32/493705_2.png) [@bananaman](https://meta.discourse.org/u/bananaman)
#### Post date: [March 13, 2025, 7:44am UTC](https://meta.discourse.org/t/use-caddy-instead-of-nginx-as-your-reverse-proxy/54716/15 "2025-03-13T07:44:10Z")

</div>

Thanks Matt!  
I can confirm that the no container setup still works in 2025 😃

```plaintext
forum.website.com {
        reverse_proxy localhost:8080
}

```

Using just “proxy” didn’t work.

---

<div class="post-metadata">

### Author: ![manuel](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/manuel/32/468169_2.png) [@manuel](https://meta.discourse.org/u/manuel)
#### Post date: [May 16, 2025, 3:20pm UTC](https://meta.discourse.org/t/use-caddy-instead-of-nginx-as-your-reverse-proxy/54716/16 "2025-05-16T15:20:14Z")

</div>

> [@bananaman](#):
>
> I can confirm that the no container setup still works in 2025 😃

Works great for me as well!

However, I got “Mixed Content” warnings following that very straightforward setup:

 ![The image showcases error messages indicating the need to upgrade insecure display requests to HTTPS on three identical files related to upgraded versions, with a visual update icon. (Captioned by AI)](https://global.discourse-cdn.com/meta/original/4X/9/d/7/9d7254aadf8310937e10cd5026b96253f8668f98.png)  
To resolve these, I had to add an additional directive to the `env` section of the config file (`app.yml` or `web_only.yml`):

```plaintext
# FORCE SSL 
DISCOURSE_FORCE_HTTPS: true

```

---

<div class="post-metadata">

### Author: ![manuel](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/manuel/32/468169_2.png) [@manuel](https://meta.discourse.org/u/manuel)
#### Post date: [June 3, 2025, 9:57am UTC](https://meta.discourse.org/t/use-caddy-instead-of-nginx-as-your-reverse-proxy/54716/17 "2025-06-03T09:57:09Z")

</div>

For reference, these are the current steps for a non-dockerized setup using Caddy as reverse proxy:

### 1) Adjust the Discourse config file

- Comment out certificates

```plaintext
templates:
# - "templates/web.ssl.template.yml"
# - "templates/web.letsencrypt.ssl.template.yml"

```

- Change port mapping and disable 443 mapping

```plaintext
expose:
- "8080:80" # http
# - "443:443" # https

```

- Force HTTPS for serving static files

```plaintext
env: 
DISCOURSE_FORCE_HTTPS: true

```

### 2) Rebuild Discourse

```plaintext
./launcher rebuild app

```

### 3) Setup Caddy

- Install Caddy, just using the official defaults: [Install — Caddy Documentation](https://caddyserver.com/docs/install#debian-ubuntu-raspbian)

- Adjust `/etc/caddy/Caddyfile`

### 4) Run Caddy

`systemctl start caddy`

Reload configuration after changes:

```plaintext
cd /etc/caddy
caddy reload

```

---

<div class="post-metadata">

### Author: ![David\_Ghost](https://avatars.discourse-cdn.com/v4/letter/d/c37758/32.png) [@David\_Ghost](https://meta.discourse.org/u/David_Ghost)
#### Post date: [June 3, 2025, 10:30am UTC](https://meta.discourse.org/t/use-caddy-instead-of-nginx-as-your-reverse-proxy/54716/18 "2025-06-03T10:30:59Z")

</div>

Hey, thanks for the tutorial.

Is there any advantage in using Caddy for a non-multisite setup? Performance or anything else?

---

<div class="post-metadata">

### Author: ![manuel](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/manuel/32/468169_2.png) [@manuel](https://meta.discourse.org/u/manuel)
#### Post date: [June 3, 2025, 10:40am UTC](https://meta.discourse.org/t/use-caddy-instead-of-nginx-as-your-reverse-proxy/54716/19 "2025-06-03T10:40:54Z")

</div>

I don’t know about that.. I just use this setup on my staging servers now because it’s really easy to add or change instances without running into certificate issues.

---

<div class="post-metadata">

### Author: ![DeanMarkTaylor](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/deanmarktaylor/32/102462_2.png) [@DeanMarkTaylor](https://meta.discourse.org/u/DeanMarkTaylor)
#### Post date: [October 13, 2025, 8:56pm UTC](https://meta.discourse.org/t/use-caddy-instead-of-nginx-as-your-reverse-proxy/54716/20 "2025-10-13T20:56:40Z")

</div>

I did something similar to this on a multisite setup to streamline the SSL setup…  
… but updated to Caddy v2, and using docker-compose with a multisite setup.

In the `web.yml`:

- using only `templates/web.socketed.template.yml` and no SSL `yml` files.
- commenting out the ports `"443:443"`, `"80:80"` etc.
- adding `DISCOURSE_HOSTNAME_ALIASES` and `DISCOURSE_FORCE_HTTPS: true`

This uses the latest version of Caddy 2, which is why it might look different from some of the Caddy v1 configs mentioned above in this topic.

This is the bash file that gets the relevant files initially created and caddy started:

```bash
#!/usr/bin/env bash

# Create necessary directories
mkdir -p /var/caddy
mkdir -p /var/caddy/data
mkdir -p /var/caddy/config

# Create the simplified Caddyfile
cat > /var/caddy/Caddyfile << 'EOF'
{
    email your-email-address-here@example.com
}

community1.example.com, community2.example.com, community3.example.com {
    reverse_proxy unix//sock/nginx.http.sock
}
EOF

# Create docker-compose.yml
cat > /var/caddy/docker-compose.yml << 'EOF'
services:
  caddy:
    image: caddy:latest
    container_name: caddy-proxy
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
      - "443:443/udp"
    volumes:
      - /var/caddy/Caddyfile:/etc/caddy/Caddyfile
      - /var/caddy/data:/data
      - /var/caddy/config:/config
      - /var/discourse/shared/standalone:/sock
EOF

# Navigate to caddy directory and start
cd /var/caddy

# Start Caddy
docker compose up -d

```

---

<div class="post-metadata">

### Author: ![lxbnks](https://avatars.discourse-cdn.com/v4/letter/l/7ab992/32.png) [@lxbnks](https://meta.discourse.org/u/lxbnks)
#### Post date: [December 3, 2025, 11:31am UTC](https://meta.discourse.org/t/use-caddy-instead-of-nginx-as-your-reverse-proxy/54716/21 "2025-12-03T11:31:31Z")

</div>

Thanks! I want to switch to Caddy from Nginx. You still have `unix//sock/nginx.http.sock` - are you using both Nginx and Caddy together?

[Next page](https://meta.discourse.org/t/use-caddy-instead-of-nginx-as-your-reverse-proxy/54716.md?page=2)
