diff --git a/group_vars/all.yml b/group_vars/all.yml index 7c2a2c4..265cd2f 100644 --- a/group_vars/all.yml +++ b/group_vars/all.yml @@ -1,9 +1,6 @@ --- timezone: "Europe/Madrid" -sysadmin_email: "admin@alicante.local" -global_db_root_pass: "RootSecret123" -global_db_app_pass: "AppSecret123" -global_redis_pass: "RedisSecret123" -authentik_secret: "GenerarStringLargoAleatorio123456" -authentik_pg_pass: "AuthDBSecret123" -pg_version: "16" +# Contraseñas Maestras (Se usan para configurar las DBs internas de cada stack) +global_db_pass: "RootSecret123" +global_redis_pass: "RedisSecret123" +authentik_secret: "AlicanteAuthSecret2025_ChangeMe" diff --git a/inventory b/inventory new file mode 100644 index 0000000..8403a89 --- /dev/null +++ b/inventory @@ -0,0 +1,2 @@ +[core_group] +10.10.10.104 ansible_user=root diff --git a/roles/common/tasks/main.yml b/roles/common/tasks/main.yml index f75a20e..154005d 100644 --- a/roles/common/tasks/main.yml +++ b/roles/common/tasks/main.yml @@ -3,31 +3,40 @@ apt: update_cache: yes upgrade: dist + environment: + DEBIAN_FRONTEND: noninteractive -- name: Instalar Dependencias Base +- name: Instalar Dependencias apt: name: - curl - git - htop - ufw + - ca-certificates - gnupg - - sudo - - python3-pip - - python3-psycopg2 state: present -- name: Instalar Docker - shell: curl -fsSL https://get.docker.com | sh +- name: Instalar Docker (Oficial) + shell: | + if [ ! -f /usr/bin/docker ]; then + curl -fsSL https://get.docker.com | sh + fi args: creates: /usr/bin/docker -- name: Instalar Webmin +- name: Configurar Firewall UFW shell: | - curl -o setup-repos.sh https://raw.githubusercontent.com/webmin/webmin/master/setup-repos.sh - sh setup-repos.sh --force - apt-get install webmin --install-recommends -y - args: - creates: /etc/webmin - environment: - DEBIAN_FRONTEND: noninteractive + ufw allow 22/tcp + ufw allow 10000/tcp # Webmin + ufw allow 9000/tcp # Authentik + ufw allow 9443/tcp # Authentik SSL + ufw allow 8080/tcp # Dolibarr + ufw allow 3000/tcp # Teable + ufw allow 8081/tcp # Activepieces + ufw allow 6875/tcp # Bookstack + ufw allow 3001/tcp # Metabase + ufw allow 7575/tcp # Homarr + ufw allow 5001/tcp # Dockge + ufw --force enable + ignore_errors: yes diff --git a/roles/core/tasks/main.yml b/roles/core/tasks/main.yml index b763e5b..2223c41 100644 --- a/roles/core/tasks/main.yml +++ b/roles/core/tasks/main.yml @@ -1,39 +1,17 @@ --- -- name: Crear Red Interna - community.docker.docker_network: name=alicante_net +- name: Crear directorios de Stacks + file: path=/opt/stacks/{{ item }} state=directory mode=0755 + loop: ['security', 'business', 'docs', 'management'] -- name: Crear directorios - file: path=/opt/stacks/{{ item }} state=directory - loop: ['infra-shared', 'business', 'docs', 'dashboard'] +- name: Copiar Templates Docker Compose + template: + src: "{{ item }}-compose.j2" + dest: "/opt/stacks/{{ item }}/compose.yaml" + loop: ['security', 'business', 'docs', 'management'] -- name: Desplegar Infra Shared - template: src=infra-shared-compose.j2 dest=/opt/stacks/infra-shared/compose.yaml - -- name: Levantar Infra - community.docker.docker_compose_v2: project_src=/opt/stacks/infra-shared - -- name: Esperar DB - command: docker exec postgres-core pg_isready - retries: 10 - delay: 5 - -- name: Crear Bases de Datos - community.postgresql.postgresql_db: - name: "{{ item }}" - login_host: "{{ ansible_host }}" - login_password: "{{ global_db_root_pass }}" - port: 5432 - loop: ['dolibarr', 'teable', 'activepieces', 'metabase', 'nextcloud'] - -- name: Configurar Negocio - template: src=apps-business-compose.j2 dest=/opt/stacks/business/compose.yaml - -- name: Configurar Docs - template: src=apps-docs-compose.j2 dest=/opt/stacks/docs/compose.yaml - -- name: Configurar Dashboard - template: src=dashboard-compose.j2 dest=/opt/stacks/dashboard/compose.yaml - -- name: Levantar Todo - community.docker.docker_compose_v2: project_src=/opt/stacks/{{ item }} - loop: ['business', 'docs', 'dashboard'] +- name: Levantar Stacks + community.docker.docker_compose_v2: + project_src: "/opt/stacks/{{ item }}" + state: present + pull: always + loop: ['security', 'business', 'docs', 'management'] diff --git a/roles/core/templates/apps-business-compose.j2 b/roles/core/templates/apps-business-compose.j2 deleted file mode 100644 index 54b17a6..0000000 --- a/roles/core/templates/apps-business-compose.j2 +++ /dev/null @@ -1,38 +0,0 @@ -services: - dolibarr: - image: upshift/dolibarr:latest - environment: - DOLI_DB_HOST: postgres-core - DOLI_DB_PASSWORD: {{ global_db_root_pass }} - DOLI_ADMIN_LOGIN: admin - DOLI_DB_TYPE: pgsql - networks: - - alicante_net - ports: - - "8080:80" - - teable: - image: teableio/teable:latest - environment: - PRISMA_DATABASE_URL: "postgresql://postgres:{{ global_db_root_pass }}@postgres-core:5432/teable" - REDIS_URL: "redis://:{{ global_redis_pass }}@redis-core:6379/0" - networks: - - alicante_net - ports: - - "3000:3000" - - activepieces: - image: activepieces/activepieces:latest - environment: - AP_POSTGRES_HOST: postgres-core - AP_POSTGRES_PASSWORD: {{ global_db_root_pass }} - AP_REDIS_HOST: redis-core - AP_REDIS_PASSWORD: {{ global_redis_pass }} - networks: - - alicante_net - ports: - - "8081:80" - -networks: - alicante_net: - external: true diff --git a/roles/core/templates/apps-docs-compose.j2 b/roles/core/templates/apps-docs-compose.j2 deleted file mode 100644 index b0ef939..0000000 --- a/roles/core/templates/apps-docs-compose.j2 +++ /dev/null @@ -1,35 +0,0 @@ -services: - metabase: - image: metabase/metabase:latest - environment: - MB_DB_TYPE: postgres - MB_DB_HOST: postgres-core - MB_DB_USER: postgres - MB_DB_PASS: {{ global_db_root_pass }} - MB_DB_DBNAME: metabase - networks: - - alicante_net - ports: - - "3001:3000" - - bookstack: - image: lscr.io/linuxserver/bookstack:latest - environment: - DB_HOST: mariadb-core - DB_USER: root - DB_PASS: {{ global_db_root_pass }} - networks: - - alicante_net - ports: - - "6875:80" - - gotenberg: - image: gotenberg/gotenberg:8 - networks: - - alicante_net - # Gotenberg es una API, no suele necesitar puerto expuesto si se usa internamente, - # pero lo dejamos accesible por si acaso en el 3000 interno (o mapeado si quieres) - -networks: - alicante_net: - external: true diff --git a/roles/core/templates/business-compose.j2 b/roles/core/templates/business-compose.j2 new file mode 100644 index 0000000..ae4b7e9 --- /dev/null +++ b/roles/core/templates/business-compose.j2 @@ -0,0 +1,81 @@ +services: + # DB Interna del Stack + db: + image: postgres:16-alpine + restart: always + environment: + POSTGRES_PASSWORD: {{ global_db_pass }} + POSTGRES_USER: postgres + POSTGRES_DB: postgres + volumes: + - pg_data:/var/lib/postgresql/data + healthcheck: + test: ["CMD-SHELL", "pg_isready -U postgres"] + interval: 5s + timeout: 5s + retries: 5 + + redis: + image: redis:alpine + restart: always + command: redis-server --requirepass {{ global_redis_pass }} + healthcheck: + test: ["CMD", "redis-cli", "ping"] + interval: 5s + timeout: 3s + retries: 5 + + # APPS + dolibarr: + image: upshift/dolibarr:latest + depends_on: + db: + condition: service_healthy + environment: + DOLI_DB_HOST: db + DOLI_DB_PORT: 5432 + DOLI_DB_TYPE: pgsql + DOLI_DB_USER: postgres + DOLI_DB_PASSWORD: {{ global_db_pass }} + DOLI_ADMIN_LOGIN: admin + DOLI_ADMIN_PASSWORD: admin + ports: + - "8080:80" + + teable: + image: teableio/teable:latest + depends_on: + db: + condition: service_healthy + redis: + condition: service_healthy + environment: + PRISMA_DATABASE_URL: "postgresql://postgres:{{ global_db_pass }}@db:5432/teable" + REDIS_URL: "redis://:{{ global_redis_pass }}@redis:6379/0" + PUBLIC_ORIGIN: "http://{{ ansible_host }}:3000" + SECRET_KEY: "TeableSecretKey123" + ports: + - "3000:3000" + + activepieces: + image: activepieces/activepieces:latest + depends_on: + db: + condition: service_healthy + redis: + condition: service_healthy + environment: + AP_POSTGRES_HOST: db + AP_POSTGRES_PORT: 5432 + AP_POSTGRES_DATABASE: activepieces + AP_POSTGRES_USERNAME: postgres + AP_POSTGRES_PASSWORD: {{ global_db_pass }} + AP_REDIS_HOST: redis + AP_REDIS_PORT: 6379 + AP_REDIS_PASSWORD: {{ global_redis_pass }} + AP_FRONTEND_URL: "http://{{ ansible_host }}:8081" + ports: + - "8081:80" + +volumes: + pg_data: diff --git a/roles/core/templates/docs-compose.j2 b/roles/core/templates/docs-compose.j2 new file mode 100644 index 0000000..4870e25 --- /dev/null +++ b/roles/core/templates/docs-compose.j2 @@ -0,0 +1,37 @@ +services: + mariadb: + image: lscr.io/linuxserver/mariadb:latest + restart: always + environment: + MYSQL_ROOT_PASSWORD: {{ global_db_pass }} + MYSQL_DATABASE: bookstackapp + MYSQL_USER: bookstack + MYSQL_PASSWORD: BookStackPass + volumes: + - mysql_data:/config + + bookstack: + image: lscr.io/linuxserver/bookstack:latest + depends_on: + - mariadb + environment: + APP_URL: http://{{ ansible_host }}:6875 + DB_HOST: mariadb + DB_USER: bookstack + DB_PASS: BookStackPass + DB_DATABASE: bookstackapp + ports: + - "6875:80" + + metabase: + image: metabase/metabase:latest + ports: + - "3001:3000" + + gotenberg: + image: gotenberg/gotenberg:8 + ports: + - "3002:3000" + +volumes: + mysql_data: diff --git a/roles/core/templates/infra-shared-compose.j2 b/roles/core/templates/infra-shared-compose.j2 deleted file mode 100644 index 6fea028..0000000 --- a/roles/core/templates/infra-shared-compose.j2 +++ /dev/null @@ -1,34 +0,0 @@ -services: - postgres: - image: postgres:{{ pg_version }} - container_name: postgres-core - environment: - POSTGRES_PASSWORD: {{ global_db_root_pass }} - ports: - - "5432:5432" - volumes: - - pg_data:/var/lib/postgresql/data - networks: - - alicante_net - - redis: - image: redis:alpine - container_name: redis-core - command: redis-server --requirepass {{ global_redis_pass }} - networks: - - alicante_net - - mariadb: - image: mariadb:10.6 - container_name: mariadb-core - environment: - MYSQL_ROOT_PASSWORD: {{ global_db_root_pass }} - networks: - - alicante_net - -networks: - alicante_net: - external: true - -volumes: - pg_data: diff --git a/roles/core/templates/dashboard-compose.j2 b/roles/core/templates/management-compose.j2 similarity index 76% rename from roles/core/templates/dashboard-compose.j2 rename to roles/core/templates/management-compose.j2 index 2672f1f..43938d1 100644 --- a/roles/core/templates/dashboard-compose.j2 +++ b/roles/core/templates/management-compose.j2 @@ -3,8 +3,6 @@ services: image: ghcr.io/ajnart/homarr:latest volumes: - /var/run/docker.sock:/var/run/docker.sock - networks: - - alicante_net ports: - "7575:7575" @@ -15,11 +13,5 @@ services: - /opt/stacks:/opt/stacks environment: - DOCKGE_STACKS_DIR=/opt/stacks - networks: - - alicante_net ports: - "5001:5001" - -networks: - alicante_net: - external: true diff --git a/roles/gateway/templates/authentik-compose.j2 b/roles/core/templates/security-compose.j2 similarity index 50% rename from roles/gateway/templates/authentik-compose.j2 rename to roles/core/templates/security-compose.j2 index fb9de7e..c029277 100644 --- a/roles/gateway/templates/authentik-compose.j2 +++ b/roles/core/templates/security-compose.j2 @@ -1,53 +1,58 @@ services: - postgresql: - image: docker.io/library/postgres:16-alpine - restart: unless-stopped + postgres: + image: postgres:16-alpine + restart: always environment: - POSTGRES_PASSWORD: {{ authentik_pg_pass }} + POSTGRES_PASSWORD: {{ global_db_pass }} POSTGRES_USER: authentik POSTGRES_DB: authentik volumes: - - database:/var/lib/postgresql/data + - db_data:/var/lib/postgresql/data redis: - image: docker.io/library/redis:alpine - restart: unless-stopped + image: redis:alpine + restart: always + command: redis-server --requirepass {{ global_redis_pass }} volumes: - - redis:/data + - redis_data:/data server: image: ghcr.io/goauthentik/server:2024.10 - restart: unless-stopped + restart: always command: server environment: AUTHENTIK_REDIS__HOST: redis - AUTHENTIK_POSTGRESQL__HOST: postgresql + AUTHENTIK_REDIS__PASSWORD: {{ global_redis_pass }} + AUTHENTIK_POSTGRESQL__HOST: postgres AUTHENTIK_POSTGRESQL__USER: authentik AUTHENTIK_POSTGRESQL__NAME: authentik - AUTHENTIK_POSTGRESQL__PASSWORD: {{ authentik_pg_pass }} + AUTHENTIK_POSTGRESQL__PASSWORD: {{ global_db_pass }} AUTHENTIK_SECRET_KEY: {{ authentik_secret }} + AUTHENTIK_BOOTSTRAP_TIMEOUT: 300 ports: - "9000:9000" - "9443:9443" depends_on: - - postgresql + - postgres - redis worker: image: ghcr.io/goauthentik/server:2024.10 - restart: unless-stopped + restart: always command: worker environment: AUTHENTIK_REDIS__HOST: redis - AUTHENTIK_POSTGRESQL__HOST: postgresql + AUTHENTIK_REDIS__PASSWORD: {{ global_redis_pass }} + AUTHENTIK_POSTGRESQL__HOST: postgres AUTHENTIK_POSTGRESQL__USER: authentik AUTHENTIK_POSTGRESQL__NAME: authentik - AUTHENTIK_POSTGRESQL__PASSWORD: {{ authentik_pg_pass }} + AUTHENTIK_POSTGRESQL__PASSWORD: {{ global_db_pass }} AUTHENTIK_SECRET_KEY: {{ authentik_secret }} + AUTHENTIK_BOOTSTRAP_TIMEOUT: 300 depends_on: - - postgresql + - postgres - redis volumes: - database: - redis: + db_data: + redis_data: diff --git a/roles/gateway/tasks/main.yml b/roles/gateway/tasks/main.yml deleted file mode 100644 index 64b7d0b..0000000 --- a/roles/gateway/tasks/main.yml +++ /dev/null @@ -1,18 +0,0 @@ ---- -- name: Crear directorios - file: path=/opt/stacks/{{ item }} state=directory mode=0755 - loop: ['npm', 'authentik'] - -- name: Configurar NPM - template: src=npm-compose.j2 dest=/opt/stacks/npm/compose.yaml - -- name: Configurar Authentik - template: src=authentik-compose.j2 dest=/opt/stacks/authentik/compose.yaml - vars: - authentik_host_ip: "{{ ansible_host }}" - -- name: Levantar Stacks - community.docker.docker_compose_v2: - project_src: "/opt/stacks/{{ item }}" - state: present - loop: ['npm', 'authentik'] diff --git a/roles/gateway/templates/npm-compose.j2 b/roles/gateway/templates/npm-compose.j2 deleted file mode 100644 index f9c1b03..0000000 --- a/roles/gateway/templates/npm-compose.j2 +++ /dev/null @@ -1,11 +0,0 @@ -services: - app: - image: 'jc21/nginx-proxy-manager:latest' - restart: unless-stopped - ports: - - '80:80' - - '81:81' - - '443:443' - volumes: - - ./data:/data - - ./letsencrypt:/etc/letsencrypt diff --git a/site.yml b/site.yml index bc51bda..b0c4e59 100644 --- a/site.yml +++ b/site.yml @@ -1,25 +1,7 @@ --- -- name: 1. Preparación Común - hosts: all - become: yes - roles: - - common - -- name: 2. Despliegue Core +- name: Despliegue Alicante Core V3 hosts: core_group become: yes roles: + - common - core - -- name: 3. Despliegue Gateway - hosts: gateway_group - become: yes - roles: - - gateway - - tasks: - - name: "INTEGRACIÓN: Añadir IP del Core al /etc/hosts del Gateway" - lineinfile: - path: /etc/hosts - line: "{{ hostvars[groups['core_group'][0]]['ansible_host'] }} alicante-core" - state: present