Convert mattermost Ngnix config to Caddy

1. The problem I’m having:

Unclear how-to convert Ngnix to Caddy, I’m well out of my depth here.

2. Error messages and/or full log output:

No error unless you consider inadequacy an error.

3. Caddy version:

v2.10.2 h1:g/gTYjGMD0dec+UgMw8SnfmJ3I9+M2TdvoRL/Ovu6U8=

4. How I installed and ran Caddy:

unzipped into directory ‘d:\caddy’ then run with ‘caddy.exe start’

a. System environment:

Windows 2019 Standard Server

b. Command:

unclear what’s needed here

c. Service/unit/compose file:

n/a

d. My complete Caddy config:

{
	# Global options block
	acme_ca https://acme-v02.api.letsencrypt.org/directory
}

download.cfts.co {
	reverse_proxy 172.16.198.31:8080
}

vps.cfts.co {
	# basic_auth {
	#	VPS_Panel $2a$14$CW0HN6t8Hqh3DfsXjXLi2u1zbI922HSewoO0nlCbCKaHyS6qvvMxe
	# }
	tls {
		protocols tls1.2 tls1.3
		ciphers TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
		curves x25519 secp256r1
		# session_tickets false
	}
	# Logging
	log {
		output file log\vps-access.log {
			roll_size 1mb
			roll_keep 20
			roll_keep_for 720h
		}
	}
	# esxi5
	reverse_proxy 172.16.198.5:443 {
		transport http {
			tls_insecure_skip_verify
		}
	}
}

redmine.cfts.co {
	tls {
		protocols tls1.2 tls1.3
		ciphers TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
		curves x25519 secp256r1
	}
	reverse_proxy 172.16.198.21:80
}

tracks.cfts.co {
	reverse_proxy 172.16.198.8:80
}

monitor.cfts.co {
	reverse_proxy 127.0.0.1:443 {
		transport http {
			tls_insecure_skip_verify
		}
	}
}

tickets.cfts.co {
	tls {
		protocols tls1.2 tls1.3
		ciphers TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
		curves x25519 secp256r1
	}
	reverse_proxy 172.16.198.55:80
}

tickets.kee.go.ug {
	tls {
		protocols tls1.2 tls1.3
		ciphers TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
		curves x25519 secp256r1
		# session_tickets false
	}
	reverse_proxy 172.16.198.55:80
}

# mattermost sorting out voice
# https://docs.mattermost.com/administration-guide/configure/calls-deployment.html
# Ports needing to be passed through
# sudo ufw allow 8443/udp
# sudo ufw allow 8443/tcp
# sudo ufw allow 8045/tcp
# sudo ufw allow 80/tcp

#tasks.cfts.co {
#	reverse_proxy 172.16.198.12:8065
#}

tasks.cfts.co {
	encode gzip
	reverse_proxy /plugins/com.mattermost.calls/api/v1/websocket 172.16.198.12:8065 {
		transport http {
			compression off
		}
	}
	reverse_proxy 172.16.198.12:8065
}

The nightmare of a Ngnix config :slight_smile: I’m trying to convert to Caddy

upstream backend {
   server 10.10.10.2:8065;
   keepalive 32;
}

server {
  listen 80 default_server;
  server_name   mattermost.example.com;
  return 301 https://$server_name$request_uri;
}

