Despliegue con Git en un servidor local (Red Local)
Introducción
Ahora que entiendes que Git vive en el host y no en el contenedor, te explicaré cómo hacer el despliegue completo en un servidor local (una computadora en tu red local que has configurado como servidor). Este es un escenario muy común en entornos de desarrollo, pruebas o incluso producción pequeña.
Escenario: Servidor local en la red
Arquitectura del entorno
Tu red local (192.168.1.0/24)
├── Tu computadora de desarrollo (192.168.1.100)
│ ├── VS Code
│ ├── Git (cliente)
│ └── Código fuente
│
├── Servidor local (192.168.1.200) ← ¡Este es tu "servidor de producción"!
│ ├── Sistema: Ubuntu Server 22.04
│ ├── Git (instalado en el host)
│ ├── Docker y Docker Compose
│ ├── Repositorio del proyecto (/home/usuario/mi-app)
│ └── Contenedores Docker (PHP, Nginx, MySQL)
│
└── Usuarios en la red
└── Acceden a: http://192.168.1.200:8000Paso 1: Configurar el servidor local
1.1 Instalar requisitos en el servidor
Conéctate a tu servidor local por SSH:
ssh usuario@192.168.1.200Instalar Git, Docker y Docker Compose:
# Actualizar sistema
sudo apt update && sudo apt upgrade -y
# Instalar Git
sudo apt install git -y
# Instalar Docker
curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh
# Agregar usuario al grupo docker
sudo usermod -aG docker $USER
# Instalar Docker Compose (plugin)
sudo apt install docker-compose-plugin -y
# Verificar instalaciones
git --version
docker --version
docker compose versionImportante: Reinicia la sesión SSH para que los cambios de grupo surtan efecto.
1.2 Crear estructura de directorios en el servidor
# Crear directorio para la aplicación
mkdir -p /home/usuario/mi-app
cd /home/usuario/mi-appPaso 2: Configurar el repositorio remoto (Git)
Opción A: Usar GitHub como repositorio central (Recomendado)
1. En tu computadora de desarrollo, crea el repositorio en GitHub:
Ve a GitHub.com y crea un nuevo repositorio (ej:
mi-app-laravel)Copia la URL del repositorio (HTTPS o SSH)
2. En el servidor local, clona el repositorio:
# En el servidor (192.168.1.200)
cd /home/usuario
git clone https://github.com/tu-usuario/mi-app-laravel.git mi-app
cd mi-app3. Configurar deploy key (opcional, para mayor seguridad):
# Generar SSH key en el servidor
ssh-keygen -t ed25519 -C "servidor-local@mi-app"
# Mostrar la clave pública
cat ~/.ssh/id_ed25519.pub
# Copiar la clave y agregarla en GitHub:
# Settings → Deploy keys → Add deploy keyOpción B: Repositorio local en el servidor (Sin GitHub)
Si no quieres usar GitHub, puedes tener un repositorio central en el servidor mismo:
1. Crear un repositorio bare (central) en el servidor:
# En el servidor
mkdir -p /home/usuario/repositorios/mi-app.git
cd /home/usuario/repositorios/mi-app.git
git init --bare2. Desde tu computadora de desarrollo, agregar el remoto:
# En tu computadora local
git remote add servidor ssh://usuario@192.168.1.200/home/usuario/repositorios/mi-app.git
git push servidor main3. En el servidor, clonar desde el repositorio bare:
# En el servidor
cd /home/usuario
git clone /home/usuario/repositorios/mi-app.git mi-app
cd mi-appPaso 3: Configurar los archivos de Docker
3.1 Crear Dockerfile (en tu computadora de desarrollo y subirlo a Git)
docker/php/Dockerfile:
FROM php:8.2-fpm
# Instalar dependencias
RUN apt-get update -y && apt-get install -y \
openssl zip unzip git curl libpng-dev libonig-dev libxml2-dev libzip-dev \
&& docker-php-ext-install pdo_mysql mbstring exif pcntl bcmath gd zip
# Instalar Composer
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer
WORKDIR /var/www/html
# Copiar código (esto se sobrescribirá con el volumen)
COPY . .
# Instalar dependencias
RUN composer install --no-dev --optimize-autoloader --no-interaction
# Crear usuario www-data como propietario
RUN chown -R www-data:www-data /var/www/html \
&& chmod -R 755 /var/www/html/storage /var/www/html/bootstrap/cache
EXPOSE 9000
CMD ["php-fpm"]3.2 Crear docker-compose.yml (para producción)
docker-compose.prod.yml:
version: '3.8'
services:
app:
build:
context: .
dockerfile: docker/php/Dockerfile
container_name: mi_app_php
restart: unless-stopped
volumes:
- ./:/var/www/html
networks:
- app-network
nginx:
image: nginx:alpine
container_name: mi_app_nginx
restart: unless-stopped
ports:
- "8000:80"
volumes:
- ./:/var/www/html
- ./docker/nginx/default.conf:/etc/nginx/conf.d/default.conf
depends_on:
- app
networks:
- app-network
db:
image: mysql:8.0
container_name: mi_app_db
restart: unless-stopped
environment:
MYSQL_DATABASE: ${DB_DATABASE:-laravel}
MYSQL_USER: ${DB_USERNAME:-laravel}
MYSQL_PASSWORD: ${DB_PASSWORD:-secret}
MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASSWORD:-rootsecret}
ports:
- "3306:3306"
volumes:
- db_data:/var/lib/mysql
networks:
- app-network
networks:
app-network:
driver: bridge
volumes:
db_data:3.3 Configurar Nginx (docker/nginx/default.conf)
server {
listen 80;
server_name localhost;
root /var/www/html/public;
index index.php index.html;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
fastcgi_pass app:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
include fastcgi_params;
}
}3.4 Subir configuración a Git
Desde tu computadora de desarrollo:
git add .
git commit -m "feat: add Docker configuration for production"
git push origin mainPaso 4: Desplegar en el servidor local
4.1 Clonar y preparar el entorno
En el servidor (192.168.1.200):
# Si ya clonaste el repositorio
cd /home/usuario/mi-app
# O clonarlo si no lo has hecho
git clone https://github.com/tu-usuario/mi-app-laravel.git mi-app
cd mi-app
# Copiar .env.example a .env y configurarlo
cp .env.example .env
# Editar .env con las configuraciones para producción local
nano .envConfiguración típica para producción local:
APP_NAME=MiApp
APP_ENV=production
APP_DEBUG=false
APP_URL=http://192.168.1.200:8000
DB_CONNECTION=mysql
DB_HOST=db
DB_PORT=3306
DB_DATABASE=laravel
DB_USERNAME=laravel
DB_PASSWORD=secret
# Cache en producción
CACHE_DRIVER=redis
SESSION_DRIVER=redis4.2 Construir y levantar los contenedores
# Construir la imagen de la aplicación
docker compose -f docker-compose.prod.yml build
# Levantar los servicios
docker compose -f docker-compose.prod.yml up -d
# Verificar que estén corriendo
docker compose -f docker-compose.prod.yml psSalida esperada:
NAME IMAGE COMMAND SERVICE STATUS PORTS
mi_app_php mi-app-app "docker-php-entrypoi…" app Up 2 minutes 9000/tcp
mi_app_nginx nginx:alpine "/docker-entrypoint.…" nginx Up 2 minutes 0.0.0.0:8000->80/tcp
mi_app_db mysql:8.0 "docker-entrypoint.s…" db Up 2 minutes 0.0.0.0:3306->3306/tcp4.3 Ejecutar migraciones y configuración inicial
# Generar clave de aplicación
docker compose -f docker-compose.prod.yml exec app php artisan key:generate
# Ejecutar migraciones
docker compose -f docker-compose.prod.yml exec app php artisan migrate --force
# Optimizar para producción
docker compose -f docker-compose.prod.yml exec app php artisan config:cache
docker compose -f docker-compose.prod.yml exec app php artisan route:cache
docker compose -f docker-compose.prod.yml exec app php artisan view:cache4.4 Acceder a la aplicación
Desde cualquier computadora en tu red local:
http://192.168.1.200:8000Paso 5: Flujo de trabajo de actualización
5.1 Hacer cambios en desarrollo (tu computadora)
# En tu computadora local
git add .
git commit -m "feat: add new feature"
git push origin main5.2 Actualizar el servidor local
En el servidor (192.168.1.200):
cd /home/usuario/mi-app
# 1. Descargar los últimos cambios
git pull origin main
# 2. Actualizar dependencias (si composer.json cambió)
docker compose -f docker-compose.prod.yml exec app composer install --no-dev --optimize-autoloader
# 3. Ejecutar migraciones (si hay nuevas)
docker compose -f docker-compose.prod.yml exec app php artisan migrate --force
# 4. Limpiar y regenerar caché
docker compose -f docker-compose.prod.yml exec app php artisan config:clear
docker compose -f docker-compose.prod.yml exec app php artisan config:cache
docker compose -f docker-compose.prod.yml exec app php artisan route:cache
docker compose -f docker-compose.prod.yml exec app php artisan view:cache
# 5. Reiniciar servicios (opcional)
docker compose -f docker-compose.prod.yml restart
echo "¡Actualización completada!"5.3 Automatizar con un script (recomendado)
Crea un archivo deploy.sh en el servidor:
#!/bin/bash
# deploy.sh - Script de despliegue automático
set -e # Detener en caso de error
echo "🚀 Iniciando despliegue..."
# 1. Actualizar código
echo "📦 Actualizando código desde Git..."
git pull origin main
# 2. Actualizar dependencias
echo "📦 Actualizando dependencias..."
docker compose -f docker-compose.prod.yml exec app composer install --no-dev --optimize-autoloader
# 3. Ejecutar migraciones
echo "🗄️ Ejecutando migraciones..."
docker compose -f docker-compose.prod.yml exec app php artisan migrate --force
# 4. Optimizar caché
echo "⚡ Optimizando caché..."
docker compose -f docker-compose.prod.yml exec app php artisan config:cache
docker compose -f docker-compose.prod.yml exec app php artisan route:cache
docker compose -f docker-compose.prod.yml exec app php artisan view:cache
# 5. Reiniciar servicios
echo "🔄 Reiniciando servicios..."
docker compose -f docker-compose.prod.yml restart
echo "✅ ¡Despliegue completado exitosamente!"Hacer ejecutable el script:
chmod +x deploy.shEjecutar:
./deploy.shPaso 6: Automatización con Webhooks (Opcional)
Para que el servidor se actualice automáticamente cuando hagas git push:
6.1 Crear un endpoint webhook en el servidor
Crea un archivo webhook.php en el servidor:
<?php
// webhook.php - Endpoint para GitHub webhooks
// Ubicación: /home/usuario/mi-app/webhook.php
// Verificar secreto (opcional)
$secret = 'tu-secreto-webhook';
$payload = file_get_contents('php://input');
$signature = $_SERVER['HTTP_X_HUB_SIGNATURE_256'] ?? '';
// Validar firma
if ($secret && $signature) {
$computed = 'sha256=' . hash_hmac('sha256', $payload, $secret);
if (!hash_equals($computed, $signature)) {
http_response_code(401);
die('Firma inválida');
}
}
// Ejecutar script de despliegue
$output = shell_exec('cd /home/usuario/mi-app && ./deploy.sh 2>&1');
echo "Despliegue ejecutado:\n" . $output;6.2 Configurar webhook en GitHub
Ve a Settings → Webhooks en tu repositorio de GitHub
Add webhook
Payload URL:
http://192.168.1.200:8000/webhook.phpContent type:
application/jsonSecret: El que configuraste en el script
Events: Just the push event
6.3 Consideraciones de seguridad
El webhook debe estar protegido (no accesible desde internet). Para un servidor local es aceptable, pero en producción:
Usa autenticación por IP (solo acepta peticiones de GitHub)
Usa HTTPS
Usa el secreto de verificación
Paso 7: Resolución de problemas comunes
⚠️ Error: "Permission denied" al hacer git pull
Causa: El usuario no tiene permisos en el directorio.
Solución:
# En el servidor
sudo chown -R $USER:$USER /home/usuario/mi-app
chmod -R 755 /home/usuario/mi-app⚠️ Error: "Could not connect to database"
Causa: El contenedor de MySQL no está listo.
Solución: Esperar unos segundos o usar healthcheck:
# En docker-compose.prod.yml
db:
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
interval: 10s
timeout: 5s
retries: 5⚠️ Error: "No such file or directory" al ejecutar deploy.sh
Causa: El script no tiene permisos de ejecución.
Solución:
chmod +x deploy.sh⚠️ El contenedor no ve los archivos actualizados
Causa: El volumen no está montado correctamente.
Solución:
# Asegurarse de que el volumen monta el directorio correcto
volumes:
- ./:/var/www/html # Monta todo el directorio actualc
Conclusión
¡Y así es como despliegas tu aplicación Laravel con Docker usando Git en un servidor local!
Puntos clave:
✅ Git está en el host (servidor local) - No en el contenedor
✅ El código se sincroniza - Los archivos del host se montan en el contenedor
✅ Actualización simple -
git pull+docker composees todo lo que necesitas✅ Automatización - Un script
deploy.shhace todo el trabajo✅ Sin FTP - Todo se maneja con Git
La belleza de este enfoque es que funciona igual en un servidor local, en la nube (AWS, DigitalOcean) o en cualquier otro lugar. El flujo es el mismo: host con Git → contenedores con Docker.
¡Felicidades! 🎉 Ahora tienes un pipeline completo de despliegue para tu entorno local
Comentarios
Publicar un comentario