70 Commits

Author SHA1 Message Date
ea1e264fd4 Merge pull request 'Certbot standalone auto-renewal' (#77) from feat-cert-auto-renewal into issue42
Reviewed-on: #77
2025-12-16 20:48:59 +00:00
a6c1bcaeff Merge branch 'master' into feat-cert-auto-renewal 2025-12-16 12:02:49 -03:00
090c397e24 Merge pull request 'Soporte para FQDN' (#76) from issue42 into master
Reviewed-on: #76
2025-12-16 15:00:07 +00:00
89866df0bf Soporte FQDN
closes #76
2025-12-16 00:45:50 -03:00
216c81df39 feat: use knsupdate only for abyayala subdomains, display DNS config for external domains
- knsupdate now only executes when is_abyayala_subdomain is true
- For external domains, display DNS configuration instructions in console
- Created dns_info.j2 template to show required DNS records for manual configuration
- External domains now show: A records, wildcard A records, and ACME challenge NS delegation

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-16 00:31:26 -03:00
a8b3a63807 se agrega expand en caso de certbot y se arregla condicion de Knsupdate (que sera solo para abyayala_subdomains).
en la amtriz testeando en prod
2025-12-16 00:30:09 -03:00
02b135f486 Merge branch 'master' into issue42 2025-12-15 19:55:15 -03:00
7e12b7b20a poner archivos de webroot 2025-12-15 19:49:25 -03:00
0a99c7f2d1 feat: implement webroot method for root domain SSL certificates
Replace dns-standalone with HTTP-01 webroot validation for root domains
(when root: yes flag is set). This change improves reliability by avoiding
DNS conflicts and simplifies the certificate obtention process.

Changes:
- Add acme_challenge.conf to serve .well-known/acme-challenge directory
- Update certbot.yml to use --webroot for root domains instead of dns-standalone
- Use official certbot/certbot:latest image for webroot (lighter, no DNS needed)
- Add certbot_webroot volume shared between nginx and certbot containers
- Configure vhost.conf to include ACME challenge location for root domains
- Add certbot_webroot variable (/var/www/certbot) to proxy vars

Benefits for root domains:
- No port 53 conflicts with Knot DNS
- Faster validation (HTTP vs DNS propagation)
- More reliable and simpler error handling
- Works with nginx already running on port 80

Wildcard domains continue using DNS-01 challenge as HTTP-01 does not
support wildcard certificates.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-15 19:48:44 -03:00
fc76a7fb91 refactor: rename no_wildcard to root and fix nginx vhost generation
Rename the flag from `no_wildcard` to `root` throughout the codebase
for better semantics, and fix nginx configuration generation for root
domains.

Changes:
1. Renamed `no_wildcard` → `root` flag in:
   - abyayala.yml (abyaya_root service)
   - roles/certbot/tasks/certbot.yml (uses is_root_domain internally)
   - README-root-domain.md (documentation)

2. Fixed nginx vhost generation in roles/proxy/templates/:
   - vhost.conf: Handle root domains without leading dot in server_name
     * root: yes → `server_name abyaya.la www.abyaya.la;` (exact match)
     * root: no  → `server_name .comun.abyaya.la;` (wildcard match)
   - stream.conf: Same logic for SSH proxy streams

Problem fixed:
- Previous: `.abyaya.la` matched all subdomains, conflicting with
  other vhosts (comun.abyaya.la, sutty.abyaya.la, etc.)
- Now: `abyaya.la www.abyaya.la` matches only root domain exactly

🤖 Generated with Claude Code

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-15 19:45:54 -03:00
7d5044f1f1 feat: add support for root domain www.abyaya.la
Add capability to route root domain (abyaya.la and www.abyaya.la)
to sutty.comun while maintaining all existing subdomain routes.

Changes:
- Add no_wildcard flag support in certbot certificate generation
- Split certificate obtention into two conditional paths:
  * Standard mode (with wildcard) for subdomains
  * No-wildcard mode for root domains
- Add abyaya_root service in matrix routing to sutty.comun
- Include implementation plan as README-root-domain.md

Technical details:
- Certificates for root domain will only include abyaya.la and
  www.abyaya.la (no *.abyaya.la wildcard)
- Prevents certificate confusion between root and subdomains
- Maintains clean separation of responsibilities
- All existing subdomain certificates remain unchanged

Generated with Claude Code
2025-12-15 19:45:20 -03:00
f1d37f21f7 tageo como instalacion esto 2025-12-15 19:45:20 -03:00
66e3c6fcaf fix: separar set_fact para compatibilidad con Ansible 2.15+
En Ansible 2.15+ las variables en el mismo set_fact se evalúan
simultáneamente, no secuencialmente. Separar needs_cert en su propio
set_fact antes de usarlo en needs_vhost y obtain_cert.
2025-12-15 19:45:20 -03:00
1fc58432dd fix: aplicar | bool en when clause de obtain_cert 2025-12-15 19:45:20 -03:00
d683f8bcd2 fix: envolver expresiones booleanas en templates Jinja2
Aplicar | bool al resultado final de cada expresión y envolver
en sintaxis {{ }} para forzar evaluación correcta como booleanos.
2025-12-15 19:45:20 -03:00
5c19e789c4 fix: forzar conversión a bool en condicionales de certbot
Ansible requiere que las condicionales resulten en booleanos.
Agregado filtro | bool para convertir explícitamente strings a booleanos
en las evaluaciones de needs_cert, needs_vhost y obtain_cert.
2025-12-15 19:45:20 -03:00
838cc5833c fix: mover limpieza de repos Docker fuera del bloque installation
La limpieza de repositorios Docker antiguos debe ejecutarse SIEMPRE,
incluso cuando se usa --skip-tags=installation, para evitar conflictos
APT antes de que knsupdate u otros roles intenten usar apt.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-15 19:45:20 -03:00
135edfe527 fix: limpiar repositorios Docker antiguos antes de configurar deb822
Soluciona conflicto APT causado por configuraciones de repositorio Docker
duplicadas con valores Signed-By contradictorios. Ahora se eliminan los
archivos de repositorio antiguos antes de agregar la configuración deb822.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-15 19:45:20 -03:00
f72983049d deabajo nodo 2025-12-15 19:45:20 -03:00
be5f8fc5e7 dns_extras en archivos con nombres de dominio principal, en
roles/knsupdate/files/dns_extras
2025-12-15 19:44:01 -03:00
acdf35e5a7 poner archivos de webroot 2025-12-15 17:06:28 -03:00
ee5513587e Merge branch 'webroot-certbot' 2025-12-15 14:26:29 -03:00
4ad59e5068 feat: implement webroot method for root domain SSL certificates
Replace dns-standalone with HTTP-01 webroot validation for root domains
(when root: yes flag is set). This change improves reliability by avoiding
DNS conflicts and simplifies the certificate obtention process.

Changes:
- Add acme_challenge.conf to serve .well-known/acme-challenge directory
- Update certbot.yml to use --webroot for root domains instead of dns-standalone
- Use official certbot/certbot:latest image for webroot (lighter, no DNS needed)
- Add certbot_webroot volume shared between nginx and certbot containers
- Configure vhost.conf to include ACME challenge location for root domains
- Add certbot_webroot variable (/var/www/certbot) to proxy vars

Benefits for root domains:
- No port 53 conflicts with Knot DNS
- Faster validation (HTTP vs DNS propagation)
- More reliable and simpler error handling
- Works with nginx already running on port 80

Wildcard domains continue using DNS-01 challenge as HTTP-01 does not
support wildcard certificates.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-15 14:03:22 -03:00
e17f872aba fix: properly handle DNS delegation for root domain and www subdomain
Updates knsupdate logic to correctly generate DNS records for:
- abyaya.la (zone apex @)
- www.abyaya.la (www subdomain)
- Existing subdomains (sutty, marmite, etc.)

This fixes the Let's Encrypt DNS-01 challenge failure for www.abyaya.la
by ensuring _acme-challenge records are created correctly.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

Merge
2025-12-15 13:47:50 -03:00
e5a756525b fix: properly handle DNS delegation for root domain and www subdomain
Updates knsupdate logic to correctly generate DNS records for:
- abyaya.la (zone apex @)
- www.abyaya.la (www subdomain)
- Existing subdomains (sutty, marmite, etc.)

This fixes the Let's Encrypt DNS-01 challenge failure for www.abyaya.la
by ensuring _acme-challenge records are created correctly.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-15 13:34:17 -03:00
c085c99382 Merge branch 'root-domain' 2025-12-15 13:17:39 -03:00
890c496b4e refactor: rename no_wildcard to root and fix nginx vhost generation
Rename the flag from `no_wildcard` to `root` throughout the codebase
for better semantics, and fix nginx configuration generation for root
domains.

Changes:
1. Renamed `no_wildcard` → `root` flag in:
   - abyayala.yml (abyaya_root service)
   - roles/certbot/tasks/certbot.yml (uses is_root_domain internally)
   - README-root-domain.md (documentation)

2. Fixed nginx vhost generation in roles/proxy/templates/:
   - vhost.conf: Handle root domains without leading dot in server_name
     * root: yes → `server_name abyaya.la www.abyaya.la;` (exact match)
     * root: no  → `server_name .comun.abyaya.la;` (wildcard match)
   - stream.conf: Same logic for SSH proxy streams

Problem fixed:
- Previous: `.abyaya.la` matched all subdomains, conflicting with
  other vhosts (comun.abyaya.la, sutty.abyaya.la, etc.)
- Now: `abyaya.la www.abyaya.la` matches only root domain exactly

🤖 Generated with Claude Code

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-15 12:15:19 -03:00
c86059e319 Merge pull request 'Custom DNS' (#78) from customdnsfiles into master
Reviewed-on: #78
2025-12-12 18:50:15 +00:00
07dfd834ca feat: add support for root domain www.abyaya.la
Add capability to route root domain (abyaya.la and www.abyaya.la)
to sutty.comun while maintaining all existing subdomain routes.

Changes:
- Add no_wildcard flag support in certbot certificate generation
- Split certificate obtention into two conditional paths:
  * Standard mode (with wildcard) for subdomains
  * No-wildcard mode for root domains
- Add abyaya_root service in matrix routing to sutty.comun
- Include implementation plan as README-root-domain.md

Technical details:
- Certificates for root domain will only include abyaya.la and
  www.abyaya.la (no *.abyaya.la wildcard)
- Prevents certificate confusion between root and subdomains
- Maintains clean separation of responsibilities
- All existing subdomain certificates remain unchanged

Generated with Claude Code
2025-12-12 15:15:22 -03:00
554c51e94c Merge branch 'master' into customdnsfiles 2025-12-12 14:26:22 -03:00
7673ccd160 tageo como instalacion esto 2025-12-12 14:25:03 -03:00
ad118402f7 fix: separar set_fact para compatibilidad con Ansible 2.15+
En Ansible 2.15+ las variables en el mismo set_fact se evalúan
simultáneamente, no secuencialmente. Separar needs_cert en su propio
set_fact antes de usarlo en needs_vhost y obtain_cert.
2025-12-12 13:42:05 -03:00
54b24af0b5 fix: aplicar | bool en when clause de obtain_cert 2025-12-12 13:34:49 -03:00
08a3e563d4 fix: envolver expresiones booleanas en templates Jinja2
Aplicar | bool al resultado final de cada expresión y envolver
en sintaxis {{ }} para forzar evaluación correcta como booleanos.
2025-12-12 12:42:50 -03:00
b31a9abcad fix: forzar conversión a bool en condicionales de certbot
Ansible requiere que las condicionales resulten en booleanos.
Agregado filtro | bool para convertir explícitamente strings a booleanos
en las evaluaciones de needs_cert, needs_vhost y obtain_cert.
2025-12-12 11:35:23 -03:00
11ec613ae9 fix: mover limpieza de repos Docker fuera del bloque installation
La limpieza de repositorios Docker antiguos debe ejecutarse SIEMPRE,
incluso cuando se usa --skip-tags=installation, para evitar conflictos
APT antes de que knsupdate u otros roles intenten usar apt.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-12 11:09:48 -03:00
3fb144d02f fix: limpiar repositorios Docker antiguos antes de configurar deb822
Soluciona conflicto APT causado por configuraciones de repositorio Docker
duplicadas con valores Signed-By contradictorios. Ahora se eliminan los
archivos de repositorio antiguos antes de agregar la configuración deb822.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-12 10:58:59 -03:00
e5dff263d1 deabajo nodo 2025-12-11 18:40:38 -06:00
f
06654b9e41 Merge branch 'master' into issue42 2025-12-06 12:09:17 -03:00
d94cfd89d0 fix: asegurar que dominio .abyaya.la esté siempre en domains[0]
Modifica la lógica para garantizar que el dominio .abyaya.la siempre
sea el primero en la lista de dominios, independientemente del orden
definido en abyayala.yml. Esto es crítico para certificados SSL y
configuraciones vhost que dependen de domains[0].
2025-12-02 19:07:38 -03:00
1a00b8a60c expand en certbot para multiples dominios variables 2025-12-02 17:44:30 -03:00
127504cb62 fix logs del certbot 2025-12-02 17:37:18 -03:00
1b69f0d13f simplifico sintaxis con include 2025-12-01 15:08:07 -03:00
5e849ecee2 Merge branch 'master' into customdnsfiles 2025-12-01 14:44:51 -03:00
a973291506 Merge pull request 'WIP fix instalacion de Abyayala toolkit' (#79) from fix_installation into master
Reviewed-on: #79
Reviewed-by: fauno <fauno@sutty.coop.ar>
Testeado por Pirra
2025-12-01 17:31:18 +00:00
43ea3c9a58 Merge branch 'master' into fix_installation 2025-12-01 14:30:01 -03:00
4bec6e7fae agregue llavero 2025-11-28 13:16:06 -06:00
f180972d15 fix: revertir proxy_ssl_name a $ssl_server_name
El uso de $host en lugar de $ssl_server_name no es correcto ya que:
- proxy_ssl_verify está deshabilitado, por lo que el SNI no importa
- $ssl_server_name es el valor correcto para SNI en proxies SSL
- $host causaba confusión innecesaria

Revierte a la configuración estándar y correcta.
2025-11-27 16:28:55 -03:00
08a9a38fa5 Merge branch 'testing' into fix_installation 2025-11-26 18:20:29 -03:00
51bd9c9935 feat: agregar configuración group_vars para host testing
- Definir host_ip: 157.180.114.62
- Requerido por rol knsupdate y certbot
2025-11-26 18:13:55 -03:00
4f18275831 Merge branch 'fix-apt-modules-deprecated' into fix_installation 2025-11-26 18:07:23 -03:00
82f6c62803 fix: actualizar prerequisitos para compatibilidad Debian 12 y 13
- Eliminar software-properties-common (no existe en Debian, solo Ubuntu)
- Eliminar apt-transport-https (incluido por defecto en Debian moderno)
- Eliminar gnupg2 (no requerido explícitamente)
- Mantener solo paquetes esenciales: ca-certificates, curl, python3-pip

Cumple con requisitos oficiales de Docker para Debian:
https://docs.docker.com/engine/install/debian/

Compatible con Debian 12 (bookworm) y 13 (trixie)
2025-11-26 18:05:47 -03:00
dcc6fe2f48 Merge branch 'fix-local-action-deprecated' into fix_installation 2025-11-26 17:59:40 -03:00
7b16934a17 Merge branch 'testing' into fix_installation 2025-11-26 17:44:55 -03:00
0e2d64d39e actualizacion de deprecaciones en instalacion 2025-11-26 17:42:40 -03:00
b750293414 Merge branch 'fix-python-modules-deprecated' into merge_fixes 2025-11-26 17:40:42 -03:00
1ab755fb10 Merge branch 'fix-apt-modules-deprecated' into merge_fixes 2025-11-26 17:40:18 -03:00
7e04c03370 Merge branch 'fix-debian-version-detection' into merge_fixes 2025-11-26 17:37:37 -03:00
cdadee266e proxy nodo llavero 2025-11-26 16:32:29 -03:00
733c9930e2 fix: reemplazar local_action deprecado con delegate_to
- Reemplazar 9 usos de local_action con delegate_to: localhost
- 7 cambios en compose.yml (stat, blockinfile, lineinfile)
- 2 cambios en main.yml (file, template)
- Agregar ansible_connection=local en hosts.production para localhost

Beneficios:
- Cumple con mejores prácticas de Ansible
- Sintaxis moderna y no deprecada
- Evita intentos de conexión SSH a localhost
- Mismo comportamiento funcional que local_action

Refs:
- https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_delegation.html
2025-11-26 16:29:00 -03:00
71e6eb9429 fix: reemplazar apt_key y apt_repository deprecados con deb822
- Reemplazar apt_key con get_url + keyrings directory
- Reemplazar apt_repository con deb822_repository (formato moderno)
- Detección automática de Debian 12 (bookworm) y 13 (trixie)
- Llave GPG específica por repositorio (más seguro)
- Requiere Ansible 2.15+

Beneficios:
- Formato DEB822 moderno y no deprecado
- Mayor seguridad con llaves por repositorio
- Compatible con Debian 12 y 13
- Cumple con mejores prácticas actuales

Refs:
- https://docs.ansible.com/ansible/latest/collections/ansible/builtin/deb822_repository_module.html
- https://manpages.debian.org/bookworm/apt/sources.list.5.en.html
2025-11-26 16:10:51 -03:00
6ed17848cd fix: eliminar módulos Python deprecados y break_system_packages
Cambios realizados:
- Instalar Docker Compose v2 via docker-compose-plugin (apt) en lugar de pip
- Especificar paquetes Docker explícitamente: docker-ce, docker-ce-cli, containerd.io, docker-compose-plugin
- Reemplazar instalación de python-docker via pip por python3-docker desde apt
- Eliminar break_system_packages que rompe aislamiento PEP 668
- Eliminar instalación obsoleta de docker-compose via pip

Beneficios:
- Cumple con PEP 668 (externally managed environments)
- Docker Compose v2 más rápido y mejor integrado
- Gestión de paquetes más limpia y mantenible
- Compatible con Debian 12 y 13

Refs:
- https://peps.python.org/pep-0668/
- https://docs.docker.com/compose/install/linux/
- https://packages.debian.org/bookworm/python3-docker
2025-11-26 15:54:08 -03:00
fd57ecd546 fix: soporte automático para Debian 12 y 13 en repositorio Docker
- Reemplaza 'bookworm' hardcodeado con detección automática usando ansible_distribution_release
- Agrega validación explícita que solo permite Debian 12 (bookworm) o 13 (trixie)
- Mensaje de error claro si se intenta usar en versión no soportada
- Comentarios actualizados indicando versiones soportadas

Esto permite que el rol funcione automáticamente en Debian 12 y 13
sin necesidad de cambios manuales en el código.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-26 15:17:46 -03:00
dfbd04480c Merge branch 'master' into cutomdnsfile 2025-11-26 14:50:46 -03:00
7cdf7bb885 ej de test net 2025-11-26 14:41:57 -03:00
ecab24c02f VPS 4 testing 2025-11-26 13:11:59 -03:00
180a7f2ab6 recorto algunos tld innecesarios
y le saco el no a ssl para otra cosa
2025-11-26 13:11:09 -03:00
f106838dc1 dns_extras en archivos con nombres de dominio principal, en
roles/knsupdate/files/dns_extras
2025-11-25 14:04:05 -03:00
a3863b9465 Merge pull request 'issue-39-default' (#72) from issue-39-default into master
Reviewed-on: #72
closes #39 o no??
2025-11-20 22:34:44 +00:00
a27a86ce6b asi seria dejar todo esto default para todos los vhosts
pero especificarlos en roles/proxy/files/custom, los sobrescribiria a estos o no?
es deseable que si
cerraria PR #65
2025-10-23 18:30:20 -03:00
27 changed files with 373 additions and 93 deletions

99
README-root-domain.md Normal file
View File

@ -0,0 +1,99 @@
# Plan: Añadir Soporte para Dominio Principal www.abyaya.la
## Objetivo
Habilitar que el dominio raíz `abyaya.la` y `www.abyaya.la` apunten al servidor `sutty.comun`, mientras se mantienen funcionando todos los subdominios existentes (ej: `sutty.abyaya.la`, `marmite.abyaya.la`).
## Estrategia de Desarrollo
### Rama Tópica
Los cambios se implementarán en esta rama tópica:
- **Nombre de rama**: `root-domain`
- **Bifurcada desde**: `master`
## Contexto Técnico
### Arquitectura Actual
- **Certificados**: Cada servicio en `abyayala.yml` con `domains` + `nodo` genera un certificado con certbot: `-d DOMAIN -d *.DOMAIN`
- **Patron actual**: Todos los dominios siguen el patrón `subdomain.abyaya.la` (ej: `sutty.abyaya.la`)
### Decisión de Diseño
Crear un **servicio separado** para el dominio raíz con un nuevo flag `root: yes` que indica a certbot que NO solicite el certificado wildcard. Esto mantiene limpia la separación de responsabilidades:
- Servicio `sutty`: maneja `sutty.abyaya.la` y `*.sutty.abyaya.la`
- Servicio `abyaya_root`: maneja únicamente `abyaya.la` y `www.abyaya.la` (sin wildcard)
## Cambios Implementados
### 1. `roles/certbot/tasks/certbot.yml`
- Lee el flag `root` del servicio y lo mapea a variable `is_root_domain`
- Dividido el bloque de certificados en dos tareas condicionales:
- Modo estándar (con wildcard): para subdominios (`when: not is_root_domain`)
- Modo sin wildcard: para dominios raíz (`when: is_root_domain`)
### 2. `roles/proxy/templates/vhost.conf`
- Agregado condicional para manejar flag `root`
- Cuando `root: yes`: genera `server_name` sin punto prefijo (exacto)
- Cuando `root: no` (default): genera `server_name .domain` (con wildcard)
### 3. `abyayala.yml`
- Agregado servicio `abyaya_root` con:
- Dominios: `abyaya.la` y `www.abyaya.la`
- Enrutamiento a: `sutty.comun`
- Flag: `root: yes`
- HTTPS forzado y compresión habilitada
## Comandos de Despliegue
### Despliegue completo
```bash
ansible-playbook deploy.yml -e "alt=abyayala host=hetzner"
```
### Despliegue solo del servicio nuevo (para testing)
```bash
ansible-playbook deploy.yml -e "alt=abyayala host=hetzner service=abyaya_root"
```
## Verificación Post-Despliegue
### 1. Verificar certificado
```bash
ssh root@hetzner
ls -la /var/lib/docker/volumes/abyayala_certs_data/_data/live/abyaya.la/
docker run --rm -v abyayala_certs_data:/etc/letsencrypt certbot/certbot certificates | grep abyaya.la
```
Debe contener: `abyaya.la`, `www.abyaya.la` (SIN `*.abyaya.la`)
### 2. Verificar nginx
```bash
cat /opt/abyayala/proxy/vhosts/abyaya.la.conf
docker exec abyayala_proxy nginx -t
```
### 3. Verificar enrutamiento
```bash
curl -I http://abyaya.la # Debe redirigir a HTTPS
curl -I https://abyaya.la # Debe devolver 200 OK
curl -I https://www.abyaya.la # Debe devolver 200 OK
```
### 4. Verificar subdominios siguen funcionando
```bash
curl -I https://sutty.abyaya.la
curl -I https://marmite.abyaya.la
```
## Requisitos DNS
Antes del despliegue, configurar:
```
abyaya.la A <IP-del-proxy>
www.abyaya.la A <IP-del-proxy>
```
## Extensibilidad Futura
Este patrón `root: yes` puede reutilizarse para otros dominios raíz:
1. Agregar entrada en `abyayala.yml` con `root: yes`
2. Desplegar con ansible-playbook
3. Configurar DNS

View File

@ -14,7 +14,6 @@ matrix:
roles:
- rap
nodos:
- llavero
- marmite
- nodochasqui
- yanapak
@ -59,6 +58,8 @@ matrix:
- carabobolibre
- samatuun
- kaasavi
- llavero
- deabajo
- service_name: respaldos
domains:
@ -165,6 +166,15 @@ matrix:
force_https: yes
enable_compression: yes
- service_name: abyaya_root
domains:
- abyaya.la
- www.abyaya.la
nodo: sutty.comun
force_https: yes
enable_compression: yes
root: yes
- service_name: mexe
domains:
- mexe.abyaya.la
@ -204,11 +214,14 @@ matrix:
- service_name: kipu
domains:
# - abyaya.la
# - www.abyaya.la
- kipu.latina.red
nodo: kipu.comun
ssl: no
ports:
- 223
ssl: yes
# root: yes
- service_name: carabobolibre
domains:
@ -227,3 +240,15 @@ matrix:
- kaasavi.abyaya.la
nodo: kaasavi.comun
force_https: yes
- service_name: llavero
domains:
- llavero.abyaya.la
nodo: llavero.comun
force_https: yes
- service_name: deabajo
domains:
- deabajo.abyaya.la
nodo: deabajo.comun
force_https: yes

1
group_vars/testing/vars Normal file
View File

@ -0,0 +1 @@
host_ip: 157.180.114.62

View File

@ -1,5 +1,5 @@
[localhost]
127.0.0.1
127.0.0.1 ansible_connection=local
[hetzner]
5.161.236.18
@ -11,3 +11,9 @@ ansible_ssh_user=root
sutty.nl
[sutty:vars]
[testing]
157.180.114.62
[testing:vars]
ansible_ssh_user=root

View File

@ -1,13 +1,13 @@
- name: check if service volumes exists
local_action:
module: stat
stat:
path: "{{ playbook_dir }}/roles/{{ item.roles[0] | default('proxy') }}/templates/volumes.yml"
delegate_to: localhost
register: volumes_def
- name: check if service networks exists
local_action:
module: stat
stat:
path: "{{ playbook_dir }}/roles/{{ item.roles[0] | default('proxy') }}/templates/networks.yml"
delegate_to: localhost
register: networks_def
- set_fact:
@ -22,53 +22,53 @@
when: networks_def.stat.exists
- name: define services in local composition
local_action:
module: blockinfile
blockinfile:
path: "{{ local_compose_path }}/docker-compose.yml"
insertafter: "services:"
marker: "# {mark} {{ service_name|upper }}"
block: "{{ services_content }}"
delegate_to: localhost
changed_when: false
- name: define volumes in local composition
local_action:
module: lineinfile
lineinfile:
path: "{{ local_compose_path }}/docker-compose.yml"
insertafter: "# volumenes compartidos"
line: "volumes: #"
state: present
regexp: "volumes: #"
delegate_to: localhost
when: volumes_def.stat.exists
changed_when: false
- name: define volumes content in local composition
local_action:
module: lineinfile
lineinfile:
path: "{{ local_compose_path }}/docker-compose.yml"
insertafter: "volumes: #"
line: "{{ volumes_content }}"
state: present
regexp: "{{ volumes_content }}"
delegate_to: localhost
when: volumes_content is defined
changed_when: false
- name: define networks in local composition
local_action:
module: lineinfile
lineinfile:
path: "{{ local_compose_path }}/docker-compose.yml"
insertafter: "# redes compartidas"
line: "networks: #"
state: present
regexp: "networks: #"
delegate_to: localhost
when: networks_def.stat.exists
changed_when: false
- name: define networks content in local composition
local_action:
module: lineinfile
lineinfile:
path: "{{ local_compose_path }}/docker-compose.yml"
insertafter: "networks: #"
line: "{{ networks_content }}"
state: present
delegate_to: localhost
when: networks_content is defined
changed_when: false

View File

@ -1,28 +1,56 @@
# DOCKER CE this is specific for Debian
# https://docs.docker.com/install/linux/docker-ce/debian/
# Soporta Debian 12 (bookworm) y Debian 13 (trixie)
# Clean up conflicting Docker repositories first (always runs, even with --skip-tags=installation)
- name: remove old docker repository files to avoid APT conflicts
file:
path: "{{ item }}"
state: absent
loop:
- /etc/apt/sources.list.d/docker.list
- /etc/apt/sources.list.d/download_docker_com_linux_debian.list
- block:
- name: "unattended upgrades"
apt:
name: "unattended-upgrades"
state: "present"
- name: required packages
apt:
name: ['apt-transport-https', 'ca-certificates', 'curl', 'gnupg2', 'software-properties-common', 'python3-pip']
name: ['ca-certificates', 'curl', 'python3-pip']
state: present
- name: docker signing key
apt_key:
- name: create keyrings directory
file:
path: /etc/apt/keyrings
state: directory
mode: '0755'
- name: download docker gpg key
get_url:
url: https://download.docker.com/linux/debian/gpg
state: present
- name: docker apt repository
apt_repository:
repo: deb [arch=amd64] https://download.docker.com/linux/debian bookworm stable
dest: /etc/apt/keyrings/docker.asc
mode: '0644'
- name: install docker community edition
- name: add docker repository with deb822 format
deb822_repository:
name: docker
types: [deb]
uris: https://download.docker.com/linux/debian
suites: ["{{ ansible_distribution_release }}"]
components: [stable]
architectures: [amd64]
signed_by: /etc/apt/keyrings/docker.asc
- name: install docker community edition and compose plugin
apt:
name: docker-ce
name:
- docker-ce
- docker-ce-cli
- containerd.io
- docker-compose-plugin
update_cache: yes
- name: is node already in swarm mode
@ -48,23 +76,11 @@
state: present
# ansible-docker requirements
- name: python package docker-py is deprecated
pip:
name: docker-py
state: absent
break_system_packages: true
- name: ensure python package docker is present
pip:
name: docker
# Use system packages instead of pip to avoid break_system_packages
- name: ensure python3-docker package is present
apt:
name: python3-docker
state: present
break_system_packages: true
- name: ensure python package docker-compose is present
pip:
name: docker-compose
state: present
break_system_packages: true
tags: installation
@ -74,16 +90,16 @@
file: path={{ compose_path }} state=directory
- name: make sure local compose path exists
local_action:
module: file
path: "{{ local_compose_path }}"
file:
path: "{{ local_compose_path }}"
state: directory
delegate_to: localhost
- name: clean docker-compose.yml
local_action:
module: template
template:
dest: "{{ local_compose_path }}/docker-compose.yml"
src: roles/althost/templates/docker-compose.yml
delegate_to: localhost
changed_when: false
- name: execute roles per domain mapping

View File

@ -10,33 +10,55 @@
register: vhost_stat
- set_fact:
needs_cert: (loop.ssl | default(domains_default_ssl) ) or (loop.force_https | default(domains_default_force_https))
needs_vhost: needs_cert and not vhost_stat.stat.exists
obtain_cert: needs_cert and not ssl_cert.stat.exists
needs_cert: "{{ ((loop.ssl | default(domains_default_ssl) | bool) or (loop.force_https | default(domains_default_force_https) | bool)) | bool }}"
- set_fact:
needs_vhost: "{{ (needs_cert | bool and not vhost_stat.stat.exists) | bool }}"
obtain_cert: "{{ (needs_cert | bool and not ssl_cert.stat.exists) | bool }}"
- name: certificate obtention
block:
- set_fact:
vhost: "{{ loop }}"
- name: fetch certificate with certbot container
- set_fact:
is_root_domain: "{{ loop.root | default(false) | bool }}"
- name: fetch certificate with certbot container (with wildcard)
docker_container:
name: chencriptemos
image: "{{ CERTBOT_image }}"
state: started
volumes:
- "{{ althost }}_certs_data:/etc/letsencrypt"
command: "--non-interactive --agree-tos --email {{ webmaster_email }} certonly --preferred-challenges dns --authenticator dns-standalone --dns-standalone-address={{ host_ip }} --dns-standalone-port=53 --dns-standalone-propagation-seconds=10 {% for domain in loop.domains %} -d {{ domain }} -d *.{{ domain }} {% endfor %}"
command: "--non-interactive --agree-tos --expand --email {{ webmaster_email }} certonly --preferred-challenges dns --authenticator dns-standalone --dns-standalone-address={{ host_ip }} --dns-standalone-port=53 --dns-standalone-propagation-seconds=10 {% for domain in loop.domains %} -d {{ domain }} -d *.{{ domain }} {% endfor %}"
detach: no
cleanup: yes
ports:
ports:
- "{{ host_ip }}:53:53/tcp"
- "{{ host_ip }}:53:53/udp"
notify:
- reload proxy
register: cert_result
when: not is_root_domain | bool
when: obtain_cert
- name: fetch certificate with certbot container (without wildcard, root domain - using webroot)
docker_container:
name: chencriptemos
image: certbot/certbot:latest
state: started
volumes:
- "{{ althost }}_certs_data:/etc/letsencrypt"
- "{{ althost }}_certbot_webroot:{{ certbot_webroot }}"
command: "--non-interactive --agree-tos --expand --email {{ webmaster_email }} certonly --webroot --webroot-path {{ certbot_webroot }} {% for domain in loop.domains %} -d {{ domain }} {% endfor %}"
detach: no
cleanup: yes
notify:
- reload proxy
register: cert_result
when: is_root_domain | bool
when: obtain_cert | bool
# RESET
- set_fact:

View File

@ -36,7 +36,7 @@
day: 4,18
hour: 0
minute: 0
job: "docker run --rm -v {{ althost }}_certs_data:/etc/letsencrypt --network host {{ CERTBOT_image }} renew --dns-standalone-address={{ host_ip }} --dns-standalone-port=53 >> /var/log/renewal.log 2>&1"
job: "docker run --rm -v {{ althost }}_certs_data:/etc/letsencrypt --network host {{ CERTBOT_image }} renew --dns-standalone-address={{ host_ip }} --dns-standalone-port=53 --log-driver=journald"
- name: proxy update, after certs renewal
cron:

View File

@ -0,0 +1,8 @@
del pilmaiken mx
del pilmaiken txt
del pilmaiken spf
add pilmaiken mx 10 correspondencia.latina.red.
add pilmaiken txt "v=spf1 mx a:correspondencia.latina.red -all"
add pilmaiken spf "v=spf1 mx a:correspondencia.latina.red -all"
add dkim._domainkey.pilmaiken txt "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDQ6JwPaawDzMXuscSgDpvipRFLGXSqgmvvI6jk18lcg0kK2lfxsvXGJ/6U7oCtKa35IEVzdigxD0o7DzklKxAsNIVbcExPJkFWzQuKuP6ATBESo7YUn7Z5qjfxBiNPS0FJp8XpbpUzN+zg/NTgmkggnwwC0tKgcEQ6HnI9AOa1LQIDAQAB"
add _dmarc.pilmaiken txt "v=DMARC1; p=reject; rua=mailto:postmaster@correspondencia.latina.red; ruf=mailto:postmaster@correspondencia.latina.red; adkim=s; aspf=s"

View File

@ -2,5 +2,6 @@
apt:
name: "knot-dnsutils"
state: "present"
tags: installation
- include_tasks: loop.yml

View File

@ -1,24 +1,31 @@
{% for dns_server in dns_servers %}
server {{ dns_server }}
zone {{ zone }}
origin {{ zone }}
ttl 60
del {{ hostname }} a
del {{ hostname }} ns
add {{ hostname }} a {{ host_ip }}
{% if is_abyayala_subdomain %}
{% if hostname != '@' and hostname != 'www' %}
add *.{{ hostname }} a {{ host_ip }}
{% else %}
add {{ domain }} a {{ host_ip }}
add *.{{ domain }} a {{ host_ip }}
{% endif %}
{% if hostname == '@' %}
add _acme-challenge a {{ host_ip }}
add _acme-challenge ns _acme-challenge
{% else %}
add _acme-challenge.{{ hostname }} a {{ host_ip }}
add _acme-challenge.{{ hostname }} ns _acme-challenge
{% if vhost.dns_extras is defined %}
{% for dns_extra in vhost.dns_extras %}
{{ dns_extra }}
{% endfor %}
{% endif %}
{% include "files/dns_extras/" ~ vhost.domains[0] ignore missing %}
send
{% endfor %}
quit

View File

@ -0,0 +1,21 @@
========================================
Configuracion de DNS requerida: {{ domain }}
========================================
Por favor configue los siguiente registros DNS en su proveedor:
{% if hostname == '@' %}
{{ zone | regex_replace('\\.$', '') }} IN A {{ host_ip }}
*.{{ zone | regex_replace('\\.$', '') }} IN A {{ host_ip }}
_acme-challenge.{{ zone | regex_replace('\\.$', '') }} IN NS ns-acme.{{ zone | regex_replace('\\.$', '') }}.
ns-acme.{{ zone | regex_replace('\\.$', '') }} IN A {{ host_ip }}
{% else %}
{{ hostname }}.{{ zone | regex_replace('\\.$', '') }} IN A {{ host_ip }}
*.{{ hostname }}.{{ zone | regex_replace('\\.$', '') }} IN A {{ host_ip }}
_acme-challenge.{{ hostname }}.{{ zone | regex_replace('\\.$', '') }} IN NS ns-acme.{{ hostname }}.{{ zone | regex_replace('\\.$', '') }}.
ns-acme.{{ hostname }}.{{ zone | regex_replace('\\.$', '') }} IN A {{ host_ip }}
{% endif %}
========================================

View File

@ -2,4 +2,4 @@
include_tasks: update_domain.yml
with_items: "{{ vhost.domains }}"
loop_control:
loop_var: domain
loop_var: domain

View File

@ -34,3 +34,9 @@
shell: knsupdate
args:
stdin: "{{ lookup('template', 'templates/commands.j2') }}"
when: is_abyayala_subdomain
- name: display DNS configuration instructions for external domains
debug:
msg: "{{ lookup('template', 'templates/dns_info.j2') }}"
when: not is_abyayala_subdomain

View File

@ -7,14 +7,6 @@ dns_servers:
compound_tlds:
- com.ar
- com.mx
- co.uk
- com.br
- gov.ar
- org.ar
- gob.ar
- net.ar
- mil.ar
- edu.ar
- co.nz
- net.nz
- org.nz
- edu.ar

View File

@ -1,11 +0,0 @@
proxy_buffering off;
proxy_request_buffering off;
proxy_redirect off;
proxy_connect_timeout 3m;
proxy_send_timeout 3m;
proxy_read_timeout 3m;
limit_conn connection_limit 50;
limit_req zone=request_limit nodelay burst=20;
add_header Retry-After $retry_after always;

View File

@ -1,4 +0,0 @@
add_header X-Frame-Options "sameorigin";
add_header X-XSS-Protection "1; mode=block";
add_header X-Content-Type-Options "nosniff";
add_header Referrer-Policy "strict-origin-when-cross-origin";

View File

@ -15,6 +15,7 @@
with_items:
- "{{ stream_path }}"
- "{{ conf_path }}"
- "{{ certbot_webroot }}"
loop_control:
loop_var: comun
@ -32,6 +33,7 @@
- common.conf
- common_ssl.conf
- nginx.conf
- acme_challenge.conf
loop_control:
loop_var: common
@ -45,13 +47,16 @@
loop_control:
loop_var: domino
- name: add default abyaya.la subdomain if not present
- name: ensure abyaya.la subdomain is always first in domains list
set_fact:
matrix_loop_with_defaults: "{{ matrix_loop_with_defaults | default([]) | union([ item_with_default ]) }}"
vars:
has_abyayala_domain: "{{ item.domains | select('match', '.*\\.abyaya\\.la$') | list | length > 0 }}"
existing_abyayala_domains: "{{ item.domains | select('match', '.*\\.abyaya\\.la$') | list }}"
has_abyayala_domain: "{{ existing_abyayala_domains | length > 0 }}"
default_domain: "{{ item.service_name }}.abyaya.la"
domains_with_default: "{{ item.domains + [default_domain] if not has_abyayala_domain else item.domains }}"
other_domains: "{{ item.domains | reject('match', '.*\\.abyaya\\.la$') | list }}"
abyayala_domain_to_use: "{{ existing_abyayala_domains[0] if has_abyayala_domain else default_domain }}"
domains_with_default: "{{ [abyayala_domain_to_use] + other_domains }}"
item_with_default: "{{ item | combine({'domains': domains_with_default}) }}"
with_items: "{{ matrix_loop | default([]) }}"

View File

@ -0,0 +1,25 @@
# Let's Encrypt ACME challenge configuration
# This configuration serves the .well-known/acme-challenge directory
# for HTTP-01 validation when using webroot method
location ^~ /.well-known/acme-challenge/ {
# Serve files from the certbot webroot
root {{ certbot_webroot }};
# Allow access to challenge files
allow all;
# Ensure plain text content type
default_type "text/plain";
# Disable any authentication
auth_basic off;
# Serve the challenge file directly
try_files $uri =404;
}
# Deny access to other .well-known paths for security
location ~ /\.well-known/ {
deny all;
}

View File

@ -0,0 +1,4 @@
add_header X-Frame-Options "sameorigin";
add_header X-XSS-Protection "1; mode=block";
add_header X-Content-Type-Options "nosniff";
add_header Referrer-Policy "strict-origin-when-cross-origin";

View File

@ -12,10 +12,12 @@
gzip_disable "msie6";
{% endif %}
client_max_body_size 1G;
proxy_ssl_verify off;
proxy_ssl_server_name on;
proxy_ssl_name $host;
proxy_ssl_name $ssl_server_name;
proxy_pass https://$comun_{{ vhost.nodo | replace(".", "") }};
@ -27,6 +29,18 @@
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection upgrade;
proxy_buffering off;
proxy_request_buffering off;
proxy_redirect off;
proxy_connect_timeout 3m;
proxy_send_timeout 3m;
proxy_read_timeout 3m;
limit_conn connection_limit 50;
limit_req zone=request_limit nodelay burst=20;
add_header Retry-After $retry_after always;
{% include "files/custom_proxy_includes/" ~ vhost.domains[0] ignore missing %}
}
# END PROXY

View File

@ -19,3 +19,4 @@
- "certs_data:{{ nginx_certs_path }}:ro"
- "{{ conf_path }}/nginx.conf:/etc/nginx/nginx.conf:ro"
- "{{ stream_path }}:/etc/nginx/stream.d/"
- "certbot_webroot:{{ certbot_webroot }}"

View File

@ -5,7 +5,11 @@ upstream ssh_{{ vhost.nodo | replace(".", "") }} {
server {
listen {{ vhost.ports[0] }};
server_name {{ vhost.service_name }}.abyaya.la;
{% if vhost.root | default(false) %}
server_name {{ vhost.domains | join(' ') }};
{% else %}
server_name .{{ vhost.domains | join(' .') }};
{% endif %}
proxy_pass ssh_{{ vhost.nodo | replace(".", "") }};
}

View File

@ -1,18 +1,31 @@
map $http_host $comun_{{ vhost.nodo | replace(".", "") }} {
hostnames;
{% for domain in vhost.domains %}
{% if vhost.root | default(false) %}
{{ domain }} {{ vhost.nodo }};
{% else %}
.{{ domain }} {{ vhost.nodo }};
{% endif %}
{% endfor %}
}
server {
{% if vhost.root | default(false) %}
server_name {{ vhost.domains | join(' ') }};
{% else %}
server_name .{{ vhost.domains | join(' .') }};
{% endif %}
listen 80;
resolver 10.13.12.1 valid=300s;
resolver_timeout 5s;
{% if vhost.root | default(false) %}
# ACME challenge for HTTP-01 validation (webroot method for root domains)
include conf/acme_challenge.conf;
{% endif %}
{% if not needs_vhost and ((vhost.ssl | default(domains_default_ssl) ) or (vhost.force_https | default(domains_default_force_https))) %}
listen 443 ssl;

View File

@ -1 +1,2 @@
certs_data:
certbot_webroot:

View File

@ -15,3 +15,4 @@ default_stream: roles/proxy/templates/stream.conf
# certbot
webmaster_email: webmaster@numerica.cl
CERTBOT_image: numericalatina/certbot-wildcard
certbot_webroot: /var/www/certbot

23
testnet.yml Normal file
View File

@ -0,0 +1,23 @@
althost: testnet
matrix:
- service_name: comun
roles:
- kemal
domains:
- comun.abyayala.red
- service_name: dns
roles:
- knsupdate
- service_name: vpn
roles:
- rap
nodos:
- qi
- service_name: qi
domains:
- qi.abyayala.red
nodo: qi.comun
# force_https: yes