Vaultwarden + ModSecurity with subpath

Hi !
I’m currently trying to set up a vaultwarden but I face issues with subpath. I have this configuration:

version: "3.3"

services:
  waf:
    image: owasp/modsecurity-crs:apache
    container_name: waf
    env_file:
      - .env
    environment:
      PARANOIA: 1
      ANOMALY_INBOUND: 10
      ANOMALY_OUTBOUND: 5
      PROXY: 1
      REMOTEIP_INT_PROXY: "172.20.0.1/16"
      BACKEND: "http://vaultwarden:80/po"
      BACKEND_WS: "ws://vaultwarden:80/po/notifications/hub"
      ERRORLOG: "/var/log/waf/waf.log"
      PROXY_ERROR_OVERRIDE: "off"
    volumes:
     - /opt/docker/waf:/var/log/waf
     - /opt/docker/waf-rules/REQUEST-900-EXCLUSION-RULES-BEFORE-CRS.conf:/etc/modsecurity.d/owasp-crs/rules/REQUEST-900-EXCLUSION-RULES-BEFORE-CRS.conf
     - /opt/docker/waf-rules/RESPONSE-999-EXCLUSION-RULES-AFTER-CRS.conf:/etc/modsecurity.d/owasp-crs/rules/RESPONSE-999-EXCLUSION-RULES-AFTER-CRS.conf
    labels:
      - traefik.enable=true
      - traefik.http.middlewares.redirect-https.redirectScheme.scheme=https
      - traefik.http.middlewares.redirect-https.redirectScheme.permanent=true
      - traefik.http.routers.vw-ui-https.rule=Host(`${VW_SUBDOMAIN}.${DOMAIN}`) && Path(`/po`)
      - traefik.http.routers.vw-ui-https.entrypoints=websecure
      - traefik.http.routers.vw-ui-https.tls=true
      - traefik.http.routers.vw-ui-https.service=vw-ui
      - traefik.http.routers.vw-ui-http.rule=Host(`${VW_SUBDOMAIN}.${DOMAIN}`) && Path(`/po`)
      - traefik.http.routers.vw-ui-http.entrypoints=web
      - traefik.http.routers.vw-ui-http.middlewares=redirect-https
      - traefik.http.routers.vw-ui-http.service=vw-ui
      - traefik.http.services.vw-ui.loadbalancer.server.port=80
      - traefik.http.routers.vw-websocket-https.rule=Host(`${VW_SUBDOMAIN}.${DOMAIN}`) && Path(`/po/notifications/hub`)
      - traefik.http.routers.vw-websocket-https.entrypoints=websecure
      - traefik.http.routers.vw-websocket-https.tls=true
      - traefik.http.routers.vw-websocket-https.service=vw-websocket
      - traefik.http.routers.vw-websocket-http.rule=Host(`${VW_SUBDOMAIN}.${DOMAIN}`) && Path(`/po/notifications/hub`)
      - traefik.http.routers.vw-websocket-http.entrypoints=web
      - traefik.http.routers.vw-websocket-http.middlewares=redirect-https
      - traefik.http.routers.vw-websocket-http.service=vw-websocket
      - traefik.http.services.vw-websocket.loadbalancer.server.port=3012

  vaultwarden:
    image: vaultwarden/server:latest
    container_name: vaultwarden
    restart: unless-stopped
    environment:
      WEBSOCKET_ENABLED: true
      SENDS_ALLOWED: false
      INVITATIONS_ALLOWED: true
      PASSWORD_ITERATIONS: 500000
      SIGNUPS_ALLOWED: false
      SIGNUPS_VERIFY: true
    labels:
      - traefik.enable=true
      - traefik.http.middlewares.redirect-https.redirectScheme.scheme=https
      - traefik.http.middlewares.redirect-https.redirectScheme.permanent=true
    volumes:
      - /opt/docker/vaultwarden:/data

