Despliega Streamlit en un VPS y haz proxy con Cloudflare Tunnels
Despliega Streamlit en un VPS y haz proxy a través de Cloudflare Tunnels. Guía paso a paso con config.toml, PM2/systemd, configuración del venv y resolución de problemas para producción.
Actualizado Publicado 34 min de lectura

Streamlit es un framework de Python para crear aplicaciones web interactivas con muy poco código. Puedes usarlo para crear dashboards de datos, demos de machine learning, herramientas internas — cualquier cosa donde un backend en Python y una UI reactiva tengan sentido. Yo lo he usado para apps rápidas de exploración de datos y dashboards internos donde montar un frontend completo en React sería excesivo.
Streamlit tiene una sintaxis sencilla: funciones y decoradores de Python definen tu layout y tu lógica. st.title añade un encabezado, st.dataframe renderiza una tabla de pandas, st.slider añade controles interactivos. La recarga en caliente actualiza tu app mientras editas el código, sin necesidad de refrescar el navegador. Tú escribes Python y Streamlit se encarga del servidor web, la comunicación WebSocket y las actualizaciones reactivas de la UI.
Si te interesa conocer los mejores frameworks web de Python, consulta: Los mejores frameworks web de Python. Si quieres ver cómo se compara Streamlit con otro framework de UI en Python, mira la comparativa de Streamlit vs NiceGUI.
Si quieres desplegar Streamlit o cualquier app de Python en Docker, puedes consultar: Cómo ejecutar cualquier app Python en Docker con Docker Compose
Esta guía te lleva paso a paso por cómo desplegar Streamlit en un VPS y hacer proxy a través de Cloudflare Tunnels. El coste total ronda los 4 a 7 USD/mes por el VPS. Los Cloudflare Tunnels son gratuitos. Obtienes HTTPS, protección DDoS y ningún puerto de entrada abierto en tu servidor.
Despliegue gratuito en Streamlit Cloud
Streamlit Community Cloud es la opción sin configuración. Conectas un repositorio de GitHub y despliega tu app en una URL *.streamlit.io. Sin servidor que gestionar, sin claves SSH, sin gestores de procesos. Haces push a GitHub y la app se actualiza automáticamente.
Está bien para demos y prototipos, pero los límites son reales:
- 1 GB de memoria. Las apps complejas o con muchos datos chocarán rápido con este techo.
- Sin dominios personalizados. Tu app vive en una URL aleatoria
*.streamlit.io. - Sin escalado. Tienes un contenedor con 1 GB, tómalo o déjalo.
- Los planes de pago han desaparecido para siempre. Streamlit está desarrollando un producto conjunto con Snowflake en su lugar.
- El nivel gratuito ahora permite un repositorio privado (antes solo se permitían repositorios públicos).
- Arranques en frío: Community Cloud apaga las apps inactivas. La primera carga tras la inactividad puede tardar de 10 a 30 segundos.
Si necesitas un dominio personalizado, más memoria, arranques en frío más rápidos o fiabilidad en producción, sigue leyendo.
Cómo desplegar Streamlit en tu VPS y hacer proxy a través de Cloudflare Tunnels
La arquitectura es sencilla:
- Tu VPS ejecuta Streamlit localmente en
localhost:8501 cloudflaredcrea un túnel cifrado hacia la red edge de Cloudflare- Tu dominio resuelve a través de Cloudflare. Obtienes HTTPS, protección DDoS, firewall y ningún puerto de entrada abierto en el VPS
El túnel conecta hacia fuera desde tu servidor. Nadie puede sondear los puertos de tu VPS porque nada escucha en una interfaz pública. Esa es la principal ventaja de seguridad frente a una configuración con reverse proxy tradicional.
Requisitos previos
Antes de empezar, asegúrate de tener:
- Un VPS con Ubuntu 22.04 o 24.04 (mínimo 1 vCPU, se recomiendan 2 GB de RAM)
- Un nombre de dominio añadido a tu cuenta de Cloudflare (el plan gratuito sirve)
- Un repositorio de GitHub que contenga tu app de Streamlit con un
requirements.txt - Acceso SSH a tu VPS (root o usuario con sudo)
- Python 3.10+ (incluido con Ubuntu 22.04+)
Si aún no tienes un VPS, puedes configurar un VPS para desarrollo o consultar la sección de abajo.
1. Crea un VPS
Elige un VPS con al menos 2 GB de RAM. Ubuntu 22.04 o 24.04 como sistema operativo. Cloudflare Tunnels es gratis. El único coste recurrente es el propio VPS, que parte de unos 4 a 5 USD/mes.
Yo uso Hetzner para la mayoría de mis servidores. Buen rendimiento, ubicaciones en la UE y precios justos. Hostinger es una alternativa económica sólida. Puedes comparar proveedores de VPS para ver cuál se ajusta a tus necesidades.
Los precios de los VPS subieron en todos los proveedores en 2026 — si te estás replanteando una máquina alquilada, mira qué cambió y cuándo gana un mini PC.
2. Actualiza el VPS y añade swap
Una vez que tengas acceso SSH, actualiza el sistema y añade espacio swap como red de seguridad. El swap actúa como memoria virtual cuando la RAM física se llena. No salvará una app mal escrita, pero evita un kill por OOM cuando tu app de Streamlit carga un dataframe o un modelo grande en memoria.
# Actualiza el sistema
sudo apt update && sudo apt -y upgrade
# Añade 2 GB de espacio swap
sudo fallocate -l 2G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstabVerifica que el swap está activo:
sudo swapon --showDeberías ver /swapfile listado con su tamaño. Si no aparece, comprueba que fallocate creó el archivo correctamente. Algunos proveedores de VPS o sistemas de archivos no soportan fallocate; en ese caso usa dd if=/dev/zero of=/swapfile bs=1M count=2048 en su lugar.
El swap evita kills por OOM en instancias VPS pequeñas, pero es 100 veces más lento que la RAM. Monitoriza con htop durante los primeros días. Si tu app usa swap de forma constante, amplía el VPS. El swap no es un sustituto de la RAM. Puedes comprobar qué procesos usan swap para detectar problemas pronto.
3. Configura un entorno virtual de Python e instala Streamlit
No instales Streamlit globalmente con pip3 install streamlit. Puede entrar en conflicto con los paquetes Python del sistema y hace que la gestión de dependencias sea un dolor. Usa un entorno virtual en su lugar.
# Instala el soporte de venv de Python (como root)
sudo apt install python3-pip python3-venvCrea un usuario dedicado para la app (lo restringiremos más en el siguiente paso):
sudo useradd -m streamlitAhora cambia al usuario streamlit y crea el venv:
sudo su - streamlit
# Crea y activa un entorno virtual
python3 -m venv /home/streamlit/venv
source /home/streamlit/venv/bin/activate
# Instala Streamlit dentro del venv
pip install streamlitVerifica la instalación:
streamlit --versionDeberías ver la versión 1.59.x o superior. Streamlit requiere Python 3.10+ desde la versión 1.51.0.
Si prefieres una resolución de dependencias más rápida, puedes usar uv para configurar un proyecto Python como alternativa a pip + venv. El enfoque con venv funciona bien para un despliegue de una sola app, pero uv brilla cuando gestionas varios proyectos Python.
4. Crea un usuario dedicado para tu app de Streamlit
Ya creamos el usuario streamlit en el paso anterior. Ejecutar la app con un usuario dedicado sin privilegios de root significa que, si la app se ve comprometida, el atacante no tiene acceso root al servidor. Es el principio de mínimo privilegio básico. No hay razón para saltárselo.
El home del usuario es /home/streamlit, y ahí es donde vivirá todo: el entorno virtual, el código de la app y los archivos de configuración. Mantenerlo todo bajo el home de un solo usuario hace que los backups y los permisos sean sencillos.
Si necesitas dar acceso a otro administrador para gestionar la app, añádelo al grupo streamlit en lugar de compartir la contraseña del usuario:
sudo usermod -aG streamlit your-username5. Lleva la app de Streamlit a tu VPS
Necesitas llevar el código de tu app al VPS. La forma más fácil es git clone desde tu repositorio de GitHub. Si tu repo es privado, tendrás que configurar una clave SSH o un token de acceso personal. GitHub tiene documentación para ambos.
Clona tu repositorio como usuario streamlit:
sudo su - streamlit
# Crea un directorio para la app
mkdir -p $HOME/streamlit-app && cd $HOME/streamlit-app
# Clona tu repositorio
git clone https://github.com/username/repo-name
cd repo-nameVerifica que el clonado funcionó y que tu archivo de app está ahí:
ls -la
# Deberías ver app.py (o como se llame tu archivo principal)Si tu repo es privado y usaste HTTPS, Git te pedirá credenciales. Para despliegues automatizados más adelante, configura claves SSH en su lugar:
ssh-keygen -t ed25519 -C "deploy-key"
cat ~/.ssh/id_ed25519.pub
# Añade esto como deploy key en la configuración de tu repo de GitHub6. Instala los requisitos con pip
Tu app probablemente depende de paquetes más allá del propio Streamlit: pandas, matplotlib, plotly, scikit-learn, etc. Deberían estar listados en un archivo requirements.txt en tu repo. Si tu repo no tiene uno, créalo primero:
# En tu máquina local (no en el VPS), en el directorio de tu proyecto:
pip freeze > requirements.txtAsegúrate de que tu venv está activado (deberías ver (venv) en tu prompt) y luego instala:
# Con el venv activado:
pip install -r requirements.txtEsto instala todo lo que tu app necesita en el venv aislado. Si una dependencia no compila (habitual con paquetes que necesitan librerías C como psycopg2 o lxml), instala primero la librería del sistema:
# Ejemplo: para psycopg2
sudo apt install libpq-dev
# Ejemplo: para lxml
sudo apt install libxml2-dev libxslt1-devVerifica que streamlit y tus dependencias clave están instaladas:
pip list | grep streamlit
pip list | grep pandas7. Configura Streamlit para producción — .streamlit/config.toml
Este es el paso que la mayoría de las guías se saltan, y es la razón por la que los despliegues detrás de Cloudflare Tunnels se rompen.
Sin enableCORS = false y enableXsrfProtection = false, tu app de Streamlit mostrará “Connection error” o se quedará colgada en “Please wait…” detrás de Cloudflare Tunnels. Este es el error de despliegue n.º 1.
Crea un archivo .streamlit/config.toml dentro del directorio de tu app:
mkdir -p /home/streamlit/streamlit-app/repo-name/.streamlit
cat > /home/streamlit/streamlit-app/repo-name/.streamlit/config.toml << 'EOF'
[server]
# Ejecutar headless (sin apertura automática del navegador, sin prompt de email)
headless = true
# Escuchar solo en localhost — Cloudflare Tunnel conecta localmente
address = "localhost"
port = 8501
# Desactivar CORS/XSRF cuando hay un reverse proxy/túnel delante
# Cloudflare Tunnel gestiona el HTTPS; la conexión es local
enableCORS = false
enableXsrfProtection = false
# Keep-alive de WebSocket — evita desconexiones con "Connection error"
websocketPingInterval = 30
[browser]
# Pon tu dominio real para que Streamlit genere URLs correctas
serverAddress = "app.example.com"
serverPort = 443
EOFSustituye app.example.com por tu nombre de dominio real. La sección [browser] le dice a Streamlit qué URL generar para el cliente — sin ella, el navegador podría intentar conectar con localhost en lugar de tu dominio.
Esto es lo que hace cada ajuste:
headless = true— Desactiva la apertura automática del navegador y el prompt de email que Streamlit muestra por defecto. Esencial en despliegues de servidor donde no hay navegador de escritorio.address = "localhost"— Streamlit solo escucha en la interfaz loopback. Esto es importante: incluso sin UFW (paso 11), la app no es accesible desde internet. Cloudflare Tunnel conecta localmente, así que esto es todo lo que necesitas.enableCORS = false— Cross-Origin Resource Sharing. Cuando tu dominio esapp.example.compero Streamlit cree que se ejecuta enlocalhost, la política CORS del navegador bloquea la conexión WebSocket. Ponerlo enfalsele dice a Streamlit que confíe en el proxy.enableXsrfProtection = false— El mismo razonamiento. La validación del token XSRF falla cuando la petición llega a través del túnel porque el origen no coincide. Desactivarlo es seguro aquí porque Cloudflare Tunnel ya proporciona la capa de seguridad.websocketPingInterval = 30— Envía un ping cada 30 segundos para mantener viva la conexión WebSocket a través del túnel. Sin esto, Cloudflare puede cerrar conexiones inactivas, causando el mensaje “Connection error”.
Estos ajustes funcionan tanto con el backend clásico Tornado como con el nuevo backend Starlette/Uvicorn (Streamlit 1.57.0+). La migración a Starlette fue un cambio importante bajo el capó, pero los flags de configuración son los mismos.
8. Ejecuta y verifica la app
Antes de configurar un gestor de procesos, comprueba que Streamlit arranca correctamente:
# Como usuario streamlit, con el venv activado:
source /home/streamlit/venv/bin/activate
streamlit run /home/streamlit/streamlit-app/repo-name/app.pyEn otra terminal, verifica el endpoint de salud:
curl -s http://localhost:8501/_stcore/healthDeberías recibir ok de vuelta. Si obtienes “Connection refused”, comprueba que address = "localhost" y port = 8501 coinciden en tu config.toml.
Streamlit expone /_stcore/health, que devuelve HTTP 200 cuando la app está en ejecución. Guarda este endpoint — es tu comando de verificación para cualquier despliegue.
Una vez verificado, detén la app en ejecución (Ctrl+C) y pasa a configurar un gestor de procesos.
9. Configura un gestor de procesos — PM2 o systemd
Tu sesión SSH terminará, y sin un gestor de procesos, Streamlit muere con ella. Necesitas algo que lo mantenga en ejecución en segundo plano y lo reinicie si falla.
Dos buenas opciones: PM2 (rico en funciones, requiere Node.js) o systemd (ya está en tu sistema Linux, cero dependencias extra). Elige la que prefieras — ambas funcionan.
Opción A: PM2
PM2 es una herramienta de Node.js gestionando un proceso Python. Si prefieres no instalar Node.js solo para esto, cambia a la pestaña de systemd — tiene menos piezas móviles.
Instala Node.js 22 LTS (como root):
curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash -
sudo apt-get install -y nodejsInstala PM2 globalmente:
sudo npm install pm2@latest -gPara más detalles sobre PM2, consulta la guía completa sobre gestión de aplicaciones con PM2.
Arranca Streamlit con PM2 (como usuario streamlit):
sudo su - streamlit
source /home/streamlit/venv/bin/activate
pm2 start '/home/streamlit/venv/bin/streamlit run /home/streamlit/streamlit-app/repo-name/app.py' \
--name my-streamlit-appO usa un archivo ecosystem de PM2 para una configuración más limpia:
cat > /home/streamlit/ecosystem.config.js << 'EOF'
module.exports = {
apps: [{
name: 'my-streamlit-app',
script: '/home/streamlit/venv/bin/streamlit',
args: 'run /home/streamlit/streamlit-app/repo-name/app.py',
interpreter: 'none',
env: {
PATH: '/home/streamlit/venv/bin:' + process.env.PATH
}
}]
};
EOF
pm2 start /home/streamlit/ecosystem.config.jsConfigura PM2 para que arranque en el boot:
# Como usuario streamlit:
pm2 startup systemd
# Copia y ejecuta el comando que muestra (se ejecuta como root)
pm2 saveVerifica:
pm2 listTu app debería aparecer como “online”. Revisa los logs con pm2 logs my-streamlit-app.
PM2 guarda los logs en ~/.pm2/logs/. Con el tiempo pueden crecer — configura la rotación de logs:
pm2 install pm2-logrotate
pm2 set pm2-logrotate:max_size 10M
pm2 set pm2-logrotate:retain 7Opción B: systemd
systemd ya está en todos los sistemas Ubuntu. Sin paquetes extra que instalar, sin dependencia de Node.js. Menos piezas móviles.
Crea un archivo de servicio (como root):
sudo cat > /etc/systemd/system/streamlit.service << 'EOF'
[Unit]
Description=Streamlit App
After=network.target
[Service]
User=streamlit
WorkingDirectory=/home/streamlit/streamlit-app/repo-name
ExecStart=/home/streamlit/venv/bin/streamlit run app.py --server.port=8501 --server.address=localhost --server.headless=true
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
EOFHabilita e inicia el servicio:
sudo systemctl daemon-reload
sudo systemctl enable --now streamlitVerifica:
sudo systemctl status streamlitDeberías ver active (running). Si dice failed, revisa los logs para ver el error:
journalctl -u streamlit -n 50 --no-pagerProblemas habituales: ruta incorrecta al binario streamlit del venv, o el archivo de la app no existe en el WorkingDirectory especificado.
Para seguir los logs en tiempo real:
journalctl -u streamlit -fsystemd gestiona la rotación de logs automáticamente mediante journald, así que no necesitas configurarla aparte.
10. Crea un Cloudflare Tunnel e instala cloudflared
Cloudflare Tunnels expone tu app a internet sin abrir ningún puerto. El túnel conecta hacia fuera desde tu VPS hacia el edge de Cloudflare. Obtienes HTTPS, protección DDoS y reglas WAF gratis.
Regístrate en Cloudflare y añade tu nombre de dominio. Apunta los nameservers de tu dominio al DNS de Cloudflare. Sigue las instrucciones del dashboard de Cloudflare.
Ve a Zero Trust > Networks > Tunnels y crea un túnel. Después de darle un nombre, obtendrás un comando de instalación:

Opción 1: instalar desde el dashboard de Cloudflare (copia el comando mostrado):
curl -L --output cloudflared.deb https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64.deb &&
sudo dpkg -i cloudflared.deb &&
sudo cloudflared service install <token>Sustituye <token> por el token real del dashboard de Cloudflare.
Opción 2: instalar desde el repositorio apt de Cloudflare (mejor para actualizaciones continuas):
sudo mkdir -p --mode=0755 /usr/share/keyrings
curl -fsSL https://pkg.cloudflare.com/cloudflare-main.gpg | sudo tee /usr/share/keyrings/cloudflare-main.gpg >/dev/null
echo "deb [signed-by=/usr/share/keyrings/cloudflare-main.gpg] https://pkg.cloudflare.com/cloudflared any main" | sudo tee /etc/apt/sources.list.d/cloudflared.list
sudo apt-get update && sudo apt-get install cloudflaredCon el repositorio apt, actualizar es simplemente sudo apt update && sudo apt upgrade cloudflared. El método .deb funciona, pero requiere descargar manualmente las nuevas versiones cada vez.
Tras instalar cloudflared con el token del dashboard, verifica que el servicio está en ejecución:
sudo systemctl status cloudflared
sudo systemctl enable cloudflaredEl comando service install del dashboard ya registra cloudflared como servicio systemd, pero enable asegura que arranque en el boot.
Ahora configura el hostname público en el dashboard de Cloudflare. Apunta tu dominio (p. ej., app.example.com) a http://localhost:8501:

