27 Commits

Author SHA1 Message Date
bb069debaf refactor: skip vhost generation for services without domains
Services with roles but without domains specified are infrastructure
services that deploy to destination servers (like knot/knsupdate,
vpn/rap). These don't need proxy vhosts. Services with roles AND
domains, or services without roles (proxy redirections) still get vhosts.

Adds skip_vhost flag during normalization to mark services that should
not generate vhosts, based on whether they have roles but no domains.

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

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-18 17:20:45 -03:00
729f931c39 refactor: improve rap_dn calculation robustness
Separates the calculation of node_name and rap_dn into intermediate
variables to make the normalization more explicit and avoid issues
with nested defaults. This makes the code clearer and more robust
when handling elements with only service_name or only nodo defined.

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

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-18 16:56:08 -03:00
45fe05844e especificar puerto e IP dinamica
TODO: otra VPN / descubrir IP con ansible
2025-12-18 16:30:00 -03:00
f6f5c90d34 fix: protect vhost.ports[0] access in stream template
Prevents error when vhost.ports is defined but empty by checking
array length before rendering the stream template that accesses ports[0].

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

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-18 16:15:26 -03:00
6d442bbaa6 fix: protect vhost.roles[0] access when array is empty
Prevents error when vhost.roles is defined but empty by checking
array length before accessing index 0 in all conditional statements.

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

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-18 16:01:46 -03:00
28c80118f7 vpn_proxy: parametrizar la IP en la VPN del Proxy 2025-12-18 15:55:53 -03:00
3467f774df fix: use service_name instead of domains[0] for stream config
Fixes error when vhost.domains is empty by using vhost.service_name
for the stream configuration filename, which is always available and
more consistent with the stream template usage.

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

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-18 14:26:36 -03:00
80ed2dea5f testnet como terminal, mientras se vuelve su propia test net 2025-12-18 14:26:13 -03:00
df8b23525e fix de orden de normalizacion, bardo del merge aun 2025-12-18 13:51:34 -03:00
5e45fed446 dns_extras ya no funciona asi 2025-12-18 13:38:08 -03:00
b201c758b7 Merge branch 'refactor-simplify-node-naming' into refactor-use-main-zone-var 2025-12-18 13:37:17 -03:00
380a588f0c refactor: remove duplicate domain normalization logic
The domain normalization logic (filtering main_zone domains, creating
default domain, and ordering) was duplicated in main.yml after already
being performed in normalize_node.yml. This removes the redundant
18-line block, keeping only the normalization in normalize_node.yml.
2025-12-18 13:05:23 -03:00
5ab33a419a Actualizo RAP y corrijo su copy 2025-12-18 13:03:33 -03:00
02bfbfc2c6 fixes: variable parametrizada, dependencia de RAP actualizada 2025-12-18 12:47:15 -03:00
fae291cdc9 corrijo estas cosas por enesima vez 2025-12-18 12:11:53 -03:00
73a562b449 refactor: replace hardcoded domain with main_zone variable
- Add main_zone_regex derived from main_zone with proper escaping
- Replace hardcoded abyaya.la references in proxy tasks
- Use main_zone and main_zone_regex for domain matching and construction
2025-12-18 12:06:38 -03:00
41b8ee5647 Merge branch 'master' into refactor-simplify-node-naming 2025-12-18 11:29:48 -03:00
0487ffde12 elimino tarea de mas 2025-12-16 17:52:18 -03:00
552911286d fix: asegurar que dominio .abyaya.la esté siempre en domains[0]
Modifica normalize_node.yml para garantizar que el dominio .abyaya.la
siempre sea el primero en la lista de dominios, independientemente del
orden definido. Esto es crítico para certificados SSL y configuraciones
vhost que dependen de domains[0].
2025-12-02 19:15:59 -03:00
8cf385b5a5 Merge branch 'customdnsfiles' into refactor-simplify-node-naming 2025-12-02 19:02:50 -03:00
5f914e071a Merge branch 'feat/parametrizar_redes' into refactor-simplify-node-naming 2025-12-02 19:01:41 -03:00
9296b21f91 Merge branch 'issue42' into refactor-simplify-node-naming 2025-12-02 19:01:01 -03:00
68ca0b5b61 fixes revision de fauno 2025-12-02 17:17:52 -03:00
f91a3360af parmetrizar los dominios de las redes: abyaya.la (proxy) y .comun (vpn)
bifurca de #issue42 en que ya estan parametrizadas zones y asi
2025-12-01 17:01:50 -03:00
76dea140c7 Merge branch 'master' into refactor-simplify-node-naming 2025-12-01 15:26:12 -03:00
ac8dd13d64 Merge branch 'master' into refactor-simplify-node-naming 2025-11-27 10:25:14 -03:00
0ee1665acb refactor: simplificar naming de nodos con auto-deducción
Cambios principales:
- Nueva variable 'nodo': nombre base (ej: marmite)
- Renombrar variable antigua 'nodo' (FQDN) -> 'rap_dn'
- Auto-deducir 'domains' desde nodo: [{{ nodo }}.abyaya.la]
- Auto-deducir 'rap_dn' desde nodo: {{ nodo }}.comun
- Extraer lógica normalización a roles/proxy/tasks/normalize_node.yml
- Agregar defaults en roles/proxy/vars/main.yml

