[{"content":"","date":"1 octubre 2026","externalUrl":null,"permalink":"/tags/ansible/","section":"Tags","summary":"","title":"Ansible","type":"tags"},{"content":"","date":"1 octubre 2026","externalUrl":null,"permalink":"/","section":"Blog Ryberxy","summary":"","title":"Blog Ryberxy","type":"page"},{"content":" 1. INTRODUCCIÓN Y ARQUITECTURA # En esta práctica levanto un clúster de Kubernetes (k3s) sin hacer nada a mano. Cada capa del despliegue la lleva una herramienta distinta:\nOpenTofu crea y destruye las VMs de forma declarativa. Ansible instala y configura el software dentro de esas VMs (k3s, NFS\u0026hellip;). Helm despliega aplicaciones dentro del clúster una vez está en marcha. El clúster tiene 4 nodos, todos ellos VMs de Multipass:\nk3s-master: el nodo master de k3s k3s-worker1 y k3s-worker2: los workers nfs-server: el servidor NFS que da almacenamiento compartido al clúster Un único Makefile encadena todo el flujo (crear VMs → generar inventario → instalar k3s → desplegar almacenamiento), así que para levantar el clúster desde cero basta con make all.\n2. REQUISITOS PREVIOS # En la máquina anfitriona hacen falta estas herramientas:\nMultipass OpenTofu Ansible Helm jq sudo apt install jq También necesitas un par de claves SSH. La pública se mete en cada VM con cloud-init, y así Ansible entra sin contraseña.\n3. OPENTOFU: CREACIÓN DE LA INFRAESTRUCTURA # OpenTofu es el fork open source de Terraform. Aquí lo uso para crear y destruir las VMs de Multipass.\n3.1 PROVIDER # opentofu/provider.tf declara el provider de Multipass:\nterraform { required_providers { multipass = { source = \u0026#34;larstobi/multipass\u0026#34; version = \u0026#34;~\u0026gt; 1.4\u0026#34; } } } 3.2 VARIABLES DE LOS NODOS # En opentofu/variables.tf el clúster entero es un mapa de objetos, con las CPUs, la memoria, el disco y el rol de cada nodo:\nvariable \u0026#34;nodes\u0026#34; { description = \u0026#34;Definición de los nodos del clúster\u0026#34; type = map(object({ cpus = number memory = string disk = string role = string })) default = { \u0026#34;k3s-master\u0026#34; = { cpus = 2, memory = \u0026#34;2G\u0026#34;, disk = \u0026#34;10G\u0026#34;, role = \u0026#34;master\u0026#34; } \u0026#34;k3s-worker1\u0026#34; = { cpus = 2, memory = \u0026#34;2G\u0026#34;, disk = \u0026#34;10G\u0026#34;, role = \u0026#34;worker1\u0026#34; } \u0026#34;k3s-worker2\u0026#34; = { cpus = 2, memory = \u0026#34;2G\u0026#34;, disk = \u0026#34;10G\u0026#34;, role = \u0026#34;worker2\u0026#34; } \u0026#34;nfs-server\u0026#34; = { cpus = 1, memory = \u0026#34;1G\u0026#34;, disk = \u0026#34;20G\u0026#34;, role = \u0026#34;nfs\u0026#34; } } } Si quiero otro nodo, añado una entrada al mapa y el resto del código se queda como está.\n3.3 CREACIÓN DE LAS INSTANCIAS # opentofu/main.tf recorre var.nodes con for_each y crea una instancia de Multipass por nodo. Cada instancia carga el cloud-init de su rol:\nresource \u0026#34;multipass_instance\u0026#34; \u0026#34;nodes\u0026#34; { for_each = var.nodes name = each.key image = \u0026#34;24.04\u0026#34; cpus = each.value.cpus memory = each.value.memory disk = each.value.disk cloudinit_file = \u0026#34;${path.module}/cloud-init/${each.value.role}/user-data.yaml\u0026#34; } 3.4 OUTPUTS # opentofu/outputs.tf saca las IPs de todos los nodos en un único mapa. Ese mapa es lo que luego lee el script que genera el inventario:\noutput \u0026#34;node_ips\u0026#34; { value = { for name, instance in multipass_instance.nodes : name =\u0026gt; instance.ipv4 } } 3.5 CLOUD-INIT # Cada rol (master, worker1, worker2, nfs) tiene su directorio en opentofu/cloud-init/ con un user-data.yaml. Se aplica al crear la VM: crea el usuario ubuntu con sudo sin contraseña y le añade la clave SSH pública para que Ansible pueda conectarse:\n#cloud-config users: - name: ubuntu sudo: ALL=(ALL) NOPASSWD:ALL groups: users, admin shell: /bin/bash ssh_authorized_keys: - ssh-ed25519 AAAAC3... tu@email.com chpasswd: expire: False users: - name: ubuntu password: ubuntu type: text Antes de lanzar nada, cambia la clave SSH de cada user-data.yaml por tu clave pública (~/.ssh/id_rsa.pub o la que uses). Si te lo saltas, Ansible no podrá conectarse a las VMs.\n4. GENERACIÓN DEL INVENTARIO # El inventario de Ansible (ansible/hosts) no lo escribo yo. Lo genera scripts/inventory.sh a partir de los outputs de OpenTofu:\n#!/bin/bash # scripts/inventory.sh ###### VARIABLES ###### # Ruta absoluta al directorio raíz del proyecto (un nivel arriba del script) PROJECT_ROOT=\u0026#34;$(cd \u0026#34;$(dirname \u0026#34;${BASH_SOURCE[0]}\u0026#34;)/..\u0026#34; \u0026amp;\u0026amp; pwd)\u0026#34; TOFU_DIR=\u0026#34;${PROJECT_ROOT}/opentofu\u0026#34; HOSTS_FILE=\u0026#34;${PROJECT_ROOT}/ansible/hosts\u0026#34; NODE_IPS=$(cd \u0026#34;$TOFU_DIR\u0026#34; \u0026amp;\u0026amp; tofu output -json node_ips | jq \u0026#39;.value // .\u0026#39;) ###### LÓGICA ###### echo \u0026#34;[node_master]\u0026#34; \u0026gt; \u0026#34;$HOSTS_FILE\u0026#34; echo \u0026#34;$NODE_IPS\u0026#34; | jq -r \u0026#39; to_entries[] | select(.key | test(\u0026#34;master\u0026#34;)) | \u0026#34;\\(.key) ansible_host=\\(.value) ansible_user=ubuntu\u0026#34; \u0026#39; \u0026gt;\u0026gt; \u0026#34;$HOSTS_FILE\u0026#34; echo \u0026#34;\u0026#34; \u0026gt;\u0026gt; \u0026#34;$HOSTS_FILE\u0026#34; echo \u0026#34;[node_workers]\u0026#34; \u0026gt;\u0026gt; \u0026#34;$HOSTS_FILE\u0026#34; echo \u0026#34;$NODE_IPS\u0026#34; | jq -r \u0026#39; to_entries[] | select(.key | test(\u0026#34;worker\u0026#34;)) | \u0026#34;\\(.key) ansible_host=\\(.value) ansible_user=ubuntu\u0026#34; \u0026#39; \u0026gt;\u0026gt; \u0026#34;$HOSTS_FILE\u0026#34; echo \u0026#34;[nfs_server]\u0026#34; \u0026gt;\u0026gt; \u0026#34;$HOSTS_FILE\u0026#34; echo \u0026#34;$NODE_IPS\u0026#34; | jq -r \u0026#39; to_entries[] | select(.key | test(\u0026#34;nfs\u0026#34;)) | \u0026#34;\\(.key) ansible_host=\\(.value) ansible_user=ubuntu\u0026#34; \u0026#39; \u0026gt;\u0026gt; \u0026#34;$HOSTS_FILE\u0026#34; cat \u0026gt;\u0026gt; \u0026#34;$HOSTS_FILE\u0026#34; \u0026lt;\u0026lt; \u0026#39;EOF\u0026#39; [k3s_cluster:children] node_master node_workers [all:children] node_master node_workers nfs_server EOF echo \u0026#34;Inventory generado:\u0026#34; cat \u0026#34;$HOSTS_FILE\u0026#34; Lo primero que hace es calcular la raíz del proyecto a partir de dónde está el propio script. Así da igual si lo lanzo desde la raíz, desde scripts/ o desde el Makefile: las rutas a opentofu/ y ansible/hosts siempre salen bien.\nCon esa ruta pide las IPs a OpenTofu con tofu output -json node_ips. El jq \u0026lsquo;.value // .\u0026rsquo; es por si la salida llega envuelta en un objeto { \u0026ldquo;value\u0026rdquo;: \u0026hellip; }, como pasa con tofu output -json sin nombre de output. En ese caso se queda con value y, si no, deja el JSON tal cual.\nDespués escribe el fichero grupo a grupo. Pone la cabecera ([node_master], [node_workers], [nfs_server]) y filtra el mapa de IPs con jq. to_entries[] convierte el mapa en pares clave/valor, select(.key | test(\u0026ldquo;worker\u0026rdquo;)) se queda con los nodos cuyo nombre contiene esa palabra y la última línea monta cada entrada con el formato que espera Ansible. El primer echo usa \u0026gt; y vacía el fichero, los demás añaden con \u0026raquo;, así que cada ejecución empieza de cero y no se acumulan nodos viejos.\nComo el filtro va por nombre, si añado un k3s-worker3 al mapa de OpenTofu, el script lo mete en [node_workers] sin cambiar nada.\nLos grupos de grupos (k3s_cluster y all) no dependen de ninguna IP, así que van fijos en un heredoc al final. Por último, el script imprime el inventario para que se vea qué ha generado.\nSe lanza así (el Makefile lo hace por mí en make up):\nbash scripts/inventory.sh El inventario queda así:\n[node_master] k3s-master ansible_host=10.x.x.x ansible_user=ubuntu [node_workers] k3s-worker1 ansible_host=10.x.x.x ansible_user=ubuntu k3s-worker2 ansible_host=10.x.x.x ansible_user=ubuntu [nfs_server] nfs-server ansible_host=10.x.x.x ansible_user=ubuntu [k3s_cluster:children] node_master node_workers [all:children] node_master node_workers nfs_server Como solo depende de los outputs de OpenTofu, si destruyo las VMs y las vuelvo a crear con otras IPs, el inventario se regenera solo.\n5. ANSIBLE: CONFIGURACIÓN DEL SOFTWARE # Con las VMs creadas y el inventario listo, le toca a Ansible instalar y configurar el software dentro de ellas.\n5.1 ANSIBLE.CFG # La configuración global está en ansible/ansible.cfg:\n[defaults] inventory = hosts remote_user = ubuntu host_key_checking = False private_key_file = ~/.ssh/id_rsa Si tu clave privada está en otra ruta (una ed25519, por ejemplo), cambia private_key_file:\nprivate_key_file = ~/.ssh/id_ed25519 5.2 PLAYBOOK PRINCIPAL # ansible/site.yaml lanza cada rol sobre su grupo de hosts:\n- hosts: k3s_cluster # todos los nodos k3s roles: [commons] - hosts: nfs_server # solo el servidor NFS roles: [nfs_server] - hosts: node_master # solo el master roles: [k3s_master] - hosts: node_workers # solo los workers roles: [k3s_worker] 5.3 ROL COMMONS # Va a todos los nodos del clúster k3s y lo único que hace es actualizar el sistema:\n- name: Actualizar el sistema y los paquetes apt: update_cache: yes upgrade: yes cache_valid_time: 3600 5.4 ROL NODES # Instala nfs-common en los nodos del clúster. Sin ese paquete no podrían montar volúmenes NFS:\n- name: Instalar nfs apt: name: [nfs-common] state: present 5.5 ROL NFS_SERVER # Convierte la VM nfs-server en el servidor NFS: instala el paquete, crea el directorio compartido y lo exporta a la subred del clúster.\n- name: Instalar nfs-kernel-server apt: name: nfs-kernel-server state: present - name: Crear directorio compartido file: path: /srv/nfs/data state: directory mode: \u0026#39;0777\u0026#39; - name: Configurar exports lineinfile: path: /etc/exports line: \u0026#34;/srv/nfs/data 10.147.215.0/24(rw,sync,no_subtree_check,no_root_squash)\u0026#34; create: yes - name: Aplicar exports y arrancar NFS shell: exportfs -ra notify: restart nfs - name: Asegurar que nfs-server está activo systemd: name: nfs-server enabled: true state: started El handler restart nfs reinicia el servicio cada vez que cambia /etc/exports:\n- name: restart nfs service: name=nfs-server state=restarted 5.6 ROL K3S_MASTER # Instala k3s en modo servidor en el master con el script oficial. Después espera a que aparezca el node-token, lo lee y lo guarda como fact global, que es de donde lo sacarán los workers. Al final se trae el kubeconfig a la máquina local y cambia 127.0.0.1 por la IP real del master:\n- name: Instalar k3s como servidor shell: | curl -sfL https://get.k3s.io | sh -s - server \\ --write-kubeconfig-mode 644 args: creates: /usr/local/bin/k3s - name: Esperar a que k3s esté listo wait_for: path: /var/lib/rancher/k3s/server/node-token timeout: 60 - name: Leer node-token slurp: src: /var/lib/rancher/k3s/server/node-token register: k3s_token - name: Guardar token como fact global set_fact: k3s_token: \u0026#34;{{ k3s_token.content | b64decode | trim }}\u0026#34; k3s_master_ip: \u0026#34;{{ ansible_host }}\u0026#34; delegate_to: localhost delegate_facts: true - name: Leer kubeconfig slurp: src: /etc/rancher/k3s/k3s.yaml register: kubeconfig_raw - name: Guardar kubeconfig en local copy: content: \u0026#34;{{ kubeconfig_raw.content | b64decode | replace(\u0026#39;127.0.0.1\u0026#39;, ansible_host) }}\u0026#34; dest: \u0026#34;~/.kube/kubeconfig-k3s\u0026#34; mode: \u0026#39;0600\u0026#39; delegate_to: localhost become: false El creates: /usr/local/bin/k3s hace que la instalación sea idempotente: si el binario ya existe, Ansible se salta la tarea.\n5.7 ROL K3S_WORKER # Cada worker coge el token y la IP del master de hostvars[\u0026rsquo;localhost\u0026rsquo;], donde los dejó el rol anterior, e instala k3s en modo agente contra ese master:\n- name: Instalar k3s como agente shell: | curl -sfL https://get.k3s.io | K3S_URL=https://{{ hostvars[\u0026#39;localhost\u0026#39;][\u0026#39;k3s_master_ip\u0026#39;] }}:6443 \\ K3S_TOKEN={{ hostvars[\u0026#39;localhost\u0026#39;][\u0026#39;k3s_token\u0026#39;] }} sh - args: creates: /usr/local/bin/k3s Así no copio el token a mano en ningún momento. Pasa de un rol a otro en los facts de Ansible.\n6. HELM: NFS PROVISIONER # Con k3s funcionando y el servidor NFS levantado, falta desplegar un NFS provisioner dentro del clúster. El provisioner crea PersistentVolumes dinámicos sobre el servidor NFS, así que un pod puede pedir almacenamiento esté en el nodo que esté.\nhelm/nfs-provisioner/values.yaml:\nnfs: path: /srv/nfs/data storageClass: name: nfs-csi La IP del servidor NFS no aparece en este fichero. El Makefile la saca del ansible/hosts generado antes y se la pasa a Helm con \u0026ndash;set nfs.server=.\nTras el despliegue, el clúster tiene una StorageClass llamada nfs-csi que puede usar cualquier PersistentVolumeClaim.\n7. MAKEFILE: AUTOMATIZACIÓN COMPLETA # Todo lo anterior se lanza desde un único Makefile:\nall: up configure nfs up: tofu-init tofu-apply inventory tofu-init: @if [ ! -d \u0026#34;$(TOFU_DIR)/.terraform\u0026#34; ]; then \\ cd $(TOFU_DIR) \u0026amp;\u0026amp; tofu init; \\ fi tofu-apply: @cd $(TOFU_DIR) \u0026amp;\u0026amp; tofu apply -auto-approve inventory: @bash scripts/inventory.sh configure: @cd $(ANSIBLE_DIR) \u0026amp;\u0026amp; ansible-playbook site.yaml nfs: @KUBECONFIG=$(KUBECONFIG) helm repo add nfs-subdir-external-provisioner \\ https://kubernetes-sigs.github.io/nfs-subdir-external-provisioner/ 2\u0026gt;/dev/null || true @NFS_IP=$$(grep \u0026#39;nfs-server\u0026#39; $(ANSIBLE_DIR)/hosts | awk \u0026#39;{print $$2}\u0026#39; | cut -d\u0026#39;=\u0026#39; -f2 | cut -d\u0026#39; \u0026#39; -f1); \\ KUBECONFIG=$(KUBECONFIG) helm upgrade --install nfs-subdir-external-provisioner \\ nfs-subdir-external-provisioner/nfs-subdir-external-provisioner \\ --values $(HELM_DIR)/nfs-provisioner/values.yaml \\ --set nfs.server=$$NFS_IP \\ --namespace nfs-provisioner \\ --create-namespace destroy: @cd $(TOFU_DIR) \u0026amp;\u0026amp; tofu destroy -auto-approve @rm -f $(ANSIBLE_DIR)/hosts @rm -f $(KUBECONFIG) Estos son los comandos:\nmake all # ejecuta up + configure + nfs make up # crea las VMs y genera el inventario make configure # instala k3s y nfs-server con Ansible make nfs # despliega el NFS provisioner con Helm make destroy # destruye todas las VMs y limpia los ficheros generados Puedo ejecutar make all las veces que quiera sin romper nada. tofu init solo corre si no existe .terraform/, tofu apply no hace nada si las VMs ya están creadas y no ha cambiado nada, los playbooks de Ansible comprueban el estado antes de actuar y helm upgrade \u0026ndash;install solo actualiza cuando hay cambios.\n8. PUESTA EN MARCHA # Para levantar el clúster desde cero:\n# 1. Clonar el repo git clone https://github.com/ryberxy/cluster-k3s cd cluster-k3s # 2. Añadir la clave SSH pública en cada cloud-init # editar opentofu/cloud-init/*/user-data.yaml # 3. Lanzar todo make all # 4. Exportar el kubeconfig export KUBECONFIG=~/.kube/kubeconfig-k3s # 5. Verificar el clúster kubectl get nodes 9. MIGRACIÓN A UN SERVIDOR DEDICADO # Como la infraestructura (OpenTofu) y la configuración (Ansible) van por separado, llevar el proyecto a un proveedor real como Hetzner no obliga a rehacer Ansible ni el Makefile:\nCambiar el provider de opentofu/provider.tf por el de Hetzner Adaptar opentofu/main.tf para crear servidores de Hetzner Cloud en lugar de instancias de Multipass Los playbooks y el Makefile se quedan igual, porque solo dependen del inventario generado En un entorno real tendría más sentido un almacenamiento distribuido como Longhorn que el NFS provisioner ","date":"1 octubre 2026","externalUrl":null,"permalink":"/posts/iac/cluster-k3s/","section":"Posts","summary":"","title":"Despliegue de un clúster K3s con OpenTofu y Ansible","type":"posts"},{"content":"","date":"1 octubre 2026","externalUrl":null,"permalink":"/tags/helm/","section":"Tags","summary":"","title":"Helm","type":"tags"},{"content":"","date":"1 octubre 2026","externalUrl":null,"permalink":"/posts/iac/","section":"Posts","summary":"","title":"IAC","type":"posts"},{"content":"","date":"1 octubre 2026","externalUrl":null,"permalink":"/tags/k3s/","section":"Tags","summary":"","title":"K3s","type":"tags"},{"content":"","date":"1 octubre 2026","externalUrl":null,"permalink":"/tags/kubernetes/","section":"Tags","summary":"","title":"Kubernetes","type":"tags"},{"content":"","date":"1 octubre 2026","externalUrl":null,"permalink":"/tags/makefile/","section":"Tags","summary":"","title":"Makefile","type":"tags"},{"content":"","date":"1 octubre 2026","externalUrl":null,"permalink":"/tags/nfs/","section":"Tags","summary":"","title":"NFS","type":"tags"},{"content":"","date":"1 octubre 2026","externalUrl":null,"permalink":"/tags/opentofu/","section":"Tags","summary":"","title":"OpenTofu","type":"tags"},{"content":"","date":"1 octubre 2026","externalUrl":null,"permalink":"/posts/","section":"Posts","summary":"","title":"Posts","type":"posts"},{"content":"","date":"1 octubre 2026","externalUrl":null,"permalink":"/tags/","section":"Tags","summary":"","title":"Tags","type":"tags"},{"content":"","date":"30 septiembre 2026","externalUrl":null,"permalink":"/tags/aso/","section":"Tags","summary":"","title":"ASO","type":"tags"},{"content":" 1. Introducción # En esta práctica vamos a instalar el kernel 6.18.4 para debian 13, primero lo buscaré en los repositorios configurados en mi sistema:\nEncontramos la versión 6.12.48, que bueno no es la que queremos pero está ahí, podemos descargarla. Yo voy a buscar en la página oficial de kernel: https://kernel.org/, aquí seleccionamos la línea estable que en este caso es la 6.18.4\n2. Descargar Dependencias Y Kernel # Instalar dependencias:\napt install build-essential libncurses-dev bison flex libssl-dev libelf-dev bc xz-utils fakeroot debhelper libdw-dev locales rsync Archivo que contiene el kernel 6.18.4:\nwget https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-6.18.4.tar.xz 3. Target Y Compilación # En primer lugar vamos a ver cuantas línea tiene nuestro fichero config actual:\nPara tener un fichero config más liviano, con la configuración mínima que usamos actualmente, es decir solo los módulos que necesitamos, ejecutamos el siguiente comando:\nmake localmodconfig Al haber lanzado kernel y darnos error, si queremos volver a compilar tenemos que limpiar:\nmake clean o make mr propper mas agresivo\nConfiguración con el config de un kernel antiguo:\nmake oldconfig Es una configuración con mucho más contenido por lo que va a tardar más, ya que utiliza el config completo del kernel más reciente en el sistema.\nTambién podemos personalizar nuestro kernel de modo que seleccionemos que módulos queremos que estén disponibles o cuales no:\nmake xconfig Finalmente nuestro config tiene los siguientes módulos en estático y dinámico::\nCompilación del kernel:\nmake -j$(proc) bindeb-pkg Instalar los paquetes .deb generados:\nsudo dpkg -i *.deb Comprobación de que el kernel se ha instalado\n4. Kernel Firmado # Lo que queremos hacer es firmar la nueva compilación del kernel de modo que nuestro sistema pueda confiar en ella.\nSecurity boot:\nsudo mokutill --sb-state Para ver que claves están usándose en mi sistema:\nsudo mokutil --list-enrolled Construimos el siguiente directorio:\nsudo mkdir -p /var/lib/shim-signed/mok cd /var/lib/shim-signed/mok A continuación genero la clave privada y certificado, pero el certificado por alguna razón no me deja convertirlo a .pem:\nsudo openssl req -new -newkey rsa:2048 -keyout MOK.priv -outform DER -out MOK.der -days 36500 -subj \u0026#34;/CN=Robemr\u0026#34; Entonces genero otro certificado autofirmado por la clave privada generada en la anterior instrucción:\nsudo openssl req -new -x509 -sha256 -key MOK.priv -out MOK.pem -days 36500 -subj \u0026#34;/CN=Robemr/\u0026#34; Ahora generamos el binario .der con el que trabajara el sistema, a partir del certificado en formato pem:\nsudo openssl x509 -in MOK.pem -outform DER -out MOK.der Importaremos el certificado en formato binario(.der) para que lo entienda el sistema y nos pedirá una contraseña de un solo uso, no tiene nada que ver con la frase de paso de la clave privada:\nsudo mokutil --import MOK.der Posteriormente reiniciaré para activar la clave:\nSeleccionamos Enroll MOK\nAquí vemos la firma realizada:\nPosterior a cargar la clave, reiniciamos:\nPara comprobar si la clave se ha activado y ya tenemos el kernel firmado podemos ejecutar lo siguiente:\nroot@pcrobe:/var/lib/shim-signed/mok# mokutil --test-key MOK.der MOK.der is already enrolled Listar las claves cargadas en nuestro sistema:\nsudo mokutil --list-enrolled Finalmente, lo que he aprendido con la práctica es que debemos tener activado el secure boot y para hacer las cosas lo mejor posible, no tendríamos que desactivarlo en ningún momento, de este modo habría que firmar el kernel para que el sistema confíe en él.\n","date":"30 septiembre 2026","externalUrl":null,"permalink":"/posts/sistemas/compilacion-kernel/","section":"Posts","summary":"","title":"Compilación de kernel Linux ","type":"posts"},{"content":"","date":"30 septiembre 2026","externalUrl":null,"permalink":"/tags/iso/","section":"Tags","summary":"","title":"ISO","type":"tags"},{"content":"","date":"30 septiembre 2026","externalUrl":null,"permalink":"/tags/linux/","section":"Tags","summary":"","title":"Linux","type":"tags"},{"content":"","date":"30 septiembre 2026","externalUrl":null,"permalink":"/posts/sistemas/","section":"Posts","summary":"","title":"Sistemas","type":"posts"},{"content":"","date":"29 septiembre 2026","externalUrl":null,"permalink":"/posts/base-de-datos/","section":"Posts","summary":"","title":"Base de datos","type":"posts"},{"content":"","date":"29 septiembre 2026","externalUrl":null,"permalink":"/tags/debian/","section":"Tags","summary":"","title":"Debian","type":"tags"},{"content":" 1. INTERCONEXIÓN ORACLE → ORACLE # El enlace solo puede ser de un servidor al otro, por lo que no es bidireccional, habrá que crear un enlace en cada servidor que apunte al otro servidor.\nPor ejemplo, si queremos hacer un enlace de base de datos desde el Servidor 1 al Servidor 2, necesitaremos un usuario en el servidor 1 que tenga permisos para crear enlaces de base de datos y un usuario en el servidor 2 que será con el que nos autentificaremos desde el servidor 1.\n1.1 CREACIÓN DE USUARIOS: # Servidor 1:\nCREATE USER robe IDENTIFIED BY robe; GRANT CONNECT, RESOURCE TO robe; GRANT CREATE DATABASE LINK to robe; Servidor 2:\nCREATE USER replica IDENTIFIED BY replica; GRANT CONNECT, RESOURCE TO replica; GRANT CREATE DATABASE LINK TO replica; 1.2 CONFIGURACIÓN DE LISTENER.ORA Y TNSNAMES.ORA # A continuación vamos a configurar estos ficheros para poder conectarnos de un servidor a otro, ya que en el momento que un servidor actúa como cliente de otro necesita un tnsnames.ora.\nORACLE 1:\nVamos a utilizar la resolución de nombres para establecer la conexión de un servidor a otro, para ello añadiremos la siguiente línea en el /etc/hosts:\n192.168.122.250 oracle2 Donde \u0026ldquo;192.168.122.250\u0026rdquo; es la ip del servidor Oracle 2.\ntnsnames.ora:\nlistener.ora:\nEstamos permitiendo conexiones en todas direcciones, pero porque estamos en un entorno de prueba, no deberíamos de hacer esto en un entorno real.\nORACLE 2:\n/etc/hosts:\n192.168.122.79 oracle1 tnsnames.ora:\nlistener.ora:\n1.3 CREACIÓN DE ENLACE DE ORACLE 1 A ORACLE 2 # Con el usuario que configuramos en Oracle 1, crearemos el enlace de base de datos a Oracle 2:\nAhora comprobamos que podamos obtener datos de una tabla del servidor enlazado:\n1.4 COMPROBACION CON TRIGGER # A continuación voy a crear un trigger que mantenga en Oracle 2 la tabla Practicas actualizada cada vez que haya un insert en Oracle 1, esto es opcional, no es necesario para que funcionen los enlaces de bases de datos.\nCREATE OR REPLACE TRIGGER trg_replica_practicas_insert AFTER INSERT ON practicas FOR EACH ROW BEGIN INSERT INTO practicas@REPLICA_LINK(dnialumno, cifempresa, fechainicio, numhoras) VALUES (:NEW.dnialumno, :NEW.cifempresa, :NEW.fechainicio, :NEW.numhoras); END; / 1.5 CREACIÓN DE ENLACE DE ORACLE 2 A ORACLE 1 # Con el usuario replica crearemos el siguiente enlace de base de datos.\nHaremos una consulta a la tabla alumnos de Oracle 1 para comprobar el funcionamiento del enlace creado.\n1.6 CONSULTAS COMBINADAS ENTRE ENLACES # Ejecutaré una consulta que obtendrá datos de la misma tabla de ambos servidores:\nselect nombre from empresas where cif IN (SELECT cif FROM empresas@ORACLE1_DBLINK WHERE sector = \u0026#39;Informatica\u0026#39;) 2. INTERCONEXIÓN POSTGRES → POSTGRES # Vamos a instalar dos servidores postgres en dos máquinas distintas y crearemos un enlace para poder recoger datos de diferentes tablas en distintos servidores de forma remota.\n2.1 CONFIGURACIÓN DE POSTGRES # Lo primero es que cada servidor postgres escuche en la dirección del otro o en un rango que abarque su dirección. Para ello voy a modificar un par de ficheros:\n/etc/postgresql/17/main:\n/etc/postgresql/17/main/ph_hba_conf:\nVamos a crear un usuario en cada base de datos , una base de datos y activaremos la extensión dblink, que trae un módulo que nos permite conectarnos a la otra base de datos:\n2.2 CONEXIÓN POSTGRES 1 A POSTGRES 2 # Dentro de la base de datos scott1, que es desde donde vamos a hacer el enlace de base de datos, habilitaremos la extensión dblink:\n2.3 CONEXIÓN POSTGRES 2 A POSTGRES 1 # Dentro de la base de datos scott2 habilitaremos la extensión dblink:\n2.4 CONSULTAS COMBINADAS # Para que la sintaxis funcione, cuando indiquemos el nombre del campo y el tipo de dato tiene que ir en el mismo orden que la select.\n3. INTERCONEXIÓN POSTGRES → ORACLE # 3.1 INSTALAR DEPENDENCIAS # En la máquina con postgres instalaremos los siguientes paquetes:\nsudo wget https://download.oracle.com/otn_software/linux/instantclient/2326000/instantclient-sdk-linux.x64-21.12.0.0.0.zip -O instantclient-sdk-23.26 https://download.oracle.com/otn_software/linux/instantclient/2112000/el9/instantclient-basic-linux.x64-21.12.0.0.0dbru.el9.zip -O instantclient-basic-23.26 https://download.oracle.com/otn_software/linux/instantclient/2112000/el9/instantclient-sqlplus-linux.x64-21.12.0.0.0dbru.el9.zip -O instantclient-sqlplus-23.26 Descomprimir:\nsudo unzip instantclient-sdk-23.26 sudo unzip instantclient-basic-23.26 sudo unzip instantclient-sqlplus-23.26 Dependencias del sistema linux:\nsudo apt install libaio1t64 postgresql-server-dev-all build-essential git zip -y Variables de entorno de oracle:\necho \u0026#34;export ORACLE_HOME=/opt/oracle/instantclient_21_12\u0026#34; \u0026gt;\u0026gt; .bashrc echo \u0026#34;export PATH=$ORACLE_HOME:$PATH\u0026#34; \u0026gt;\u0026gt; .bashrc echo \u0026#34;export LD_LIBRARY_PATH=$ORACLE_HOME:$LD_LIBRARY_PATH\u0026#34; \u0026gt;\u0026gt; .bashrc Para acceder a la base de datos lo hacemos con la siguiente instrucción:\nsqlplus robe/robe@//192.168.122.79:1521/ORCLCDB Ahora tenemos que descargar oracle fdw, para ello tenemos que compilarlo de un repositorio de github:\ngit clone https://github.com/laurenz/oracle_fdw.git cd oracle_fdw make sudo make install 3.2 SOLUCIÓN DE ERROR DE LIBERÍAS # Ahora tenemos que entrar en postgres a la base de datos scott1 y crear la extension de oracle_fdw:\nscott1=# CREATE EXTENSION oracle_fdw; ERROR: no se pudo cargar la biblioteca «/usr/lib/postgresql/17/lib/oracle_fdw.so»: libclntsh.so.21.1: no se puede abrir el fichero del objeto compartido: No existe el fichero o el directorio Puede dar ese problema, es porque el .bashrc afecta a la sesión actual, en momento que entremos a postgres con una bash o shell con distinto pid a la que está utilizando el usuario que carga el .bashrc, entonces nos surgirá este error porque postgres no está leyendo las variables de entorno, esto ocurre porque postgres es un demonio en segundo plano.\nLa solución es la siguiente:\necho \u0026#34;/opt/oracle/instantclient_21_12\u0026#34; | sudo tee /etc/ld.so.conf.d/oracle-instantclient.conf sudo ldconfig De esta forma registramos los directorios de instantclient en el sistema global y volvemos a cargar las librerías para que postgres las detecte.\n3.3 CONFIGURACIÓN DEL ENLACE # Procedemos a cargar la extensión de oracle_fdw de nuevo:\nCREATE EXTENSION oracle_fdw; Creamos el esquema oracle :\nCREATE SCHEMA oracle; Creamos un servidor foráneo que hace referencia a la base de datos del servicio de ORACLE que hay en la otra máquina:\ncreate server oracle foreign data wrapper oracle_fdw options (dbserver \u0026#39;//192.168.122.79/ORCLCDB\u0026#39;); Vamos a mapear el usuario local de postgres y el del servidor de oracle, con el de oracle nos identificamos con contraseña:\ncreate user mapping for robe server oracle options (user \u0026#39;robe\u0026#39;, password \u0026#39;robe\u0026#39;); Por último le damos a privilegios al usuario que hemos creado en postgres sobre el esquema oracle y el servidor foráneo.\ngrant all privileges on schema oracle to robe; grant all privileges on foreign server oracle to robe; import foreign schema \u0026#34;RAUL\u0026#34; from server oracle_prueba into raul; Ahora accedemos con el usuario robe a la base de datos scott1 y comprobamos que pueda consultar tablas de oracle:\n4. INTERCONEXIÓN ORACLE → POSTGRES # 4.1 INSTALACIÓN Y CONFIGURACIÓN DEL DRIVER ODBC # En la máquina oracle que será cliente de postgres instalaremos unixodbc y odbc-postgresql, el controlador para postgres.\napt update \u0026amp;\u0026amp; apt install unixodbc odbc-postgresql -y Vamos a modificar el fichero /etc/odbcinst.ini:\n#[PostgreSQL ANSI] #Description=PostgreSQL ODBC driver (ANSI version) #Driver=psqlodbca.so #Setup=libodbcpsqlS.so #Debug=0 #CommLog=1 #UsageCount=1 [PostgreSQL Unicode] Description=PostgreSQL ODBC driver (Unicode version) Driver=/usr/lib/x86_64-linux-gnu/odbc/psqlodbcw.so #Setup=libodbcpsqlS.so Debug=0 CommLog=1 UsageCount=1 He comentado las líneas que no nos sirven, ya que utilizaremos una conexión unicode, además he comentado el setup porque en sistemas operativos actualizados no existe libodbcpsqlS.so ya que no es necesario para que el driver funcione, era una librería auxiliar de ODBC.\nel debug registra logs detallados para ver el diagnóstico de lo que está pasando, lo dejamos en 0 de momento.\nCommLog = 1, está activado y sirve para registrar las comunicaciones entre cliente y servidor, mientras que UsageCount lleva el conteo de cuantas veces se ha utilizado el driver.\nAhora configuraremos el DSN, la fuente de datos a la que nos conectaremos:\n/etc/odbc.ini:\n[PSQLU] Debug = 0 CommLog = 0 ReadOnly = 0 Driver = PostgreSQL Unicode Servername = 192.168.122.1 Username = robe Password = robe Port = 5432 Database = scott1 Trace = 0 TraceFile = /tmp/sql.log La directiva Trace la podemos poner a 1 si queremos sirve para guardar las consultas que se van realizando.\nReadOnly lo dejamos en 0 para poder escribir, no solo leer.\nAntes dentro de la base de datos que corresponda, scott1 en este caso, debemos darle privilegios al usuario robe:\nGRANT SELECT, INSERT, UPDATE, DELETE ON public.\u0026lt;tabla\u0026gt; TO robe; Para comprobar que funciona:\n4.2 HETEROGENEUS SERVICE (HS) # Ahora que hemos verificado que el driver funciona, crearemos un servicio heterogéneo HS, para que oracle pueda hacer uso del driver mediante el enlace de base de datos que crearemos.\n/opt/oracle/product/19c/dbhome_1/hs/admin/initPSQLU.ora:\nHS_FDS_CONNECT_INFO = PSQLU HS_FDS_TRACE_LEVEL = DEBUG HS_FDS_SHAREABLE_NAME = /usr/lib/x86_64-linux-gnu/odbc/psqlodbcw.so HS_LANGUAGE = AMERICAN_AMERICA.WE8ISO8859P1 set ODBCINI=/etc/odbc.ini Configurar listener.ora:\n/opt/oracle/product/19c/dbhome_1/network/admin/listener.ora:\nSID_LIST_LISTENER = (SID_LIST = (SID_DESC = (SID_NAME = PSQLU) (ORACLE_HOME=/opt/oracle/product/19c/dbhome_1) (PROGRAM=dg4odbc) ) ) Estamos creando una especie de puente entre oracle y postgres de modo que se utiliza HS service para llamar al programa dg4odbc. Por lo tanto SID_NAME aquí no es una nueva instancia, solo es un alias lógico que sirve para la conexión de oracle a postgres.\nConfigurar tnsnames.ora\n/opt/oracle/product/19c/dbhome_1/network/admin/tnsnames.ora:\nPSQLU = (DESCRIPTION= (ADDRESS=(PROTOCOL=tcp)(HOST=localhost)(PORT=1521)) (CONNECT_DATA=(SID=PSQLU)) (HS=OK) ) Ahora apagaremos y levantaremos con lsnrctl, listener control los listener configurados en listener.ora:\nlsnrctl stop lsnrctl start lsnrctl services Tras ver los servicios de listener, si sale el que hemos configurado y todo esta bien, podemos crear en dblink y utilizarlo:\n4.3 CREACIÓN DEL DBLINK # dblink:\nCREATE DATABASE LINK dblink_postgres CONNECT TO \u0026#34;robe\u0026#34; IDENTIFIED BY \u0026#34;robe\u0026#34; using \u0026#39;PSQLU\u0026#39;; La identificación es del usuario de postgres.\nYa podemos desde oracle consultar datos a la base de datos de postgres.\n5. CAMBIAR NAME INSTANCIA Y CREAR ESQUEMA DE USUARIO ORACLE # ###### cambiar nombre de la instancia sqlplus / as sysdba alter system checkpoint; alter system switch logfile; shutdown immediate; startup mount; create pfile=\u0026#39;/tmp/init_nuevo2.ora\u0026#39; from spfile; #linux cp /tmp/init_nuevo.ora $ORACLE_HOME/dbs/init\u0026lt;newsid\u0026gt;.ora cambiar parametro db_name=newsid export ORACLE_SID=oldsid nid target=/ dbname=newsid export ORACLE_SID=newsid chown oracle:oinstall $ORACLE_HOME/dbs/initGN.ora chmod 644 $ORACLE_HOME/dbs/initGN.ora sqlplus / as sysdba STARTUP MOUNT PFILE=\u0026#39;$ORACLE_HOME/dbs/initGN.ora\u0026#39;; ALTER DATABASE OPEN RESETLOGS; select name from v$database; ######Crear esquema usuario en oracle alter session set \u0026#34;_ORACLE_SCRIPT\u0026#34;=true; CREATE USER user IDENTIFIED BY contraseña; GRANT CONNECT, RESOURCE TO RAUL; GRANT CREATE SESSION, CREATE TABLE, CREATE VIEW, CREATE SEQUENCE TO RAUL; GRANT CREATE DATABASE LINK TO usuario_oracle; ALTER USER RAUL QUOTA UNLIMITED ON USERS; ","date":"29 septiembre 2026","externalUrl":null,"permalink":"/posts/base-de-datos/interconexi%C3%B3n-bd/","section":"Posts","summary":"","title":"Interconexión de servidores de base de datos","type":"posts"},{"content":"","date":"29 septiembre 2026","externalUrl":null,"permalink":"/tags/mariadb/","section":"Tags","summary":"","title":"MariaDB","type":"tags"},{"content":"","date":"29 septiembre 2026","externalUrl":null,"permalink":"/tags/oracle/","section":"Tags","summary":"","title":"Oracle","type":"tags"},{"content":"","date":"29 septiembre 2026","externalUrl":null,"permalink":"/tags/postgresql/","section":"Tags","summary":"","title":"PostgreSQL","type":"tags"},{"content":"","date":"28 septiembre 2026","externalUrl":null,"permalink":"/tags/openvpn/","section":"Tags","summary":"","title":"OpenVPN","type":"tags"},{"content":"","date":"28 septiembre 2026","externalUrl":null,"permalink":"/posts/vpn/","section":"Posts","summary":"","title":"VPN","type":"posts"},{"content":"","date":"28 septiembre 2026","externalUrl":null,"permalink":"/tags/vpn/","section":"Tags","summary":"","title":"VPN","type":"tags"},{"content":" 1. ¿QUÉ ES UNA VPN? # Una VPN o red virtual privada es un método que sirve para crear una interconexión entre dos redes que no están conectadas directa y físicamente, de forma que se encapsula la trama TCP/IP dentro de la trama de la VPN, de modo que se obtienen datos comprimidos, cifrados asimétricamente y autentificación de usuarios.\nUn ejemplo es un usuario que intenta acceder a la red interna de su empresa desde su casa. Este sería un ejemplo de acceso remoto.\n1.1 VPN DE ACCESO REMOTO # El cliente se conecta a otra red utilizando un software, cuando la conexión llega al servidor destino, este nos permite conectarnos con su red como si nuestra máquina estuviese allí físicamente, entonces tendremos acceso a los recursos de esa red y accederemos a internet desde ella, pero realmente iniciando la conexión remota desde nuestra ubicación física.\n1.2 VPN SITE TO SITE # Este es el tipo de VPN que suelen utilizar las empresas, ya que sirve para interconectar dos sedes por ejemplo.\nEl site to site consiste en la creación de un tunel intermedio que permite a cada servidor de vpn coger las peticiones de sus clientes y mandarlas por ese túnel para que puedan acceder a los recursos de la otra red. Cabe destacar que aunque haya dos servidores vpn uno actúara de cliente al otro.\n2. VPN DE ACCESO REMOTO OPENVPN # Tenemos un servidor conectado a dos redes, y un cliente por otro lado que tiene que acceder a los servidores de esas redes\nEl servidor VPN será un contenedor LXC y el cliente VPN una instancia de OpenStack.\n2.1 CERTIFICADOS Y CLAVES # Con esta instrucción generaré el fichero de solicitud en el cliente, que posteriormente será firmado por la CA:\nopenssl req -new -key /etc/ssl/private/debiansecurity.key -out /root/debianOS.csr En el servidor de vpn generamos los parametros Diffie-Helman:\nopenssl dhparam -out /etc/openvpn/dh.pem 2048 Montamos la Autoridad certificadora en el mismo servidor de VPN:\nopenssl genrsa -aes256 -out /home/ryberxy/CA/private/ca_key.pem 4096 chmod 600 private/ca_key.pem openssl req -config ~/CA/openssl.cnf \\ -key ~/CA/private/ca_key.pem \\ -new -x509 -days 3650 -sha256 \\ -extensions v3_ca \\ -out ~/CA/certsdb/ca_cert.pem # Clave privada local openssl genrsa -out /etc/ssl/private/server.key 4096 Firmaremos el certificado local del servidor por la CA y también firmaremos el del cliente:\nOpcionalmente podemos generar una clave compartida, que utilizará openvpn para firmar los paquetes que se transmiten en el túnel de VPN, esta clave utilizará la autentificación TLS, la generamos de la siguiente forma:\nsudo openvpn --genkey secret ta.key 2.2 SUMINISTRACIÓN DE CLAVES # Ahora compartiremos las claves y certificados al directorio /etc/openvpn/bunchkeys:\nroot@e6proxy:~# mkdir /etc/openvpn/bunchkeys root@e6proxy:~# cp CA/certsdb/ca_cert.pem /etc/openvpn/bunchkeys/ root@e6proxy:~# cp /root/server.pem /etc/openvpn/bunchkeys/ root@e6proxy:~# cp /etc/ssl/private/server.key /etc/openvpn/bunchkeys/ root@e6proxy:~# cp /root/ta.key /etc/openvpn/bunchkeys/ Cliente:\nDebemos tener la clave privada local del cliente, el certificado de la CA y el certificado del cliente firmado por la CA, esto lo moveremos al directorio de openvpn:\nmkdir /etc/openvpn/bunchkeys cp /etc/ssl/private/debianOS.key /etc/openvpn/bunchkeys/ cp /etc/ssl/private/ca_cert.pem /etc/openvpn/bunchkeys/ cp /etc/ssl/private/debianOS.pem /etc/openvpn/bunchkeys/ 2.3 PREPARACIÓN PREVIA DEL SERVIDOR # Como voy a usar un contenedor lxc para el servidor vpn, tendré que configurar br0, un puente directo a mi red, lo haré con NetworkManager:\nAhora en /var/lib/lxc/name_contenedor/config indicamos la interfaz br0.\n2.4 CONFIGURACIÓN VPN # 2.4.1 SERVIDOR: # Como voy a utilizar un contenedor lxc y este usa el kernel del host, tendremos que cargar el módulo tun en el host:\nroot@pcrobe:/home/ryberxy# modprobe tun root@pcrobe:/home/ryberxy# lsmod | grep tun tun 69632 2 Para hacerlo persistente tras reinicio:\necho \u0026#34;tun\u0026#34; \u0026gt;\u0026gt; /etc/modules Ahora en la configuración del contenedor:\nnano /var/lib/lxc/e6_proxy/config # Permite el dispositivo TUN lxc.cgroup2.devices.allow = c 10:200 rwm # Monta el dispositivo lxc.mount.entry = /dev/net dev/net none bind,create=dir 0 0 # Desactiva AppArmor lxc.apparmor.profile = unconfined # Para manterner las capabilities necesarias lxc.cap.drop = Desde el contenedor comprobamos que existe el dispositivo y que tenemos permisos sobre él:\nConfiguración del servidor vpn:\n/etc/openvpn/server/server-home.conf: #Dispositivo de túnel dev tun #Protocolo proto tcp #Direcciones IP virtuales server 10.99.99.0 255.255.255.0 #subred local push \u0026#34;route 192.168.1.0 255.255.255.0\u0026#34; push \u0026#34;route 192.168.144.0 255.255.255.0\u0026#34; push \u0026#34;route 10.0.0.0 255.255.255.0\u0026#34; # Rol de servidor tls-server #Par metros Diffie-Hellman dh /etc/openvpn/bunchkeys/dh.pem #Certificado de la CA ca /etc/openvpn/bunchkeys/ca_cert.pem #Certificado local cert /etc/openvpn/bunchkeys/server.pem #Clave privada local key /etc/openvpn/bunchkeys/server.key #Activar la compresión LZO comp-lzo #Detectar ca das de la conexión keepalive 10 60 #Nivel de información verb 3 Configuraremos una regla snat para cambiar la ip origen del cliente vpn por la del servidor y así pueda acceder a los recursos de la red.\niptables -t nat -A POSTROUTING -s 10.99.99.0/24 -o eth0 -j MASQUERADE Habilitar servicio:\nsystemctl start openvpn-server@server 2.4.2 CLIENTE: # #Dispositivo de túnel dev tun #Direcciones remota remote 85.50.230.73 #Aceptar directivas del extremo remoto pull #Protocolo proto tcp-client #Rol de cliente tls-client #Certificado de la CA ca /etc/openvpn/bunchkeys/ca_cert.pem #Certificado local cert /etc/openvpn/bunchkeys/debianOS.pem #Clave privada local key /etc/openvpn/bunchkeys/debiansecurity.key #Activar la compresión LZO comp-lzo #Detectar caídas de la conexión keepalive 10 60 # logs log /var/log/openvpn-home.log #Nivel de información verb 3 Habilitar servicio:\nsystemctl start openvpn-client@client En mi caso, al haber utilizado un contenedor en mi red local, tendré que abrir el puerto que utiliza openvpn en el router, es decir haré snat con ese puerto hacia la dirección del contenedor:\nFuncionamiento:\nCliente → Red y subred del servidor\nVerificación de certificados:\n3. EASY-RSA PARA OPENVPN # Construir estructura pki (Autoridad certificadora):\n./easyrsa init-pki Generar parámetros Diffie-Hellman:\n./easyrsa gen-dh Generar certificado de la CA:\nsudo ./easyrsa build-ca nopass Generar certificado del servidor 1:\n./easyrsa gen-req servidor1 nopass Firmar certificado servidor 1:\n./easyrsa sign-req server servidor1 Firmar certificado cliente:\nsudo ./easyrsa sign-req client servidor2 Por último pasamos las claves al directorio de /etc/openvpn/bunchkeys y operamos como hicimos anteriormente.\n","date":"28 septiembre 2026","externalUrl":null,"permalink":"/posts/vpn/acceso-remoto-openvpn/","section":"Posts","summary":"","title":"VPN de acceso remoto con OpenVPN","type":"posts"},{"content":" 1. VPN ACCESO REMOTO WIREGUARD # Seguiremos el mismo escenario que anteriormente, ahora la máquina contenedor será el servidor VPN de acceso remoto mientras que la instancia de openstack será el cliente que va a acceder.\nPara comenzar vamos a instalar wireguard en cada máquina:\nsudo apt update \u0026amp;\u0026amp; sudo apt install wireguard 1.1 CONFIGURACIÓN DEL SERVIDOR1 # Para que el tráfico de la vpn con wireguard sea cifrado, vamos a generar las claves con la herramienta wg, que trae wireguard por defecto.\nClave privada:\nwg genkey Clave pública:\nwg pubkey Almacenaremos las claves en /etc/wireguard cada una en un fichero diferente, con el siguiente comando podemos realizar las dos instrucciones a la vez:\nwg genkey | sudo tee /etc/wireguard/private.key | wg pubkey | sudo tee /etc/wireguard/public.key Ahora vamos a configurar el servidor para poder acceder desde el cliente:\n[Interface] # Dirección IP del túnel de VPN Servidor Address = 10.99.99.1 #Clave privada del servidor PrivateKey = GMtU1HXOvd4p6xZrBJKxK7czL3pwMYZr/RjB9G7oJkw= #Puerto de escucha , 51820 es el puerto por defecto de Wireguard ListenPort = 51820 # Si no tienes activado el bit de forwarding por defecto puedes hacerlo asi : PreUp = sysctl -w net.ipv4.ip_forward=1 # Configuración de la sección clientes [Peer] # Clave pública del cliente Publickey = q1IATbSN3fw/tB24KRWiHSHusIWk8a6RhJ1Yd32Cohs= # IP del túnel VPN del cliente AllowedIPs = 10.99.99.2/32 # Tiempo de espera para apagar el túnel si no hay tráfico PersistentKeepAlive = 30 Con \\[interface\\] definimos la interfaz virtual que será wg0, mientras que \\[peer\\] sirve para configurar los clientes que van a acceder al túnel.\nLevantamos la interfaz virtual:\n1.2 CONFIGURACIÓN DEL SERVIDOR2 (CLIENTE) # También hemos generado sus claves de la misma forma que con el servidor 1:\nConfiguración del fichero cliente:\n[Interface] Address = 10.99.99.2/32 #Clave privada del cliente PrivateKey = CJek7lMo1fhypq4dXgitVFQ2OUAsELJuHA81r8cOaUU= #Puerto de escucha del servidor por defecto ListenPort = 51820 [Peer] # Clave pública del servidor PublicKey = tUhtnrr6T6PuGn0XAQW+A26/1NK8sVwwSaWLYJOSjGg= AllowedIPs = 0.0.0.0/0 # Punto de acceso por donde se accede al servidor Endpoint = 80.0.0.2:51820 #Tiempo de espera de la conexión PersistentKeepalive = 30 Levantamos la interfaz virtual:\nEnrutamiento:\nComo vemos no aparecen rutas que apunten a 10.99.99.0/24, eso es porque se ha creado una tabla aparte para las rutas de la vpn, ya que estamos usando tunelado para cualquier dirección ip (0.0.0.0), entonces estas rutas no aparecen en la tabla main que es la que controla el enrutamiento en Linux.\nCon el siguiente comando podemos ver la ruta escrita en la tabla del túnel VPN:\n1.2.1 FUNCIONAMIENTO # Puede alcanzar la red 10.0.1.0/24 y salir a internet por el túnel:\n1.3 CONFIGURACIÓN DE CLIENTE WINDOWS # En el servidor VPN generamos las claves para el cliente Windows de la misma forma que anteriormente:\nwg genkey | tee windowsprivate | wg pubkey | tee windowspublic Configuramos un fichero que será el túnel del cliente Windows, windows.conf:\n[Interface] Address = 10.99.99.3 PrivateKey = +Cis2XVRdbc/UVGrmEwy3Hcm5fGPFnHWMmy9EBrV7EY= ListenPort = 51820 [Peer] Publickey = tUhtnrr6T6PuGn0XAQW+A26/1NK8sVwwSaWLYJOSjGg= AllowedIPs = 0.0.0.0/0 Endpoint = 80.0.0.2:51820 En el servidor VPN configuramos una sección peer para el cliente:\nnano /etc/wireguard/wg0.conf [Peer] #Clave pública del cliente Publickey = vMtMURebGTXAKXBHYFGY3S6pJtPusRw5kqo3Prtx9yE= #IP del túnel VPN del cliente AllowedIPs = 10.99.99.3/32 #Tiempo de espera que tendrá activo el túnel si no hay trafico PersistentKeepAlive = 30 Para pasarle al cliente windows su fichero de configuración, montaremos un servidor web en el servidor VPN, lo haré con python, pero siempre en un entorno que no sea real.\nDescargar el archivo desde el cliente Windows:\nActivamos el túnel:\n1.3.1 FUNCIONAMIENTO # Configuración IP:\nDesde el servidor podemos comprobar los clientes conectados, y el windows está(10.99.99.3):\nsudo wg show Desde el cliente Windows accedemos a la red interna del servidor 1 y a internet:\n1.4 CONFIGURACIÓN DE CLIENTE ANDROID # En nuestro servidor de VPN generaremos las claves para el cliente android:\nwg genkey | tee androidprivate | wg pubkey | tee androidpublic Configuramos el android.conf, que es el fichero de configuración de wireguard para el android:\n[Interface] Address = 10.99.99.4 PrivateKey = wAaPZogR7qLnxYNNIF5eBm6eCgkaluYVRm/EHua0YEU= ListenPort = 51820 [Peer] Publickey = tUhtnrr6T6PuGn0XAQW+A26/1NK8sVwwSaWLYJOSjGg= AllowedIPs = 0.0.0.0/0 Endpoint = 80.0.0.2:51820 Mientras que en el servidor añadimos otra sección de peer, como dijimos antes sirve para configurar el acceso de un cliente al túnel de VPN:\nnano /etc/wireguard/wg0.conf [Peer] #Clave pública del cliente Publickey = FCFKS6N/Lmhx4eAPNV54cNaSw3iRvk1SoQaL5mPZml8= #IP del túnel VPN del cliente AllowedIPs = 10.99.99.4/32 #Tiempo de espera que tendrá activo el túnel si no hay trafico PersistentKeepAlive = 25 Lo descargamos desde el android con wget, primero montamos un servidor web en el puerto 8080 con python por ejemplo, en el servidor VPN. Cuidado, esto no es seguro en un entorno real.\nDesde el cliente android:\nAhora movemos el archivo a descargas:\nSi nos hace falta permisos de superusuario, utilizamos:\nsu - Ahora desde el cliente android, podemos acceder a toda la red de la vpn, al igual que antes desde el cliente linux, a pesar de que el cliente android está en la red 10.0.1.0/24 físicamente.\nSi queremos que se salga a internet por wg0 desde los clientes vpn, en el servidor de VPN tendremos que configurar una regla SNAT para la dirección del tunel:\niptables -t nat -A POSTROUTING -s 10.99.99.0/24 -o eth0 -j MASQUERADE 1.4.1 FUNCIONAMIENTO # ","date":"28 septiembre 2026","externalUrl":null,"permalink":"/posts/vpn/acceso-remoto-wireguard/","section":"Posts","summary":"","title":"VPN de acceso remoto con WireGuard","type":"posts"},{"content":" 1. VPN SITE TO SITE OPENVPN # 1.1 CONFIGURACIÓN DE RED OPENSTACK - SERVIDOR2 # Para esta configuración de vpn necesitamos que un cliente de una red pueda acceder a otro cliente de la red del otro extremo, para ello necesitamos que nuestra instancia de openstack sea un router linux y tenga clientes conectados en su red.\n# Creamos la red openstack network create red-interna # Creamos la subred sin gateway, ya que la configuramos después openstack subnet create subnet-interna --network red-interna --subnet-range 192.168.100.0/24 --gateway none --no-dhcp # Creamos el puerto que será la interfaz del router openstack port create --network red-interna --fixed-ip subnet=subnet-interna,ip-address=192.168.100.254 puerto-router-interna # Colocamos el puerto al router openstack server add port debian_Security puerto-router-interna # Creamos el puerto del cliente openstack port create --network red-interna --fixed-ip ip-address=192.168.100.2 port_cliente # Creamos la instancia cliente openstack server create --flavor m1.mini \\ --image \u0026#34;Debian 13 Trixie\u0026#34; \\ --security-group default \\ --key-name OS \\ --port port_cliente \\ cliente # Deshabilitamos la seguridad de puertos del cliente para que su tráfico no se interprete como amenaza y sea bloqueado, ya que es una red interna y openstack puede interpretarla como amenaza. openstack port set --disable-port-security port_cliente 1.2 CONFIGURACIÓN VPN # 1.2.1 SERVIDOR 1: # sudo nano /etc/openvpn/server/server1.conf #Protocolo proto tcp-server #Dispositivo de tunel dev tun #Direcciones IP virtuales ifconfig 10.99.99.1 10.99.99.2 #Ruta para llegar de servidor1 a servidor2 route 10.0.0.0 255.255.255.0 route 192.168.100.0 255.255.255.0 # Rol de servidor tls-server #Parámetros Diffie-Hellman dh /etc/openvpn/bunchkeys/dh.pem #Certificado de la CA ca /etc/openvpn/bunchkeys/ca_cert.pem #Certificado local cert /etc/openvpn/bunchkeys/server.pem #Clave privada local key /etc/openvpn/bunchkeys/server.key #Activar la compresión LZO comp-lzo #Detectar caídas de la conexión keepalive 10 60 #Nivel de información verb 3 1.2.2 SERVIDOR 2: # sudo nano /etc/openvpn/server/server2.conf #Dispositivo de túnel dev tun #Direcciones remota remote 85.50.230.73 #Aceptar directivas del extremo remoto ifconfig 10.99.99.2 10.99.99.1 #Rutas para conectar con las demás interfaces de Servidor 1. route 192.168.1.0 255.255.255.0 route 192.168.144.0 255.255.255.0 #Protocolo proto tcp-client #Rol de cliente tls-client #Certificado de la CA ca /etc/openvpn/bunchkeys/ca_cert.pem #Certificado local cert /etc/openvpn/bunchkeys/debianOS.pem #Clave privada local key /etc/openvpn/bunchkeys/debiansecurity.key #Activar la compresión LZO comp-lzo #Detectar caídas de la conexión keepalive 10 60 # logs log /var/log/openvpn-home.log #Nivel de información verb 3 1.3 FUNCIONAMIENTO # Servidor 1\nServidor 2\nPING ENTRE AMBOS SERVIDORES\nServidor 2 → Servidor 1\nServidor 1 → Servidor 2\nConexión ssh Cliente del servidor 1 → cliente del servidor 2\nConexión Cliente del servidor 2 → Cliente del servidor 1\n","date":"28 septiembre 2026","externalUrl":null,"permalink":"/posts/vpn/site-to-site-openvpn/","section":"Posts","summary":"","title":"VPN Site to Site con OpenVPN","type":"posts"},{"content":" 1. VPN SITE TO SITE WIREGUARD # Necesitaremos dos servidores, el servidor 1 y el servidor 2, por lo tanto generamos las claves en cada servidor, si aún no las tenemos:\nwg genkey | sudo tee /etc/wireguard/private.key | wg pubkey | sudo tee /etc/wireguard/public.key 1.1 CONFIGURACIÓN DEL SERVIDOR 1 # wg-quick up wg0 1.2 CONFIGURACIÓN DEL SERVIDOR 2 # wg-quick up wg0 1.3 FUNCIONAMIENTO # Enrutamiento servidor 1:\nEnrutamiento servidor 2:\nCliente 1 → Red Servidor 2\nCliente 2 → Red Servidor 1\n","date":"28 septiembre 2026","externalUrl":null,"permalink":"/posts/vpn/site-to-site-wireguard/","section":"Posts","summary":"","title":"VPN Site to Site con WireGuard","type":"posts"},{"content":"","date":"28 septiembre 2026","externalUrl":null,"permalink":"/tags/wireguard/","section":"Tags","summary":"","title":"WireGuard","type":"tags"},{"content":"","externalUrl":null,"permalink":"/authors/","section":"Authors","summary":"","title":"Authors","type":"authors"},{"content":"","externalUrl":null,"permalink":"/categories/","section":"Categories","summary":"","title":"Categories","type":"categories"},{"content":"","externalUrl":null,"permalink":"/posts/redes/","section":"Posts","summary":"","title":"Redes","type":"posts"},{"content":"","externalUrl":null,"permalink":"/series/","section":"Series","summary":"","title":"Series","type":"series"},{"content":"Escribe aquí tu párrafo de presentación: quién eres, qué estudias, qué buscas con este blog.\n","externalUrl":null,"permalink":"","section":"Blog Ryberxy","summary":"","title":"Sobre mí","type":"page"},{"content":"","externalUrl":null,"permalink":"","section":"Blog Ryberxy","summary":"","title":"Stack","type":"page"}]