Help with CORS settings for synapse-admin?

1. The problem I’m having:

I’m running a matrix server and trying to get synapse-admin from etke.cc from GitHub - etkecc/synapse-admin: A maintained fork of the admin console for (Matrix) Synapse homeservers, including additional features to work to control things. I have gotten most of the parts of matrix that I wanted up and running, but I can’t get synapse-admin to run. I thought it was a bug with the software, but it works just fine if I use my install to connect to another server. It keeps saying:
Screenshot from 2025-04-19 02-02-07

I’ve been putting all the header lines in as many places as I could to try and find where I have to put it for it to actually take effect. I also went through several tutorials about getting matrix up and running with caddy and have mixed things together to try and find what will actually work for this. Matrix has worked fine from near the start, but synapse-admin has been failing. I spoke to etke.cc about configuration and they told me it was a caddy issue, so I’m hoping someone here can tell me what I’m doing wrong.
I am running synapse-admin in 2 places because it’s made to be the root level but can be run from a subfolder type as well. I wanted to see what would work, so I have it in the subdomain madmin as well as ../synapse-admin/ and neither works, but they give different errors.

I’m using caddy 2.9.1 with the linode dns plugin

2. Error messages and/or full log output:

Screenshot from 2025-04-19 02-02-07
Screenshot from 2025-04-23 16-23-02

(matrix-well-known-header) {
  header {
    Access-Control-Allow-Origin "*"
    Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS"
    Access-Control-Allow-Headers "Origin, X-Requested-With, Content-Type, Accept, Authorization"
    Content-Type "application/json"
  }
}

(matrix) {
  handle /.well-known/matrix/server {
    import matrix-well-known-header
    respond `{"m.server":"matrix.dragonmail.cloud"}`
  }
  handle /.well-known/matrix/client {
    import matrix-well-known-header
    respond `{"m.homeserver":{"base_url":"https://chat.dragonmail.cloud"}}`
  }
}

dragonmail.cloud {
    import matrix
    respond "placeholder"
    }
}