I have this response on subdomain.example.com/po
image

I’m kind of new with traefik so maybe I have misunderstood some configuration. I hope someone will be able to help !

Thank you by advance

I’m not that familiar ModSecurity so not sure if the configuration is correct but I think you’ll have to at least set the DOMAIN too. C.f. the .env.template and

ModSecurity blocks several methods which Bitwarden needs to work, and it also adds or adjusts some other headers which tend to break the functionality.

I managed to do it this way:

version: "3.3"

services:
  waf:
    image: owasp/modsecurity-crs:apache
    container_name: waf
    networks:
      - vaultwarden
    environment:
      PARANOIA: 1
      ANOMALY_INBOUND: 10
      ANOMALY_OUTBOUND: 5
      PROXY: 1
      REMOTEIP_INT_PROXY: "172.20.0.1/16"
      BACKEND: "http://vaultwarden:80"
      BACKEND_WS: "ws://vaultwarden:80/notifications/hub"
      ERRORLOG: "/var/log/waf/waf.log"
      PROXY_ERROR_OVERRIDE: "off"
    volumes:
      - /opt/docker/waf:/var/log/waf
      - /opt/docker/waf-rules/REQUEST-900-EXCLUSION-RULES-BEFORE-CRS.conf:/etc/modsecurity.d/owasp-crs/rules/REQUEST-900-EXCLUSION-RULES-BEFORE-CRS.conf
      - /opt/docker/waf-rules/RESPONSE-999-EXCLUSION-RULES-AFTER-CRS.conf:/etc/modsecurity.d/owasp-crs/rules/RESPONSE-999-EXCLUSION-RULES-AFTER-CRS.conf
    labels:
      traefik.enable: true
      traefik.docker.network: waf

      # Vaultwarden UI
      traefik.http.services.vaultwarden-ui.loadbalancer.server.port: 80
      traefik.http.routers.vaultwarden-ui.rule: Host(`${VW_SUBDOMAIN}.${DOMAIN}`) && PathPrefix(`/vault/${SUBPATH}`)
      traefik.http.routers.vaultwarden-ui.entrypoints: websecure
      traefik.http.routers.vaultwarden-ui.tls: true
      traefik.http.routers.vaultwarden-ui.service: vaultwarden-ui

      # Vaultwarden WS
      traefik.http.services.vaultwarden-ws.loadbalancer.server.port: 3012
      traefik.http.routers.vaultwarden-ws.rule: Host(`${VW_SUBDOMAIN}.${DOMAIN}`) && Path(`/vault/${SUBPATH}/notifications/hub`)
      traefik.http.routers.vaultwarden-ws.entrypoints: websecure
      traefik.http.routers.vaultwarden-ws.tls: true
      traefik.http.routers.vaultwarden-ws.service: vaultwarden-ws

      traefik.http.middlewares.redirect-https.redirectScheme.scheme: https
      traefik.http.middlewares.redirect-https.redirectScheme.permanent: true

  vaultwarden:
    image: vaultwarden/server:latest
    container_name: vaultwarden
    restart: unless-stopped
    networks:
      - vaultwarden
    environment:
      DOMAIN: "https://${VW_SUBDOMAIN}.${DOMAIN}/vault/${SUBPATH}/"
    labels:
      traefik.enable: true
      traefik.docker.network: vaultwarden
      traefik.http.middlewares.redirect-https.redirectScheme.scheme: https
      traefik.http.middlewares.redirect-https.redirectScheme.permanent: true
    volumes:
      - /opt/docker/vaultwarden:/data

networks:
  vaultwarden:
    name: vaultwarden
    external: true
DOMAIN="example.com"
VW_SUBDOMAIN="vaultwarden"
SUBPATH="s3cr3t"

This way, to access the vault you have to go to vaultwarden.example.com/vault/s3cr3t/
Only downside is that you have to put the / at the end or it doesn’t work.

Thanks for your help !