# 03 — docker-stack-infra.yml Changes (Test)

## Context
- **File:** `docker-stack-infra.yml` (repo root)
- **Goal:** Add SWAG as TLS-terminating reverse proxy; remove all published ports from internal services (they become reachable only via SWAG through the `iklimco-net` overlay network); remove Vault's external port entirely.

## Changes Summary

| Service | Before | After |
|---------|--------|-------|
| **swag** | does not exist | add: ports 80+443, manager-pinned |
| **cert-reloader** | does not exist | add: manager-pinned, Docker socket |
| **vault** | publishes 8200 | no published port |
| **apisix** | publishes 8080, 8443, 9180 | no published ports |
| **rabbitmq** | publishes 5672, 15672, 61613, 15674 | no published ports |
| **prometheus** | publishes 9090 | no published port |
| **grafana** | publishes 3000 | no published port |
| **apisix-dashboard** | publishes 9000 | no published port |

> **RabbitMQ STOMP note:** Ports 61613 (STOMP) and 15674 (WebSocket STOMP) are removed because
> APISIX already proxies WebSocket STOMP to RabbitMQ via the overlay network. Verify that
> APISIX has a stream/WebSocket route for STOMP before removing these if external clients
> connect to STOMP directly (not via APISIX).

## Step 1 — Add `swag` service

Add after the `apisix-dashboard` service block:

```yaml
  swag:
    image: lscr.io/linuxserver/swag:latest
    cap_add:
      - NET_ADMIN
    environment:
      - PUID=1000
      - PGID=1000
      - TZ=Europe/Istanbul
      - URL=iklim.co
      - SUBDOMAINS=wildcard
      - VALIDATION=dns
      - DNSPLUGIN=godaddy
      - ONLY_SUBDOMAINS=false
      - EMAIL=muratozdemir@tarla.io
      - DNSPROPAGATION=90
    volumes:
      - ${SWAG_CONFIG_DIR:-swag-vl}:/config
      - ${SWAG_DNS_CONFIG_DIR:-/opt/iklimco/swag/dns-conf}:/config/dns-conf
      - ${SWAG_SITE_CONFS_DIR:-/opt/iklimco/swag/site-confs}:/config/nginx/site-confs
    ports:
      - target: 80
        published: 80
        protocol: tcp
        mode: host
      - target: 443
        published: 443
        protocol: tcp
        mode: host
    deploy:
      mode: replicated
      replicas: 1
      placement:
        constraints:
          - node.role == manager
      restart_policy:
        condition: on-failure
        delay: 5s
    labels:
      project: co.iklim
```

## Step 2 — Add `cert-reloader` service

Add after the `swag` service block:

```yaml
  cert-reloader:
    image: docker:27-cli
    volumes:
      - ${SWAG_CONFIG_DIR:-swag-vl}:/swag-config:ro
      - ${SWAG_CERT_DIR:-/opt/iklimco/ssl}:/host-ssl
      - /var/run/docker.sock:/var/run/docker.sock
    entrypoint: ["/bin/sh", "-c"]
    command:
      - |
        CERT_DIR=/swag-config/etc/letsencrypt/live/iklim.co
        HOST_DIR=/host-ssl
        LAST_HASH=""
        echo "[cert-reloader] started"
        while true; do
          if [ -f "$$CERT_DIR/fullchain.pem" ]; then
            CURR=$$(md5sum "$$CERT_DIR/fullchain.pem" | cut -d' ' -f1)
            if [ "$$CURR" != "$$LAST_HASH" ]; then
              echo "[cert-reloader] cert changed — copying and reloading Vault"
              cp "$$CERT_DIR/fullchain.pem" "$$HOST_DIR/STAR.iklim.co.full.crt"
              cp "$$CERT_DIR/privkey.pem"   "$$HOST_DIR/STAR.iklim.co_key.pem"
              docker service update --force iklimco_vault
              LAST_HASH="$$CURR"
              echo "[cert-reloader] done"
            fi
          fi
          sleep 3600
        done
    deploy:
      mode: replicated
      replicas: 1
      placement:
        constraints:
          - node.role == manager
      restart_policy:
        condition: on-failure
        delay: 10s
    labels:
      project: co.iklim
```

> `$$` is required in Docker Swarm YAML to escape `$` and prevent host-side variable expansion.

## Step 3 — Remove `vault` published port

Find the `vault` service `ports:` block and **delete it entirely**:

```yaml
# DELETE this entire block from vault service:
    ports:
      - target: 8200
        published: 8200
        protocol: tcp
        mode: host
```

Vault remains reachable within `iklimco-net` via the overlay alias `vault.iklim.co:8200`. The `VAULT_LOCAL_CONFIG` `api_addr` and `networks.default.aliases` entries stay unchanged.

## Step 4 — Remove `apisix` published ports

Find the `apisix` service `ports:` block and **delete it entirely**:

```yaml
# DELETE this entire block from apisix service:
    ports:
      - target: 9080
        published: 8080
        protocol: tcp
        mode: host
      - target: 9443
        published: 8443
        protocol: tcp
        mode: host
      - target: 9180
        published: 9180
        protocol: tcp
        mode: host
```

APISIX admin API (9180) access: use `docker exec` or SSH tunnel. APISIX is reachable from SWAG via `http://apisix:9080` on the overlay network.

## Step 5 — Remove `apisix-dashboard` published port

```yaml
# DELETE from apisix-dashboard:
    ports:
      - target: 9000
        published: 9000
        protocol: tcp
        mode: host
```

## Step 6 — Remove `rabbitmq` published ports

```yaml
# DELETE from rabbitmq:
    ports:
      - target: 5672
        published: 5672
        protocol: tcp
        mode: host
      - target: 15672
        published: 15672
        protocol: tcp
        mode: host
      - target: 61613
        published: 61613
        protocol: tcp
        mode: host
      - target: 15674
        published: 15674
        protocol: tcp
        mode: host
```

## Step 7 — Remove `prometheus` published port

```yaml
# DELETE from prometheus:
    ports:
      - target: 9090
        published: 9090
        protocol: tcp
        mode: host
```

## Step 8 — Remove `grafana` published port

```yaml
# DELETE from grafana:
    ports:
      - target: 3000
        published: 3000
        protocol: tcp
        mode: host
```

## Step 9 — Add `swag-vl` volume

In the `volumes:` section at the bottom of the file, add:

```yaml
  swag-vl:
    labels:
      project: co.iklim
```

## Verification

After deploy:
```bash
docker service ls --filter label=project=co.iklim
```

Confirm `iklimco_swag` and `iklimco_cert-reloader` appear in the list.

```bash
docker service ps iklimco_swag
docker service ps iklimco_cert-reloader
```

Both should show `Running`.