Después de guardar, visita https://app.example.com en tu navegador. Si ves la app de Streamlit cargando, el túnel funciona. El dashboard de Cloudflare debería mostrar el túnel como “Healthy”.
Para más información sobre autoalojamiento con Cloudflare Tunnels, consulta cómo autoalojar Cloudreve con Docker y Cloudflare Tunnels.
11. Configura el firewall UFW (defensa en profundidad)
Como Cloudflare Tunnel significa que no hacen falta puertos de entrada, bloquea el VPS con UFW. Incluso si Streamlit se enlaza accidentalmente a una interfaz pública en lugar de localhost, UFW bloquea el acceso externo. Defensa en profundidad — no dependas de una sola capa.
Asegúrate de que SSH (puerto 22) está permitido antes de activar UFW, o te quedarás fuera del VPS. Compruébalo dos veces con sudo ufw status antes de sudo ufw enable.
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow 22/tcp
sudo ufw enableVerifica:
sudo ufw status verboseSolo el puerto 22 debería aparecer como permitido. Todo lo demás está denegado. Si más adelante necesitas exponer otro servicio (digamos, una segunda app de Streamlit en el puerto 8502 a través de un túnel aparte), tampoco necesitas abrir ese puerto — el túnel conecta localmente.
Para una configuración más robusta con detección de intrusiones y baneo automático de IPs de fuerza bruta, puedes securizar tu VPS con CrowdSec encima de UFW.
Resolución de problemas comunes
"Connection error" / WebSocket atascado en "Please wait..."
Causa: Faltan enableCORS = false y enableXsrfProtection = false en .streamlit/config.toml.
Solución: Añade ambos ajustes a tu config.toml (ver paso 7), reinicia Streamlit y limpia la caché del navegador. Verifica también que browser.serverAddress está configurado con tu dominio real, no localhost.
Streamlit carga pero los widgets no responden
Causa: Problema de proxy del WebSocket. Cloudflare Tunnel soporta WebSockets por defecto, pero puede que haya que ajustar el intervalo de ping.
Solución: Configura server.websocketPingInterval = 30 en config.toml. En el dashboard de Cloudflare, en los ajustes HTTP del hostname público de tu túnel, pon connectionTimeout en 300 segundos para operaciones largas.
La app falla al subir archivos grandes
Causa: El límite de subida por defecto es de 200 MB, pero el VPS puede no tener memoria suficiente.
Solución: Aumenta server.maxUploadSize en config.toml. Asegúrate de que el swap está activado (paso 2). Para archivos muy grandes, considera una subida basada en S3 en lugar de procesamiento en memoria.
Cloudflared muestra "version outdated"
Causa: Instalado mediante descarga .deb en lugar del repositorio apt.
Solución: Si usas el repo apt: sudo apt update && sudo apt upgrade cloudflared. Si usas el método .deb: vuelve a descargar y ejecuta sudo dpkg -i cloudflared.deb.
Problemas de auth o sesión tras actualizar a Streamlit 1.57.0+
Causa: Streamlit 1.57.0 migró de Tornado a Starlette/Uvicorn. Se reportaron algunas regresiones en la persistencia de cookies de auth y en el comportamiento CORS en 1.57.x.
Solución: Asegúrate de estar en Streamlit 1.58.0+, que corrigió la mayoría de las regresiones. Si usas st.login() para autenticación OIDC, prueba después de cualquier actualización de versión de Streamlit.
Alternativa: despliegue con Docker
Docker es ahora el método de despliegue oficialmente recomendado por Streamlit. Si ya usas Docker para otros servicios en tu VPS, este es el camino más limpio — gestiona el aislamiento de dependencias, las políticas de reinicio y elimina la necesidad de PM2 o systemd. La contrapartida es Docker como dependencia y un poco más de complejidad para depurar (logs de contenedor en lugar de archivos locales).
Aquí tienes un Dockerfile mínimo:
FROM python:3.12-slim
WORKDIR /app
RUN apt-get update && apt-get install -y build-essential curl git && rm -rf /var/lib/apt/lists/*
COPY requirements.txt .
RUN pip3 install -r requirements.txt
COPY . .
EXPOSE 8501
HEALTHCHECK CMD curl --fail http://localhost:8501/_stcore/health
ENTRYPOINT ["streamlit", "run", "app.py", "--server.port=8501", "--server.address=0.0.0.0"]Compila y ejecuta:
docker build -t my-streamlit-app .
docker run -d -p 8501:8501 --name my-streamlit-app --restart unless-stopped my-streamlit-appSigues necesitando el .streamlit/config.toml con CORS/XSRF desactivados si haces proxy a través de Cloudflare Tunnels. Puedes copiarlo dentro de la imagen Docker durante el build o montarlo como volumen:
docker run -d -p 8501:8501 \
-v /home/streamlit/streamlit-app/repo-name/.streamlit:/app/.streamlit \
--name my-streamlit-app \
--restart unless-stopped \
my-streamlit-appCon Docker Compose puedes fijar la versión y añadir límites de recursos:
version: "3.8"
services:
streamlit:
build: .
ports:
- "8501:8501"
volumes:
- ./.streamlit:/app/.streamlit
restart: unless-stopped
mem_limit: 1gEl mem_limit evita que una app descontrolada consuma toda la RAM del VPS — algo a vigilar si tu app carga datasets grandes.
Verifica que el contenedor está sano:
docker ps
curl -s http://localhost:8501/_stcore/healthPara una guía completa de Docker + Python, consulta Cómo ejecutar cualquier app Python en Docker con Docker Compose.
Mantén tu despliegue actualizado
Una vez que la app está en ejecución, tendrás que actualizar tres cosas con el tiempo: el código de la app, el propio Streamlit y cloudflared. Esta es la rutina:
Actualiza el código de la app:
sudo su - streamlit
cd /home/streamlit/streamlit-app/repo-name
git pullSi tu requirements.txt cambió, activa el venv y reinstala:
source /home/streamlit/venv/bin/activate
pip install -r requirements.txtLuego reinicia el gestor de procesos:
# PM2
pm2 restart my-streamlit-app
# systemd
sudo systemctl restart streamlitActualiza el propio Streamlit:
sudo su - streamlit
source /home/streamlit/venv/bin/activate
pip install --upgrade streamlitReinicia después de actualizar.
Actualiza cloudflared (si usas el repo apt):
sudo apt update && sudo apt upgrade cloudflaredMonitoriza los logs:
# PM2
pm2 logs my-streamlit-app
# systemd
journalctl -u streamlit -fConsidera configurar Uptime Kuma para monitorización — apúntalo a https://app.example.com/_stcore/health para recibir alertas si la app se cae.
Backup: El código de tu app vive en Git (seguro). Pero .streamlit/config.toml y cualquier archivo de datos en el VPS deberían respaldarse por separado. Si ejecutas varias apps, cada una necesita un puerto diferente (8501, 8502, etc.) y entradas de hostname del Cloudflare Tunnel separadas.
Los Cloudflare Tunnels son gratuitos. Tu único coste recurrente es el VPS (~4–7 USD/mes). Sin cargos por ancho de banda, sin tarifas por petición.
Conclusión
Ahora tienes un despliegue de Streamlit listo para producción: un usuario dedicado con un entorno virtual, un config.toml adecuado para compatibilidad con Cloudflare Tunnel, un gestor de procesos que lo mantiene en ejecución y un firewall bien bloqueado. El coste total es de 4–7 USD/mes por el VPS — Cloudflare Tunnels, HTTPS, protección DDoS y el WAF son todos gratis.
El mismo patrón funciona para otros frameworks web de Python como Flask, FastAPI o Gradio. Las piezas clave son siempre las mismas: escuchar en localhost, usar un gestor de procesos, hacer proxy a través de Cloudflare Tunnel y bloquear el firewall.
Si necesitas restringir el acceso a tu app, Streamlit 1.42.0+ añadió st.login() y st.logout() para autenticación OIDC nativa. Puedes usarlo con Google o cualquier proveedor OIDC para controlar el acceso sin construir una capa de auth personalizada. Para herramientas internas que no deberían ser públicas, esto es lo primero que configuraría una vez que el despliegue básico funciona.


