Cuando tu sitio en WordPress/WooCommerce es crítico para ventas y captación, actualizar “a mano” es arriesgado. Con CI/CD en GitHub Actions puedes probar, construir y desplegar cambios de forma atómica y sin downtime, con rollback en un clic.
¿Qué resuelve un pipeline CI/CD?
-
Zero downtime: el nuevo release se prepara en segundo plano y se activa cambiando un symlink (
current → releases/2025…). -
Calidad: linters, tests y checks antes de tocar producción.
-
Seguridad: claves en GitHub Secrets; acceso al servidor por SSH key de solo despliegue.
-
Trazabilidad: cada deploy queda versionado y con logs.
Arquitectura de despliegue (recomendada)
/var/www/mi-sitio/
├─ shared/ # persistente (uploads, cache, claves)
│ └─ wp-content/uploads → se comparte entre releases
├─ releases/
│ ├─ 2025-09-01_12-00-03/ # release generado por el pipeline
│ └─ 2025-08-28_19-44-10/
└─ current → releases/2025-09-01_12-00-03/ # symlink activo
En cada release, enlaza wp-content/uploads a ../shared/uploads y cualquier otro recurso persistente (cache, claves locales, etc.).
Ejemplo de workflow (GitHub Actions)
Archivo:
.github/workflows/deploy.yml
Deploy por push a main o manual (workflow_dispatch). Ajusta rutas/usuarios y añade tus pasos de build de tema/plug-ins.
name: Deploy WordPress (Zero-Downtime)
on:
push:
branches: [ "main" ]
workflow_dispatch:
jobs:
build-test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: "8.2"
tools: composer, phpstan, phpcs
- name: Install Composer deps (no-dev in prod)
run: composer install --no-interaction --prefer-dist
- name: Lint PHP
run: find . -type f -name "*.php" -not -path "./vendor/*" -print0 | xargs -0 -n 1 -P 4 php -l
- name: WordPress Coding Standards (PHPCS)
run: phpcs --standard=WordPress --ignore=vendor,node_modules .
- name: Build assets (theme/plugins)
run: |
if [ -f package.json ]; then npm ci && npm run build; fi
- name: Archive artifact
run: |
mkdir -p artifact
rsync -a --delete --exclude '.git' --exclude 'node_modules' --exclude '.github' ./ artifact/app/
tar -czf artifact.tar.gz -C artifact app
shell: bash
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: site-artifact
path: artifact.tar.gz
deploy:
needs: build-test
runs-on: ubuntu-latest
environment:
name: production
url: https://tusitio.com
steps:
- uses: actions/download-artifact@v4
with:
name: site-artifact
path: .
- name: Prepare release name
id: rel
run: echo "REL=releases/$(date +'%Y-%m-%d_%H-%M-%S')" >> $GITHUB_OUTPUT
- name: Upload & Extract via SSH
uses: appleboy/[email protected]
with:
host: ${{ secrets.SSH_HOST }}
username: ${{ secrets.SSH_USER }}
key: ${{ secrets.SSH_KEY }}
port: ${{ secrets.SSH_PORT }}
script: |
set -e
BASE=/var/www/tusitio
REL=${{ steps.rel.outputs.REL }}
mkdir -p "$BASE/$REL" "$BASE/shared/uploads"
tar -xzf site-artifact.tar.gz -C "$BASE/$REL"
ln -sfn "$BASE/shared/uploads" "$BASE/$REL/app/wp-content/uploads"
- name: Health check (pre-switch)
uses: appleboy/[email protected]
with:
host: ${{ secrets.SSH_HOST }}
username: ${{ secrets.SSH_USER }}
key: ${{ secrets.SSH_KEY }}
port: ${{ secrets.SSH_PORT }}
script: |
curl -sSf https://tusitio.com | head -n 5 > /dev/null
- name: Atomic switch (no downtime)
uses: appleboy/[email protected]
with:
host: ${{ secrets.SSH_HOST }}
username: ${{ secrets.SSH_USER }}
key: ${{ secrets.SSH_KEY }}
port: ${{ secrets.SSH_PORT }}
script: |
set -e
BASE=/var/www/tusitio
REL=${{ steps.rel.outputs.REL }}
ln -sfn "$BASE/$REL/app" "$BASE/current"
- name: Post-deploy (cache & checks)
uses: appleboy/[email protected]
with:
host: ${{ secrets.SSH_HOST }}
username: ${{ secrets.SSH_USER }}
key: ${{ secrets.SSH_KEY }}
port: ${{ secrets.SSH_PORT }}
script: |
set -e
cd /var/www/tusitio/current
if command -v wp >/dev/null 2>&1; then
wp cache flush --allow-root || true
wp rewrite flush --hard --allow-root || true
fi
# Purga LiteSpeed/Cloudflare si aplica (curl a endpoint o WP-CLI plugin)
# Mantén 5 releases
cd /var/www/tusitio/releases && ls -1t | tail -n +6 | xargs -r rm -rf
Rollback en 10 segundos
-
Lista releases (
ls -1t /var/www/tusitio/releases) y apunta el anterior. -
Cambia symlink:
ln -sfn /var/www/tusitio/releases/FECHA_HORA/app /var/www/tusitio/current. -
(Opcional) Purga caché y verifica health check.
Seguridad y buenas prácticas
-
Secrets en GitHub (host, user, key, port).
-
Usuario SSH solo para deploy y sin shell interactivo si es posible.
-
WAF/CDN activado (Cloudflare/QUIC.cloud).
-
Backups automáticos previos al switch.
-
Presupuestos de rendimiento: falla el build si LCP/INP excede tu umbral.
Checklist express
-
Repositorio limpio (sin
wp-content/uploads). -
Workflows: build-test y deploy con approvals.
-
shared/uploadsenlazado por symlink. -
Health checks antes y después del switch.
-
Rollback documentado.
-
Purga de caché/OPcache.
-
Mantener 5 releases.
-
Logs centralizados del deploy.
