# Puente de webhooks Consuerte

## Objetivo

Este servidor funciona como puente de seguridad entre las IP publicas de los
webhooks y los backends internos de Consuerte.

El puente recibe la solicitud HTTP, identifica el ambiente por el puerto de
entrada y la reenvia una sola vez al backend correspondiente. Conserva el
metodo, ruta, query string, encabezados, cuerpo JSON y respuesta HTTP.

Este directorio no contiene una aplicacion PHP. La comunicacion es realizada
por Apache mediante proxy inverso. Este archivo solo documenta la operacion.

## Arquitectura

### Pruebas

```text
Internet
13.216.178.124:8094
        |
        | NAT de Telecom
        v
10.1.1.10:8094
        |
        | Apache reverse proxy
        v
10.231.0.136:8094/webhook
```

URL publica:

```text
http://13.216.178.124:8094/webhook
```

### Produccion

```text
Internet
190.60.232.235:8090
        |
        | NAT de Telecom
        v
10.1.1.10:8090
        |
        | Apache reverse proxy
        v
10.1.1.4:8094/webhook
```

URL publica:

```text
http://190.60.232.235:8090/webhook
```

## Regla para identificar el ambiente

El ambiente se determina exclusivamente por el puerto interno recibido:

| Puerto en 10.1.1.10 | Ambiente | Backend destino |
|---|---|---|
| 8094 | pruebas | `http://10.231.0.136:8094` |
| 8090 | produccion | `http://10.1.1.4:8094` |

Telecom debe conservar estos puertos en el NAT. No se deben dirigir ambas IP
publicas al mismo puerto interno.

Apache sobrescribe los siguientes encabezados antes de enviar la solicitud:

```text
X-Webhook-Environment: pruebas | produccion
X-Webhook-Public-Endpoint: IP_PUBLICA:PUERTO
```

Estos encabezados son informativos para trazabilidad. La seleccion efectiva
del backend se realiza en la configuracion de Apache, no usando datos enviados
por el cliente.

## Archivos que hacen funcionar el puente

```text
/etc/apache2/ports.conf
/etc/apache2/sites-available/webhook-bridge-8094.conf
/etc/apache2/sites-enabled/webhook-bridge-8094.conf
/etc/apache2/sites-available/webhook-bridge-8090.conf
/etc/apache2/sites-enabled/webhook-bridge-8090.conf
```

Modulos requeridos:

```text
proxy
proxy_http
headers
rewrite
```

La carpeta actual se usa como `DocumentRoot`, pero Apache bloquea el acceso a
archivos. Solamente se permite el proxy de `/webhook` y sus subrutas.

## Funcionamiento de una solicitud

1. El proveedor envia una solicitud a la IP publica del ambiente.
2. Telecom aplica NAT hacia `10.1.1.10`, conservando el puerto definido.
3. Apache acepta la solicitud en `8094` o `8090`.
4. Apache rechaza rutas que no pertenezcan a `/webhook`.
5. Apache agrega los encabezados internos del ambiente.
6. Apache reenvia la solicitud al backend interno correspondiente.
7. El backend valida su token y procesa el webhook.
8. Apache devuelve al proveedor el mismo codigo, encabezados y cuerpo de respuesta.

No se deben configurar envios simultaneos al puente y al backend final porque
podrian producir mensajes o procesos duplicados.

## Controles de seguridad actuales

- `ProxyRequests Off`: impide usar el servidor como proxy abierto.
- Solo `/webhook` y sus subrutas se envian al backend.
- Las demas rutas responden `404`.
- Limite de cuerpo de solicitud: 2 MB.
- Tiempo maximo del proxy: 65 segundos.
- El backend conserva la validacion de su token.
- Los logs registran metadatos, pero no guardan el cuerpo del webhook.
- Pruebas y produccion tienen puertos, destinos y logs independientes.

El endpoint publico sigue usando HTTP. Como mejora posterior se recomienda usar
HTTPS y, si el proveedor publica sus rangos, una lista permitida de IP origen.

## Comandos de revision

Todos los comandos de esta seccion se ejecutan en `10.1.1.10` como usuario con
permisos administrativos.

### Estado de Apache

```bash
systemctl status apache2 --no-pager
systemctl is-active apache2
apache2ctl configtest
apache2ctl -S
```

El resultado esperado de validacion es:

```text
Syntax OK
```

### Puertos activos

```bash
ss -ltnp | grep -E ':(8090|8094)\b'
```

Deben aparecer los dos puertos en estado `LISTEN`.

### Modulos habilitados

```bash
apache2ctl -M | grep -E 'proxy|proxy_http|headers|rewrite'
```