matrix.dragonmail.cloud {
  header {
      X-Content-Type-Options nosniff
      #Referrer-Policy strict-origin-when-cross-origin
      Access-Control-Allow-Origin "*"
      Strict-Transport-Security "max-age=63072000; includeSubDomains;"
      Permissions-Policy "accelerometer=(), camera=(), geolocation=(), gyroscope=(), magnetometer=(), microphone=(), payment=(), usb=(), interest-cohort=()"
      #X-Frame-Options SAMEORIGIN
      #Access-Control-Allow-Credentials true
      X-XSS-Protection 1
      X-Robots-Tag none
      -server
      X-Real-IP {remote_host}
      X-Forwarded-For {remote_host}
      X-Permitted-Cross-Domain-Policies "*"
      defer
  }
  handle /.well-known/matrix/server {
#      #import matrix-well-known-header
      #respond `{"m.server":"matrix.dragonmail.cloud:443"}`
      respond `{"m.server":"matrix.dragonmail.cloud"}`
  }
#
  handle /.well-known/matrix/client {
      #import matrix-well-known-header
      respond `{"m.homeserver":{"base_url":"https://matrix.dragonmail.cloud"}}`
  }
  #@media {
  #    path_regexp /_synapse/admin/v1/(purge_media_cache|((room|user)/.*/media.*)|media/.*|/quarantine_media/.*)$
  #    path_regexp /_matrix/media(/?(.*)?)$
  #}
  #route @media {
  #    reverse_proxy matrix-synapse:8015
  #}
  @federation {
      path_regexp /_matrix/federation/(v1|v2)/(send|event|state|state_ids|backfill|get_missing_events|publicRooms|query|make_join|make_leave|send_join|send>
      #path_regexp /_matrix/key/v2/query/?$
  }
  route @federation {
      reverse_proxy matrix-synapse:8017
  }

  # Handle Synapse Admin requests
  handle_path /synapse-admin* {
      header {
          Access-Control-Allow-Origin "*"
          Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS"
          Access-Control-Allow-Headers "Origin, X-Requested-With, Content-Type, Accept, Authorization"
          Access-Control-Allow-Credentials true
          defer
      }
      #try_files {path} {path}/ /index.html
      #@static_files {
      #    path_regexp .*(css|js|jpg|jpeg|gif|png|svg|ico|woff|woff2|ttf|eot|webp)$
      #}
      #header @static_files Cache-Control "public, max-age=2592000"
      reverse_proxy http://matrix-synapse-admin:80
  }

  reverse_proxy /_matrix/* matrix-synapse:8008
  reverse_proxy /_synapse/client/* matrix-synapse:8008
  reverse_proxy /_matrix/media/* matrix-synapse:8008
  #reverse_proxy /_synapse/admin/* matrix-synapse:8008
  header {
      X-Content-Type-Options nosniff
      #Referrer-Policy strict-origin-when-cross-origin
      #Access-Control-Allow-Origin "http://192.168.3.50:8195"
      Access-Control-Allow-Origin *
      Strict-Transport-Security "max-age=63072000; includeSubDomains;"
      Permissions-Policy "accelerometer=(), camera=(), geolocation=(), gyroscope=(), magnetometer=(), microphone=(), payment=(), usb=(), interest-cohort=()"
      #X-Frame-Options SAMEORIGIN
      #Access-Control-Allow-Credentials true
      X-XSS-Protection 1
      X-Robots-Tag none
      -server
      X-Real-IP {remote_host}
      X-Forwarded-For {remote_host}
      defer
  }
}

element.dragonmail.cloud {
  encode zstd gzip
  #reverse_proxy element:80
  #reverse_proxy 10.10.10.3:80
  reverse_proxy matrix-element:80

  header {
    X-Content-Type-Options nosniff
    Strict-Transport-Security "max-age=63072000; includeSubDomains;"
    Permissions-Policy "accelerometer=(), camera=(), geolocation=(), gyroscope=(), magnetometer=(), microphone=(), payment=(), usb=(), interest-cohort=()"
    X-Frame-Options SAMEORIGIN
    X-XSS-Protection 1
    X-Robots-Tag none
    -server
  }
}

chat.dragonmail.cloud {
  encode zstd gzip
  #reverse_proxy element:80
  #reverse_proxy 10.10.10.3:80
  reverse_proxy matrix-element:80

  header {
    X-Content-Type-Options nosniff
    Strict-Transport-Security "max-age=63072000; includeSubDomains;"
    Permissions-Policy "accelerometer=(), camera=(), geolocation=(), gyroscope=(), magnetometer=(), microphone=(), payment=(), usb=(), interest-cohort=()"
    X-Frame-Options SAMEORIGIN
    X-XSS-Protection 1
    X-Robots-Tag none
    -server
  }
}

3. Caddy version:

2.9.1 in docker compose but built from git

4. How I installed and ran Caddy:

services:
  caddy:
    container_name: caddy
    build:
      dockerfile: dockerfile-caddy
      context: ./caddy
    ports:
      - 80:80
      - 443:443
      - 443:443/udp
    volumes:
      - /media/configs/caddy/Caddyfile:/etc/caddy/Caddyfile
      - /media/configs/caddy/config:/config
      - /media/configs/caddy/data:/data
      - /media/configs/caddy/site:/srv
    environment:
      PUID: '1000'
      PGID: '1000'
      TZ: 'America/vancouver'
      #GODADDY_TOKEN: '####'
      LINODE_TOKEN: '####'
    networks:
      dragonio:
        aliases: []

My dockerfile:

FROM caddy:2.9.1-builder AS builder
ENV GOTOOLCHAIN=go1.24.1

RUN xcaddy build \
    --with github.com/caddy-dns/linode

FROM caddy:2.9.1

COPY --from=builder /usr/bin/caddy /usr/bin/caddy

a. System environment:

popos 22.04 LTS

b. Command:

docker compose up caddy

c. Service/unit/compose file:

---
name: "dragonmail"
networks:
  dragonio:
    name: 'dragonio'
    driver: 'bridge'
    external: true
  matrix_net:
    name: 'matrix_net'
    driver: 'bridge'
    external: true


services:
  caddy:
    container_name: caddy
    build:
      dockerfile: dockerfile-caddy
      context: ./caddy
    ports:
      - 80:80
      - 443:443
      - 443:443/udp
    volumes:
      - /media/configs/caddy/Caddyfile:/etc/caddy/Caddyfile
      - /media/configs/caddy/config:/config
      - /media/configs/caddy/data:/data
      - /media/configs/caddy/site:/srv
    environment:
      PUID: '1000'
      PGID: '1000'
      TZ: 'America/vancouver'
      LINODE_TOKEN: '####'
    networks:
      dragonio:
        aliases: []

  ###########################################################################################
  matrix-synapse:
    container_name: 'matrix-synapse'
    image: 'matrixdotorg/synapse:latest'
    #image: 'matrixdotorg/synapse:v1.119.0'
    init: true
    restart: 'unless-stopped'
    #pull_policy: always
    networks:
      matrix_net:
        aliases: []
        #ipv4_address: 10.10.10.4
      dragonio:
        aliases: []
    environment:
      SYNAPSE_SERVER_NAME: 'matrix.dragonmail.cloud'
      SYNAPSE_REPORT_STATS: 'yes'
      allow_unsafe_locale: true
    volumes:
      - '/media/matrix/synapse:/data'
      #- '/media/matrix/synapse/homeserver.log:/homeserver.log'
      - '/media/matrix/whatsapp/data:/data/appservices/whatsapp'
      - '/media/matrix/telegram:/data/appservices/telegram'
      - '/media/matrix/meta:/data/appservices/meta'
    ports:
      - 8008:8008
    depends_on:
     - matrix-postgres
     - caddy
     - authentik
  ###########################################################################################
  matrix-element:
    container_name: 'matrix-element'
    image: 'vectorim/element-web:latest'
    restart: 'unless-stopped'
    #pull_policy: always
    volumes:
      - '/media/matrix/element/element-config.json:/app/config.json'
    #ports:
    #  - 8180:80
    networks:
      dragonio:
        aliases: []
      matrix_net:
        #ipv4_address: 10.10.10.3
        aliases: []
    depends_on:
      - matrix-synapse
      - matrix-postgres
      - caddy
  ###########################################################################################
  matrix-postgres:
    #image: 'docker.io/library/postgres:16-alpine'
    image: 'postgres:14'
    container_name: 'matrix-postgres'
    restart: 'unless-stopped'
    #pull_policy: always
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -d $${POSTGRES_DB} -U $${POSTGRES_USER}"]
      start_period: 20s
      interval: 30s
      retries: 5
      timeout: 5s
    volumes:
      - '/media/matrix/database:/var/lib/postgresql/data'
    environment:
      POSTGRES_PASSWORD: ${PG_PASS}
      POSTGRES_USER: ${POSTGRES_USER}
      POSTGRES_DB: ${POSTGRES_DB}
      allow_unsafe_locale: true
    env_file:
      - .env
    networks:
      matrix_net:
        #ipv4_address: 10.10.10.2
        aliases: []
  ###########################################################################################
  matrix-synapse-admin:
    container_name: matrix-synapse-admin
    hostname: matrix-synapse-admin
    build:
      context: https://github.com/etkecc/synapse-admin.git
      dockerfile: Dockerfile.build
      args:
        - BUILDKIT_CONTEXT_KEEP_GIT_DIR=1
        #   - NODE_OPTIONS="--max_old_space_size=1024"
        - BASE_PATH=/synapse-admin
    restart: unless-stopped
    networks:
      matrix_net:
        aliases: []
      dragonio:
        aliases: []
    depends_on:
     - caddy
     - matrix-synapse
  ###########################################################################################

d. My complete Caddy config:

{
  #admin :2019
  email ####
  acme_dns linode {env.LINODE_TOKEN}
  debug
}

(matrix-well-known-header) {
  header {
    Access-Control-Allow-Origin "*"
    Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS"
    Access-Control-Allow-Headers "Origin, X-Requested-With, Content-Type, Accept, Authorization"
    Content-Type "application/json"
  }
}

(matrix) {
  handle /.well-known/matrix/server {
    import matrix-well-known-header
    respond `{"m.server":"matrix.dragonmail.cloud"}`
  }
  handle /.well-known/matrix/client {
    import matrix-well-known-header
    respond `{"m.homeserver":{"base_url":"https://chat.dragonmail.cloud"}}`
  }
}

dragonmail.cloud {
    handle /.well-known/matrix/server {
        import matrix-well-known-header
        respond `{"m.server":"matrix.dragonmail.cloud:443"}`
    }

    handle /.well-known/matrix/client {
        import matrix-well-known-header
        respond `{"m.homeserver":{"base_url":"https://matrix.dragonmail.cloud"}}`
    }

}

auth.dragonmail.cloud {
  #reverse_proxy http://authentik:9000
  reverse_proxy authentik:9000
}

mail.dragonmail.social {
  reverse_proxy http://stalwart-mail:8080
}

https://nextcloud.dragonmail.cloud:443 {
  redir /.well-known/carddav /remote.php/dav/ 301
  redir /.well-known/caldav /remote.php/dav/ 301
  reverse_proxy nextcloud-aio-apache:11000
}

nextcloud.dragonmail.cloud:8080 {
  #redir /.well-known/carddav /remote.php/dav/ 301
  #redir /.well-known/caldav /remote.php/dav/ 301
  reverse_proxy nextcloud-aio-apache:8080
}

matrix.dragonmail.cloud {
  header {
      X-Content-Type-Options nosniff
      #Referrer-Policy strict-origin-when-cross-origin
      #Access-Control-Allow-Origin "http://192.168.3.50:8195"
      Access-Control-Allow-Origin "*"
      Strict-Transport-Security "max-age=63072000; includeSubDomains;"
      Permissions-Policy "accelerometer=(), camera=(), geolocation=(), gyroscope=(), magnetometer=(), microphone=(), payment=(), usb=(), interest-cohort=()"
      #X-Frame-Options SAMEORIGIN
      #Access-Control-Allow-Credentials true
      X-XSS-Protection 1
      X-Robots-Tag none
      -server
      X-Real-IP {remote_host}
      X-Forwarded-For {remote_host}
      X-Permitted-Cross-Domain-Policies "*"
      defer
  }
  handle /.well-known/matrix/server {
      #import matrix-well-known-header
      respond `{"m.server":"matrix.dragonmail.cloud"}`
  }

  handle /.well-known/matrix/client {
      #import matrix-well-known-header
      respond `{"m.homeserver":{"base_url":"https://matrix.dragonmail.cloud"}}`
  }
  #@media {
  #    path_regexp /_synapse/admin/v1/(purge_media_cache|((room|user)/.*/media.*)|media/.*|/quarantine_media/.*)$
  #    path_regexp /_matrix/media(/?(.*)?)$
  #}
  #route @media {
  #    reverse_proxy matrix-synapse:8015
  #}
  @federation {
      path_regexp /_matrix/federation/(v1|v2)/(send|event|state|state_ids|backfill|get_missing_events|publicRooms|query|make_join|make_leave|send_join|send>
      #path_regexp /_matrix/key/v2/query/?$
  }
  route @federation {
      reverse_proxy matrix-synapse:8017
  }
  # Handle Synapse Admin requests
  handle_path /synapse-admin* {
      header {
          Access-Control-Allow-Origin "*"
          Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS"
          Access-Control-Allow-Headers "Origin, X-Requested-With, Content-Type, Accept, Authorization"
          Access-Control-Allow-Credentials true
          defer
      }
      #try_files {path} {path}/ /index.html
      #@static_files {
      #    path_regexp .*(css|js|jpg|jpeg|gif|png|svg|ico|woff|woff2|ttf|eot|webp)$
      #}
      #header @static_files Cache-Control "public, max-age=2592000"
      reverse_proxy http://matrix-synapse-admin:80
  }

  reverse_proxy /_matrix/* matrix-synapse:8008
  reverse_proxy /_synapse/client/* matrix-synapse:8008
  reverse_proxy /_matrix/media/* matrix-synapse:8008
  #reverse_proxy /_synapse/admin/* matrix-synapse:8008
  header {
      X-Content-Type-Options nosniff
      #Referrer-Policy strict-origin-when-cross-origin
      Access-Control-Allow-Origin *
      Strict-Transport-Security "max-age=63072000; includeSubDomains;"
      Permissions-Policy "accelerometer=(), camera=(), geolocation=(), gyroscope=(), magnetometer=(), microphone=(), payment=(), usb=(), interest-cohort=()"
      #X-Frame-Options SAMEORIGIN
      #Access-Control-Allow-Credentials true
      X-XSS-Protection 1
      X-Robots-Tag none
      -server
      X-Real-IP {remote_host}
      X-Forwarded-For {remote_host}
      defer
  }
}


element.dragonmail.cloud {
  encode zstd gzip
  reverse_proxy matrix-element:80

  header {
    X-Content-Type-Options nosniff
    Strict-Transport-Security "max-age=63072000; includeSubDomains;"
    Permissions-Policy "accelerometer=(), camera=(), geolocation=(), gyroscope=(), magnetometer=(), microphone=(), payment=(), usb=(), interest-cohort=()"
    X-Frame-Options SAMEORIGIN
    X-XSS-Protection 1
    X-Robots-Tag none
    -server
  }
}
chat.dragonmail.cloud {
  encode zstd gzip
  reverse_proxy matrix-element:80

  header {
    X-Content-Type-Options nosniff
    Strict-Transport-Security "max-age=63072000; includeSubDomains;"
    Permissions-Policy "accelerometer=(), camera=(), geolocation=(), gyroscope=(), magnetometer=(), microphone=(), payment=(), usb=(), interest-cohort=()"
    X-Frame-Options SAMEORIGIN
    X-XSS-Protection 1
    X-Robots-Tag none
    -server
  }
}

track.dragonmail.cloud {
  reverse_proxy http://ryot:8000
}

#srv.dragonmail.cloud {
#  respond "placeholder"
#}

#matrix.dragonmail.cloud/synapse-admin {
#  reverse_proxy http://synapse-admin:80
#}

madmin.dragonmail.cloud {
  tls internal
  reverse_proxy http://matrix-synapse-admin-test:80
}

5. Links to relevant resources:

Check in the network tab to see if it’s a the OPTION request failing or the subsequent request

Also share caddy logs for those requests

1 Like

yes, there is an option request that’s failing:
Screenshot from 2025-04-25 20-43-41
It says because “CORS Missing Allow Origin” but my allow origin in my caddyfile is set to *, so I’m confused by this.

I see some errors in the logs, but they’re all about getting /_matrix/client/versions

docker compose logs caddy|grep Error
caddy  | {"level":"error","ts":1745483960.2638025,"logger":"http.log.error","msg":"dial tcp 172.19.0.11:9000: connect: connection refused","request":{"remote_ip":"216.232.21.194","remote_port":"49348","client_ip":"216.232.21.194","proto":"HTTP/1.1","method":"GET","host":"auth.dragonmail.cloud","uri":"/ws/outpost/adf71752-93d4-4bef-85c3-e19cecb22bfd/?attempt=3&instance_uuid=febd258e-b449-4620-bc0b-e3e83004648b","headers":{"Sec-Websocket-Key":["rRRYKofL/CqY1L0/ghtiwg=="],"Sec-Websocket-Version":["13"],"Upgrade":["websocket"],"User-Agent":["goauthentik.io/outpost/2025.2.3"],"Authorization":["REDACTED"],"Connection":["Upgrade"]},"tls":{"resumed":false,"version":772,"cipher_suite":4865,"proto":"","server_name":"auth.dragonmail.cloud"}},"duration":0.02029792,"status":502,"err_id":"awz2atxq3","err_trace":"reverseproxy.statusError (reverseproxy.go:1373)"}
caddy  | {"level":"error","ts":1745483961.3385203,"logger":"http.log.error","msg":"dial tcp: lookup matrix-synapse on 127.0.0.11:53: server misbehaving","request":{"remote_ip":"216.232.21.194","remote_port":"36874","client_ip":"216.232.21.194","proto":"HTTP/2.0","method":"GET","host":"matrix.dragonmail.cloud","uri":"/_matrix/client/versions","headers":{"Accept-Encoding":["gzip, deflate, br, zstd"],"Sec-Fetch-Site":["same-site"],"Priority":["u=4"],"Sec-Gpc":["1"],"Te":["trailers"],"User-Agent":["Mozilla/5.0 (X11; Linux x86_64; rv:137.0) Gecko/20100101 Firefox/137.0"],"Sec-Fetch-Mode":["cors"],"Cache-Control":["max-age=0"],"Origin":["https://chat.dragonmail.cloud"],"Sec-Fetch-Dest":["empty"],"Accept":["application/json"],"Accept-Language":["en-US,en;q=0.5"]},"tls":{"resumed":false,"version":772,"cipher_suite":4865,"proto":"h2","server_name":"matrix.dragonmail.cloud"}},"duration":0.004699017,"status":502,"err_id":"fyfk34mqp","err_trace":"reverseproxy.statusError (reverseproxy.go:1373)"}
caddy  | {"level":"error","ts":1745483967.244641,"logger":"http.log.error","msg":"dial tcp 172.19.0.13:8008: connect: connection refused","request":{"remote_ip":"216.232.21.194","remote_port":"36874","client_ip":"216.232.21.194","proto":"HTTP/2.0","method":"GET","host":"matrix.dragonmail.cloud","uri":"/_matrix/client/versions","headers":{"Cache-Control":["max-age=0"],"Accept":["application/json"],"Origin":["https://chat.dragonmail.cloud"],"Sec-Fetch-Mode":["cors"],"Sec-Gpc":["1"],"Te":["trailers"],"User-Agent":["Mozilla/5.0 (X11; Linux x86_64; rv:137.0) Gecko/20100101 Firefox/137.0"],"Accept-Language":["en-US,en;q=0.5"],"Sec-Fetch-Site":["same-site"],"Priority":["u=4"],"Accept-Encoding":["gzip, deflate, br, zstd"],"Sec-Fetch-Dest":["empty"]},"tls":{"resumed":false,"version":772,"cipher_suite":4865,"proto":"h2","server_name":"matrix.dragonmail.cloud"}},"duration":0.159223453,"status":502,"err_id":"nf6k3mkzd","err_trace":"reverseproxy.statusError (reverseproxy.go:1373)"}
caddy  | {"level":"error","ts":1745483976.2306664,"logger":"http.log.error","msg":"dial tcp 172.19.0.13:8008: connect: connection refused","request":{"remote_ip":"216.232.21.194","remote_port":"36874","client_ip":"216.232.21.194","proto":"HTTP/2.0","method":"GET","host":"matrix.dragonmail.cloud","uri":"/_matrix/client/versions","headers":{"Sec-Fetch-Site":["same-site"],"Accept-Encoding":["gzip, deflate, br, zstd"],"Origin":["https://chat.dragonmail.cloud"],"Accept":["application/json"],"Accept-Language":["en-US,en;q=0.5"],"Cache-Control":["max-age=0"],"Te":["trailers"],"Sec-Fetch-Dest":["empty"],"Sec-Fetch-Mode":["cors"],"Sec-Gpc":["1"],"Priority":["u=4"],"User-Agent":["Mozilla/5.0 (X11; Linux x86_64; rv:137.0) Gecko/20100101 Firefox/137.0"]},"tls":{"resumed":false,"version":772,"cipher_suite":4865,"proto":"h2","server_name":"matrix.dragonmail.cloud"}},"duration":0.000784461,"status":502,"err_id":"58ktibphk","err_trace":"reverseproxy.statusError (reverseproxy.go:1373)"}
caddy  | {"level":"error","ts":1745483985.592457,"logger":"http.log.error","msg":"dial tcp 172.19.0.13:8008: connect: connection refused","request":{"remote_ip":"216.232.21.194","remote_port":"36874","client_ip":"216.232.21.194","proto":"HTTP/2.0","method":"GET","host":"matrix.dragonmail.cloud","uri":"/_matrix/client/versions","headers":{"Sec-Fetch-Mode":["cors"],"Sec-Fetch-Site":["same-site"],"Sec-Gpc":["1"],"Accept":["application/json"],"Accept-Language":["en-US,en;q=0.5"],"Origin":["https://chat.dragonmail.cloud"],"Sec-Fetch-Dest":["empty"],"Priority":["u=4"],"Cache-Control":["max-age=0"],"User-Agent":["Mozilla/5.0 (X11; Linux x86_64; rv:137.0) Gecko/20100101 Firefox/137.0"],"Te":["trailers"],"Accept-Encoding":["gzip, deflate, br, zstd"]},"tls":{"resumed":false,"version":772,"cipher_suite":4865,"proto":"h2","server_name":"matrix.dragonmail.cloud"}},"duration":0.000818265,"status":502,"err_id":"rwyqserhq","err_trace":"reverseproxy.statusError (reverseproxy.go:1373)"}

Is that related to the error in the browser.

Those log lines are not the relevant ones. The failing request is the pre-flight of CORS, i.e. the OPTIONS request. It doesn’t seem that your configuration allows for the Access-Control-Allow-* headers to be applied. I cannot tell for sure because there’s only a screenshot of the error, and your configuration handles many paths differently. You’ll need to handle requests with OPTIONS method with the correct Access-Control-* headers.

Thank you very much!

The only information I found about the CORS handling was about this:

  header {
    Access-Control-Allow-Origin "*"
    Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS"
    Access-Control-Allow-Headers "Origin, X-Requested-With, Content-Type, Accept, Authorization"
    Content-Type "application/json"
  }

But that’s not for options requests, I’m guessing. Is there a reference I can look to showing examples of how to configure that somewhere? A google search didn’t turn up anything useful. Thank you in advance if you know of anything!

I’m not aware of Caddy specific guide discussing CORS, but the MDN is always good for general information of how the web works.

Basically, when the browser detects a request going to a different domain name than the one hosting the page, then it’ll first send an OPTIONS request to the other host to check the Access-Control-* headers values it’ll respond with. You’ll need to have a matcher for the OPTIONS request, and respond with the headers and respond 200. You can use handle to avoid multiple handling of the requests.

Also, this is not recommended:

Access-Control-Allow-Origin "*"

Be specific about the hosts that are allowed to talk to your server in cross-origin scenario.

You only seem to be applying the matrix-well-known-header snippet (to add the CORS headers) for two specific URLs. What is the full URL that is causing the error? It is cut off in your screenshot.

Thank you! Yes, I’m only applying the cors header to specific paths because I wasn’t aware I could do it generally as a blanket thing. Everything I’ve seen in the documentation an examples shows using a header statement to define it for a specific address.
I’ve continued working on it and have gotten it to allow the login and it starts getting the responses it’s expecting, except here:

Those paths are defined in my caddyfile because the tutorials about getting matrix to work show that we need to set those paths:

  reverse_proxy /_matrix/* matrix-synapse:8008
  reverse_proxy /_synapse/client/* matrix-synapse:8008
  reverse_proxy /_matrix/media/* matrix-synapse:8008

If I add in:

  reverse_proxy matrix-synapse:8008

It stops erroring with the CORS response now that I altered the header and preflight to be:

matrix.dragonmail.cloud {
  header {
      X-Content-Type-Options nosniff
      Access-Control-Allow-Origin "*"
      Strict-Transport-Security "max-age=63072000; includeSubDomains;"
      Permissions-Policy "accelerometer=(), camera=(), geolocation=(), gyroscope=(), magnetometer=(), microphone=(), payment=(), usb=(), interest-cohort=()"
      X-XSS-Protection 1
      X-Robots-Tag none
      -server
      X-Real-IP {remote_host}
      X-Forwarded-For {remote_host}
      X-Permitted-Cross-Domain-Policies "*"
      defer
  }
  @cors_preflight method OPTIONS
  handle @cors_preflight {
    header {
      Access-Control-Allow-Origin "*"
      Access-Control-Allow-Headers "Authorization,Content-Type"
      Strict-Transport-Security "max-age=63072000; includeSubDomains;"
      Permissions-Policy "accelerometer=(), camera=(), geolocation=(), gyroscope=(), magnetometer=(), microphone=(), payment=(), usb=(), interest-cohort=()"
      X-XSS-Protection 1
      X-Robots-Tag none
      -server
      X-Real-IP {remote_host}
      X-Forwarded-For {remote_host}
      X-Permitted-Cross-Domain-Policies "*"
    }
    respond "" 204
  }

Now that I’ve made these changes it doesn’t error on CORS anymore, but also doesn’t allow me to login. Now it says:


And I’m more confused than I was before. It feels like I took a step forward but two steps back.

thank you!
respond 200 seems to be the big thing I was missing. Thank you very much! It’s working better, but still erroring, just on authentication now. It logs in for a split-second and then logs out and tells me 403 on access. I’m so confused.

You have to share more than that you’re getting 403. Check Caddy logs. Check the network tab.

Check the app logs too.

Thank you very much for all the help. I went down a rabbit hole and cycled through everything I could think of, but it turned out to be a bug somewhere in synapse-admin itself. The latest update/commit from etke.cc fixed it completely. I have no idea which bug it was, but after I pulled the latest commit everything works again. No CORS issues anymore at all. Next, it complained about user permissions, but that was easy to fix and then it worked exactly as it was supposed to. Thank you again!

1 Like