Sintaxis nueva (simplificada):
  - nodo: marmite
    force_https: yes
    # Auto: domains: [marmite.abyaya.la], rap_dn: marmite.comun

Sintaxis FQDN externo:
  - nodo: kipu
    domains:
      - kipu.latina.red
    # Auto: rap_dn: kipu.comun

Retrocompatibilidad:
  - service_name: antigua
    domains: [antigua.abyaya.la]
    rap_dn: antigua.comun

Beneficios:
- DRY: Una sola variable define nombre
- Menos errores de tipeo
- Configuración más limpia
- Retrocompatible con service_name
2025-11-26 21:49:41 -03:00
23 changed files with 95 additions and 86 deletions

View File

@ -60,6 +60,7 @@ matrix:
- kaasavi
- llavero
- deabajo
- testnet
- service_name: respaldos
domains:
@ -67,11 +68,9 @@ matrix:
nodo: respaldos.comun
force_https: yes
- service_name: marmite
domains:
- marmite.abyaya.la
nodo: marmite.comun
- nodo: marmite
force_https: yes
# Auto-deduced: domains: [marmite.abyaya.la], rap_dn: marmite.comun
- service_name: yanapak
domains:

View File

@ -1,3 +1,6 @@
host_ip: 5.161.236.18
main_zone: abyaya.la
vpn_name: comun
vpn_proxy: 10.13.12.1
proxy_scale: 2
domains_default_force_https: yes

View File

@ -1 +1,5 @@
host_ip: 157.180.114.62
main_zone: abyayala.red
vpn_name: comun
vpn_proxy: 10.13.12.159
proxy_scale: 1

View File

@ -1,9 +1,10 @@
- set_fact:
current_service: "{{ item }}"
service_name: "{{ item.service_name }}"
# Deducir service_name: usar 'nodo' si existe, sino 'service_name' (retrocompatibilidad)
service_name: "{{ item.nodo | default(item.service_name) }}"
service_roles: "{{ item.roles | default([]) }}"
- include_role:
- include_role:
name: "{{ current_role_name }}"
with_items: "{{ service_roles }}"
loop_control:

View File

@ -44,12 +44,4 @@
day: 4,18
hour: 6
minute: 10
job: "docker service update --force {{ althost }}_proxy"
- name: mail proxy update, after certs renewal
cron:
name: mail proxy update
day: 4,18
hour: 6
minute: 20
job: "docker service update {{ althost }}_correspondencia_front"
job: "docker service update --force {{ althost }}_proxy"

View File

@ -2,12 +2,14 @@
apt:
name: dnsmasq
state: present
- name: configuracion de red comun
template:
src: dnsmasq.conf
dest: "/etc/dnsmasq.conf"
notify:
- restart dnsmasq
- name: activar el servicio
systemd_service:
name: dnsmasq

View File

