Skip to content
Crow CI

Reverse Proxy

Configure a reverse proxy to expose Crow CI with TLS termination.

Port Service Required
8000 Web UI and API Yes
9000 GRPC (agent communication) Only for remote agents

Crow reads the client IP from the X-Forwarded-For and X-Real-IP headers. It uses the IP to rate-limit failed LDAP sign-ins. Without CROW_TRUSTED_PROXIES Crow trusts those headers from any client, so a client can fake its address and avoid the per-IP limit. Set CROW_TRUSTED_PROXIES to the IP addresses or CIDR ranges of your reverse proxies:

CROW_TRUSTED_PROXIES=10.0.0.0/8,192.168.1.10

The server refuses to start when an entry is not a valid IP address or CIDR range. It logs a warning at startup when LDAP is enabled and the variable is unset.

# Web UI
crow.example.com {
    reverse_proxy crow-server:8000
}

# GRPC (optional - for remote agents)
grpc.crow.example.com {
    reverse_proxy h2c://crow-server:9000
}
server {
    listen 443 ssl;
    server_name crow.example.com;

    ssl_certificate /path/to/cert;
    ssl_certificate_key /path/to/key;

    location / {
        proxy_set_header X-Forwarded-For $remote_addr;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header Host $http_host;
        proxy_pass http://127.0.0.1:8000;
        proxy_redirect off;
        proxy_http_version 1.1;
        proxy_buffering off;
        chunked_transfer_encoding off;
    }
}

# GRPC (optional - for remote agents)
server {
    listen 443 ssl;
    server_name grpc.crow.example.com;

    ssl_certificate /path/to/cert;
    ssl_certificate_key /path/to/key;

    location / {
        grpc_pass grpc://127.0.0.1:9000;
    }
}

Docker Compose with TLS termination and HTTP→HTTPS redirect:

services:
  server:
    image: codefloe.com/crowci/crow-server:v4
    networks:
      - traefik
    volumes:
      - crow-data:/var/lib/crow
    deploy:
      labels:
        - traefik.enable=true
        # Web UI
        - traefik.http.services.crow.loadbalancer.server.port=8000
        - traefik.http.routers.crow-secure.rule=Host(`crow.example.com`)
        - traefik.http.routers.crow-secure.tls=true
        - traefik.http.routers.crow-secure.tls.certresolver=letsencrypt
        - traefik.http.routers.crow-secure.entrypoints=web-secure
        - traefik.http.routers.crow-secure.service=crow
        # HTTP redirect
        - traefik.http.routers.crow.rule=Host(`crow.example.com`)
        - traefik.http.routers.crow.entrypoints=web
        - traefik.http.middlewares.crow-redirect.redirectscheme.scheme=https
        - traefik.http.routers.crow.middlewares=crow-redirect@docker
        # GRPC (optional - for remote agents)
        - traefik.http.services.crow-grpc.loadbalancer.server.port=9000
        - traefik.http.services.crow-grpc.loadbalancer.server.scheme=h2c
        - traefik.http.routers.crow-grpc-secure.rule=Host(`grpc.crow.example.com`)
        - traefik.http.routers.crow-grpc-secure.tls=true
        - traefik.http.routers.crow-grpc-secure.tls.certresolver=letsencrypt
        - traefik.http.routers.crow-grpc-secure.entrypoints=web-secure
        - traefik.http.routers.crow-grpc-secure.service=crow-grpc

networks:
  traefik:
    external: true
frontend https_in
    mode http
    bind :::443 v4v6 ssl crt /path/to/cert

    acl is_crow hdr(host) -i crow.example.com
    acl is_crow_grpc hdr(host) -i grpc.crow.example.com

    use_backend crow if is_crow
    use_backend crow_grpc if is_crow_grpc

backend crow
    mode http
    balance roundrobin
    http-request del-header X-Forwarded-For
    http-request del-header X-Real-IP
    option forwardfor
    server crow 127.0.0.1:8000 maxconn 100000 check

backend crow_grpc
    mode http
    server crow_grpc 127.0.0.1:9000 maxconn 100000 no-check proto h2

Required modules: proxy, proxy_http

ProxyPreserveHost On
RequestHeader set X-Forwarded-Proto "https"
ProxyPass / http://127.0.0.1:8000/
ProxyPassReverse / http://127.0.0.1:8000/