Que aprendas a usar la terminal Linux, manejes el control de versiones con Git y despliegues un proyecto real (tanto estático como dinámico) en un servidor VPS. Vas a entender todo el proceso de desarrollo a producción, perdiéndole el miedo a los servidores, añadiendo capas de seguridad esencial y sin depender de plataformas cerradas.
Mirar antes las instrucciones del taller: https://gist.github.com/melizeche/e35612c29e1c5565d0ff3bf0b2d3fdf3
Para este taller, necesitás:
- Un Servidor VPS: Un VPS limpio (ej. Ubuntu 22.04) de un proveedor como DigitalOcean, Linode, Vultr, Hetzner, etc.
- Acceso Root: La IP de tu servidor y la contraseña de
root(o acceso por SSH key). - Un Cliente SSH: La terminal (en Linux/Mac) o un cliente como PuTTY o Windows Terminal (en Windows).
- Una Cuenta de GitHub: Para la parte de Git (opcional pero recomendado).
- (Opcional) Un Dominio: Si querés configurar un dominio real con HTTPS. Para pruebas, podés usar la IP.
Acá es donde perdemos el miedo a la terminal. Vas a aprender a navegar, editar archivos, gestionar permisos y procesos. Lo más importante: asegurar el servidor antes de subir nada. (Créeme, no querés aprender esto de la manera difícil)
pwd # Muestra la ruta actual
ls # Lista archivos del directorio actual
ls -la # Lista todo (l=largo, a=all/ocultos)
cd carpeta # Entra a una carpeta
cd .. # Sube un nivel
cd ~ # Vuelve al directorio "home" del usuario
cd /var/log # Va a una ruta absolutaProbá esto:
- Verificá en qué directorio estás con
pwd - Andá a tu home:
cd ~ - Creá una carpeta
proyecto_demoy entrá - Creá subcarpetas:
mkdir src docs tests
# Creación
touch archivo.txt # Crear archivo vacío
mkdir carpeta_nueva # Crear carpeta
echo "Hola Mundo" > hola.txt # Crear archivo y escribir texto
echo "Linea 2" >> hola.txt # Añadir texto al final de un archivo
# Visualización
cat hola.txt # Mostrar contenido (para archivos cortos)
# Edición
nano hola.txt # Editar archivo con 'nano' (Ctrl+X para salir)
# Copiar y Mover
cp hola.txt copia.txt # Copiar archivo
mv copia.txt carpeta_nueva/ # Mover archivo
mv carpeta_nueva/copia.txt . # Mover archivo al directorio actual "."
# Borrado
rm hola.txt # Borrar archivo (pide confirmación)
rm -f hola.txt # Borrar forzadamente (force)
rmdir carpeta_nueva # Borrar carpeta (solo si está vacía)
rm -r carpeta_llena # Borrar carpeta y todo su contenido (recursive)
# Enlaces (¡Importante para Nginx!)
ln -s /ruta/original /ruta/enlace # Crear un enlace simbólicoAhora te toca:
- Creá
index.htmlensrccon el texto "Página" (echo "Página" > src/index.html). - Editalo con
nano src/index.htmly añadí " web". Guardá (Ctrl+O) y Salí (Ctrl+X). - Movelo a la carpeta
docs. - Creá un enlace simbólico llamado
atajo.htmlque apunte adocs/index.html. - Borrá la carpeta
tests(que está vacía) y luego borráatajo.html.
ls -l # Ver permisos (ej. -rwxr-xr-x)
whoami # Ver qué usuario sos
sudo <comando> # Ejecutar un comando como Super-Usuario (root)
# Cambiar permisos
chmod +x script.sh # Añadir permiso de ejecución (eXecutable)
chmod 644 archivo.txt # (Dueño: RW, Grupo: R, Otros: R)
chmod 755 carpeta # (Dueño: RWX, Grupo: RX, Otros: RX)
# Cambiar propietario
chown usuario:grupo archivo.txtDesafío:
Creá un archivo run.sh con echo "Corriendo..." e intentá ejecutarlo con ./run.sh. Va a fallar. ¿Por qué? Porque no tiene permisos de ejecución. Arreglalo con chmod +x run.sh y probá de nuevo.
#!/bin/bash
# setup.sh - Configuración inicial del proyecto
echo "Creando estructura de proyecto..."
mkdir -p proyecto/{src,docs,tests,logs}
touch proyecto/README.md
touch proyecto/.gitignore
# Ignorar archivos comunes
echo "*.log" >> proyecto/.gitignore
# Python
echo "__pycache__/" >> proyecto/.gitignore
echo "*.py[cod]" >> proyecto/.gitignore
echo "venv/" >> proyecto/.gitignore
echo "env/" >> proyecto/.gitignore
echo ".venv/" >> proyecto/.gitignore
# Node.js (si usás frontend)
echo "node_modules/" >> proyecto/.gitignore
echo "✅ Proyecto creado en ./proyecto"
ls -la proyectoPara usarlo:
nano setup.sh # Pegá el código
chmod +x setup.sh # Dale permisos
./setup.sh # Ejecutalo💡 Nota: El
#!/bin/bash(shebang) le dice al sistema qué intérprete usar.
# Búsqueda
find . -name "*.py" # Buscar archivos por nombre
grep "Hola" *.txt # Buscar texto dentro de archivos
grep -r "Hola" . # Buscar texto recursivamente
# Visualización de archivos grandes
less /var/log/syslog # Ver archivo interactivamente (q para salir)
head -n 20 archivo.txt # Ver las primeras 20 líneas
tail -n 20 archivo.txt # Ver las últimas 20 líneas
tail -f /var/log/nginx/access.log # Ver el final en tiempo real (Follow)Probá buscar "Hola" en tus archivos con grep y usá head para ver las primeras líneas de cualquier archivo. Son comandos que vas a usar TODO el tiempo.
ps aux # Ver todos los procesos activos
top # Monitoreo en tiempo real (q para salir)
htop # 'top' mejorado (requiere instalación)
sleep 60 & # Ejecutar en segundo plano (el &)
jobs # Ver trabajos en segundo plano
kill <PID> # Terminar proceso por su ID
killall sleep # Terminar todos los procesos con ese nombre
# Uso del sistema
df -h # Ver uso del disco (Human-readable)
free -h # Ver uso de RAM (Human-readable)Mini desafío:
Ejecutá sleep 300 & (el & lo manda a segundo plano), buscá el proceso con ps aux | grep sleep, y matálo con kill <PID>. Después chequeá el espacio en disco con df -h - esto es clave en un VPS.
#!/bin/bash
# health_check.sh - Monitoreo básico del servidor
echo "=== 🏥 Estado del Servidor ==="
echo "Fecha: $(date)"
echo ""
echo "💾 Uso de Disco:"
df -h / | tail -1
echo ""
echo "🧠 Uso de Memoria:"
free -h | grep Mem
echo ""
echo "⚙️ Servicios activos:"
systemctl is-active nginx 2>/dev/null && echo " ✅ Nginx: activo" || echo " ❌ Nginx: inactivo"
systemctl is-active ssh 2>/dev/null && echo " ✅ SSH: activo" || echo " ❌ SSH: inactivo"
echo ""
echo "👥 Últimos 5 logins:"
last -n 5Uso: Ejecutalo periódicamente para verificar el estado de tu VPS.
sudo apt update # Actualiza la lista de paquetes disponibles
sudo apt upgrade -y # Actualiza todos los paquetes instalados
sudo apt install htop nginx # Instala paquetes
sudo apt remove htop # Desinstala un paquete
sudo apt search "web server" # Busca paquetesActualizá los paquetes con apt update e instalá htop. Es como top pero mucho mejor. Una vez que lo uses, no vas a volver atrás.
ping google.com # Verifica conectividad (Ctrl+C para parar)
wget https://url/archivo.zip # Descarga un archivo
curl https://google.com # Muestra el contenido de una URL en terminal
curl -L https://url # Sigue redireccionesProbá ping google.com para verificar conectividad y curl https://google.com para ver el HTML crudo. curl es una navaja suiza para debugging.
# Comprimir
tar -czvf backup.tar.gz /ruta/a/carpeta
# (c=create, z=gzip, v=verbose, f=file)
# Descomprimir
tar -xzvf backup.tar.gz
# (x=extract)Comprimí tu carpeta proyecto_demo en un .tar.gz. Esto lo vas a usar para backups todo el tiempo.
#!/bin/bash
# backup.sh - Backup automático de proyecto
FECHA=$(date +%Y%m%d_%H%M%S)
ORIGEN="/home/deploy/mi_proyecto_live"
DESTINO="/home/deploy/backups"
echo "📦 Creando backup..."
mkdir -p $DESTINO
tar -czf $DESTINO/backup_$FECHA.tar.gz $ORIGEN
echo "✅ Backup creado: backup_$FECHA.tar.gz"
# Borrar backups de más de 7 días
find $DESTINO -name "backup_*.tar.gz" -mtime +7 -delete
echo "🧹 Backups antiguos eliminados"Uso avanzado: Podés automatizar este script con cron para que corra diariamente:
# Editar crontab
crontab -e
# Añadir esta línea para backup diario a las 2 AM
0 2 * * * /home/deploy/backup.shTab→ Autocompletado de comandos y rutasCtrl + C→ Detener proceso actualCtrl + R→ Buscar en el historial de comandos!!→ Repetir el último comando (útil consudo !!)Ctrl + D→ Salir de la sesión (exit)clear(oCtrl + L) → Limpiar la pantalla
Git es una de esas herramientas que al principio parece complicada, pero después no podés vivir sin ella. Acá vamos a ver el flujo básico: commits, ramas, y cómo conectarlo a GitHub.
git config --global user.name "Tu Nombre"
git config --global user.email "[email protected]"
git config --global init.defaultBranch main # Usar 'main' como rama por defectogit init # iniciar repositorio local
git status # ver cambios✨ Mejora: Creá un
.gitignoreantes del primer add.touch .gitignore(Añadenode_modules/,.env,*.log, etc. según tu proyecto)
git add . # agregar archivos al staging
git commit -m "Primer commit"
git log # historial de commits
git restore archivo.txt # descartar cambios en un archivo
git restore --staged archivo.txt # quitar del stagingEjercicio:
- Creá
README.mdy.gitignore - Escribí algo en el README y hacétu primer commit
git switch -c nueva-feature
echo "Cambio nuevo" > feature.txt
git add feature.txt
git commit -m "Nueva feature"
git switch main
git merge nueva-feature
git branch -d nueva-feature # borrar rama ya mergeadaAhora probá crear una rama dev, agregá algún archivo, y mergeálo a main. Así es como se trabaja en equipos.
git log --oneline --graph --all # visualizar historial compacto con ramas
git show <commit-hash> # ver detalles de un commit específico
git diff # ver cambios no staged
git diff --staged # ver cambios en stagingUsá git log --oneline --graph --all - para ver el árbol de commits. Yo tengo esto como alias git lg.
git commit --amend -m "Mensaje corregido" # modificar el último commit
git revert <commit-hash> # deshacer un commit creando uno nuevo
git reset --soft HEAD~1 # deshacer último commit, mantener cambios
git reset --hard HEAD~1 # deshacer último commit, BORRAR cambios (¡cuidado!)
⚠️ Ojo acá:git reset --hardborra cambios SIN vuelta atrás. Yo una vez perdí 2 horas de trabajo por esto. No seas yo.
Hacé un commit con un typo en el mensaje y corregilo con --amend. Es re útil.
git stash # guardar cambios temporalmente
git stash list # ver stashes guardados
git stash pop # recuperar último stash
git stash apply stash@{0} # aplicar un stash específico
git stash drop # borrar último stashCaso de uso: Estás trabajando en algo, pero necesitás cambiar de rama urgentemente sin hacer commit.
Ejercicio:
- Hacé cambios en un archivo sin commitear
- Guardalos con
git stash - Verificá que el directorio está limpio (
git status) - Recuperalos con
git stash pop
git fetch origin # descargar cambios sin mergear
git pull origin main # fetch + merge (equivale a fetch + merge)
git push origin --delete rama # borrar rama remota
git remote -v # ver remotos configurados
git branch -r # ver ramas remotasPro tip: Usá git fetch + git log --oneline --graph --all para ver qué hay en el remoto antes de hacer pull. Me salvó de varios conflictos.
git tag v1.0.0 # crear tag ligero
git tag -a v1.0.0 -m "Release 1.0" # tag anotado (recomendado)
git push origin v1.0.0 # subir tag específico
git push origin --tags # subir todos los tags
git tag -l # listar tagsCuando hagas tu primer release, creá un tag v0.1.0 y subílo. Los tags son perfectos para marcar versiones.
Cuando dos personas modifican la misma línea de código:
git switch main
git pull origin main
git switch mi-rama
git merge main
# ¡Conflicto!Pasos para resolver:
- Abrí el archivo en conflicto. Verás marcas como:
<<<<<<< HEAD
Tu código
=======
Código de la otra persona
>>>>>>> main
- Editá el archivo manualmente, decidí qué código mantener y borrá las marcas (
<<<<<<<,=======,>>>>>>>) - Agregá el archivo resuelto:
git add archivo-resuelto.txt
git commit # completar el mergeEjercicio (importante):
Creá un conflicto a propósito: modificá la misma línea en dos ramas diferentes e intentá mergear. Vas a ver las marcas <<<<<<< y >>>>>>>. Resolvé el conflicto manualmente. Esto te va a pasar en la vida real, mejor practicarlo ahora.
git config --global alias.st status
git config --global alias.co checkout
git config --global alias.br branch
git config --global alias.lg "log --oneline --graph --all --decorate"
git config --global alias.unstage "restore --staged"Ahora podés usar: git st, git lg, git unstage archivo.txt, etc.
Configurá algunos aliases. Mis favoritos son git st para status y git lg para el log lindo. Ahorra muchísimo tiempo.
git remote add origin [email protected]:usuario/mi_proyecto.git
git push -u origin mainEjercicio:
- Creá un repositorio en GitHub y subí tu proyecto
Acá viene lo bueno. Vamos a conectar tu VPS, asegurarlo (IMPORTANTE), y configurar un deploy automático con Git. Cada vez que hagas git push production main, tu código va a estar en vivo.
Conectate por SSH como root:
ssh root@ip_vpsActualizar e instalar dependencias:
apt update && apt upgrade -y
# Añadimos Python, pip y venv, esenciales para Django
apt install git nginx python3-pip python3-venv -y
adduser deploy
usermod -aG sudo deployConfigurar acceso SSH sin contraseña: (Hacé esto en tu máquina local, no en el servidor)
ssh-keygen -t ed25519
ssh-copy-id deploy@ip_vpsAhora, salí (exit) y volvé a entrar como deploy: ssh deploy@ip_vps.
(Conectado como deploy@ip_vps)
Firewall con UFW:
sudo ufw allow OpenSSH
sudo ufw allow 'Nginx Full' # Permite HTTP (80) y HTTPS (443)
sudo ufw enableDeshabilitar login de root por SSH:
sudo nano /etc/ssh/sshd_configBuscá y cambiá estas líneas:
PermitRootLogin no
PasswordAuthentication no
(Asegurate de que ssh-copy-id funcionó antes de deshabilitar passwords, sino te quedás afuera)
Reiniciá SSH:
sudo systemctl restart sshd(Conectado como deploy@ip_vps)
mkdir -p ~/repos/mi_proyecto.git
cd ~/repos/mi_proyecto.git
git init --bareEste hook es ahora mucho más inteligente y se encarga de todo el ciclo de vida de Django.
cd ~/repos/mi_proyecto.git/hooks
nano post-receivePega este contenido:
#!/bin/bash
# --- Configuración ---
TARGET="/home/deploy/mi_proyecto_live" # Carpeta de archivos "vivos"
GIT_DIR="/home/deploy/repos/mi_proyecto.git"
VENV_DIR="/home/deploy/venvs/mi_proyecto_venv" # Carpeta para el entorno virtual
BRANCH="main"
SERVICE_NAME="gunicorn_mi_proyecto" # Nombre de nuestro servicio systemd
while read oldrev newrev ref
do
# Revisar si la rama es la que queremos (ej. "main")
if [[ $ref = refs/heads/$BRANCH ]];
then
echo "Deploying $BRANCH branch..."
# 1. Hacer checkout de los archivos
mkdir -p $TARGET
git --work-tree=$TARGET --git-dir=$GIT_DIR checkout -f $BRANCH
# --- MAGIA DE PYTHON/DJANGO ---
# 2. Crear Venv si no existe
if [ ! -d "$VENV_DIR" ]; then
echo "Creating Python virtual environment at $VENV_DIR..."
python3 -m venv $VENV_DIR
fi
# 3. Activar venv e instalar dependencias
echo "Activating venv and installing requirements..."
source $VENV_DIR/bin/activate
# Asegurate de que 'gunicorn' está en tu requirements.txt
pip install -r $TARGET/requirements.txt
# 4. Correr comandos de Django (desde la carpeta del proyecto)
echo "Running Django management commands..."
cd $TARGET
python manage.py migrate --noinput
python manage.py collectstatic --noinput # Recolecta estáticos
# 5. Reiniciar el servicio Gunicorn
# (Este servicio lo crearemos en el Paso 6)
echo "Restarting Gunicorn service: $SERVICE_NAME..."
sudo systemctl restart $SERVICE_NAME
echo "Deploy complete."
else
echo "Push received for branch $ref, no deploy action taken."
fi
doneDar permisos y crear carpetas:
chmod +x post-receive
mkdir -p /home/deploy/mi_proyecto_live
mkdir -p /home/deploy/venvs/mi_proyecto_venv(En tu máquina local, en la carpeta de tu proyecto)
¡Importante! Antes de hacer push, asegurate de que tu proyecto Django esté listo para producción:
- Añadí
gunicorna tu archivorequirements.txt.- En
settings.py:
DEBUG = FalseALLOWED_HOSTS = ['tu-dominio.com', 'ip_vps']STATIC_ROOT = BASE_DIR / 'staticfiles'(oos.path.join(BASE_DIR, 'staticfiles'))
Añadí el remoto y hacé push:
git remote add production deploy@ip_vps:~/repos/mi_proyecto.git
git push production mainEl primer deploy va a fallar al final (al intentar reiniciar Gunicorn), porque aún no hemos creado el servicio. ¡No te preocupés! Los archivos ya están en el servidor, que es lo que necesitábamos.
Ahora conectaremos todo. Usaremos systemd (el gestor de servicios de Linux) para manejar Gunicorn.
(Conectado como deploy@ip_vps)
Gunicorn será el "trabajador" que ejecuta tu código Python.
sudo nano /etc/systemd/system/gunicorn_mi_proyecto.servicePegá esta configuración (ajustá mi_proyecto.wsgi:application al nombre de tu proyecto):
[Unit]
Description=gunicorn daemon for mi_proyecto
After=network.target
[Service]
User=deploy
Group=www-data
WorkingDirectory=/home/deploy/mi_proyecto_live
ExecStart=/home/deploy/venvs/mi_proyecto_venv/bin/gunicorn \
--access-logfile - \
--workers 3 \
--bind unix:/run/gunicorn_mi_proyecto.sock \
mi_proyecto.wsgi:application
[Install]
WantedBy=multi-user.targetWorkingDirectory: Dónde vive tumanage.py.ExecStart: Apunta al ejecutable degunicorndentro del venv y le dice que cree un "socket" (un archivo de comunicación) en/run/gunicorn_mi_proyecto.sock.mi_proyecto.wsgi:application: Es el "punto de entrada" de tu app. Se encuentra enmi_proyecto/wsgi.py.
sudo systemctl start gunicorn_mi_proyecto
sudo systemctl enable gunicorn_mi_proyectoComprobá que esté corriendo: sudo systemctl status gunicorn_mi_proyecto (Presioná q para salir).
Nginx será el "recepcionista". Le pedirá a Gunicorn el contenido dinámico y servirá los archivos estáticos (CSS/JS) él mismo.
sudo nano /etc/nginx/sites-available/mi_proyectoPegá esta configuración:
server {
listen 80;
server_name tu-dominio.com www.tu-dominio.com; # O tu IP
# Ubicación del socket de Gunicorn
location / {
include proxy_params;
proxy_pass http://unix:/run/gunicorn_mi_proyecto.sock;
}
# ¡IMPORTANTE! Servir archivos estáticos
# Esta ruta debe coincidir con tu STATIC_ROOT
location /static/ {
root /home/deploy/mi_proyecto_live;
}
# (Opcional) Servir archivos subidos por usuarios (media)
# location /media/ {
# root /home/deploy/mi_proyecto_live;
# }
}sudo ln -s /etc/nginx/sites-available/mi_proyecto /etc/nginx/sites-enabled/
# Quitamos el sitio por defecto si existe
sudo rm /etc/nginx/sites-enabled/default
sudo nginx -t
sudo systemctl reload nginx¡Visitá tu IP o dominio! Deberías ver tu app Django.
Ahora que todo está configurado, hacé un pequeño cambio en tu código local (ej. en un README.md), y volvé a hacer push:
(En tu máquina local)
git commit -m "Probando deploy automático"
git push production mainObservá la terminal. Esta vez, el hook post-receive se ejecutará por completo, instalará dependencias, correrá collectstatic y migrate, y reiniciará Gunicorn sin errores. Tu cambio aparecerá en vivo en segundos.
Si preferís hacer deploy manualmente (sin Git hooks), podés usar este script en el servidor:
#!/bin/bash
# deploy.sh - Helper para deploy manual
echo "🚀 Iniciando deploy..."
cd /home/deploy/mi_proyecto_live
echo "📥 Descargando cambios..."
git pull origin main
echo "🐍 Activando entorno virtual..."
source /home/deploy/venvs/mi_proyecto_venv/bin/activate
echo "📦 Instalando dependencias..."
pip install -r requirements.txt
echo "🗄️ Migrando base de datos..."
python manage.py migrate --noinput
echo "📁 Recolectando archivos estáticos..."
python manage.py collectstatic --noinput
echo "🔄 Reiniciando Gunicorn..."
sudo systemctl restart gunicorn_mi_proyecto
echo "✅ Deploy completado!"Uso: Corre ./deploy.sh cuando quieras deployar manualmente. Yo lo uso cuando algo falló con el hook y necesito debuggear.
(Esto es igual que antes, pero vale la pena repetirlo)
sudo apt install certbot python3-certbot-nginx
sudo certbot --nginx -d tu-dominio.com -d www.tu-dominio.comSeguí las instrucciones y Certbot configurará automáticamente Nginx para usar SSL.
Cosas que aprendí a las piñas:
- Hacé commits chicos y con mensajes claros. "fix" no es un mensaje de commit.
- NUNCA, NUNCA subas
.envo API keys a Git. Usá.gitignorereligiosamente. - Variables de entorno: usá archivos
.enven el servidor (fuera de Git) y cargalos conpython-decoupleo similar. - Hacé backups. En serio. Configurá snapshots automáticos en tu proveedor de VPS.
- Este setup con Git hooks está genial para proyectos personales. Para cosas más grandes, mirá GitHub Actions o GitLab CI.
Si llegaste hasta acá, felicitaciones. Ahora tenés:
- Conocimientos sólidos de Linux (ya no le tenés miedo a la terminal)
- Git bajo control (branches, merges, conflictos, todo)
- Tu proyecto corriendo en un VPS real, con HTTPS
- Deploy automático con
git push(esto es lo más satisfactorio) - Independencia de plataformas cerradas
Ahora podés deployar lo que quieras, cuando quieras. Esa sensación no tiene precio.
Si no querés o no podés pagar un VPS todavía, hay alternativas para exponer tu proyecto local a internet. Son geniales para demos, testing, o webhooks.
ngrok crea un túnel seguro desde internet a tu localhost. Es súper fácil de usar.
Instalación:
# Mac (con Homebrew)
brew install ngrok
# Linux
curl -s https://ngrok-agent.s3.amazonaws.com/ngrok.asc | \
sudo tee /etc/apt/trusted.gpg.d/ngrok.asc >/dev/null && \
echo "deb https://ngrok-agent.s3.amazonaws.com buster main" | \
sudo tee /etc/apt/sources.list.d/ngrok.list && \
sudo apt update && sudo apt install ngrokUso básico:
# Registrate en https://ngrok.com y obtené tu authtoken
ngrok config add-authtoken TU_TOKEN
# Exponer un servidor local en el puerto 8000
ngrok http 8000Te va a dar una URL tipo https://abc123.ngrok.io que apunta a tu localhost:8000.
Ejemplo con Django:
# Terminal 1: Corré tu servidor Django
python manage.py runserver
# Terminal 2: Exponelo con ngrok
ngrok http 8000Pros:
- Setup en 2 minutos
- HTTPS gratis
- Perfecto para demos y webhooks
- Plan gratuito disponible
Contras:
- La URL cambia cada vez (en el plan free)
- No es para producción
- Límites en el plan gratuito
Cloudflare Tunnels es similar a ngrok pero con más features y sin límites de ancho de banda.
Instalación:
# Mac
brew install cloudflared
# Linux (Ubuntu/Debian)
wget -q https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64.deb
sudo dpkg -i cloudflared-linux-amd64.debSetup rápido (sin dominio):
# Exponer localhost:8000
cloudflared tunnel --url http://localhost:8000Te da una URL tipo https://random-words.trycloudflare.com.
Setup con dominio propio:
Si tenés un dominio en Cloudflare, podés crear un túnel permanente:
# 1. Login
cloudflared tunnel login
# 2. Crear túnel
cloudflared tunnel create mi-proyecto
# 3. Configurar DNS
cloudflared tunnel route dns mi-proyecto app.tudominio.com
# 4. Crear config
nano ~/.cloudflared/config.ymlContenido de config.yml:
tunnel: mi-proyecto
credentials-file: /home/user/.cloudflared/TUNNEL_ID.json
ingress:
- hostname: app.tudominio.com
service: http://localhost:8000
- service: http_status:404Correr el túnel:
cloudflared tunnel run mi-proyectoPros:
- Sin límites de ancho de banda
- Podés usar tu propio dominio
- Más estable que ngrok
- Gratis
Contras:
- Setup inicial un poco más complejo
- Necesitás Cloudflare para usar dominio propio
ngrok:
- Demos rápidas
- Testing de webhooks (Stripe, GitHub, etc.)
- Mostrarle algo a un cliente
- No querés configurar nada
Cloudflare Tunnels:
- Proyectos más permanentes
- Tenés dominio en Cloudflare
- Necesitás más ancho de banda
- Querés algo más profesional
VPS (lo que vimos en el taller):
- Producción real
- Control total
- Aprender DevOps
- Proyectos serios
Nota: ngrok y Cloudflare Tunnels son geniales para desarrollo y demos, pero para producción real, un VPS te da mucho más control y aprendizaje.
Algunos tips si usás túneles:
# Django settings.py
# Agregá el dominio de ngrok/cloudflare a ALLOWED_HOSTS
ALLOWED_HOSTS = [
'localhost',
'127.0.0.1',
'abc123.ngrok.io', # Tu URL de ngrok
'app.tudominio.com', # Tu dominio de Cloudflare
]
# Nunca dejes DEBUG=True en producción
DEBUG = FalseProtección básica con contraseña (opcional):
# Con ngrok, podés agregar autenticación básica
ngrok http 8000 --basic-auth="usuario:password"- ngrok: https://ngrok.com/docs
- Cloudflare Tunnels: https://developers.cloudflare.com/cloudflare-one/connections/connect-apps/
- Comparación: Para proyectos de aprendizaje, cualquiera de los dos está bien. Para producción, VPS. Más opciones: https://github.com/cloudcommunity/Cloud-Free-Tier-Comparison
- Practicar visual de git https://learngitbranching.js.org/
- DevOps Roadmap https://roadmap.sh/devops
- Aprender más sobre servers https://serversforhackers.com/s/start-here