# 04 — SWAG Nginx Proxy Configs (Test)

## Context
SWAG nginx auto-includes only `site-confs/*.conf`. All proxy config templates live in `template/swag/site-confs/` in the repo and are rendered to `/opt/iklimco/swag/site-confs/` on the host at deploy time.

Templates use `${VAR}` placeholders processed with `envsubst` at deploy time.

## Required env vars (in `.env` on storagebox `test/secrets/iklim.co/.env`)

```bash
API_SUBDOMAIN=api-test.iklim.co
APIGW_SUBDOMAIN=apigw-test.iklim.co
RABBITMQ_SUBDOMAIN=rabbitmq-test.iklim.co
GRAFANA_SUBDOMAIN=grafana-test.iklim.co
# Comma-separated list of allowed CIDRs for IP-restricted subdomains
RESTRICTED_IPS="78.187.87.109/32,95.70.151.248/32"
```

## Files to create

### `template/swag/site-confs/default.conf`
Default catch-all: HTTP→HTTPS redirect + 444 for unknown HTTPS hosts.

```nginx
server {
    listen 80 default_server;
    listen [::]:80 default_server;
    server_name _;
    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl http2 default_server;
    listen [::]:443 ssl http2 default_server;
    server_name _;
    include /config/nginx/ssl.conf;
    return 444;
}
```

### `template/swag/site-confs/api.conf.tpl`
Public API gateway — no IP restriction.

```nginx
server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name ${API_SUBDOMAIN};

    include /config/nginx/ssl.conf;
    include /config/nginx/resolver.conf;

    client_max_body_size 50m;

    location / {
        include /config/nginx/proxy.conf;
        include /config/nginx/resolver.conf;
        set $upstream_app apisix;
        set $upstream_port 9080;
        set $upstream_proto http;
        proxy_pass $upstream_proto://$upstream_app:$upstream_port;
    }
}
```

### `template/swag/site-confs/apigw.conf.tpl`
APISIX Dashboard — IP restricted.

```nginx
server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name ${APIGW_SUBDOMAIN};

    include /config/nginx/ssl.conf;
    include /config/nginx/resolver.conf;

    client_max_body_size 0;

    location / {
${RESTRICTED_IPS_BLOCK}
        deny all;

        include /config/nginx/proxy.conf;
        include /config/nginx/resolver.conf;
        set $upstream_app apisix-dashboard;
        set $upstream_port 9000;
        set $upstream_proto http;
        proxy_pass $upstream_proto://$upstream_app:$upstream_port;
    }
}
```

> `${RESTRICTED_IPS_BLOCK}` is generated at deploy time from `RESTRICTED_IPS` (comma-separated CIDRs)
> as multi-line `allow` directives with `/32` suffix. See `07-deploy-pipeline-update.md` for the pipeline step.

### `template/swag/site-confs/rabbitmq.conf.tpl`
RabbitMQ Management UI — IP restricted.

```nginx
server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name ${RABBITMQ_SUBDOMAIN};

    include /config/nginx/ssl.conf;
    include /config/nginx/resolver.conf;

    client_max_body_size 0;

    location / {
${RESTRICTED_IPS_BLOCK}
        deny all;

        include /config/nginx/proxy.conf;
        include /config/nginx/resolver.conf;
        set $upstream_app rabbitmq;
        set $upstream_port 15672;
        set $upstream_proto http;
        proxy_pass $upstream_proto://$upstream_app:$upstream_port;
    }
}
```

### `template/swag/site-confs/grafana.conf.tpl`
Grafana — IP restricted.

```nginx
server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name ${GRAFANA_SUBDOMAIN};

    include /config/nginx/ssl.conf;
    include /config/nginx/resolver.conf;

    client_max_body_size 0;

    location / {
${RESTRICTED_IPS_BLOCK}
        deny all;

        include /config/nginx/proxy.conf;
        include /config/nginx/resolver.conf;
        set $upstream_app grafana;
        set $upstream_port 3000;
        set $upstream_proto http;
        proxy_pass $upstream_proto://$upstream_app:$upstream_port;
    }
}
```

## Deploy step (handled by pipeline — see `07-deploy-pipeline-update.md`)

```bash
set -a; . ./.env; . ./.env.secrets.swag; set +a

docker run --rm -v /opt/iklimco/swag:/output alpine \
  mkdir -p /output/dns-conf /output/site-confs

envsubst < template/swag/dns-conf/godaddy.ini.tpl | docker run --rm -i \
  -v /opt/iklimco/swag/dns-conf:/output \
  alpine sh -c "cat > /output/godaddy.ini && chmod 600 /output/godaddy.ini"

# RESTRICTED_IPS → multi-line allow block (indented 8 spaces per nginx style)
export RESTRICTED_IPS_BLOCK="$(echo "$RESTRICTED_IPS" | tr ',' '\n' | sed 's|.*|        allow &;|')"

# Explicit var list prevents nginx $upstream_* from being substituted by envsubst
SWAG_VARS='${API_SUBDOMAIN}${APIGW_SUBDOMAIN}${GRAFANA_SUBDOMAIN}${RABBITMQ_SUBDOMAIN}${RESTRICTED_IPS_BLOCK}'
for tpl in template/swag/site-confs/*.conf.tpl; do
  fname=$(basename "${tpl%.tpl}")
  envsubst "$SWAG_VARS" < "$tpl" | docker run --rm -i \
    -v /opt/iklimco/swag/site-confs:/output \
    alpine sh -c "cat > /output/${fname}"
  echo "✅ ${fname}"
done

cat template/swag/site-confs/default.conf | docker run --rm -i \
  -v /opt/iklimco/swag/site-confs:/output \
  alpine sh -c "cat > /output/default.conf"
```

## Verification

After deploy, check SWAG nginx config is valid:
```bash
docker exec $(docker ps -q -f name=iklimco_swag) nginx -t
```

Check subdomains resolve (from outside the server):
```bash
curl -sk https://api-test.iklim.co/health    # expects APISIX response
curl -sk https://grafana-test.iklim.co       # expects 403 Forbidden (wrong IP)
```

## Notes
- `include /config/nginx/resolver.conf` enables dynamic upstream resolution via Docker DNS —
  required for overlay service names like `apisix`, `grafana`, etc.
- SWAG's `proxy.conf` already sets `X-Real-IP`, `X-Forwarded-For`, `X-Forwarded-Proto` and
  WebSocket upgrade headers. No manual addition needed.
- `*.iklim.co` cert covers both `api.iklim.co` and `api-test.iklim.co` subdomains —
  both test and prod servers can independently obtain and use it.
