# Instalación y Despliegue — Catálogo de Servicios Sin Docker, sin pip, sin CI/CD. Solo Python 3 y `systemd`. --- ## Requisitos - **Python 3.8+** (stdlib únicamente) - Linux con `systemd` para correr como servicio (en Windows/Mac corre con `python3 server.py`) --- ## 1. Desarrollo local ```bash git clone https://git.consultoria-as.com/consultoria-as/catalogo-servicios.git cd catalogo-servicios python3 server.py # → http://localhost:4403 ``` Primera vez: pantalla de **setup** para crear la cuenta admin. Genera `catalogo.db` y `secret.key`. --- ## 2. Despliegue en servidor (Tailscale `iclaude`) Ubicación en producción: `/mnt/iclaude/catalogo-borrador/`. Puerto **4403** (4401 = Hub, 4402 = airbnb-pricing, 4404 = foto-studio). ### a) Copiar archivos (sin secretos ni datos) ```bash scp server.py index.html claude@iclaude:/mnt/iclaude/catalogo-borrador/ ``` > **No copiar** `secret.key` ni `catalogo.db` — el servidor ya tiene los suyos. Los datos viven solo en el servidor. ### b) Servicio systemd `/etc/systemd/system/catalogo-borrador.service`: ```ini [Unit] Description=Catalogo (borrador) - builder de servicios After=network.target [Service] Type=simple User=claude WorkingDirectory=/mnt/iclaude/catalogo-borrador ExecStart=/usr/bin/python3 /mnt/iclaude/catalogo-borrador/server.py Restart=always RestartSec=5 Environment=PYTHONUNBUFFERED=1 [Install] WantedBy=multi-user.target ``` ```bash sudo systemctl daemon-reload sudo systemctl enable --now catalogo-borrador ``` ### c) Redespliegue ```bash scp index.html server.py claude@iclaude:/mnt/iclaude/catalogo-borrador/ ssh claude@iclaude "sudo systemctl restart catalogo-borrador" ``` Migraciones de esquema corren solas al reiniciar (idempotentes). ### Logs ```bash sudo journalctl -u catalogo-borrador -n 50 --no-pager ``` --- ## 3. Acceso - **Privado** (tailnet): `http://iclaude:4403/` · `http://192.168.50.46:4403/` - **Público** (clientes, sin Tailscale): vía **Tailscale Funnel** en puerto dedicado (8443). ```bash tailscale funnel --bg 8443 tailscale funnel status ``` > Nota: usar puerto dedicado (no un path bajo `/catalogo`) porque la app usa rutas absolutas `/api/...`. --- ## 4. Solución de problemas | Síntoma | Causa | Solución | |---|---|---| | "Sesión inválida" constante | reloj del servidor desfasado | corregir hora (cron `sync_clock.sh`) | | Logins rotos bajo Funnel con path | rutas absolutas `/api/` | exponer en puerto propio (8443), no en `/catalogo` | | Thumbnail equivocado | prefijos de archivo | `first_image` prefiere `foto_`, excluye `menu`/docs | --- *Stack mínimo: todo corre con un solo `python3 server.py`.*