server {
   listen 443 ssl http2;
   listen [::]:443 ssl http2;
   server_name    mattermost.example.com;

   ssl_certificate /etc/letsencrypt/live/{domain-name}/fullchain.pem;
   ssl_certificate_key /etc/letsencrypt/live/{domain-name}/privkey.pem;
   ssl_session_timeout 1d;

   # Enable TLS versions (TLSv1.3 is required upcoming HTTP/3 QUIC).
   ssl_protocols TLSv1.2 TLSv1.3;

   # Enable TLSv1.3's 0-RTT. Use $ssl_early_data when reverse proxying to
   # prevent replay attacks.
   #
   # @see: https://nginx.org/en/docs/http/ngx_http_ssl_module.html#ssl_early_data
   ssl_early_data on;

   ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384';
   ssl_prefer_server_ciphers on;
   ssl_session_cache shared:SSL:50m;
   # HSTS (ngx_http_headers_module is required) (15768000 seconds = six months)
   add_header Strict-Transport-Security max-age=15768000;
   # OCSP Stapling ---
   # fetch OCSP records from URL in ssl_certificate and cache them
   ssl_stapling on;
   ssl_stapling_verify on;

   add_header X-Early-Data $tls1_3_early_data;

   location ~ /api/v[0-9]+/(users/)?websocket$ {
       proxy_set_header Upgrade $http_upgrade;
       proxy_set_header Connection "upgrade";
       client_max_body_size 50M;
       proxy_set_header Host $host;
       proxy_set_header X-Real-IP $remote_addr;
       proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
       proxy_set_header X-Forwarded-Proto $scheme;
       proxy_set_header X-Frame-Options SAMEORIGIN;
       proxy_buffers 256 16k;
       proxy_buffer_size 16k;
       client_body_timeout 60s;
       send_timeout 300s;
       lingering_timeout 5s;
       proxy_connect_timeout 90s;
       proxy_send_timeout 300s;
       proxy_read_timeout 90s;
       proxy_http_version 1.1;
       proxy_pass http://backend;
   }

   location / {
       client_max_body_size 100M;
       proxy_set_header Connection "";
       proxy_set_header Host $host;
       proxy_set_header X-Real-IP $remote_addr;
       proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
       proxy_set_header X-Forwarded-Proto $scheme;
       proxy_set_header X-Frame-Options SAMEORIGIN;
       proxy_buffers 256 16k;
       proxy_buffer_size 16k;
       proxy_read_timeout 600s;
       proxy_http_version 1.1;
       proxy_pass http://backend;
   }
}

# This block is useful for debugging TLS v1.3. Please feel free to remove this
# and use the `$ssl_early_data` variable exposed by NGINX directly should you
# wish to do so.
map $ssl_early_data $tls1_3_early_data {
  "~." $ssl_early_data;
  default "";
}

5. Links to relevant resources:

There are several major issues with your Caddy configuration:

  • Syntax errors (outdated Caddy v1 syntax)

  • Incomplete Mattermost configuration

  • Unnecessarily complex TLS settings

tasks.cfts.co {

WebSocket 路径特殊处理

@websocket {
path_regexp ^/api/v[0-9]+/(users/)?websocket$
}

handle @websocket {
    reverse_proxy 172.16.198.12:8065 {
        # WebSocket 需要这些头部
        header_up Connection {>Connection}
        header_up Upgrade {>Upgrade}
    }
}

# 所有其他请求
handle {
    reverse_proxy 172.16.198.12:8065
}

# 文件上传大小限制
reverse_proxy {
    max_body_size 100MB
}

}

Thank you let me look at this, I started looking at a different options, seems most of your code is redundant, it won’t fix calls coming externally for our situation. However this seems to work.

tasks.cfts.co {
    reverse_proxy 172.16.198.12:8065
}

The above works fine internally, I just need to setup external DNS an external<>internal routing

  1. Calls ≠ HTTP. The audio/screen-share is UDP/TCP 8443 to the SFU and never goes through Caddy. That’s why the fix is to expose 8443 at the edge → 172.16.198.12:8443 and set the ICE host override172.16.198.12.
  2. Two clean DNS patterns (pick one):
    1. Single hostname (tasks.cfts.co) + hairpin/split-DNS so 8443 reaches the SFU.

    2. Media subdomain (calls.tasks.cfts.co) → SFU for 8443; leave tasks.cfts.co for the web UI. (No hairpin needed; simplest.)

  3. Edge rules: forward UDP 8443 and TCP 8443 to 172.16.198.12; disable ALGs/inspection on those rules; keep returns symmetric (policy route or SNAT on the edge router).

I post this as a solution without needing any black magic :slight_smile: hope it helps someone else.

But thanks for the help, it crystalized my thoughts on the matter.

1 Like

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