commit 10b8e750cbb0e77b8e9f3ee11a8ef10a9c438afe Author: groales Date: Thu Dec 4 15:36:36 2025 +0100 Commit inicial: BookStack con MariaDB 11, Traefik/NPM, sin standalone diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..dee64b6 --- /dev/null +++ b/.env.example @@ -0,0 +1,15 @@ +# === CONTRASEÑAS REQUERIDAS === +# Generar DB_PASSWORD con: openssl rand -base64 32 +DB_PASSWORD='' + +# === CONFIGURACIÓN OPCIONAL === +# Base de datos (valores por defecto) +DB_NAME=bookstack +DB_USER=bookstack + +# === SOLO PARA TRAEFIK === +# Dominio para certificado SSL (no necesario con NPM) +DOMAIN_HOST=bookstack.example.com + +# IMPORTANTE: Usa comillas simples si las contraseñas contienen caracteres especiales +# Ejemplo: DB_PASSWORD='tu_password_con_$_especiales' diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..800d517 --- /dev/null +++ b/.gitignore @@ -0,0 +1,13 @@ +# Docker +.env +docker-compose.override.yml + +# Backups +*.sql +*.sql.gz +*.tar.gz +backups/ + +# Logs +*.log +logs/ diff --git a/README.md b/README.md new file mode 100644 index 0000000..4afb3e3 --- /dev/null +++ b/README.md @@ -0,0 +1,531 @@ +# BookStack + +Plataforma de documentación y wiki de código abierto. Organiza contenido en libros, capítulos y páginas con editor WYSIWYG y Markdown. + +## Características + +- 📚 **Organización jerárquica**: Libros → Capítulos → Páginas +- ✏️ **Editor dual**: WYSIWYG y Markdown +- 🔍 **Búsqueda potente**: Busca en todo el contenido +- 🔐 **Control de acceso**: Permisos granulares por rol +- 📝 **Historial de cambios**: Seguimiento completo de ediciones +- 🖼️ **Gestión de imágenes**: Biblioteca de medios integrada +- 🔗 **Integración**: LDAP, SAML, OAuth +- 🌍 **Multi-idioma**: Soporte para múltiples idiomas + +## Requisitos Previos + +- Docker Engine instalado +- Portainer configurado (recomendado) +- **Para Traefik o NPM**: Red Docker `proxy` creada +- **Dominio configurado**: Para acceso HTTPS +- **Contraseña generada**: DB_PASSWORD + +⚠️ **IMPORTANTE**: BookStack requiere MariaDB 11. Este compose incluye el contenedor de base de datos. + +## Generar Contraseña + +**Antes de cualquier despliegue**, genera una contraseña segura: + +```bash +# DB_PASSWORD (MariaDB) +openssl rand -base64 32 +``` + +Guarda el resultado, lo necesitarás en el archivo `.env`. + +> ⚠️ **Importante**: Usa comillas simples en el archivo `.env` si la contraseña contiene caracteres especiales. +> Ejemplo: `DB_PASSWORD='tu_password_generado'` + +--- + +## Despliegue con Portainer + +### Opción A: Git Repository (Recomendada) + +Permite mantener la configuración actualizada automáticamente desde Git. + +1. En Portainer, ve a **Stacks** → **Add stack** +2. Nombra el stack: `bookstack` +3. Selecciona **Git Repository** +4. Configura: + - **Repository URL**: `https://git.ictiberia.com/groales/bookstack` + - **Repository reference**: `refs/heads/main` + - **Compose path**: `docker-compose.yml` + - **GitOps updates**: Activado (opcional - auto-actualización) +5. **Solo para Traefik**: En **Additional paths**, añade: + - `docker-compose.override.traefik.yml.example` +6. En **Environment variables**, añade: + +```env +DB_PASSWORD=tu_password_generado +``` + +7. **Solo para Traefik**: Añade también `DOMAIN_HOST=bookstack.example.com` +8. Click en **Deploy the stack** + +### Opción B: Web editor + +Para personalización completa del compose. + +1. En Portainer, ve a **Stacks** → **Add stack** +2. Nombra el stack: `bookstack` +3. Selecciona **Web editor** +4. Pega el contenido de `docker-compose.yml` +5. En **Environment variables**, añade las mismas variables que la Opción A +6. Click en **Deploy the stack** + +--- + +## Modos de Despliegue + +### Traefik (Proxy Inverso con SSL automático) + +**Requisitos**: +- Stack de Traefik desplegado +- Red `proxy` creada +- DNS apuntando al servidor + +Si desplegaste con **Opción A (Git Repository)**, ya configuraste todo en el paso 5 y 7. Simplemente accede a `https://bookstack.tudominio.com` + +Si usas otra forma de despliegue: + +1. Asegúrate de tener el archivo `docker-compose.override.traefik.yml.example` como `docker-compose.override.yml` + +2. En las **Environment variables**, añade: + ```env + DOMAIN_HOST=bookstack.tudominio.com + ``` + +3. Despliega el stack y accede a `https://bookstack.tudominio.com` + +**Ejemplo de compose completo con Traefik**: + +```yaml +services: + bookstack: + container_name: bookstack + image: lscr.io/linuxserver/bookstack:latest + restart: unless-stopped + environment: + PUID: 1000 + PGID: 1000 + TZ: Europe/Madrid + APP_URL: https://${DOMAIN_HOST:-bookstack.example.com} + DB_HOST: bookstack-db + DB_PORT: 3306 + DB_DATABASE: ${DB_NAME:-bookstack} + DB_USERNAME: ${DB_USER:-bookstack} + DB_PASSWORD: ${DB_PASSWORD} + volumes: + - bookstack_config:/config + networks: + - proxy + - bookstack-internal + depends_on: + - bookstack-db + labels: + - traefik.enable=true + - traefik.http.routers.bookstack-http.rule=Host(`${DOMAIN_HOST}`) + - traefik.http.routers.bookstack-http.entrypoints=web + - traefik.http.routers.bookstack-http.middlewares=redirect-to-https + - traefik.http.routers.bookstack.rule=Host(`${DOMAIN_HOST}`) + - traefik.http.routers.bookstack.entrypoints=websecure + - traefik.http.routers.bookstack.tls=true + - traefik.http.routers.bookstack.tls.certresolver=letsencrypt + - traefik.http.routers.bookstack.service=bookstack-svc + - traefik.http.services.bookstack-svc.loadbalancer.server.port=80 + - traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https + - traefik.http.middlewares.redirect-to-https.redirectscheme.permanent=true + + bookstack-db: + container_name: bookstack-db + image: mariadb:11-alpine + restart: unless-stopped + environment: + MYSQL_DATABASE: ${DB_NAME:-bookstack} + MYSQL_USER: ${DB_USER:-bookstack} + MYSQL_PASSWORD: ${DB_PASSWORD} + MYSQL_RANDOM_ROOT_PASSWORD: 'yes' + volumes: + - bookstack_db:/var/lib/mysql + networks: + - bookstack-internal + +volumes: + bookstack_config: + name: bookstack_config + bookstack_db: + name: bookstack_db + +networks: + proxy: + external: true + bookstack-internal: + name: bookstack-internal +``` + +### Nginx Proxy Manager (NPM) + +**Requisitos**: +- NPM desplegado y accesible +- Red `proxy` creada +- DNS apuntando al servidor + +**Pasos**: + +1. Despliega el stack con el `docker-compose.yml` base (sin override) + +2. En NPM, crea un nuevo **Proxy Host**: + - **Domain Names**: `bookstack.tudominio.com` + - **Scheme**: `http` + - **Forward Hostname / IP**: `bookstack` + - **Forward Port**: `80` + - **Cache Assets**: ✅ Activado + - **Block Common Exploits**: ✅ Activado + - **Websockets Support**: ✅ Activado + +3. En la pestaña **SSL**: + - **SSL Certificate**: Request a new SSL Certificate (Let's Encrypt) + - **Force SSL**: ✅ Activado + - **HTTP/2 Support**: ✅ Activado + - **HSTS Enabled**: ✅ Activado (opcional) + +4. Guarda y accede a `https://bookstack.tudominio.com` + +--- + +## Configuración Inicial + +### Primer Acceso + +1. Accede a BookStack usando tu dominio configurado +2. Login con credenciales por defecto: + - **Email**: `admin@admin.com` + - **Password**: `password` + +3. **⚠️ CRÍTICO**: Cambia la contraseña inmediatamente: + - Click en tu avatar (esquina superior derecha) + - **Edit Profile** → **Change Password** + +### Panel de Administración + +Accede al panel: **Settings** (engranaje superior derecho) + +#### Configuración Básica + +**Settings → Settings**: +- **Application Name**: Nombre de tu wiki +- **Application Description**: Descripción breve +- **Application Logo**: Sube tu logo personalizado +- **Default Language**: Español u otro idioma + +#### Registro de Usuarios + +**Settings → Registration Settings**: +- **Allow public registration**: Desactivar (❌) +- **Allow public viewing**: Activar si quieres que usuarios no autenticados puedan leer +- **Default role for new users**: Seleccionar rol apropiado + +#### Roles y Permisos + +**Settings → Roles**: + +1. **Admin**: Control total +2. **Editor**: Puede crear y editar contenido +3. **Viewer**: Solo lectura + +Crea roles personalizados según necesites: +- **Permissions**: Granular por libros, capítulos, páginas +- **System Permissions**: Gestión de imágenes, ajustes + +#### Personalización de Tema + +**Settings → Customization**: +- **Custom HTML Head Content**: Añadir CSS personalizado +- **Color Scheme**: Claro/Oscuro +- **Custom Styles**: CSS para personalización avanzada + +--- + +## Personalización + +### Integración con LDAP + +**Settings → Authentication → LDAP**: + +```env +# Añadir al .env +LDAP_SERVER=ldap.example.com:389 +LDAP_BASE_DN=dc=example,dc=com +LDAP_DN=cn=bookstack,ou=Services,dc=example,dc=com +LDAP_PASS=password +LDAP_USER_FILTER=(&(uid=${user})) +LDAP_VERSION=3 +``` + +Reinicia el contenedor: `docker restart bookstack` + +### SAML / OAuth + +**Settings → Authentication**: +- **SAML 2.0**: Para Active Directory con ADFS +- **OAuth**: Google, GitHub, GitLab, etc. + +Consulta la [documentación oficial](https://www.bookstackapp.com/docs/admin/third-party-auth/) para configuración específica. + +### Comandos Personalizados + +Acceso al contenedor: + +```bash +# Shell de BookStack +docker exec -it bookstack bash + +# Comandos artisan disponibles +docker exec bookstack php artisan list + +# Limpiar caché +docker exec bookstack php artisan cache:clear + +# Regenerar permisos de búsqueda +docker exec bookstack php artisan bookstack:regenerate-search +``` + +--- + +## Backup y Restauración + +### Backup Manual + +```bash +# Backup de MariaDB +docker exec bookstack-db mariadb-dump -u bookstack -p${DB_PASSWORD} bookstack > bookstack-backup-$(date +%Y%m%d).sql + +# Backup de configuración y uploads +docker run --rm -v bookstack_config:/backup -v $(pwd):/target alpine tar czf /target/bookstack-config-$(date +%Y%m%d).tar.gz -C /backup . +``` + +### Backup Automático + +Crea un script en `/root/backup-bookstack.sh`: + +```bash +#!/bin/bash +BACKUP_DIR="/backups/bookstack" +DATE=$(date +%Y%m%d-%H%M%S) +DB_PASSWORD="tu_password_aqui" + +mkdir -p $BACKUP_DIR + +# MariaDB +docker exec bookstack-db mariadb-dump -u bookstack -p${DB_PASSWORD} bookstack | gzip > $BACKUP_DIR/bookstack-db-$DATE.sql.gz + +# Configuración +docker run --rm -v bookstack_config:/backup -v $BACKUP_DIR:/target alpine tar czf /target/bookstack-config-$DATE.tar.gz -C /backup . + +# Limpiar backups antiguos (mantener 7 días) +find $BACKUP_DIR -name "*.sql.gz" -mtime +7 -delete +find $BACKUP_DIR -name "*.tar.gz" -mtime +7 -delete + +echo "Backup completado: $DATE" +``` + +Programa con cron: + +```bash +chmod +x /root/backup-bookstack.sh +crontab -e + +# Backup diario a las 2 AM +0 2 * * * /root/backup-bookstack.sh +``` + +### Restauración + +```bash +# Detener BookStack +docker stop bookstack + +# Restaurar MariaDB +gunzip < bookstack-db-20250101.sql.gz | docker exec -i bookstack-db mariadb -u bookstack -p${DB_PASSWORD} bookstack + +# Restaurar configuración +docker run --rm -v bookstack_config:/restore -v $(pwd):/source alpine tar xzf /source/bookstack-config-20250101.tar.gz -C /restore + +# Iniciar BookStack +docker start bookstack +``` + +--- + +## Actualización + +### Actualizar BookStack + +```bash +# 1. Backup ANTES de actualizar +docker exec bookstack-db mariadb-dump -u bookstack -p${DB_PASSWORD} bookstack > bookstack-pre-update-$(date +%Y%m%d).sql + +# 2. Detener stack +docker stop bookstack bookstack-db + +# 3. Actualizar imágenes +docker pull lscr.io/linuxserver/bookstack:latest +docker pull mariadb:11-alpine + +# 4. Iniciar stack +docker start bookstack-db +sleep 10 +docker start bookstack + +# 5. Verificar logs +docker logs -f bookstack + +# 6. Verificar versión en Settings → About +``` + +### Actualizar MariaDB + +Si necesitas actualizar de MariaDB 10 a 11 (ya está en 11): + +```bash +# 1. Backup +docker exec bookstack-db mariadb-dump -u bookstack -p${DB_PASSWORD} bookstack > bookstack-db-migration.sql + +# 2. Detener y eliminar contenedor antiguo +docker stop bookstack-db +docker rm bookstack-db + +# 3. Eliminar volumen antiguo +docker volume rm bookstack_db + +# 4. Recrear con MariaDB 11 +docker compose up -d bookstack-db + +# 5. Esperar inicialización +sleep 15 + +# 6. Restaurar datos +cat bookstack-db-migration.sql | docker exec -i bookstack-db mariadb -u bookstack -p${DB_PASSWORD} bookstack + +# 7. Iniciar BookStack +docker start bookstack +``` + +--- + +## Solución de Problemas + +### BookStack no inicia + +**Síntomas**: Contenedor se reinicia constantemente + +**Diagnóstico**: +```bash +docker logs bookstack +``` + +**Soluciones**: +- Verificar que MariaDB esté funcionando: `docker logs bookstack-db` +- Comprobar contraseña en `.env` +- Verificar permisos del volumen: `docker exec bookstack ls -la /config` + +### Error de conexión a base de datos + +**Síntomas**: `SQLSTATE[HY000] [2002] Connection refused` + +**Solución**: +```bash +# Verificar que MariaDB esté lista +docker exec bookstack-db mariadb -u bookstack -p${DB_PASSWORD} -e "SELECT 1" + +# Reiniciar servicios en orden +docker restart bookstack-db +sleep 10 +docker restart bookstack +``` + +### Error de permisos + +**Síntomas**: `PermissionError: [Errno 13] Permission denied` + +**Solución**: +```bash +docker run --rm -v bookstack_config:/data alpine chown -R 1000:1000 /data +docker restart bookstack +``` + +### BookStack lento o no responde + +**Diagnóstico**: +```bash +# Ver uso de recursos +docker stats bookstack bookstack-db + +# Ver queries lentas en MariaDB +docker exec bookstack-db mariadb -u bookstack -p${DB_PASSWORD} -e "SHOW FULL PROCESSLIST;" +``` + +**Soluciones**: +- Limpiar caché: `docker exec bookstack php artisan cache:clear` +- Optimizar BD: `docker exec bookstack-db mariadb-optimize -u bookstack -p${DB_PASSWORD} bookstack` +- Regenerar índices de búsqueda: `docker exec bookstack php artisan bookstack:regenerate-search` + +### Comandos de emergencia + +```bash +# Reiniciar todo el stack +docker restart bookstack bookstack-db + +# Ver logs en tiempo real +docker logs -f --tail 100 bookstack + +# Acceder a shell de BookStack +docker exec -it bookstack bash + +# Ejecutar comandos artisan +docker exec bookstack php artisan tinker + +# Limpiar todo el caché +docker exec bookstack php artisan cache:clear +docker exec bookstack php artisan config:clear +docker exec bookstack php artisan view:clear +docker restart bookstack +``` + +--- + +## Variables de Entorno + +### Requeridas + +| Variable | Descripción | Ejemplo | +|----------|-------------|---------| +| `DB_PASSWORD` | Contraseña de MariaDB | `generada_con_openssl` | + +### Opcionales + +| Variable | Descripción | Valor por defecto | +|----------|-------------|-------------------| +| `DB_NAME` | Nombre de la base de datos | `bookstack` | +| `DB_USER` | Usuario de MariaDB | `bookstack` | +| `DOMAIN_HOST` | Dominio (solo Traefik) | `bookstack.example.com` | +| `PUID` / `PGID` | UID/GID del usuario | `1000` | +| `TZ` | Zona horaria | `Europe/Madrid` | + +--- + +## Recursos + +- [Documentación oficial de BookStack](https://www.bookstackapp.com/docs/) +- [LinuxServer BookStack Image](https://docs.linuxserver.io/images/docker-bookstack) +- [BookStack GitHub](https://github.com/BookStackApp/BookStack) +- [BookStack Demo](https://demo.bookstackapp.com/) +- [API Documentation](https://demo.bookstackapp.com/api/docs) + +--- + +## Licencia + +BookStack es software de código abierto bajo licencia MIT. diff --git a/docker-compose.override.traefik.yml.example b/docker-compose.override.traefik.yml.example new file mode 100644 index 0000000..d15e89d --- /dev/null +++ b/docker-compose.override.traefik.yml.example @@ -0,0 +1,22 @@ +services: + bookstack: + labels: + # Habilitar Traefik + - traefik.enable=true + + # Router HTTP (redirige a HTTPS) + - traefik.http.routers.bookstack-http.rule=Host(`${DOMAIN_HOST}`) + - traefik.http.routers.bookstack-http.entrypoints=web + - traefik.http.routers.bookstack-http.middlewares=redirect-to-https + + # Router HTTPS + - traefik.http.routers.bookstack.rule=Host(`${DOMAIN_HOST}`) + - traefik.http.routers.bookstack.entrypoints=websecure + - traefik.http.routers.bookstack.tls=true + - traefik.http.routers.bookstack.tls.certresolver=letsencrypt + - traefik.http.routers.bookstack.service=bookstack-svc + - traefik.http.services.bookstack-svc.loadbalancer.server.port=80 + + # Redirect middleware + - traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https + - traefik.http.middlewares.redirect-to-https.redirectscheme.permanent=true diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..9f4cfa2 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,48 @@ +services: + bookstack: + container_name: bookstack + image: lscr.io/linuxserver/bookstack:latest + restart: unless-stopped + environment: + PUID: 1000 + PGID: 1000 + TZ: Europe/Madrid + APP_URL: https://${DOMAIN_HOST:-bookstack.example.com} + DB_HOST: bookstack-db + DB_PORT: 3306 + DB_DATABASE: ${DB_NAME:-bookstack} + DB_USERNAME: ${DB_USER:-bookstack} + DB_PASSWORD: ${DB_PASSWORD} + volumes: + - bookstack_config:/config + networks: + - proxy + - bookstack-internal + depends_on: + - bookstack-db + + bookstack-db: + container_name: bookstack-db + image: mariadb:11-alpine + restart: unless-stopped + environment: + MYSQL_DATABASE: ${DB_NAME:-bookstack} + MYSQL_USER: ${DB_USER:-bookstack} + MYSQL_PASSWORD: ${DB_PASSWORD} + MYSQL_RANDOM_ROOT_PASSWORD: 'yes' + volumes: + - bookstack_db:/var/lib/mysql + networks: + - bookstack-internal + +volumes: + bookstack_config: + name: bookstack_config + bookstack_db: + name: bookstack_db + +networks: + proxy: + external: true + bookstack-internal: + name: bookstack-internal