Desarrollar directamente en producción es receta para desastres. Un entorno de staging te permite probar cambios antes de que lleguen a usuarios reales.
Un VPS de desarrollo te da libertad para experimentar, romper cosas y aprender sin consecuencias. Esta guía te enseña a montar tu flujo de trabajo profesional.
Por qué necesitas entornos separados
El problema de desarrollar en producción
| Riesgo | Consecuencia |
|---|---|
| Bug en código | Usuarios ven errores |
| Migración fallida | Base de datos corrupta |
| Dependencia rota | Sitio caído |
| Prueba de rendimiento | Servidor saturado |
| Experimento fallido | Pérdida de datos |
La solución: entornos separados
Development → Staging → Production
(romper) (probar) (estable)
Los tres entornos
Development (desarrollo)
- Propósito: Escribir y probar código
- Datos: Ficticios o anonimizados
- Acceso: Solo desarrolladores
- Estabilidad: Puede romperse
Staging (preproducción)
- Propósito: Probar antes de producción
- Datos: Copia de producción (anonimizada)
- Acceso: Equipo + QA + cliente
- Estabilidad: Debe ser estable
Production (producción)
- Propósito: Usuarios reales
- Datos: Reales
- Acceso: Público
- Estabilidad: Crítica
Configuración del VPS
Opción 1: Un VPS para todo
Económico, ideal para proyectos pequeños:
VPS 4GB RAM
├── /var/www/proyecto-dev/
├── /var/www/proyecto-staging/
└── /var/www/proyecto-prod/
Opción 2: VPS separados
Más aislamiento, recomendado:
VPS Dev (2GB) → dev.tudominio.com
VPS Staging (4GB) → staging.tudominio.com
VPS Prod (4-8GB) → tudominio.com
Requisitos por entorno
| Entorno | RAM | CPU | Almacenamiento |
|---|---|---|---|
| Development | 2 GB | 1-2 cores | 20 GB |
| Staging | 2-4 GB | 2 cores | 40 GB |
| Production | 4+ GB | 2+ cores | 80+ GB |
Flujo de trabajo con Git
Estrategia de ramas
main (producción)
│
├── develop (staging)
│ │
│ ├── feature/nueva-funcionalidad
│ ├── feature/otra-cosa
│ └── bugfix/corregir-error
│
└── hotfix/urgente (directo a main)
Flujo típico
- Desarrollador crea rama desde
develop - Desarrolla y prueba localmente
- Push a repositorio remoto
- Merge a
develop→ se despliega en staging - QA prueba en staging
- Merge a
main→ se despliega en producción
Configurar Git en el servidor
Instalar Git
sudo apt install git -y
Crear usuario para despliegues
sudo useradd -m -s /bin/bash deploy
sudo passwd deploy
sudo usermod -aG www-data deploy
Configurar SSH keys
# En tu máquina local
ssh-keygen -t ed25519 -C "deploy@proyecto"
# Copiar al servidor
ssh-copy-id -i ~/.ssh/id_ed25519.pub deploy@tu-servidor
Repositorio bare en servidor
# En el servidor
sudo mkdir -p /var/repos/proyecto.git
sudo chown deploy:deploy /var/repos/proyecto.git
cd /var/repos/proyecto.git
git init --bare
Hook de despliegue automático
nano /var/repos/proyecto.git/hooks/post-receive
#!/bin/bash
TARGET="/var/www/proyecto-staging"
GIT_DIR="/var/repos/proyecto.git"
BRANCH="develop"
while read oldrev newrev ref
do
if [ "$ref" = "refs/heads/$BRANCH" ]; then
echo "Desplegando rama $BRANCH..."
git --work-tree=$TARGET --git-dir=$GIT_DIR checkout -f $BRANCH
cd $TARGET
# Instalar dependencias (ejemplo Node.js)
npm ci --production
# Build
npm run build
# Reiniciar aplicación
pm2 restart proyecto-staging
echo "Despliegue completado!"
fi
done
chmod +x /var/repos/proyecto.git/hooks/post-receive
Añadir remote en local
git remote add staging deploy@tu-servidor:/var/repos/proyecto.git
git push staging develop
Docker para entornos consistentes
Por qué Docker
- Misma configuración en dev, staging y prod
- Aislamiento entre proyectos
- Fácil de replicar y escalar
- Dependencias versionadas
Instalar Docker
curl -fsSL https://get.docker.com | sh
sudo usermod -aG docker $USER
Docker Compose para desarrollo
# docker-compose.yml
version: '3.8'
services:
app:
build: .
ports:
- "3000:3000"
volumes:
- .:/app
- /app/node_modules
environment:
- NODE_ENV=development
- DATABASE_URL=postgres://user:pass@db:5432/proyecto_dev
depends_on:
- db
- redis
db:
image: postgres:15
environment:
POSTGRES_USER: user
POSTGRES_PASSWORD: pass
POSTGRES_DB: proyecto_dev
volumes:
- postgres_data:/var/lib/postgresql/data
ports:
- "5432:5432"
redis:
image: redis:7-alpine
ports:
- "6379:6379"
volumes:
postgres_data:
Docker Compose para staging
# docker-compose.staging.yml
version: '3.8'
services:
app:
image: tu-registry/proyecto:staging
ports:
- "3000:3000"
environment:
- NODE_ENV=staging
- DATABASE_URL=postgres://user:pass@db:5432/proyecto_staging
depends_on:
- db
- redis
restart: unless-stopped
db:
image: postgres:15
environment:
POSTGRES_USER: user
POSTGRES_PASSWORD: ${DB_PASSWORD}
POSTGRES_DB: proyecto_staging
volumes:
- postgres_staging:/var/lib/postgresql/data
restart: unless-stopped
redis:
image: redis:7-alpine
restart: unless-stopped
nginx:
image: nginx:alpine
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf
- ./certs:/etc/nginx/certs
depends_on:
- app
restart: unless-stopped
volumes:
postgres_staging:
Comandos útiles
# Desarrollo
docker compose up -d
docker compose logs -f app
docker compose exec app bash
# Staging
docker compose -f docker-compose.staging.yml up -d
docker compose -f docker-compose.staging.yml pull
docker compose -f docker-compose.staging.yml down
CI/CD con GitHub Actions
Despliegue automático a staging
# .github/workflows/staging.yml
name: Deploy to Staging
on:
push:
branches: [develop]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Run tests
run: npm test
- name: Build
run: npm run build
- name: Deploy to staging
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.STAGING_HOST }}
username: deploy
key: ${{ secrets.SSH_PRIVATE_KEY }}
script: |
cd /var/www/proyecto-staging
git pull origin develop
npm ci --production
npm run build
pm2 restart proyecto-staging
Despliegue a producción con aprobación
# .github/workflows/production.yml
name: Deploy to Production
on:
push:
branches: [main]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
- run: npm ci
- run: npm test
deploy:
needs: test
runs-on: ubuntu-latest
environment: production # Requiere aprobación manual
steps:
- name: Deploy to production
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.PROD_HOST }}
username: deploy
key: ${{ secrets.SSH_PRIVATE_KEY }}
script: |
cd /var/www/proyecto-prod
git pull origin main
npm ci --production
npm run build
pm2 restart proyecto-prod
Configurar subdominios
Nginx para múltiples entornos
# /etc/nginx/sites-available/proyecto-dev
server {
listen 80;
server_name dev.tudominio.com;
location / {
proxy_pass http://localhost:3001;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
# /etc/nginx/sites-available/proyecto-staging
server {
listen 80;
server_name staging.tudominio.com;
# Autenticación básica para staging
auth_basic "Staging - Acceso restringido";
auth_basic_user_file /etc/nginx/.htpasswd;
location / {
proxy_pass http://localhost:3002;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
Crear contraseña para staging
sudo apt install apache2-utils -y
sudo htpasswd -c /etc/nginx/.htpasswd staging_user
SSL para todos los entornos
sudo certbot --nginx -d dev.tudominio.com -d staging.tudominio.com
Variables de entorno por entorno
Archivo .env.example
# .env.example (comittear al repo)
NODE_ENV=development
PORT=3000
DATABASE_URL=
REDIS_URL=
API_KEY=
SECRET_KEY=
.env.development
NODE_ENV=development
PORT=3001
DATABASE_URL=postgres://dev:dev@localhost:5432/proyecto_dev
REDIS_URL=redis://localhost:6379/0
API_KEY=dev_key_no_importa
SECRET_KEY=dev_secret_cualquiera
DEBUG=true
.env.staging
NODE_ENV=staging
PORT=3002
DATABASE_URL=postgres://staging:pass@localhost:5432/proyecto_staging
REDIS_URL=redis://localhost:6379/1
API_KEY=staging_api_key
SECRET_KEY=staging_secret_key
DEBUG=false
.env.production
NODE_ENV=production
PORT=3000
DATABASE_URL=postgres://prod:secure_pass@localhost:5432/proyecto_prod
REDIS_URL=redis://localhost:6379/2
API_KEY=real_api_key
SECRET_KEY=very_secure_secret_key
DEBUG=false
Base de datos por entorno
Crear bases de datos separadas
-- PostgreSQL
CREATE DATABASE proyecto_dev;
CREATE DATABASE proyecto_staging;
CREATE DATABASE proyecto_prod;
CREATE USER dev WITH PASSWORD 'dev_pass';
CREATE USER staging WITH PASSWORD 'staging_pass';
CREATE USER prod WITH PASSWORD 'prod_secure_pass';
GRANT ALL ON DATABASE proyecto_dev TO dev;
GRANT ALL ON DATABASE proyecto_staging TO staging;
GRANT ALL ON DATABASE proyecto_prod TO prod;
Sincronizar datos de producción a staging
#!/bin/bash
# sync-db-to-staging.sh
# Exportar de producción
pg_dump -U prod proyecto_prod > /tmp/prod_backup.sql
# Anonimizar datos sensibles
sed -i 's/[email protected]/[email protected]/g' /tmp/prod_backup.sql
# Añadir más transformaciones según necesites
# Importar a staging
psql -U staging proyecto_staging < /tmp/prod_backup.sql
# Limpiar
rm /tmp/prod_backup.sql
echo "Base de datos sincronizada"
Testing automatizado
Ejecutar tests antes de desplegar
# En GitHub Actions
- name: Run tests
run: |
npm test
npm run test:e2e
npm run test:coverage
Tests de humo post-despliegue
#!/bin/bash
# smoke-test.sh
URL=$1
echo "Ejecutando smoke tests en $URL..."
# Test 1: La página carga
STATUS=$(curl -s -o /dev/null -w "%{http_code}" $URL)
if [ $STATUS -eq 200 ]; then
echo "✓ Homepage OK ($STATUS)"
else
echo "✗ Homepage FAIL ($STATUS)"
exit 1
fi
# Test 2: API responde
API_STATUS=$(curl -s -o /dev/null -w "%{http_code}" $URL/api/health)
if [ $API_STATUS -eq 200 ]; then
echo "✓ API Health OK ($API_STATUS)"
else
echo "✗ API Health FAIL ($API_STATUS)"
exit 1
fi
# Test 3: Base de datos conecta
DB_STATUS=$(curl -s $URL/api/health | jq -r '.database')
if [ "$DB_STATUS" = "connected" ]; then
echo "✓ Database OK"
else
echo "✗ Database FAIL"
exit 1
fi
echo "Todos los smoke tests pasaron!"
Rollback rápido
Con Git
# Ver últimos deploys
git log --oneline -10
# Rollback al commit anterior
git checkout HEAD~1
npm ci --production
npm run build
pm2 restart proyecto
# O a un commit específico
git checkout abc1234
Con Docker
# Ver imágenes disponibles
docker images tu-registry/proyecto
# Rollback a versión anterior
docker compose -f docker-compose.staging.yml down
docker compose -f docker-compose.staging.yml pull tu-registry/proyecto:v1.2.3
docker compose -f docker-compose.staging.yml up -d
Script de rollback
#!/bin/bash
# rollback.sh
ENV=$1
COMMITS_BACK=${2:-1}
if [ "$ENV" = "staging" ]; then
cd /var/www/proyecto-staging
elif [ "$ENV" = "prod" ]; then
cd /var/www/proyecto-prod
else
echo "Uso: rollback.sh [staging|prod] [commits_back]"
exit 1
fi
git checkout HEAD~$COMMITS_BACK
npm ci --production
npm run build
pm2 restart proyecto-$ENV
echo "Rollback completado en $ENV"
Preguntas frecuentes
¿Necesito un VPS separado para staging?
No es obligatorio. Puedes usar el mismo VPS con diferentes puertos o subdominios. VPS separados son mejores para proyectos grandes o cuando necesitas aislar recursos.
¿Cómo mantengo staging sincronizado con producción?
Crea scripts que copien la base de datos de producción a staging periódicamente, anonimizando datos sensibles. Automatízalo con cron semanal.
¿Docker o instalación directa?
Docker garantiza consistencia entre entornos. Instalación directa es más simple para proyectos pequeños. Para equipos, Docker es mejor.
¿Cómo protejo el entorno de staging?
Usa autenticación básica en Nginx, IP whitelisting, o VPN. Nunca expongas staging públicamente sin protección.
¿Cada desarrollador necesita su propio entorno?
Idealmente sí, al menos localmente. Con Docker, cada uno puede levantar el stack completo en su máquina. El VPS de desarrollo puede ser compartido para pruebas de integración.
Nuestra recomendación
Para empezar:
- VPS 4GB compartido para dev + staging
- Git hooks para despliegue automático
- Subdominios con SSL
Para equipos:
- VPS separados por entorno
- Docker Compose para consistencia
- GitHub Actions para CI/CD
- Tests automatizados obligatorios
¿Necesitas ayuda configurando tu flujo de desarrollo? La administración gestionada de Avantys incluye configuración de entornos de desarrollo y CI/CD.
Conclusión
Un flujo de desarrollo profesional con entornos separados te ahorra dolores de cabeza y bugs en producción. La inversión inicial en configuración se paga en tranquilidad.
Empieza simple: un VPS con staging y producción. Añade automatización según crezcas.
¿Listo para profesionalizar tu desarrollo? Explora los VPS de Avantys para montar tus entornos de desarrollo y staging.
¿Quieres que lo hagamos por ti?
En Avantys gestionamos tu web, hosting y crecimiento digital de punta a punta. Tú a lo importante.