Problema
Al intentar autoalojar una aplicación web que combina registro de entrenamientos, gestión de usuarios y un módulo opcional de IA, muchos administradores encuentran fallos intermitentes: el contenedor se reinicia, los enlaces de restablecimiento de contraseña llegan con el esquema incorrecto, o los datos desaparecen tras una actualización. El patrón típico es una configuración Docker incompleta o una integración deficiente con el proxy inverso y los volúmenes persistentes. Cuando la aplicación depende de variables como BASE_URL o de secretos para APIs externas, cualquier desalineación entre el entorno de Docker y el front‑end provoca errores de carga, pérdida de sesiones y problemas de sincronización multi‑dispositivo.
Causa
-
Variables de entorno no sincronizadas –
BASE_URL,X_FORWARDED_PROTOy los tokens de API deben coincidir con la ruta pública del servicio. Si el proxy reescribe la URL y el contenedor sigue usando la ruta interna, los enlaces generados (invitaciones, restablecimientos) apuntan al host equivocado. -
Volúmenes mal montados – LiftTrace guarda la base SQLite y los archivos de respaldo en
/data. Un volumen host que se recrea en cada despliegue borra el historial y rompe la sincronización de UUID entre dispositivos. -
Proxy inverso sin encabezados correctos – Nginx, Caddy o Traefik deben pasar
X‑Forwarded‑ProtoyX‑Forwarded‑Host. Sin ellos, la aplicación asume HTTP aunque el tráfico llegue por TLS, generando redirecciones infinitas o enlaces inseguros. -
Secretos de Docker no expuestos – Las claves para proveedores de IA, notificaciones o SMTP se suelen pasar como Docker secrets. Si el contenedor se lanza sin
--secret, la aplicación entra en modo degradado y desactiva funcionalidades críticas sin aviso visible. -
Arquitectura de múltiples nodos – En entornos ARM/AMD mixtos, usar una imagen multi‑arch sin especificar la variante puede lanzar una versión incompatible, provocando fallos al iniciar.
Solución
Adoptar una plantilla Docker‑Compose que cubra los puntos críticos y validar cada capa antes de pasar a producción.
-
Definir variables estáticas en un archivo
.envBASE_URLcon la ruta completa (incluye sub‑ruta si se usa).HOST_PORTpara mapear el puerto interno 8080.TZpara zona horaria y evitar discrepancias en timestamps.
-
Montar un volumen persistente nombrado
docker volume create lifttrace_dataAsí el directorio
/datase conserva aunque el contenedor se recree. -
Configurar Docker secrets
- Crear archivos
ai_key.txt,smtp_user.txt,smtp_pass.txten un directorio protegido (/run/secrets). - Declarar los secretos en
docker-compose.ymly referenciarlos consecrets:.
- Crear archivos
-
Proxy inverso con encabezados (ejemplo Nginx)
location /lifttrace/ { proxy_pass http://localhost:8080/; proxy_set_header Host $host; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Forwarded-Host $host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; }La ruta
/lifttrace/coincide conBASE_URL=/lifttrace. -
Imagen multi‑arch – Usar la etiqueta
latestdel repositorio oficial, que incluyeamd64yarm64. En Docker‑Compose especificarplatform: linux/amd64olinux/arm64según el host. -
Backup automatizado – Programar un contenedor ligero (
alpine+cron) que comprima/datay lo suba a un bucket S3 o a una ubicación NAS. Mantener al menos dos copias rotativas. -
Validar la sincronización de UUID – Después de la primera instalación, crear un registro de prueba desde dos dispositivos diferentes. Si los UUID colisionan, revisar que la variable
LIFTTRACE_UUIDno esté sobrescrita por undocker-compose.override.yml.
Cuándo aplicar esta solución
- Síntomas: enlaces de correo con dominio interno, pérdida de historial tras reinicio, contenedor que entra en bucle de reinicio, errores 502/504 del proxy, o notificaciones que nunca llegan.
- Entornos: homelab con Docker, Raspberry Pi 4/5, servidores NAS con Docker‑Compose, o despliegues en VPS que usan Traefik como gateway.
- Exclusiones: si la aplicación se ejecuta en Kubernetes con Helm, la lógica de secrets y volúmenes cambia; la guía está orientada a Docker‑Compose puro.
Código
# .env
BASE_URL=/lifttrace
HOST_PORT=8080
TZ=America/Argentina/Buenos_Aires
# docker-compose.yml
version: "3.9"
services:
lifttrace:
image: ghcr.io/traceapps/lifttrace:latest
container_name: lifttrace
restart: unless-stopped
ports:
- "${HOST_PORT}:8080"
env_file:
- .env
environment:
- BASE_URL=${BASE_URL}
- TZ=${TZ}
volumes:
- lifttrace_data:/data
secrets:
- ai_key
- smtp_user
- smtp_pass
# opcional: limitar arquitectura
# platform: linux/arm64
backup:
image: alpine:latest
container_name: lifttrace_backup
restart: unless-stopped
volumes:
- lifttrace_data:/data:ro
- ./backups:/backup
entrypoint: ["/bin/sh","-c"]
command: |
"while true; do
tar -czf /backup/lifttrace_$(date +%F_%H%M).tar.gz -C /data .;
sleep 86400;
done"
depends_on:
- lifttrace
volumes:
lifttrace_data:
secrets:
ai_key:
file: ./secrets/ai_key.txt
smtp_user:
file: ./secrets/smtp_user.txt
smtp_pass:
file: ./secrets/smtp_pass.txt
Verificación
- Ejecutar
docker compose up -dy comprobar que el contenedor estáhealthy(Dockerfile incluye healthcheck en/health). - Acceder a
http://<host_ip>:8080/lifttracey validar que la página carga sin redirecciones. - Generar un enlace de invitación desde la UI; el correo debe contener
https://<dominio>/lifttrace/.... - Verificar que el archivo
lifttrace_*.tar.gzaparece en./backupsdespués de 24 h. - Simular una caída del contenedor (
docker restart lifttrace) y confirmar que los datos persisten y la sesión no se pierde.
Notas adicionales
- En entornos con Cloudflare o cualquier CDN, habilitar
Proxyen el DNS y añadir la cabeceraCF-Visitoral bloque de Nginx evita que el proxy elimineX‑Forwarded‑Proto. - Si se usa OIDC (Keycloak, Authelia), la URL de callback debe incluir
BASE_URLexactamente; de lo contrario la autenticación falla coninvalid_redirect_uri. - Para usuarios que no requieren IA, basta con omitir los secretos
ai_key; la aplicación detecta la ausencia y desactiva el módulo sin afectar el resto. - Cuando se actualiza a una nueva versión, primero detener el servicio, crear una copia de seguridad manual (
docker run --rm -v lifttrace_data:/data -v $(pwd):/backup alpine tar -czf /backup/pre_update.tar.gz -C /data .), luego lanzardocker compose pull && docker compose up -d. - En Raspberry Pi, asegúrese de que la tarjeta SD tenga al menos 8 GB libres; la base SQLite crece rápidamente con logs de series y notas.