Saltar a contenido

Despliegue en servidor

Para quién es esta guía

Una guía paso a paso y muy detallada para instalar Gestión Civis en un servidor Linux, pensada para alguien con poca o ninguna experiencia administrando servidores. Copia cada comando tal cual, en orden, y verifica el resultado antes de pasar al siguiente.

¿Qué vamos a montar?

Gestión Civis tiene dos partes: un backend (el "cerebro", en Python/Flask) y un frontend (lo que se ve en el navegador). Para que funcionen en Internet necesitamos varias piezas trabajando juntas:

flowchart LR
    U["👤 Usuario<br/>(navegador)"] -->|HTTPS| N["Nginx<br/>(recepcionista)"]
    N -->|páginas| D["Frontend<br/>(carpeta dist/)"]
    N -->|/api| G["gunicorn + Flask<br/>(backend)"]
    G --> P[("PostgreSQL<br/>base de datos")]
    G --> S["Almacenamiento<br/>de ficheros"]
    T["Tarea programada<br/>(cada 5 min)"] --> G
Pieza Qué hace (en palabras sencillas)
Nginx El "recepcionista": recibe a los usuarios por HTTPS, les entrega las páginas web y pasa las peticiones de datos al backend.
gunicorn El "motor" que mantiene el backend Flask funcionando y atendiendo peticiones.
PostgreSQL La base de datos: donde se guarda toda la información.
Tarea programada Un "despertador" que cada pocos minutos ejecuta las tareas automáticas (SIR, avisos, etc.).

¿Qué servidor necesito?

Un servidor con Ubuntu Server 22.04 (o Debian 12), 4 vCPU y 8 GB de RAM (ver Requisitos) y una dirección IP pública. Puede ser un VPS de cualquier proveedor o una máquina del propio ayuntamiento. Si vas a usar Google Cloud, sigue mejor la guía específica.


Paso 0. Conectarse al servidor

Para administrar el servidor se usa SSH (una conexión segura por terminal). Necesitas la IP del servidor y un usuario con contraseña (te los da tu proveedor o quien montó la máquina).

  1. Abre PowerShell o Windows Terminal (botón Inicio → escribe "PowerShell").
  2. Escribe (sustituye la IP por la real):
    ssh usuario@203.0.113.10
    
  3. La primera vez te preguntará si confías en el servidor: escribe yes y pulsa Enter. Luego introduce la contraseña (no se ve mientras escribes; es normal).

Abre el Terminal y ejecuta:

ssh usuario@203.0.113.10

Cuando veas algo como usuario@servidor:~$ ya estás dentro del servidor. A partir de aquí, todos los comandos se escriben en esa terminal conectada.

Sobre sudo

Muchos comandos empiezan por sudo, que significa "ejecutar como administrador". La primera vez te pedirá tu contraseña. Es necesario para instalar programas y cambiar la configuración del sistema.

Editar archivos: el editor nano

Varias veces habrá que crear o editar archivos de texto. Usaremos nano, que es el más sencillo:

  • Abrir/crear: sudo nano /ruta/al/archivo
  • Guardar: Ctrl + O y luego Enter.
  • Salir: Ctrl + X.

Paso 1. Actualizar el sistema e instalar dependencias

Primero ponemos el sistema al día y luego instalamos todo lo que la aplicación necesita (Python, la base de datos, el servidor web y las librerías para generar PDF, leer XML, etc.).

# Actualiza la lista de programas disponibles y los ya instalados
sudo apt update && sudo apt upgrade -y

# Instala todas las dependencias de una vez
sudo apt install -y \
  python3 python3-venv python3-dev build-essential \
  libpq-dev libpango-1.0-0 libpangocairo-1.0-0 libgdk-pixbuf-2.0-0 \
  libcairo2 libffi-dev libxml2 libxslt1.1 fonts-dejavu \
  postgresql nginx git curl

Esto puede tardar unos minutos. Si termina sin errores en rojo, vamos bien.