### Ver configuracion del puente

```bash
cat /etc/apache2/sites-available/webhook-bridge-8094.conf
cat /etc/apache2/sites-available/webhook-bridge-8090.conf
```

### Ver sitios habilitados

```bash
readlink -f /etc/apache2/sites-enabled/webhook-bridge-8094.conf
readlink -f /etc/apache2/sites-enabled/webhook-bridge-8090.conf
```

### Comprobar conectividad con los backends

Una respuesta `405 Method Not Allowed` a GET confirma que `/webhook` existe y
que espera POST.

```bash
curl -i --connect-timeout 5 --max-time 12 \
  http://10.231.0.136:8094/webhook

curl -i --connect-timeout 5 --max-time 12 \
  http://10.1.1.4:8094/webhook
```

### Prueba segura del puente

Estas pruebas usan un token deliberadamente invalido. El resultado esperado es
`HTTP 403` con `Token invalido`. No generan una operacion real.

Pruebas:

```bash
curl -i --connect-timeout 5 --max-time 12 \
  -H 'Content-Type: application/json' \
  -X POST \
  --data '{"token":"token-control-invalido"}' \
  http://10.1.1.10:8094/webhook
```

Produccion:

```bash
curl -i --connect-timeout 5 --max-time 12 \
  -H 'Content-Type: application/json' \
  -X POST \
  --data '{"token":"token-control-invalido"}' \
  http://10.1.1.10:8090/webhook
```

### Comprobar bloqueo de otras rutas

El resultado esperado es `HTTP 404`:

```bash
curl -i http://10.1.1.10:8094/api
curl -i http://10.1.1.10:8090/api
```

## Logs

### Organizacion operativa por ambiente

Apache crea un archivo independiente por ambiente y por dia, usando la fecha
local del servidor:

```text
/var/www/html/serversoap/whatsapp/logs/dev/AAAA-MM-DD-access.log
/var/www/html/serversoap/whatsapp/logs/dev/AAAA-MM-DD-error.log
/var/www/html/serversoap/whatsapp/logs/prod/AAAA-MM-DD-access.log
/var/www/html/serversoap/whatsapp/logs/prod/AAAA-MM-DD-error.log
```

`dev` corresponde a pruebas y `prod` a produccion. Apache usa `rotatelogs` para
cerrar el archivo anterior y crear el del nuevo dia automaticamente. No se
mezclan registros de ambientes ni de fechas diferentes.

### Pruebas

```text
logs/dev/AAAA-MM-DD-access.log
logs/dev/AAAA-MM-DD-error.log
```

```bash
tail -f logs/dev/$(date +%F)-access.log logs/dev/$(date +%F)-error.log
```

### Produccion

```text
logs/prod/AAAA-MM-DD-access.log
logs/prod/AAAA-MM-DD-error.log
```

```bash
tail -f logs/prod/$(date +%F)-access.log logs/prod/$(date +%F)-error.log
```

El log de acceso contiene IP origen, fecha, metodo, ruta, estado HTTP, bytes y
tiempo de respuesta en microsegundos. No contiene el JSON recibido.

## Aplicar cambios de configuracion

Antes de recargar Apache siempre se debe ejecutar:

```bash
apache2ctl configtest
```

Si devuelve `Syntax OK`, aplicar sin detener el servicio:

```bash
systemctl reload apache2
```

Despues validar:

```bash
systemctl is-active apache2
ss -ltnp | grep -E ':(8090|8094)\b'
```

No usar `restart` si un `reload` es suficiente.

## Habilitar o deshabilitar los sitios

Habilitar:

```bash
a2ensite webhook-bridge-8094
a2ensite webhook-bridge-8090
apache2ctl configtest
systemctl reload apache2
```

Deshabilitar temporalmente:

```bash
a2dissite webhook-bridge-8094
a2dissite webhook-bridge-8090
apache2ctl configtest
systemctl reload apache2
```

Deshabilitar el sitio no elimina sus archivos ni modifica los backends.

## Copias de seguridad y reversion

Las configuraciones originales de `ports.conf` y del puente de pruebas tienen
copias con fecha. Consultarlas con:

```bash
ls -1t /etc/apache2/ports.conf.bak-webhook-*
ls -1t /etc/apache2/sites-available/webhook-bridge-8094.conf.bak-*
```

Para una reversion se debe:

1. Deshabilitar los dos sitios con `a2dissite`.
2. Seleccionar manualmente la copia correcta de `ports.conf`.
3. Restaurarla conservando permisos y propietario.
4. Ejecutar `apache2ctl configtest`.
5. Recargar Apache solamente si el resultado es `Syntax OK`.
6. Confirmar que los servicios existentes en otros puertos siguen activos.