@ -74,8 +74,8 @@ resolv-file=/etc/resolv.local
# Add local-only domains here, queries in these domains are answered
# from /etc/hosts or DHCP only.
local=/comun/
domain=comun
local=/{{ vpn_name }}/
domain={{ vpn_name }}
# Add domains which you want to force to an IP address here.
# The example below send any host in double-click.net to a local
@ -117,12 +117,12 @@ domain=comun
# specified interfaces (and the loopback) give the name of the
# interface (eg eth0) here.
# Repeat the line for more than one interface.
interface=comun
interface={{ vpn_name }}
# Or you can specify which interface _not_ to listen on
except-interface=eth0
# Or which to listen on by address (remember to include 127.0.0.1 if
# you use this.)
listen-address=10.13.12.1,127.0.0.1
listen-address={{ vpn_proxy }},127.0.0.1
# If you want dnsmasq to provide only DNS service on an interface,
# configure it as shown above, and then use the following line to
# disable DHCP and TFTP on it.

View File

@ -6,7 +6,7 @@
-A INPUT -m conntrack --ctstate INVALID -j DROP
-A INPUT -p icmp -m icmp --icmp-type 8 -m conntrack --ctstate NEW -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -i comun -j ACCEPT
-A INPUT -i {{ vpn_name }} -j ACCEPT
-A INPUT -p tcp -m tcp --dport 22 -j ACCEPT
-A INPUT -p udp -m udp --dport 53 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 53 -j ACCEPT

View File

@ -5,6 +5,6 @@ server {
client_max_body_size 4k;
location / {
proxy_pass http://10.13.12.1:3000;
proxy_pass http://{{ vpn_proxy }}:3000;
}
}

View File

@ -1,10 +1,10 @@
- set_fact:
is_abyayala_subdomain: "{{ domain.endswith('.abyaya.la') }}"
is_abyayala_subdomain: "{{ domain.endswith('.' ~ main_zone) }}"
- name: extract zone and hostname for abyaya.la subdomains
- name: extract zone and hostname for main zone subdomains
set_fact:
zone: "abyaya.la."
hostname: "{{ domain | regex_replace('([a-z0-9-]+)\\.abyaya\\.la', '\\1') }}"
zone: "{{ main_zone ~ '.' }}"
hostname: "{{ domain | regex_replace('([a-z0-9-]+)\\.' ~ main_zone|regex_escape , '\\1') }}"
when: is_abyayala_subdomain
- name: split domain into parts
@ -30,6 +30,11 @@
hostname: "{{ domain_parts[:-2] | join('.') if domain_parts | length > 2 else '@' }}"
when: not is_abyayala_subdomain and not uses_compound_tld
- name: Debug knsupdate for this domain
debug:
msg: "{{ lookup('template', 'templates/commands.j2') }}"
when: is_abyayala_subdomain
- name: knsupdate for this domain
shell: knsupdate
args:

View File

@ -10,14 +10,18 @@
include_role: name=certbot
tags: certbot
- name: set main_zone_regex from main_zone
set_fact:
main_zone_regex: "{{ '.' ~ main_zone | replace('.', '\\.') }}"
- name: configuration paths
file: path={{ comun }} state=directory
file: path={{ abc }} state=directory
with_items:
- "{{ stream_path }}"
- "{{ conf_path }}"
- "{{ certbot_webroot }}"
loop_control:
loop_var: comun
loop_var: abc
- name: virtual hosts path
file: path={{ vhosts_path }} state=directory
@ -37,34 +41,15 @@
loop_control:
loop_var: common
- name: domains' stuff
- name: neo stuff
block:
- name: slice matrix with those having domains defined
set_fact:
matrix_loop: "{{ matrix_loop | default([]) | union([ domino ]) }}"
with_items: "{{ matrix }}"
when: "{{ domino.domains is defined and domino.nodo is defined }}"
- name: normalize and build matrix_loop
include_tasks: normalize_node.yml
with_items: "{{ matrix }}"
when: "{{ (domino.domains is defined or domino.nodo is defined or domino.service_name is defined) }}"
loop_control:
loop_var: domino
- 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:
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"
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([]) }}"
- name: update matrix_loop with defaults
set_fact:
matrix_loop: "{{ matrix_loop_with_defaults }}"
when: matrix_loop_with_defaults is defined
- name: certificates loop
include_tasks: ../../certbot/tasks/certbot.yml
with_items: "{{ matrix_loop | default([]) }}"
@ -78,7 +63,7 @@
with_items: "{{ matrix_loop }}"
loop_control:
loop_var: vhost
when: (service is undefined) or (service is defined and service == vhost.service_name)
when: ((service is undefined) or (service is defined and service == vhost.service_name)) and not vhost.skip_vhost
- name: streams loop
include_tasks: stream.yml