¿Qué acabo de instalar?

  • python3… → el lenguaje del backend.
  • postgresql → la base de datos.
  • nginx → el servidor web.
  • libpango…, libcairo2, fonts-dejavu → para que la aplicación pueda generar PDF (recibos, informes).
  • libxml2, libxslt1.1 → para el XML de facturas y registro.
  • git → para descargar el código.

Paso 2. Crear un usuario para la aplicación

Por seguridad, la aplicación no debe ejecutarse como administrador. Creamos un usuario propio llamado civis y una carpeta para el código:

sudo useradd -m -s /bin/bash civis
sudo mkdir -p /opt/gestion-civis
sudo chown civis:civis /opt/gestion-civis
  • useradd crea el usuario civis.
  • /opt/gestion-civis será la carpeta donde vivirá la aplicación.
  • chown da la propiedad de esa carpeta al usuario civis.

Paso 3. Crear la base de datos

La base de datos PostgreSQL ya está instalada y funcionando. Ahora creamos un usuario de base de datos y una base de datos para Gestión Civis:

sudo -u postgres psql <<'SQL'
CREATE USER civis WITH PASSWORD 'CAMBIA-ESTA-CONTRASEÑA';
CREATE DATABASE gestion_civis OWNER civis;
SQL

Cambia la contraseña

Sustituye CAMBIA-ESTA-CONTRASEÑA por una contraseña larga y única. Anótala, la necesitarás en el Paso 5.

Con esto, la "dirección" de la base de datos (que usaremos después) es:

postgresql://civis:CAMBIA-ESTA-CONTRASEÑA@localhost:5432/gestion_civis

(localhost significa "este mismo servidor"; 5432 es el puerto de PostgreSQL.)

Paso 4. Descargar el código del backend

Ahora trabajamos como el usuario civis. Para "convertirte" en ese usuario:

sudo su - civis

Verás que el prompt cambia a civis@servidor:~$. Descarga el código en la carpeta preparada:

cd /opt/gestion-civis
git clone <URL-DEL-REPOSITORIO> .

Si no usas Git

Si tienes el código en un .zip, súbelo al servidor y descomprímelo dentro de /opt/gestion-civis. Lo importante es que run.py y requirements.txt queden directamente en esa carpeta.

Paso 5. Instalar el backend

Creamos un entorno virtual (una "burbuja" de Python aislada para la app) e instalamos sus dependencias:

cd /opt/gestion-civis
python3 -m venv .venv
source .venv/bin/activate
pip install --upgrade pip
pip install -r requirements.txt
pip install gunicorn
  • python3 -m venv .venv crea la burbuja en la carpeta .venv.
  • source .venv/bin/activate "entra" en la burbuja (verás (.venv) al principio de la línea).
  • pip install -r requirements.txt instala todo lo que la app necesita (tarda varios minutos; descarga bastante).
  • gunicorn es el motor que servirá la app.

Crear el fichero de configuración .env

La aplicación lee su configuración de un fichero llamado .env. Vamos a crearlo:

nano /opt/gestion-civis/.env

Pega este contenido ajustando los valores a tu caso:

# Clave secreta: invéntate una cadena larga y aleatoria (no la compartas)
SECRET_KEY=pega-aqui-una-cadena-larga-y-aleatoria

# Base de datos (la misma contraseña del Paso 3)
DATABASE_URL=postgresql://civis:CAMBIA-ESTA-CONTRASEÑA@localhost:5432/gestion_civis

# Almacenamiento de ficheros en el propio servidor
STORAGE_PROVIDER=local
STORAGE_LOCAL_PATH=/opt/gestion-civis/storage

# Tu dominio (lo configuraremos en el Paso 9)
FRONTEND_URL=https://civis.tu-ayuntamiento.es
FRONTEND_ALLOWED_ORIGINS=https://civis.tu-ayuntamiento.es

# Inteligencia artificial (opcional; déjalo así si no la usas)
IA_AUDITORIA_ENABLED=false
GOOGLE_API_KEY=

Guarda con Ctrl+O, Enter, y sal con Ctrl+X.

Generar una SECRET_KEY segura

Ejecuta este comando y copia el resultado como valor de SECRET_KEY:

python3 -c "import secrets; print(secrets.token_urlsafe(48))"