No restaurar automaticamente usando comodines, porque puede elegirse una copia
incorrecta.

## Diagnostico de errores

### HTTP 403 Token invalido

El puente alcanzo el backend, pero el token fue rechazado. En una prueba con
token deliberadamente invalido este resultado es correcto.

### HTTP 404

La ruta solicitada no pertenece a `/webhook`, o el endpoint no existe en el
backend. Verificar la URL completa.

### HTTP 405 Method Not Allowed

El endpoint existe, pero se uso un metodo incorrecto. El webhook principal
requiere POST.

### HTTP 502 Bad Gateway

Apache no pudo comunicarse con el backend correspondiente. Revisar:

```bash
curl -i --connect-timeout 5 --max-time 12 http://10.231.0.136:8094/webhook
curl -i --connect-timeout 5 --max-time 12 http://10.1.1.4:8094/webhook
tail -50 logs/dev/$(date +%F)-error.log
tail -50 logs/prod/$(date +%F)-error.log
```

### Timeout desde Internet

Revisar primero si Apache registra la solicitud. Si no aparece en el log, el
problema esta antes del puente: NAT, firewall, ruta o proveedor.

Si aparece en el log y termina en `502` o tarda demasiado, revisar la
conectividad entre `10.1.1.10` y el backend interno.

## Lista de validacion para Telecom

```text
[ ] 13.216.178.124 TCP/8094 apunta a 10.1.1.10 TCP/8094
[ ] 190.60.232.235 TCP/8090 apunta a 10.1.1.10 TCP/8090
[ ] Se retiro el acceso publico directo a los backends finales
[ ] 10.1.1.10 puede llegar a 10.231.0.136 TCP/8094
[ ] 10.1.1.10 puede llegar a 10.1.1.4 TCP/8094
[ ] Se probo cada URL desde una red realmente externa
[ ] La solicitud aparece solamente en el log de su ambiente
[ ] No existen envios duplicados al puente y al backend final
```

## Alcance de este README

Este archivo no participa en el procesamiento. Puede editarse o consultarse sin
interrumpir el webhook. La operacion real depende de Apache, sus modulos, los
dos VirtualHost y el enrutamiento configurado por Telecom.

## Accesos operativos desde este directorio

Para facilitar la validacion, este directorio contiene los logs diarios
separados por ambiente:

```text
logs/dev/AAAA-MM-DD-access.log
logs/dev/AAAA-MM-DD-error.log
logs/prod/AAAA-MM-DD-access.log
logs/prod/AAAA-MM-DD-error.log
```

Las rutas HTTP de este directorio permanecen bloqueadas por Apache.

Revision resumida del puente:

```bash
cd /var/www/html/serversoap/whatsapp
./verificar_puente.sh
```

Mostrar las ultimas 50 entradas por ambiente:

```bash
./verificar_puente.sh 50
```

Observar solicitudes en tiempo real:

```bash
tail -f logs/dev/$(date +%F)-access.log
tail -f logs/prod/$(date +%F)-access.log
```

Durante una prueba externa se recomienda acordar la hora exacta y la IP origen
con Telecom, ejecutar `tail -f` en el ambiente correspondiente y verificar que
la solicitud no aparezca en el log del otro ambiente.

## Configuracion en UltraMsg

Cada instancia de UltraMsg debe utilizar exclusivamente la URL publica de su
ambiente. El token se agrega como query string y nunca debe escribirse en este
README.

Pruebas:

```text
http://13.216.178.124:8094/webhook?token=TOKEN_REAL_DE_PRUEBAS
```

Produccion:

```text
http://190.60.232.235:8090/webhook?token=TOKEN_REAL_DE_PRODUCCION
```

No usar simultaneamente la URL publica y una URL de ngrok para una misma
instancia. UltraMsg debe realizar un solo envio por evento; de lo contrario el
backend puede registrar mensajes duplicados.

Validacion en tiempo real desde el puente:

```bash
cd /var/www/html/serversoap/whatsapp
tail -f logs/dev/$(date +%F)-access.log logs/dev/$(date +%F)-error.log
```

Para produccion:

```bash
cd /var/www/html/serversoap/whatsapp
tail -f logs/prod/$(date +%F)-access.log logs/prod/$(date +%F)-error.log
```

El `access.log` confirma metodo, ruta, codigo HTTP, IP origen y tiempo de
respuesta. No guarda el JSON del evento. El contenido funcional debe revisarse
en los logs propios del backend de cada ambiente.
