# New Taiga, reverse proxying with HTTPS using Caddy

**URL:** <https://community.taiga.io/t/new-taiga-reverse-proxying-with-https-using-caddy/5615>\
**Category:** Self hosted Taiga\
**Created:** [February 26, 2025, 3:34pm UTC](https://community.taiga.io/t/new-taiga-reverse-proxying-with-https-using-caddy/5615 "2025-02-26T15:34:39Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![NickyDoes](https://dub1.discourse-cdn.com/flex017/user_avatar/community.taiga.io/nickydoes/32/2920_2.png) [@NickyDoes](https://community.taiga.io/u/NickyDoes)\
**Post date:** [February 26, 2025, 3:34pm UTC](https://community.taiga.io/t/new-taiga-reverse-proxying-with-https-using-caddy/5615/1 "2025-02-26T15:34:39Z")

</div>

Hello all,

Another proxy help request. Seems we need a tag for these. I’ve read the others, but it still looks like the Matrix to me.

![giphy](https://europe1.discourse-cdn.com/flex017/uploads/taiga/original/2X/e/e597d535886f3c4aef3f1fc8ff0b2b9310494a1d.gif)

I have Taiga Docker installed, and I’m intending to access as `https://projects.example.com`, with Caddy terminating SSL.

I’m having troubles understanding the websocket - proxy details. I’m fairly new to proxies in general, aside from cut-paste following of guides. My domain is proxied with Caddy. I add blocks for each service:

```auto
        import tls_cloudflare

        reverse_proxy http://taiga.home.arpa:9000 {
                transport http {
                        versions h1
                }

                header_up Host {host}
                header_up Upgrade {upgrade}
                header_up Connection {connection}
        }
}

```

No matter what I do with Caddy, I constantly get 426 unexpected server response and 400 connection refused when testing. I’m testing with:

`wscat -c wss://projects.example.com/events`

and

`curl -i -N -H "Connection: Upgrade" -H "Upgrade: websocket" -H "Host: projects.example.com" https://projects.example.com/events`

My .env is:

```auto
TAIGA_DOMAIN=projects.example.com # Taiga's base URL
SUBPATH="" # it'll be appended to the TAIGA_DOMAIN (use either "" or a "/subpath")
WEBSOCKETS_SCHEME=wss # events connection protocol (use either "ws" or "wss")
...

```

Here is the docker-compose.yml (I attached an external postgres server):

_If someone knows how to syntax highlight in this Discourse, please lmk_

> ****
>
> ``` version: "3.5"
> 
> x-environment:  
> &default-back-environment
> 
> # These environment variables will be used by taiga-back and taiga-async.
> 
> # Database settings
> 
> POSTGRES\_DB: “taiga”  
> POSTGRES\_USER: “${POSTGRES\_USER}”  
> POSTGRES\_PASSWORD: “${POSTGRES\_PASSWORD}”  
> POSTGRES\_HOST: “${POSTGRES\_HOST}”
> 
> # Taiga settings
> 
> TAIGA\_SECRET\_KEY: “${SECRET\_KEY}”  
> TAIGA\_SITES\_SCHEME: “${TAIGA\_SCHEME}”  
> TAIGA\_SITES\_DOMAIN: “${TAIGA\_DOMAIN}”  
> TAIGA\_SUBPATH: “${SUBPATH}”
> 
> # Email settings.
> 
> EMAIL\_BACKEND: “django.core.mail.backends.${EMAIL\_BACKEND}.EmailBackend”  
> DEFAULT\_FROM\_EMAIL: “${EMAIL\_DEFAULT\_FROM}”  
> EMAIL\_USE\_TLS: “${EMAIL\_USE\_TLS}”  
> EMAIL\_USE\_SSL: “${EMAIL\_USE\_SSL}”  
> EMAIL\_HOST: “${EMAIL\_HOST}”  
> EMAIL\_PORT: “${EMAIL\_PORT}”  
> EMAIL\_HOST\_USER: “${EMAIL\_HOST\_USER}”  
> EMAIL\_HOST\_PASSWORD: “${EMAIL\_HOST\_PASSWORD}”
> 
> # Rabbitmq settings
> 
> RABBITMQ\_USER: “${RABBITMQ\_USER}”  
> RABBITMQ\_PASS: “${RABBITMQ\_PASS}”
> 
> # Telemetry settings
> 
> ENABLE\_TELEMETRY: “${ENABLE\_TELEMETRY}”
> 
> # …your customizations go here
> 
> x-volumes:  
> &default-back-volumes
> 
> # These volumens will be used by taiga-back and taiga-async.
> 
> - taiga-static-data:/taiga-back/static
> - taiga-media-data:/taiga-back/media
> 
> # - ./config.py:/taiga-back/settings/config.py
> 
> services:
> 
> # taiga-db:
> 
> # image: postgres:12.3
> 
> # environment:
> 
> # POSTGRES\_DB: “taiga”
> 
> # POSTGRES\_USER: “${POSTGRES\_USER}”
> 
> # POSTGRES\_PASSWORD: “${POSTGRES\_PASSWORD}”
> 
> # healthcheck:
> 
> # test: [“CMD-SHELL”, “pg\_isready -U ${POSTGRES\_USER}”]
> 
> # interval: 2s
> 
> # timeout: 15s
> 
> # retries: 5
> 
> # start\_period: 3s
> 
> # volumes:
> 
> # - taiga-db-data:/var/lib/postgresql/data
> 
> # networks:
> 
> # - taiga
> 
> taiga-back:  
> image: taigaio/taiga-back:latest  
> environment: \*default-back-environment  
> volumes: \*default-back-volumes  
> networks:  
> - taiga  
> depends\_on:
> 
> # taiga-db:
> 
> # condition: service\_healthy
> 
> ```
> taiga-events-rabbitmq:
> condition: service_started
> taiga-async-rabbitmq:
> condition: service_started
> 
> ```
> 
> taiga-async:  
> image: taigaio/taiga-back:latest  
> entrypoint: [“/taiga-back/docker/async\_entrypoint.sh”]  
> environment: \*default-back-environment  
> volumes: \*default-back-volumes  
> networks:  
> - taiga  
> depends\_on:
> 
> # taiga-db:
> 
> # condition: service\_healthy
> 
> ```
> taiga-events-rabbitmq:
> condition: service_started
> taiga-async-rabbitmq:
> condition: service_started
> 
> ```
> 
> taiga-async-rabbitmq:  
> image: rabbitmq:3.8-management-alpine  
> environment:  
> RABBITMQ\_ERLANG\_COOKIE: “${RABBITMQ\_ERLANG\_COOKIE}”  
> RABBITMQ\_DEFAULT\_USER: “${RABBITMQ\_USER}”  
> RABBITMQ\_DEFAULT\_PASS: “${RABBITMQ\_PASS}”  
> RABBITMQ\_DEFAULT\_VHOST: “${RABBITMQ\_VHOST}”  
> hostname: “taiga-async-rabbitmq”  
> volumes:  
> - taiga-async-rabbitmq-data:/var/lib/rabbitmq  
> networks:  
> - taiga
> 
> taiga-front:  
> image: taigaio/taiga-front:latest  
> environment:  
> TAIGA\_URL: “${TAIGA\_SCHEME}://${TAIGA\_DOMAIN}”  
> TAIGA\_WEBSOCKETS\_URL: “${WEBSOCKETS\_SCHEME}://${TAIGA\_DOMAIN}”  
> TAIGA\_SUBPATH: “${SUBPATH}”  
> # …your customizations go here  
> networks:  
> - taiga  
> # volumes:  
> # - ./conf.json:/usr/share/nginx/html/conf.json
> 
> taiga-events:  
> image: taigaio/taiga-events:latest  
> environment:  
> RABBITMQ\_USER: “${RABBITMQ\_USER}”  
> RABBITMQ\_PASS: “${RABBITMQ\_PASS}”  
> TAIGA\_SECRET\_KEY: “${SECRET\_KEY}”  
> networks:  
> - taiga  
> depends\_on:  
> taiga-events-rabbitmq:  
> condition: service\_started  
> ports:  
> - “8888:8888” # Expose websocket port on Taiga VM
> 
> taiga-events-rabbitmq:  
> image: rabbitmq:3.8-management-alpine  
> environment:  
> RABBITMQ\_ERLANG\_COOKIE: “${RABBITMQ\_ERLANG\_COOKIE}”  
> RABBITMQ\_DEFAULT\_USER: “${RABBITMQ\_USER}”  
> RABBITMQ\_DEFAULT\_PASS: “${RABBITMQ\_PASS}”  
> RABBITMQ\_DEFAULT\_VHOST: “${RABBITMQ\_VHOST}”  
> hostname: “taiga-events-rabbitmq”  
> volumes:  
> - taiga-events-rabbitmq-data:/var/lib/rabbitmq  
> networks:  
> - taiga
> 
> taiga-protected:  
> image: taigaio/taiga-protected:latest  
> environment:  
> MAX\_AGE: “${ATTACHMENTS\_MAX\_AGE}”  
> SECRET\_KEY: “${SECRET\_KEY}”  
> networks:  
> - taiga
> 
> taiga-gateway:  
> image: nginx:1.19-alpine  
> ports:  
> - “9000:80”  
> volumes:  
> - ./taiga-gateway/taiga.conf:/etc/nginx/conf.d/default.conf  
> - taiga-static-data:/taiga/static  
> - taiga-media-data:/taiga/media  
> networks:  
> - taiga  
> depends\_on:  
> - taiga-front  
> - taiga-back  
> - taiga-events
> 
> volumes:  
> taiga-static-data:  
> taiga-media-data:
> 
> # taiga-db-data:
> 
> taiga-async-rabbitmq-data:  
> taiga-events-rabbitmq-data:
> 
> networks:  
> taiga:
> 
> ```auto
> </details>
> ```

---

<div class="post-metadata">

**Author:** ![NickyDoes](https://dub1.discourse-cdn.com/flex017/user_avatar/community.taiga.io/nickydoes/32/2920_2.png) [@NickyDoes](https://community.taiga.io/u/NickyDoes)\
**Post date:** [March 3, 2025, 8:04pm UTC](https://community.taiga.io/t/new-taiga-reverse-proxying-with-https-using-caddy/5615/2 "2025-03-03T20:04:38Z")

</div>

I’m fairly new to self-hosting Taiga. Please point me in the right direction.

---

<div class="post-metadata">

**Author:** ![csmu](https://dub1.discourse-cdn.com/flex017/user_avatar/community.taiga.io/csmu/32/2289_2.png) [@csmu](https://community.taiga.io/u/csmu)\
**Post date:** [March 8, 2025, 3:55am UTC](https://community.taiga.io/t/new-taiga-reverse-proxying-with-https-using-caddy/5615/3 "2025-03-08T03:55:59Z")

</div>

**Sorry for the delay in responding**.

I don’t use Caddy but it looks to me like your setup is wrong.A proxy is supposed to sit in front of a server. I can’t see any external public facing directive to point to an internal service in your post.

However, I had similar issues getting web sockets to work. The front end was try to access an internal service - it never reached the proxy.

I added a volumes directive in taiga-front to make conf.json file accessible in the taiga-docker directory.

**In docker-composer.yml. Note the volumes: block**

```yml
  taiga-front:
    image: taigaio/taiga-front:latest
    environment:
      TAIGA_URL: "${TAIGA_SCHEME}://${TAIGA_DOMAIN}"
      TAIGA_WEBSOCKETS_URL: "${WEBSOCKETS_SCHEME}://${TAIGA_DOMAIN}"
      TAIGA_SUBPATH: "${SUBPATH}"
      # ...your customizations go here
    networks:
      - taiga
    volumes:
      - ./conf.json:/usr/share/nginx/html/conf.json

```

I changed conf.json events url from what is was - either 127.0.0.1/events or localhost/events, to my Fully Qualified Domain Name/events

```json
{
    "api": "https://sub.domain.tld/api/v1/",
    "eventsUrl": "wss://sub.domain.tld/events",
    "baseHref": "/",
    "eventsMaxMissedHeartbeats": 5,
    "eventsHeartbeatIntervalTime": 60000,
    "eventsReconnectTryInterval": 10000,
    "debug": false,
    "debugInfo": false,
    "defaultLanguage": "en",
    "themes": ["taiga"],
    "defaultTheme": "taiga",
    "defaultLoginEnabled": true,
    "publicRegisterEnabled": false,
    "feedbackEnabled": true,
    "supportUrl": "https://community.taiga.io/",
    "privacyPolicyUrl": null,
    "termsOfServiceUrl": null,
    "maxUploadFileSize": null,
    "contribPlugins": [],
    "gitHubClientId": "",
    "gitLabClientId": "",
    "gitLabUrl": "",
    "tagManager": { "accountId": null },
    "tribeHost": null,
    "enableAsanaImporter": false,
    "enableGithubImporter": false,
    "enableJiraImporter": false,
    "enableTrelloImporter": false,
    "gravatar": false,
    "rtlLanguages": [
        "ar",
        "fa",
        "he"
    ]
}

```

There is an internal nginx conf file at ./taiga-gateway/taiga.conf. I studied it but did not make any changes.

**Environment Variables:**

In the environment variables I changed everything to wss and to https, and removed the port :9000 directive

I also changed localhost:9000 to our fully qualified domain name.

_ **Environment variables extract** _:

```bash
# Taiga's URLs - Variables to define where Taiga should be served
# TAIGA_SCHEME=http # serve Taiga using "http" or "https" (secured) connection
TAIGA_SCHEME=https # serve Taiga using "http" or "https" (secured) connection
# TAIGA_DOMAIN=localhost:9000 # Taiga's base URL
TAIGA_DOMAIN=taiga.domain.tld # Taiga's base URL
SUBPATH="" # it'll be appended to the TAIGA_DOMAIN (use either "" or a "/subpath")
# WEBSOCKETS_SCHEME=ws # events connection protocol (use either "ws" or "wss")
WEBSOCKETS_SCHEME=wss # events connection protocol (use either "ws" or "wss")

```

**Nginx Proxy**

Finally - we serve our taiga instance behind a nginx proxy - similar to what you want to do.

This a sample based on our nginx.conf file.

```bash
server {
    listen 80 ;
    server_name taiga.domain.tld ;
    add_header Strict-Transport-Security max-age=2592000 ;
    rewrite ^/.*$ https://$host$request_uri? permanent ;
}

server {
    listen 443 ;
    server_name taiga.domain.tld ;

    ssl on;
    ssl_certificate "/etc/letsencrypt/live/tauga.domain.tld/fullchain.pem" ;
    ssl_certificate_key "/etc/letsencrypt/live/tauga.domain.tld/privkey.pem" ;
    keepalive_timeout 60;

    ssl_ciphers HIGH:!ADH:!MD5;
    ssl_protocols SSLv3 TLSv1 TLSv1.2;
    ssl_prefer_server_ciphers on;
		
    large_client_header_buffers 4 32k;
    client_max_body_size 50M;
    charset utf-8;

    access_log /home/taiga/logs/nginx.access.log;
    error_log /home/taiga/logs/nginx.error.log;

    # Frontend
    location / {
           proxy_set_header Host $http_host;
           proxy_set_header X-Real-IP $remote_addr;
           proxy_set_header X-Scheme $scheme;
           proxy_set_header X-Forwarded-Proto $scheme;
           proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
           proxy_redirect off;
           proxy_pass http://localhost:9000/;
     }

     # Events
     location /events {
       proxy_pass http://localhost:9000/events;
       proxy_http_version 1.1;
       proxy_set_header Upgrade $http_upgrade;
       proxy_set_header Connection "upgrade";
       proxy_set_header Host $host;
       proxy_connect_timeout 7d;
       proxy_send_timeout 7d;
       proxy_read_timeout 7d;
     }
	 

    # Backend
	# API
    # location /api/ {
    # proxy_pass http://taiga-back:8000/api/;
    # proxy_pass_header Server;
    # proxy_set_header Host $http_host;
    # proxy_redirect off;
    # proxy_set_header X-Real-IP $remote_addr;
    # proxy_set_header X-Scheme $scheme;
    # }
    #
    # # Admin access (/admin/)
    # location /admin/ {
    # proxy_pass http://taiga-back:8000/admin/;
    # proxy_pass_header Server;
    # proxy_set_header Host $http_host;
    # proxy_redirect off;
    # proxy_set_header X-Real-IP $remote_addr;
    # proxy_set_header X-Scheme $scheme;
    # }

    # Static files
	# Static
    location /static/ {
        alias /taiga/static/;
    }

	# Media
    location /_protected/ {
        internal;
        alias /taiga/media/;
        add_header Content-disposition "attachment";
    }

    # Unprotected section
    location /media/exports/ {
        alias /taiga/media/exports/;
        add_header Content-disposition "attachment";
    }

    # location /media/ {
    # proxy_set_header Host $http_host;
    # proxy_set_header X-Real-IP $remote_addr;
    # proxy_set_header X-Scheme $scheme;
    # proxy_set_header X-Forwarded-Proto $scheme;
    # proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    # proxy_pass http://taiga-protected:8003/;
    # proxy_redirect off;
    # }

}

```

Note the

```auto
#Frontend
location /

```

and the

```bash
#Events
location /events

```

blocks.

Hopefully that’s enough to help resolve your issues.

Cheers

Keith
