Hosting Equipo Avantys 6 min

VPS para Desarrollo y Staging: Guía Completa

Configura un VPS para entornos de desarrollo y staging. Git, CI/CD, Docker, entornos de prueba y flujos de trabajo profesionales.

// Compartir

VPS para Desarrollo y Staging: Guía Completa
VPS para desarrollo y staging

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

RiesgoConsecuencia
Bug en códigoUsuarios ven errores
Migración fallidaBase de datos corrupta
Dependencia rotaSitio caído
Prueba de rendimientoServidor saturado
Experimento fallidoPérdida de datos

La solución: entornos separados

Development → Staging → Production
   (romper)    (probar)   (estable)

Los tres entornos

Entornos desarrollo staging producción

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

EntornoRAMCPUAlmacenamiento
Development2 GB1-2 cores20 GB
Staging2-4 GB2 cores40 GB
Production4+ GB2+ cores80+ GB

Flujo de trabajo con Git

Flujo desarrollo 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

  1. Desarrollador crea rama desde develop
  2. Desarrolla y prueba localmente
  3. Push a repositorio remoto
  4. Merge a develop → se despliega en staging
  5. QA prueba en staging
  6. 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.

Hablar con Avantys
// Boletín

Suscríbete al boletín

Guías nuevas, sin spam. Cancela cuando quieras.