View File

@ -0,0 +1,21 @@
- set_fact:
_existing_abyayala_domains: "{{ (domino.domains | default([])) | select('match', '.*' ~ main_zone_regex ~ '$') | list }}"
_other_domains: "{{ (domino.domains | default([])) | reject('match', '.*' ~ main_zone_regex ~ '$') | list }}"
_node_name: "{{ domino.nodo | default(domino.service_name) }}"
_default_domain: "{{ (domino.nodo | default(domino.service_name)) ~ '.' ~ main_zone }}"
_default_rap_dn: "{{ (domino.nodo | default(domino.service_name)) ~ '.' ~ vpn_name }}"
- set_fact:
domino_normalized:
nodo: "{{ _node_name }}"
rap_dn: "{{ domino.rap_dn | default(_default_rap_dn) }}"
domains: "{{ [(_existing_abyayala_domains[0] if (_existing_abyayala_domains | length > 0) else _default_domain)] + _other_domains }}"
force_https: "{{ domino.force_https | default(domains_default_force_https) }}"
ports: "{{ domino.ports | default([]) }}"
enable_compression: "{{ domino.enable_compression | default(domains_default_enable_compression) }}"
roles: "{{ domino.roles | default([]) }}"
service_name: "{{ domino.service_name | default(_node_name) }}"
skip_vhost: "{{ (domino.roles is defined and (domino.roles | length > 0) and domino.domains is not defined) }}"
- set_fact:
matrix_loop: "{{ matrix_loop | default([]) | union([ domino_normalized ]) }}"

View File

@ -1,10 +1,10 @@
- set_fact:
vhost_dest: "{{ stream_path }}/{{ vhost.domains[0] }}.conf"
vhost_dest: "{{ stream_path }}/{{ vhost.service_name }}.conf"
- name: default stream for ssh
template:
src: "{{ default_stream }}"
dest: "{{ vhost_dest }}"
when: vhost.ports is defined
when: vhost.ports is defined and (vhost.ports | length > 0)
notify:
- reload proxy

View File

@ -1,12 +1,12 @@
- set_fact:
vhost_dest: "{{ vhosts_path }}/{{ vhost.domains[0] }}.conf"
- block:
- block:
- set_fact:
custom_vhost: "roles/{{ vhost.roles[0] }}/templates/vhost.conf"
- set_fact:
proxy_conf: "roles/{{ vhost.roles[0] }}/templates/proxy.conf"
when: vhost.roles is defined
when: vhost.roles is defined and (vhost.roles | length > 0)
- set_fact:
proxy_conf_look: "{{ lookup('template', proxy_conf) }}"
@ -16,7 +16,7 @@
template:
src: "{{ default_vhost }}"
dest: "{{ vhost_dest }}"
when: (vhost.roles is undefined or vhost.roles[0] == 'proxy') or (custom_vhost is undefined or custom_vhost is not is_file)
when: (vhost.roles is undefined or (vhost.roles | length == 0) or vhost.roles[0] == 'proxy') or (custom_vhost is undefined or custom_vhost is not is_file)
notify:
- reload proxy
@ -24,6 +24,6 @@
template:
src: "{{ custom_vhost }}"
dest: "{{ vhost_dest }}"
when: (vhost.roles is defined and vhost.roles[0] != 'proxy') and custom_vhost is defined and custom_vhost is is_file
when: (vhost.roles is defined and (vhost.roles | length > 0) and vhost.roles[0] != 'proxy') and custom_vhost is defined and custom_vhost is is_file
notify:
- reload proxy

View File

@ -19,7 +19,7 @@
proxy_ssl_server_name on;
proxy_ssl_name $ssl_server_name;
proxy_pass https://$comun_{{ vhost.nodo | replace(".", "") }};
proxy_pass https://$comun_{{ vhost.rap_dn | replace(".", "") }};
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;

View File

