# Reverse Proxy Setup Guide

It is recommended to run `nostr-rs-relay` behind a reverse proxy such
as `haproxy`, `nginx` or `traefik` to provide TLS termination.  Simple examples
for `haproxy`, `nginx` and `traefik` configurations are documented here.

## Minimal HAProxy Configuration

Assumptions:

* HAProxy version is `2.4.10` or greater (older versions not tested).
* Hostname for the relay is `relay.example.com`.
* Your relay should be available over wss://relay.example.com
* Your (NIP-11) relay info page should be available on https://relay.example.com
* SSL certificate is located in `/etc/certs/example.com.pem`.
* Relay is running on port 8080.
* Limit connections to 400 concurrent.
* HSTS (HTTP Strict Transport Security) is desired.
* Only TLS 1.2 or greater is allowed.

```
global
    ssl-default-bind-ciphersuites TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256
    ssl-default-bind-options prefer-client-ciphers no-sslv3 no-tlsv10 no-tlsv11 no-tls-tickets

frontend fe_prod
    mode    http
    bind    :443 ssl crt /etc/certs/example.com.pem alpn h2,http/1.1
    bind    :80
    http-request set-header X-Forwarded-Proto https if { ssl_fc }
    redirect scheme https code 301 if !{ ssl_fc }
    acl host_relay hdr(host) -i -m beg relay.example.com
    use_backend relay if host_relay
    # HSTS (1 year)
    http-response set-header Strict-Transport-Security max-age=31536000

backend relay
    mode http
    timeout connect 5s
    timeout client 50s
    timeout server 50s
    timeout tunnel 1h
    timeout client-fin 30s
    option tcp-check
    default-server maxconn 400 check inter 20s fastinter 1s
    server relay 127.0.0.1:8080
```

### HAProxy Notes

You may experience WebSocket connection problems with Firefox if
HTTP/2 is enabled, for older versions of HAProxy (2.3.x).  Either
disable HTTP/2 (`h2`), or upgrade HAProxy.

## Bare-bones Nginx Configuration

Assumptions:

* `Nginx` version is `1.18.0` (other versions not tested).
* Hostname for the relay is `relay.example.com`.
* SSL certificate and key are located at `/etc/letsencrypt/live/relay.example.com/`.
* Relay is running on port `8080`.

```
http {
    server {
        listen 443 ssl;
        server_name relay.example.com;
        ssl_certificate /etc/letsencrypt/live/relay.example.com/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/relay.example.com/privkey.pem;
        ssl_protocols TLSv1.3 TLSv1.2;
        ssl_prefer_server_ciphers on;
        ssl_ecdh_curve secp521r1:secp384r1;
        ssl_ciphers EECDH+AESGCM:EECDH+AES256;

        # Optional Diffie-Helmann parameters
        # Generate with openssl dhparam -out /etc/ssl/certs/dhparam.pem 4096
        #ssl_dhparam /etc/ssl/certs/dhparam.pem;

        ssl_session_cache shared:TLS:2m;
        ssl_buffer_size 4k;

        # OCSP stapling
        ssl_stapling on;
        ssl_stapling_verify on;
        resolver 1.1.1.1 1.0.0.1 [2606:4700:4700::1111] [2606:4700:4700::1001]; # Cloudflare

        # Set HSTS to 365 days
        add_header Strict-Transport-Security 'max-age=31536000; includeSubDomains; preload' always;
        keepalive_timeout 70;

        location / {
            proxy_pass http://localhost:8080;
            proxy_http_version 1.1;
            proxy_read_timeout 1d;
            proxy_send_timeout 1d;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "Upgrade";
            proxy_set_header Host $host;
        }
    }
}
```

### Nginx Notes

The above configuration was tested on `nginx` `1.18.0` on `Ubuntu` `20.04` and `22.04`

For help installing `nginx` on `Ubuntu`, see [this guide](https://www.digitalocean.com/community/tutorials/how-to-install-nginx-on-ubuntu-20-04).

For guidance on using `letsencrypt` to obtain a cert on `Ubuntu`, including an `nginx` plugin, see [this post](https://www.digitalocean.com/community/tutorials/how-to-secure-nginx-with-let-s-encrypt-on-ubuntu-20-04).


## Example Traefik Configuration

Assumptions:

* `Traefik` version is `2.9` (other versions not tested).
* `Traefik` is used for provisioning of Let's Encrypt certificates.
* `Traefik` is running in `Docker`, using `docker compose` and labels for the static configuration. An equivalent setup using a Traefik config file is possible too (but not covered here).
* Strict Transport Security is enabled.
* Hostname for the relay is `relay.example.com`, email address for ACME certificates provider is `name@example.com`.
* ipv6 is enabled, a viable private ipv6 subnet is specified in the example below.
* Relay is running on port `8080`.

```
version: '3'

networks:
  nostr:
    enable_ipv6: true
    ipam:
      config:
        - subnet: fd00:db8:a::/64
          gateway: fd00:db8:a::1

services:
  traefik:
    image: traefik:v2.9
    networks:
      nostr:
    command:
      - "--log.level=ERROR"
      # letsencrypt configuration
      - "--certificatesResolvers.http.acme.email==name@example.com"
      - "--certificatesResolvers.http.acme.storage=/certs/acme.json"
      - "--certificatesResolvers.http.acme.httpChallenge.entryPoint=http"
      # define entrypoints
      - "--entryPoints.http.address=:80"
      - "--entryPoints.http.http.redirections.entryPoint.to=https"
      - "--entryPoints.http.http.redirections.entryPoint.scheme=https"
      - "--entryPoints.https.address=:443"
      - "--entryPoints.https.forwardedHeaders.insecure=true"
      - "--entryPoints.https.proxyProtocol.insecure=true"
      # docker provider (get configuration from container labels)
      - "--providers.docker.endpoint=unix:///var/run/docker.sock"
      - "--providers.docker.exposedByDefault=false"
      - "--providers.file.directory=/config"
      - "--providers.file.watch=true"
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - "/var/run/docker.sock:/var/run/docker.sock:ro"
      - "$(pwd)/traefik/certs:/certs"
      - "$(pwd)/traefik/config:/config"
    logging:
      driver: "local"
    restart: always

  # example nostr config. only labels: section is relevant for Traefik config
  nostr:
   image: nostr-rs-relay:latest
   container_name: nostr-relay
   networks:
     nostr:
   restart: always
   user: 100:100
   volumes:
   - '$(pwd)/nostr/data:/usr/src/app/db:Z'
   - '$(pwd)/nostr/config/config.toml:/usr/src/app/config.toml:ro,Z'
   labels:
     - "traefik.enable=true"
     - "traefik.http.routers.nostr.entrypoints=https"
     - "traefik.http.routers.nostr.rule=Host(`relay.example.com`)"
     - "traefik.http.routers.nostr.tls.certresolver=http"
     - "traefik.http.routers.nostr.service=nostr"
     - "traefik.http.services.nostr.loadbalancer.server.port=8080"
     - "traefik.http.services.nostr.loadbalancer.passHostHeader=true"
     - "traefik.http.middlewares.nostr.headers.sslredirect=true"
     - "traefik.http.middlewares.nostr.headers.stsincludesubdomains=true"
     - "traefik.http.middlewares.nostr.headers.stspreload=true"
     - "traefik.http.middlewares.nostr.headers.stsseconds=63072000"
     - "traefik.http.routers.nostr.middlewares=nostr"
```

### Traefik Notes

Traefik will take care of the provisioning and renewal of certificates. In case of an ipv4-only relay, simply detele the `enable_ipv6:` and `ipam:` entries in the `networks:` section of the docker-compose file.