Preparar la base de datos y los datos iniciales

flask db upgrade     # crea todas las tablas
python seed.py       # carga datos iniciales (roles, permisos, etc.)

Comprobar que el backend arranca

gunicorn -w 2 -b 127.0.0.1:5000 "app:create_app()"

Si ves líneas como Booting worker y no aparecen errores, ¡funciona! Pulsa Ctrl+C para pararlo (lo dejaremos como servicio permanente en el Paso 7).

Si falla aquí

  • Lee el mensaje de error: suele indicar el problema (p. ej. contraseña de base de datos incorrecta en .env, o una librería que faltó instalar).
  • Asegúrate de tener la burbuja activada ((.venv) al inicio de la línea); si no, ejecuta source /opt/gestion-civis/.venv/bin/activate.

Paso 6. Compilar el frontend

El frontend hay que compilarlo (convertir el código en archivos que el navegador entiende). Necesita Node.js. Si no está instalado:

# (como tu usuario normal con sudo; sal de 'civis' con 'exit' si hace falta)
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
sudo apt install -y nodejs

Compila el frontend (como usuario civis):

sudo su - civis
cd /opt/gestion-civis/gestion-civis-frontend
npm install
npm run build        # crea la carpeta dist/ con la web ya compilada
exit

Copia el resultado a la carpeta desde la que Nginx servirá la web:

sudo mkdir -p /var/www/civis
sudo cp -r /opt/gestion-civis/gestion-civis-frontend/dist/* /var/www/civis/

Alternativa: compilar en tu PC

Si el servidor tiene poca memoria, puedes ejecutar npm install y npm run build en tu ordenador y subir solo la carpeta dist/ al servidor.

Paso 7. Mantener el backend siempre encendido (systemd)

Queremos que el backend arranque solo y se reinicie si se cae. Para eso creamos un servicio de systemd:

sudo nano /etc/systemd/system/gestion-civis.service

Pega:

[Unit]
Description=Gestion Civis (backend)
After=network.target postgresql.service

[Service]
User=civis
Group=civis
WorkingDirectory=/opt/gestion-civis
Environment="PATH=/opt/gestion-civis/.venv/bin"
ExecStart=/opt/gestion-civis/.venv/bin/gunicorn -w 4 --timeout 120 -b 127.0.0.1:5000 "app:create_app()"
Restart=always

[Install]
WantedBy=multi-user.target

Actívalo:

sudo systemctl daemon-reload
sudo systemctl enable --now gestion-civis
sudo systemctl status gestion-civis      # debe aparecer "active (running)"

(Pulsa q para salir de la pantalla de estado.)

¿Qué es -w 4?

El número de "trabajadores" (workers) que atienden peticiones a la vez. Con la búsqueda/IA, cada worker consume bastante memoria: con 8 GB de RAM, 4 es un buen punto de partida. Si ves que se queda sin memoria, baja a 2.

Paso 8. Las tareas automáticas (scheduler)

Gestión Civis tiene tareas que deben ejecutarse cada pocos minutos (envíos al SIR, avisos de vencimiento, prescripciones, etc.). Se lanzan con el comando flask civis-system-run. Programamos que se ejecute cada 5 minutos:

sudo mkdir -p /opt/gestion-civis/logs
sudo chown civis:civis /opt/gestion-civis/logs
sudo crontab -u civis -e

(La primera vez te preguntará qué editor usar: elige nano, normalmente la opción 1.) Añade esta línea al final:

*/5 * * * * cd /opt/gestion-civis && /opt/gestion-civis/.venv/bin/flask civis-system-run >> /opt/gestion-civis/logs/scheduler.log 2>&1

Guarda y sal. Esto significa: "cada 5 minutos, ejecuta el scheduler y guarda el resultado en un log".

Solo una vez

Esta tarea debe estar programada en un único sitio. No la pongas también dentro del backend ni en otra máquina, o se duplicarían las acciones.

Paso 9. Configurar Nginx (la web y el HTTPS)

Nginx servirá el frontend y reenviará las peticiones /api al backend. Crea su configuración:

sudo nano /etc/nginx/sites-available/gestion-civis

Pega (sustituye civis.tu-ayuntamiento.es por tu dominio real):

server {
    listen 80;
    server_name civis.tu-ayuntamiento.es;

    root /var/www/civis;
    index index.html;

    # El frontend es una "SPA": cualquier ruta desconocida va a index.html
    location / {
        try_files $uri $uri/ /index.html;
    }

    # Las peticiones de datos van al backend
    location /api/ {
        proxy_pass http://127.0.0.1:5000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        client_max_body_size 15m;     # tamaño máximo de adjuntos
        proxy_read_timeout 180s;      # margen para PDF/IA
    }
}

Activa la configuración y reinicia Nginx:

sudo ln -s /etc/nginx/sites-available/gestion-civis /etc/nginx/sites-enabled/
sudo rm -f /etc/nginx/sites-enabled/default     # quita la página por defecto
sudo nginx -t                                   # comprueba que no hay errores
sudo systemctl reload nginx

Apunta tu dominio al servidor

Para usar civis.tu-ayuntamiento.es necesitas un registro DNS de tipo A que apunte ese nombre a la IP pública del servidor. Eso se configura donde gestionas tu dominio. Mientras tanto, puedes probar con la IP directamente.

Activar HTTPS (candado de seguridad)

sudo apt install -y certbot python3-certbot-nginx
sudo certbot --nginx -d civis.tu-ayuntamiento.es

Certbot pedirá un email, aceptará los términos y configurará el certificado HTTPS gratuito automáticamente, además de renovarlo solo. A partir de aquí, la web funciona con https://.

Paso 10. Comprobar que todo funciona

  1. Abre en el navegador https://civis.tu-ayuntamiento.es → debe aparecer la pantalla de inicio de sesión.
  2. Entra con el usuario administrador inicial (el que crea seed.py; consúltalo con quien preparó los datos).
  3. Comprueba el backend por terminal:
    curl https://civis.tu-ayuntamiento.es/api/_routes
    
    Debe devolver una lista de rutas (texto JSON).

Ver los registros (logs) si algo va mal

sudo journalctl -u gestion-civis -f        # log del backend (Ctrl+C para salir)
sudo tail -f /opt/gestion-civis/logs/scheduler.log   # log de las tareas
sudo tail -f /var/log/nginx/error.log       # log de Nginx

Mantenimiento

Actualizar a una versión nueva

sudo su - civis
cd /opt/gestion-civis
git pull                                  # baja los cambios
source .venv/bin/activate
pip install -r requirements.txt           # nuevas dependencias
flask db upgrade                          # nuevas tablas/migraciones
# si cambió el frontend, recompílalo (Paso 6)
exit
sudo systemctl restart gestion-civis      # reinicia el backend

Copias de seguridad (imprescindible)

# Base de datos (hazlo a diario, p. ej. con cron)
sudo -u postgres pg_dump gestion_civis > /ruta/segura/civis_$(date +%F).sql

# Ficheros (los documentos subidos)
tar czf /ruta/segura/storage_$(date +%F).tar.gz /opt/gestion-civis/storage

Guarda estas copias fuera del servidor.


Problemas frecuentes

Síntoma Posible causa y solución
La web muestra "502 Bad Gateway" El backend no está corriendo. Revisa sudo systemctl status gestion-civis y los logs.
Error al arrancar sobre la base de datos Contraseña incorrecta en .env o base de datos no creada (Paso 3).
Los PDF no se generan Faltan las librerías de WeasyPrint (Paso 1). Reinstálalas.
El servidor se queda sin memoria Reduce el número de workers (-w 2) en el Paso 7.
Las tareas automáticas no se ejecutan Revisa el cron del Paso 8 y logs/scheduler.log.
"413 Request Entity Too Large" al subir Sube client_max_body_size en Nginx (Paso 9).

¿Y ahora?

Con esto tienes Gestión Civis funcionando en producción. Repasa la lista de seguridad y backups de Puesta en marcha y, si vas a usar SIR/FACe/firma, configura sus credenciales en el .env (ver Configuración).