@ -1,15 +1,11 @@
upstream ssh_{{ vhost.nodo | replace(".", "") }} {
server {{ vhost.nodo }}:22;
upstream ssh_{{ vhost.rap_dn | replace(".", "") }} {
server {{ vhost.rap_dn }}:22;
}
server {
listen {{ vhost.ports[0] }};
{% if vhost.root | default(false) %}
server_name {{ vhost.domains | join(' ') }};
{% else %}
server_name .{{ vhost.domains | join(' .') }};
{% endif %}
server_name {{ vhost.service_name }}.{{ main_zone }};
proxy_pass ssh_{{ vhost.nodo | replace(".", "") }};
proxy_pass ssh_{{ vhost.rap_dn | replace(".", "") }};
}

View File

@ -1,10 +1,10 @@
map $http_host $comun_{{ vhost.nodo | replace(".", "") }} {
map $http_host $comun_{{ vhost.rap_dn | replace(".", "") }} {
hostnames;
{% for domain in vhost.domains %}
{% if vhost.root | default(false) %}
{{ domain }} {{ vhost.nodo }};
{{ domain }} {{ vhost.rap_dn }};
{% else %}
.{{ domain }} {{ vhost.nodo }};
.{{ domain }} {{ vhost.rap_dn }};
{% endif %}
{% endfor %}
}
@ -18,7 +18,7 @@ server {
listen 80;
resolver 10.13.12.1 valid=300s;
resolver {{ vpn_proxy }} valid=300s;
resolver_timeout 5s;
{% if vhost.root | default(false) %}

View File

@ -1,5 +1,6 @@
domains_default_ssl: no
domains_default_force_https: no
domains_default_enable_compression: no
# nginx
vhosts_path: "{{ compose_path }}/proxy/vhosts"

View File

@ -2,7 +2,7 @@
# https://serverfault.com/questions/1108989/isc-dhcp-client-dhclient-alternative
- name: instalar dependecias de la RAP
apt:
name: ['tinc', 'rsync', 'dhcp5']
name: ['tinc', 'rsync', 'dhcpcd5']
state: latest
# update_cache: yes
tags: installation
@ -11,13 +11,13 @@
- name: copiar el codigo fuente
synchronize:
src: ../roles/rap/code/rap
src: ../roles/rap/code/rap/
dest: "{{ rap_path }}"
perms: true
- name: hacer ejecutable el archivo rap
file:
path: "{{ rap_path }}/rap/rap"
path: "{{ rap_path }}/rap"
state: touch
mode: '774'
modification_time: preserve
@ -26,13 +26,13 @@
- name: inicializar el nodo
shell:
cmd: "./rap init -i {{ nodo }}"
chdir: "{{ rap_path }}/rap"
chdir: "{{ rap_path }}"
environment:
NETWORK: comun
NETWORK: "{{ vpn_name }}"
- name: instalar el nodo
shell:
cmd: "./rap install -v {{ nodo }}"
chdir: "{{ rap_path }}/rap"
chdir: "{{ rap_path }}"
environment:
NETWORK: comun
NETWORK: "{{ vpn_name }}"

View File

@ -24,9 +24,9 @@
cmd: "./rap add-host {{ althost }} {{ nod }}"
chdir: "{{ rap_path }}"
args:
creates: "{{ rap_path }}/networks/comun/abyayala/hosts/{{ nod }}"
creates: "{{ rap_path }}/networks/{{ vpn_name }}/abyayala/hosts/{{ nod }}"
environment:
NETWORK: comun
NETWORK: "{{ vpn_name }}"
with_items: "{{ item.nodos }}"
loop_control:
loop_var: nod
@ -36,4 +36,4 @@
cmd: "./rap install -v {{ althost }}"
chdir: "{{ rap_path }}"
environment:
NETWORK: comun
NETWORK: "{{ vpn_name }}"

View File

@ -1,5 +1,6 @@
# Instalacion de la RAP en maquina local
# ansible-playbook --become tasks/rap.yml -e "host=localhost nodo=chem" -i hosts.local
# ansible-playbook tasks/rap.yml -e "host=testing nodo=testnet"
---
- hosts: "{{ host }}"
tasks:

View File

@ -16,8 +16,7 @@ matrix:
nodos:
- qi
- service_name: qi
domains:
- qi.abyayala.red
nodo: qi.comun
- nodo: qi
ports:
- 531
# force_https: yes