---
title: Almacenamiento en caché y CDN para la difusión OTT
url: https://doc2.pstreamer.tv/es/manual/extras/ott_caching.html
lang: es
product: Perfect Streamer
version: 2.0.2.362
---

# Almacenamiento en caché y CDN para la difusión OTT

Apéndice para la explotación de instalaciones de gran tamaño: cómo funciona el almacenamiento en caché de las respuestas OTT de Perfect Streamer y cómo situar un reverse proxy con caché o una CDN delante del nodo. Los modos de difusión, los formatos de URL y la autorización se describen en la sección principal [OTT y DVR](../streamer/ott_dvr.md#streamer-ott-dvr).

El servidor genera respuestas de tres categorías, que se diferencian por el tiempo de vida del contenido y por su idoneidad para el almacenamiento en caché por nodos intermedios (reverse proxy, CDN, caché del cliente).

## 1. Modelo de caché

### 1.1. Recursos y cabeceras HTTP

| Recurso | URL | Content-Type | Cache-Control |
| --- | --- | --- | --- |
| Segmento TS (HLS) | `/h<sess>/<keyHex>.ts` | `video/mp2t` | `public, max-age=60, immutable` |
| Segmento VTT (subtítulos) | `/h<sess>/sub/<pid>/<keyHex>.vtt` | `text/vtt; charset=utf-8` | `public, max-age=60, immutable` |
| Segmento fMP4 (DASH / LL-HLS) | `/h<sess>/init.mp4`, `/h<sess>/<key\|N>.m4s` | `video/mp4` | `public, max-age=60, immutable` |
| DASH MPD | `/h<sess>/index.mpd` | `application/dash+xml; charset=utf-8` | `public, max-age=1` |
| HLS master | `/hls/<stream>/<login>/<pass>/index.m3u8` | `application/vnd.apple.mpegurl` | `public, max-age=1` |
| HLS media | `/h<sess>/index.m3u8`, `/h<sess>/sub/<pid>/index.m3u8` | `application/vnd.apple.mpegurl` | `public, max-age=1` |
| 302 Redirect | `/dash/<stream>/<login>/<pass>/index.mpd` | — | `no-cache, no-store` |
| Raw TS | `/http/<stream>/<login>/<pass>` | `video/mp2t` | no definido; no se almacena en caché |

### 1.2. Características de los segmentos

El identificador hexadecimal del segmento en el URL (`<keyHex>` en las rutas `/h<sess>/<keyHex>.ts`) se calcula como CRC64 del instante de inicio del segmento y del ID del flujo, y es globalmente único. El URL del segmento direcciona contenido inmutable: las solicitudes repetidas del mismo URL devuelven un flujo de bytes idéntico (mientras el segmento permanezca dentro de la ventana deslizante).

La directiva `immutable` suprime la revalidación condicional por parte del cliente (`If-None-Match`, `If-Modified-Since`). El valor `max-age=60` garantiza la compatibilidad con el valor típico `timeShiftBufferDepth=40s`.

Los segmentos fMP4 CMAF (`.m4s`) y el `init.mp4` común para DASH / Low-Latency HLS se direccionan de forma análoga y se almacenan en caché según el mismo modelo (`immutable`, `max-age=60`). Los segmentos parciales (parts) de LL-HLS son solicitudes byte-range dentro del mismo `.m4s`, por lo que no generan una entrada de caché propia.

### 1.3. Características de los manifiestos

`max-age=1` limita a un segundo la cota superior de obsolescencia del contenido en la caché. Usado junto con `proxy_cache_lock on` (nginx), los picos de solicitudes al manifiesto se agrupan en una única solicitud al origin por segundo.

### 1.4. Variabilidad del contenido

Con `absPath=0` (valor por defecto, sin el parámetro de URL `a`), los manifiestos HLS media y DASH MPD no contienen el identificador de sesión en el cuerpo. El contenido del manifiesto es idéntico entre las sesiones que pertenecen a una misma combinación (flujo, param). Esto permite que la caché del reverse proxy reutilice la entrada entre sesiones cuando se normaliza la clave de caché.

Con `absPath=1` (parámetro de URL `a=1`), el cuerpo del manifiesto contiene URL absolutos que incluyen el esquema, el host y el identificador de sesión. El contenido pasa a ser específico de la sesión y no existe la posibilidad de reutilizar la caché entre sesiones.

## 2. Comportamiento de los clientes

| Cliente | URL de actualización del manifiesto | Efecto sobre el número de sesiones |
| --- | --- | --- |
| Reproductores HLS mediante el media playlist | `/h<sess>/index.m3u8` | Una sesión por sesión de reproducción |
| Reproductores DASH mediante el URL raíz | `/dash/<stream>/.../index.mpd` (ciclo de repetición) | Se resuelve mediante session reuse (véase 3.2) |
| Reproductores de navegador (MSE) | `/h<sess>/...` mediante `<Location>` / session URL | Una sesión por sesión de reproducción |

## 3. Mecanismos especiales

### 3.1. HTTP 302 Redirect para DASH

Una solicitud de la forma `/dash/<stream>/<login>/<pass>/index.mpd` devuelve una respuesta `302 Found` con la cabecera `Location: /h<sess>/index.mpd`. El cuerpo de la respuesta está vacío. La autorización y la asignación de la sesión se realizan durante el procesamiento de la redirección.

Los clientes que admiten el almacenamiento en caché de la redirección acceden directamente al session URL en las solicitudes posteriores. Los clientes que no lo admiten repiten la solicitud de redirección. El coste del procesamiento repetido de la redirección se limita a la comprobación de autenticación y a las operaciones de session reuse.

### 3.2. Session reuse para DASH

Al procesar una solicitud `/dash/.../index.mpd` procedente del mismo login y dirigida al mismo flujo (con el mismo indicador adaptive), el servidor localiza una sesión DASH ya existente y devuelve de nuevo su identificador. No se crea una sesión nueva ni se consume una plaza del límite de conexiones simultáneas. Solo se reutilizan sesiones que estén en el mismo modo de reproducción: una sesión en directo y una sesión VOD del archivo (parámetros `t`/`d`/`epg`) no se combinan.

Se aplica únicamente a DASH. Para HLS no se requiere un mecanismo de reuse independiente: los clientes HLS actualizan el media playlist mediante el session-URL y no crean una sesión nueva en cada actualización.

### 3.3. Reutilización de segmentos entre sesiones

La ruta `/h<sess>/<keyHex>.ts` no depende de `<sess>` al resolver `<keyHex>` en contenido: `<keyHex>` identifica de forma globalmente inequívoca un segmento TS dentro del flujo. Nginx con una cache key normalizada (que recorta el prefijo `/h<sess>/`) atiende todas las solicitudes de un mismo `<keyHex>` desde una única entrada de caché, con independencia de qué clientes las hayan emitido.

La deduplicación solo es aplicable a los nombres content-addressed: los segmentos con identificador hexadecimal de 16 caracteres (`.ts`, `.m4s` con `<keyHex>`, `.vtt`). Los segmentos numerados de live-DASH (`<número>.m4s`), el `init.mp4` y los manifiestos son únicos solo dentro de su propia sesión: su clave de caché debe conservar el prefijo `/h<sess>/`, de lo contrario la caché entregaría el contenido de un flujo a los espectadores de otro. En DASH, la deduplicación de manifiestos entre los clientes de un mismo login la proporciona el session reuse (véase 3.2).

## 4. Parámetros de la solicitud

| Parámetro | Valor por defecto | Efecto |
| --- | --- | --- |
| `a` | `0` | `1` — URL absolutos en los manifiestos; `0` — relativos |
| `s` | `40` | `timeShiftBufferDepth` en segundos |
| `m` | `40` | Longitud mínima de la ventana para emitir el manifiesto |
| `v` | `6` para los modos OTT, `3` para Peering / HLS | `#EXT-X-VERSION` en HLS (DASH lo ignora); un valor explícito en el URL prevalece sobre el valor por defecto |
| `h3` | ausente (off) | opt-in a HTTP/3 (QUIC): obliga al servidor a emitir `Alt-Svc` en la respuesta; sticky en el session-URL. Véase [HTTP/3 (QUIC)](../streamer/ott_dvr.md#streamer-ott-http3) |

La modificación de un parámetro mediante la query string actualiza los valores guardados en la sesión en su siguiente reapertura. Los parámetros de reproducción del archivo `t`, `d` y `epg` se describen en [Reproducción del archivo (VOD)](../streamer/ott_dvr.md#streamer-dvr-vod).

## 5. Características de carga

La carga sobre el origin escala con el número de flujos distintos vistos simultáneamente. El aumento del número de clientes que ven un mismo flujo no incrementa la cantidad de solicitudes al origin cuando existe una caché de reverse proxy y una cache key normalizada.

| Escenario | Frecuencia de solicitudes al origin (ref.) |
| --- | --- |
| 1 cliente en el flujo X | MPD: 0.4 req/s, segment: 0.2 req/s |
| N clientes en un mismo flujo X (caché activada) | MPD: 1 req/s, segment: 0.2 req/s |
| N clientes DASH en modo de repetición sobre un mismo flujo | MPD: 1 req/s (con `proxy_cache_lock`) |
| N clientes en N flujos distintos | MPD: 0.4·N req/s, segment: 0.2·N req/s |

Los segmentos se deduplican globalmente por sus nombres content-addressed; la deduplicación de manifiestos entre clientes la proporcionan el session reuse (DASH) y la caché dentro de la sesión.

## 6. Nginx como reverse proxy con caché

### 6.1. Configuración básica

```nginx
proxy_cache_path /var/cache/nginx/pss_segments
    levels=1:2 keys_zone=pss_segments:100m
    max_size=20g inactive=30m use_temp_path=off;

proxy_cache_path /var/cache/nginx/pss_manifests
    levels=1:2 keys_zone=pss_manifests:10m
    max_size=256m inactive=5m use_temp_path=off;

upstream pss_backend {
    server 127.0.0.1:43972;
    keepalive 64;
}

map $uri $pss_cache_key {
    "~^/h[0-9a-f]{16}(?<tail>(/[0-9]+)?/[0-9a-f]{16}\.(ts|m4s)|/sub/[0-9]+/[0-9a-f]{16}\.vtt)$"  "stream:$tail";
    default  $uri;
}

server {
    listen 80;
    server_name stream.example.com;

    location ~* "^/h[0-9a-f]{16}(/[0-9]+|/sub/[0-9]+)?/([0-9a-f]+\.(ts|m4s|vtt)|init\.mp4)$" {
        proxy_cache               pss_segments;
        proxy_cache_key           $pss_cache_key;
        proxy_cache_valid         200 60s;
        proxy_cache_valid         404 403 0s;
        proxy_cache_lock          on;
        proxy_cache_use_stale     updating error timeout;
        proxy_cache_revalidate    on;
        proxy_ignore_headers      Vary;
        add_header                X-Cache-Status $upstream_cache_status;

        proxy_pass                http://pss_backend;
        proxy_http_version        1.1;
        proxy_set_header          Connection "";
        proxy_buffering           on;
    }

    location ~* "(^/h[0-9a-f]{16}(/[0-9]+|/sub/[0-9]+)?/index\.(m3u8|mpd)$|^/(hls|dash|llhls)/.*\.(m3u8|mpd)$)" {
        proxy_cache               pss_manifests;
        proxy_cache_key           $pss_cache_key;
        proxy_cache_valid         200 1s;
        proxy_cache_valid         404 403 0s;
        proxy_cache_lock          on;
        proxy_cache_lock_timeout  2s;
        proxy_cache_use_stale     updating;
        add_header                X-Cache-Status $upstream_cache_status;

        proxy_pass                http://pss_backend;
        proxy_http_version        1.1;
        proxy_set_header          Connection "";
    }

    location / {
        proxy_pass                http://pss_backend;
        proxy_http_version        1.1;
        proxy_set_header          Connection "";
        proxy_set_header          X-Forwarded-Proto $scheme;
        proxy_set_header          X-Forwarded-Host  $host;
        proxy_buffering           off;
        proxy_read_timeout        3600s;
    }
}
```

El puerto del origin en el ejemplo es el puerto por defecto del servidor HTTP de streaming (43972; HTTPS — 43982). Solo se normalizan los nombres content-addressed de los segmentos (véase 3.3); los manifiestos, el `init.mp4` y los segmentos numerados se almacenan en caché por el URI completo de su sesión. La directiva `proxy_ignore_headers Vary` en el location de los segmentos está justificada: el servidor acompaña las respuestas OTT con la cabecera `Vary: Origin` y, sin ella, la caché se dividiría en variantes según el valor de Origin del cliente (véase 7).

### 6.2. Función de las directivas

| Directiva | Función |
| --- | --- |
| `proxy_cache_lock on` | Serializa la ejecución de las solicitudes upstream ante cache miss simultáneos sobre una misma clave |
| `proxy_cache_use_stale updating` | Devuelve la copia obsoleta a las solicitudes paralelas durante el periodo de actualización de la caché |
| `proxy_cache_revalidate on` | Utiliza `If-Modified-Since` en caso de cache miss con una copia almacenada |
| `proxy_cache_valid 404 403 0s` | Prohíbe el almacenamiento en caché de los errores de autorización y de los 404 |
| `keepalive 64` en el upstream | Mantiene un pool de conexiones persistentes con el origin |
| `proxy_buffering on` | Para los segmentos; activa el almacenamiento en búfer de la respuesta en nginx |
| `proxy_buffering off` | Para la sección `/`; desactiva el almacenamiento en búfer (raw streaming) |

### 6.3. Cálculo de `max_size` de la caché de segmentos

Valor orientativo: `bitrate × timeShiftBufferDepth × distinct_streams × 2`

Ejemplo: 10 flujos × 8 Mbps × 40 s × 2 ≈ 800 MB. Se recomienda prever un margen de 10x para tener en cuenta la variabilidad del bitrate.

### 6.4. Terminación TLS

El servidor Perfect Streamer acepta conexiones en los puertos HTTP y HTTPS. Cuando la terminación TLS se realiza en nginx, el upstream utiliza el puerto HTTP. El reenvío de las cabeceras `X-Forwarded-Proto` y `X-Forwarded-Host` es obligatorio para formar correctamente los URL absolutos con `absPath=1`.

```nginx
server {
    listen 443 ssl http2;
    server_name stream.example.com;

    ssl_certificate           /etc/letsencrypt/live/stream.example.com/fullchain.pem;
    ssl_certificate_key       /etc/letsencrypt/live/stream.example.com/privkey.pem;
    ssl_protocols             TLSv1.2 TLSv1.3;
    ssl_session_cache         shared:SSL:10m;
    ssl_session_timeout       1d;

    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;

    location ... {
        proxy_pass                http://pss_backend;
        proxy_set_header          X-Forwarded-Proto https;
        proxy_set_header          X-Forwarded-Host  $host;
        proxy_set_header          Host              $host;
        # + caching directives from 6.1
    }
}

server {
    listen 80;
    server_name stream.example.com;
    return 301 https://$host$request_uri;
}
```

Si se emplea HTTPS entre nginx y el origin, se aplican las directivas `proxy_ssl_verify` y `proxy_ssl_trusted_certificate`. Para las conexiones loopback el cifrado es superfluo.

### 6.5. Multihost

Cuando un mismo proceso de nginx atiende varios `server_name`, se añade `$host` a la cache key para aislar el contenido:

```nginx
map $uri $pss_cache_key {
    "~^/h[0-9a-f]{16}(?<tail>(/[0-9]+)?/[0-9a-f]{16}\.(ts|m4s)|/sub/[0-9]+/[0-9a-f]{16}\.vtt)$"  "$host:stream:$tail";
    default  "$host:$uri";
}
```

El tamaño de `keys_zone` se calcula a razón de 8000 claves/MB. Para instalaciones multihost con miles de flujos se recomienda `keys_zone=...:300m` o superior.

## 7. Almacenamiento en caché en el cliente

`Cache-Control: immutable` es procesado por los navegadores modernos. La caché del cliente devuelve el segmento sin solicitud condicional cuando se accede de nuevo a él (incluido el seek hacia atrás dentro del búfer del reproductor).

Los Service Workers pueden aplicar la estrategia `cache-first` basándose en el contenido de Cache-Control. Los reproductores DASH utilizan MSE a través de `SourceBuffer`; un segmento colocado en el búfer permanece disponible sin una nueva solicitud HTTP hasta que sale del límite de la ventana deslizante.

Para las solicitudes entre dominios, el servidor devuelve `Access-Control-Allow-Origin: *` junto con la cabecera `Vary: Origin, Access-Control-Request-Headers`. Un proxy con caché que respete Vary divide las entradas en variantes según el valor de Origin del cliente (los reproductores de navegador envían Origin; los de consola, no), lo que reduce el HIT rate. Dado que ACAO es el «*» universal, en el location de los segmentos es seguro añadir `proxy_ignore_headers Vary` (véase 6.1).

## 8. Distribución a través de CDN

Perfect Streamer es compatible con CDN en modo pull-from-origin.

**Origin shield.** Se recomienda situar uno o varios nodos shield entre el CDN edge y el origin para reducir la frecuencia de solicitudes al origin cuando los clientes están distribuidos globalmente.

**Purge.** Los segmentos content-addressed no requieren purge. Al cambiar los metadatos del flujo (códec, resolución), los manifiestos se actualizan en el plazo de `max-age=1` sin purge explícito.

**Cache warming.** Si se prevé un aumento de la carga sobre un flujo concreto, es admisible precalentar la CDN desde varios puntos geográficos antes del inicio de la emisión.

**Distribución geográfica.** Los segmentos (`max-age=60`) se adaptan bien al almacenamiento en caché geográficamente distribuido. Los manifiestos (`max-age=1`) admiten un retardo de entrega de hasta un segundo, lo que resulta aceptable para la emisión en directo sin baja latencia.

## 9. Monitorización

### 9.1. `X-Cache-Status`

Se añade `add_header X-Cache-Status $upstream_cache_status;` a cada location con caché. Valores:

| Valor | Descripción |
| --- | --- |
| `HIT` | Respuesta servida desde la caché |
| `MISS` | No estaba en la caché; se obtuvo del origin y se almacenó |
| `EXPIRED` | Caducado; se actualizó |
| `UPDATING` | Se entregó una copia stale a una solicitud paralela durante la actualización |
| `STALE` | `use_stale` devolvió una copia caducada (origin no disponible) |
| `REVALIDATED` | El origin devolvió 304 Not Modified |
| `BYPASS` | Se activó `proxy_cache_bypass` |

### 9.2. Formato del access-log

```nginx
log_format pss_cache '$remote_addr $status $request_method "$request" '
                     '$body_bytes_sent rt=$request_time ut=$upstream_response_time '
                     'cache=$upstream_cache_status key=$pss_cache_key';

server {
    access_log /var/log/nginx/pss.log pss_cache;
}
```

### 9.3. Métricas

El módulo `nginx-vts` exporta métricas per-zone en formato Prometheus:

```
GET /status/format/prometheus
```

Umbrales recomendados para las alertas:

| Métrica | Umbral | Causa posible |
| --- | --- | --- |
| Segment HIT rate | < 90% durante 5 minutos | Normalización de la cache key incorrecta; `max_size` insuficiente |
| Manifest MISS rate | > 50% durante 1 minuto | `proxy_cache_lock` no serializa las solicitudes |
| Upstream response time p95 | > 500 ms durante 1 minuto | Sobrecarga del origin |
| Cache zone fill | > 90% durante 10 minutos | Proximidad a `max_size`; se prevé LRU-eviction |

La calidad de la entrega en el lado del nodo se observa en las métricas de sesión de la pantalla «Clientes» ([Clientes](../webui/monitor.md#webui-clients)).

## 10. Diagnóstico

| Síntoma | Causa probable | Solución |
| --- | --- | --- |
| Segment HIT rate bajo | `Vary: Origin` divide la caché en variantes; normalización incorrecta en `map` | Añadir `proxy_ignore_headers Vary` en el location de los segmentos; revisar la regex de la directiva `map` |
| 404 en los segmentos tras salir de la ventana | 404 almacenado en caché de un segmento que salió de la sliding window | Añadir `proxy_cache_valid 404 0s` en el location segments |
| Retardo del playback start de 2–5 s | `proxy_cache_lock_timeout` supera la target latency | Reducirlo a 1–2 s; activar `proxy_cache_use_stale updating` |
| El manifest no se actualiza | está definido `proxy_ignore_headers Cache-Control` y rige un `proxy_cache_valid` con un TTL elevado | Indicar explícitamente `proxy_cache_valid 200 1s` o eliminar la omisión de las cabeceras |
| Crecimiento de TIME_WAIT en el upstream | Falta `keepalive` en el bloque upstream | Añadir `keepalive 64`, `proxy_http_version 1.1`, `proxy_set_header Connection ""` |
| 403 en `/dash/.../<segment>.m4s` desde clientes de consola | El cliente resuelve los URL relativos respecto al URL pre-redirect | El servidor emite `<BaseURL>` con ruta absoluta; compatible en la build actual |
| Cortes y rebúferes frecuentes en los clientes remotos | Throughput TCP efectivo bajo debido al slow start y al idle restart con RTT elevados (300 ms o más) | Ajuste de la pila de red de Linux en el origin: véase 10.1 |

### 10.1. Ajuste TCP del origin para clientes con RTT alto

El problema se manifiesta en los clientes con un RTT elevado hasta el origin (por ejemplo, 300 ms o más) cuando el bitrate del flujo se aproxima a la capacidad del canal. Los síntomas en el reproductor son rebúferes e interrupciones frecuentes; en el servidor, en cambio, el cliente se ve normal y no hay errores.

Causa:

- **TCP slow start.** Cada nueva conexión TCP comienza con una congestion window de unos 14 KB y la incrementa a lo largo de varios RTT. Con un RTT de 300 ms, alcanzar la ventana completa lleva de 2 a 3 segundos. Durante ese tiempo, un segmento HLS/DASH de 5 s de duración (4–6 MB) se descarga notablemente más despacio que en tiempo real.
- **TCP idle restart.** Entre las solicitudes de segmentos, el cliente hace una pausa de 4–5 s conforme al modelo pull de HLS. Por defecto, tras esa pausa el kernel de Linux restablece la congestion window de la conexión al initial cwnd (comportamiento `net.ipv4.tcp_slow_start_after_idle=1`). Como resultado, en el siguiente GET la conexión keep-alive vuelve a iniciar la transmisión con arranque lento, incluso en una sesión ya calentada.

Adicionalmente, la situación se agrava porque el congestion control CUBIC, activo por defecto, tolera mal los RTT largos y las pérdidas de paquetes en los tramos intermedios de la red.

La solución consiste en dos parámetros sysctl en el origin:

```bash
# Keep congestion window across idle pauses inside keep-alive sessions.
sysctl -w net.ipv4.tcp_slow_start_after_idle=0

# Use BBR instead of CUBIC: better behaviour on long-RTT paths
# with mild packet loss; paces sending instead of bursting.
modprobe tcp_bbr
sysctl -w net.ipv4.tcp_congestion_control=bbr
```

Para aplicarlos de forma permanente:

```bash
cat > /etc/sysctl.d/99-pss-net.conf <<EOF
net.ipv4.tcp_slow_start_after_idle = 0
net.ipv4.tcp_congestion_control    = bbr
EOF
sysctl --system
```

El efecto principal lo aporta el primer parámetro (`tcp_slow_start_after_idle=0`): elimina directamente el slow start repetido entre las solicitudes de segmentos dentro de una misma conexión keep-alive. El segundo (BBR) aporta robustez adicional y se aplica a todas las conexiones nuevas. El ajuste no requiere reiniciar Perfect Streamer. Estos parámetros no afectan a los clientes HTTP/3 (QUIC): QUIC funciona sobre UDP con su propio control de congestión.

## 11. Seguridad

### 11.1. Session URL

Un URL con el formato `/h<sess>/...` desempeña la función de token de sesión: no requiere una nueva autenticación. Su tiempo de vida está limitado por un tiempo de espera de inactividad de 60 segundos; si no hay actividad, la sesión se elimina automáticamente.

Requisitos:

- HTTPS para todas las rutas OTT (`/hls/`, `/dash/`, `/h<sess>/`) en producción;
- El Session ID de la cabecera `Location` de la respuesta 302 no se almacena en caché (`no-cache, no-store`).

### 11.2. Rate limiting

```nginx
limit_req_zone $binary_remote_addr zone=dash_top:10m  rate=5r/s;
limit_req_zone $binary_remote_addr zone=hls_top:10m   rate=5r/s;
limit_req_zone $binary_remote_addr zone=llhls_top:10m rate=5r/s;

server {
    location /dash/ {
        limit_req zone=dash_top burst=20 nodelay;
        proxy_pass http://pss_backend;
    }
    location /hls/ {
        limit_req zone=hls_top burst=20 nodelay;
        proxy_pass http://pss_backend;
    }
    location /llhls/ {
        limit_req zone=llhls_top burst=20 nodelay;
        proxy_pass http://pss_backend;
    }
}
```

El session URL (`/h<sess>/`) no requiere rate limiting: su procesamiento es barato y las respuestas se almacenan en caché.

### 11.3. Almacenamiento en caché de las respuestas con errores

```nginx
proxy_cache_valid 200 60s;
proxy_cache_valid 301 302 0s;
proxy_cache_valid 404 403 0s;
proxy_cache_valid any 1s;
```

Prohíbe el almacenamiento en caché de las redirecciones (sess único en Location) y de las respuestas con errores de autorización o de recurso inexistente.

### 11.4. Restricción del acceso de red al origin

El puerto del servidor HTTP de streaming (43972 por defecto; 43982 para HTTPS) debe estar cerrado al tráfico externo. Configuraciones admisibles:

1. Vincular Perfect Streamer a `127.0.0.1` (con nginx local)
2. Regla de firewall:

```
iptables -A INPUT -p tcp -m multiport --dports 43972,43982 ! -s 10.0.0.0/8 -j DROP
```

## 12. Integración con middleware

### 12.1. Modelo prefix-login

Perfect Streamer permite delegar la identificación del usuario en un sistema middleware mediante el mecanismo prefix-login, una alternativa integrada a la integración completa con una facturación externa (las cuentas verificadas por un sistema externo se configuran en la pantalla «Usuarios / Inicios de sesión», pestaña «Externos (facturación)», [Usuarios / Inicios de sesión](../webui/configure.md#webui-users)).

En un login local se activa el indicador de prefijo, tras lo cual el servidor acepta URL con un login de la forma `<prefix><id_de_suscriptor>`:

```
/dash/test1/sub42/xxx/index.mpd
/hls/test1/sub43/xxx/index.m3u8
```

Aquí `sub` es el prefijo de login configurado y `42`/`43` son los identificadores de los suscriptores del middleware; la contraseña es común.

### 12.2. Estadísticas por suscriptor

En la lista de clientes, cada sesión lleva tanto el login de configuración como el login de URL real del suscriptor (match-login), con el que el middleware asocia las sesiones a sus abonados. Los datos se muestran en la pantalla «Clientes» ([Clientes](../webui/monitor.md#webui-clients)).

### 12.3. Limitaciones de prefix-login

- **Contraseña común.** Todos los suscriptores del pool de prefijo utilizan un único valor de contraseña. El compromiso de la contraseña otorga acceso a cualquier `<prefix><cadena>`.
- **Granularidad del acceso.** La lista de flujos permitidos se aplica a todo el pool de prefijo. El acceso a nivel de suscriptor individual lo proporciona la integración con una facturación externa.
- **Rotación de la contraseña.** El cambio de contraseña desconecta a todos los suscriptores activos. Para una sustitución gradual es necesario usar temporalmente dos prefix-logins.
