diff --git a/docs/books/admin_guide/05-vi.it.md b/docs/books/admin_guide/05-vi.it.md
index f9d6ad7051..7d0ab387e8 100644
--- a/docs/books/admin_guide/05-vi.it.md
+++ b/docs/books/admin_guide/05-vi.it.md
@@ -355,7 +355,7 @@ Queste operazioni sono fatte in modalità *comando*.
* Annulla una cancellazione
-Ctrl+R
+Ctrl+r
## comando EX
@@ -363,7 +363,7 @@ La modalità *Ex* ti consente di agire sul file (salvataggio, disposizione, opzi
Per passare alla modalità *Ex*, dalla modalità *comando*, digita :.
-### Numerazione delle linee
+### Numeri di riga del file
* Mostra/nascondi numerazione:
diff --git a/docs/books/learning_ansible/03-working-with-files.es.md b/docs/books/learning_ansible/03-working-with-files.es.md
new file mode 100644
index 0000000000..aeb13d2d9f
--- /dev/null
+++ b/docs/books/learning_ansible/03-working-with-files.es.md
@@ -0,0 +1,151 @@
+---
+title: Gestión de archivos
+---
+
+# Ansible - Gestión de archivos
+
+En este capítulo aprenderás a gestionar archivos con Ansible.
+
+****
+
+**Objetivos**: En este capítulo aprenderá a:
+
+:heavy_check_mark: modificar el contenido de un archivo;
+:heavy_check_mark: subir archivos a los servidores de destino;
+:heavy_check_mark: descargar archivos desde los servidores de destino.
+
+:checkered_flag: **ansible**, **module**, **files**
+
+**Conocimiento**: :star: :star:
+**Complejidad**: :star:
+
+**Tiempo de lectura**: 20 minutos
+
+****
+
+Dependiendo de sus necesidades, tendrá que utilizar módulos de Ansible diferentes para modificar los archivos de configuración del sistema.
+
+## Módulo `ini_file`
+
+Cuando quiera modificar un archivo INI (la sección entre `[]` y los pares `clave=valor`), la forma más fácil es utilizar el módulo `ini_file`.
+
+!!! Note
+
+ Puede encontrar más información [aquí](https://docs.ansible.com/ansible/latest/collections/community/general/ini_file_module.html).
+
+El módulo requiere:
+
+* El valor de la sección
+* El nombre de la opción
+* El nuevo valor
+
+Ejemplo de uso:
+
+```
+- name: change value on inifile
+ community.general.ini_file:
+ dest: /path/to/file.ini
+ section: SECTIONNAME
+ option: OPTIONNAME
+ value: NEWVALUE
+```
+
+## Módulo `lineinfile`
+
+Para asegurarse de que una línea está presente en un archivo, o cuando se necesita añadir o modificar una sola línea en un archivo, utilice el módulo `linefile`.
+
+!!! El comando leerá el flujo de entrada hasta que encuentre la palabra clave definida después de la redirección de entrada.
+
+ Puede encontrar más información [aquí](https://docs.ansible.com/ansible/latest/collections/ansible/builtin/lineinfile_module.html).
+
+En este caso, la línea a modificar en un archivo se encontrará mediante una regexp.
+
+Por ejemplo, para garantizar que la línea que comienza con `SELINUX=` en el archivo `/etc/selinux/config` contiene el valor `enforcing`:
+
+```
+- ansible.builtin.lineinfile:
+ path: /etc/selinux/config
+ regexp: '^SELINUX='
+ line: 'SELINUX=enforcing'
+```
+
+## Módulo `copy`
+
+Cuando hay que copiar un archivo desde el servidor Ansible a uno o más hosts, es mejor utilizar el módulo `copy`.
+
+!!! El comando leerá el flujo de entrada hasta que encuentre la palabra clave definida después de la redirección de entrada.
+
+ Puede encontrar más información [aquí](https://docs.ansible.com/ansible/latest/collections/ansible/builtin/copy_module.html).
+
+Aquí estamos copiando el archivo `myflile.conf` de una ubicación a otra:
+
+```
+- ansible.builtin.copy:
+ src: /data/ansible/sources/myfile.conf
+ dest: /etc/myfile.conf
+ owner: root
+ group: root
+ mode: 0644
+```
+
+## Módulo `fetch`
+
+Cuando hay que copiar un archivo de un servidor remoto a un servidor local, lo mejor es utilizar el módulo `fetch`.
+
+!!! El comando leerá el flujo de entrada hasta que encuentre la palabra clave definida después de la redirección de entrada.
+
+ Puede encontrar más información [aquí](https://docs.ansible.com/ansible/latest/collections/ansible/builtin/fetch_module.html).
+
+Este módulo hace lo contrario que el módulo `copy`:
+
+```
+- ansible.builtin.fetch:
+ src: /etc/myfile.conf
+ dest: /data/ansible/backup/myfile-{{ inventory_hostname }}.conf
+ flat: yes
+```
+
+## Módulo `template`
+
+Ansible y su módulo `template` utilizan el sistema de plantillas **Jinja2** (http://jinja.pocoo.org/docs/) para generar archivos en los hosts de destino.
+
+!!! El comando leerá el flujo de entrada hasta que encuentre la palabra clave definida después de la redirección de entrada.
+
+ Puede encontrar más información [aquí](https://docs.ansible.com/ansible/latest/collections/ansible/builtin/template_module.html).
+
+Por ejemplo:
+
+```
+- ansible.builtin.template:
+ src: /data/ansible/templates/monfichier.j2
+ dest: /etc/myfile.conf
+ owner: root
+ group: root
+ mode: 0644
+```
+
+Es posible añadir un paso de validación si el servicio de destino lo permite (por ejemplo Apache con el comando `apachectl -t`):
+
+```
+- template:
+ src: /data/ansible/templates/vhost.j2
+ dest: /etc/httpd/sites-available/vhost.conf
+ owner: root
+ group: root
+ mode: 0644
+ validate: '/usr/sbin/apachectl -t'
+```
+
+## Módulo `get_url`
+
+Para subir archivos desde un sitio web o ftp a uno o más hosts, utilice el módulo `get_url`:
+
+```
+- get_url:
+ url: http://site.com/archive.zip
+ dest: /tmp/archive.zip
+ mode: 0640
+ checksum: sha256:f772bd36185515581aa9a2e4b38fb97940ff28764900ba708e68286121770e9a
+```
+
+Al proporcionar una suma de comprobación del archivo, éste no se volverá a descargar si ya está presente en la ubicación de destino y su suma de comprobación coincide con el valor proporcionado.
diff --git a/docs/books/learning_ansible/04-ansible-galaxy.es.md b/docs/books/learning_ansible/04-ansible-galaxy.es.md
new file mode 100644
index 0000000000..dc0cada3d1
--- /dev/null
+++ b/docs/books/learning_ansible/04-ansible-galaxy.es.md
@@ -0,0 +1,536 @@
+---
+title: Ansible Galaxy
+---
+
+# Ansible Galaxy: Colecciones y roles
+
+En este capítulo aprenderá a utilizar, instalar y gestionar los roles y colecciones de Ansible.
+
+****
+
+**Objetivos**: En este capítulo aprenderá a:
+
+:heavy_check_mark: instalar y gestionar colecciones;
+:heavy_check_mark: instalar y gestionar roles;.
+
+:checkered_flag: **ansible**, **ansible-galaxy**, **roles**, **colecciones**
+
+**Conocimiento**: :star: :star:
+**Complejidad**: :star: :star: :star:
+
+**Tiempo de lectura**: 40 minutos
+
+****
+
+[Ansible Galaxy](https://galaxy.ansible.com) proporciona roles y colecciones de Ansible desde la comunidad Ansible.
+
+Los elementos proporcionados se pueden referenciar en los playbooks y ser utilizados tal y como están
+
+## Comando `ansible-galaxy`
+
+El comando `ansible-galaxy` gestiona los roles y las colecciones utilizando [galaxy.ansible.com](http://galaxy.ansible.com).
+
+* Para gestionar los roles:
+
+```
+ansible-galaxy role [import|init|install|login|remove|...]
+```
+
+| Sub-comandos | Observaciones |
+| ------------ | ------------------------------------------------------------------------------- |
+| `install` | instalar un rol. |
+| `remove` | elimina uno o más roles. |
+| `lista` | muestra el nombre y la versión de los roles instalados. |
+| `info` | muestra la información sobre un rol. |
+| `init` | genera la estructura básica de un nuevo rol. |
+| `import` | importa un rol desde el sitio web de Ansible Galaxy. Requiere inicio de sesión. |
+
+* Para gestionar las colecciones:
+
+```
+ansible-galaxy collection [import|init|install|login|remove|...]
+```
+
+| Sub-comandos | Observaciones |
+| ------------ | ------------------------------------------------------------- |
+| `init` | genera la estructura básica de una nueva colección. |
+| `install` | instala una colección. |
+| `list` | muestra el nombre y la versión de las colecciones instaladas. |
+
+## Roles de Ansible
+
+Un rol de Ansible es una unidad que promueve la reutilización de los playbooks.
+
+!!! El comando leerá el flujo de entrada hasta que encuentre la palabra clave definida después de la redirección de entrada.
+
+ Puede encontrar más información [aquí](https://docs.ansible.com/ansible/latest/user_guide/playbooks_reuse_roles.html)
+
+### Instalación de roles útiles
+
+Para resaltar el interés del uso de roles, le sugiero que utilice el rol `alemorvan/patchmanagement`, que le permitirá realizar un montón de tareas (preactualización o postactualización, por ejemplo) durante su proceso de actualización, en sólo unas pocas líneas de código.
+
+Puedes consultar el código en el repo de github del rol \[aquí\](https://github. com/alemorvan/patchmanagement).
+
+* Instalar el rol. Para ello, sólo es necesario un comando:
+
+```
+ansible-galaxy role install alemorvan.patchmanagement
+```
+
+* Cree un playbook para incluir el rol:
+
+```
+- name: Start a Patch Management
+ hosts: ansible_clients
+ vars:
+ pm_before_update_tasks_file: custom_tasks/pm_before_update_tasks_file.yml
+ pm_after_update_tasks_file: custom_tasks/pm_after_update_tasks_file.yml
+
+ tasks:
+ - name: "Include patchmanagement"
+ include_role:
+ name: "alemorvan.patchmanagement"
+```
+
+Con este rol, puede añadir sus propias tareas para todo su inventario o sólo para su nodo objetivo.
+
+Vamos a crear tareas que se ejecutarán antes y después del proceso de actualización:
+
+* Cree la carpeta `custom_tasks`:
+
+```
+mkdir custom_tasks
+```
+
+* Cree el archivo `custom_tasks/pm_before_update_tasks_file.yml` (siéntase libre de cambiar el nombre y el contenido de este archivo)
+
+```
+---
+- name: sample task before the update process
+ debug:
+ msg: "This is a sample tasks, feel free to add your own test task"
+```
+
+* Cree el archivo `custom_tasks/pm_after_update_tasks_file.yml` (siéntase libre de cambiar el nombre y el contenido de este archivo)
+
+```
+---
+- name: sample task after the update process
+ debug:
+ msg: "This is a sample tasks, feel free to add your own test task"
+```
+
+Y lance su primera gestión de parches:
+
+```
+ansible-playbook patchmanagement.yml
+
+PLAY [Start a Patch Management] *************************************************************************
+
+TASK [Gathering Facts] **********************************************************************************
+ok: [192.168.1.11]
+
+TASK [Include patchmanagement] **************************************************************************
+
+TASK [alemorvan.patchmanagement : MAIN | Linux Patch Management Job] ************************************
+ok: [192.168.1.11] => {
+ "msg": "Start 192 patch management"
+}
+
+...
+
+TASK [alemorvan.patchmanagement : sample task before the update process] ********************************
+ok: [192.168.1.11] => {
+ "msg": "This is a sample tasks, feel free to add your own test task"
+}
+
+...
+
+TASK [alemorvan.patchmanagement : MAIN | We can now patch] **********************************************
+included: /home/ansible/.ansible/roles/alemorvan.patchmanagement/tasks/patch.yml for 192.168.1.11
+
+TASK [alemorvan.patchmanagement : PATCH | Tasks depends on distribution] ********************************
+ok: [192.168.1.11] => {
+ "ansible_distribution": "Rocky"
+}
+
+TASK [alemorvan.patchmanagement : PATCH | Include tasks for CentOS & RedHat tasks] **********************
+included: /home/ansible/.ansible/roles/alemorvan.patchmanagement/tasks/linux_tasks/redhat_centos.yml for 192.168.1.11
+
+TASK [alemorvan.patchmanagement : RHEL CENTOS | yum clean all] ******************************************
+changed: [192.168.1.11]
+
+TASK [alemorvan.patchmanagement : RHEL CENTOS | Ensure yum-utils is installed] **************************
+ok: [192.168.1.11]
+
+TASK [alemorvan.patchmanagement : RHEL CENTOS | Remove old kernels] *************************************
+skipping: [192.168.1.11]
+
+TASK [alemorvan.patchmanagement : RHEL CENTOS | Update rpm package with yum] ****************************
+ok: [192.168.1.11]
+
+TASK [alemorvan.patchmanagement : PATCH | Inlude tasks for Debian & Ubuntu tasks] ***********************
+skipping: [192.168.1.11]
+
+TASK [alemorvan.patchmanagement : MAIN | We can now reboot] *********************************************
+included: /home/ansible/.ansible/roles/alemorvan.patchmanagement/tasks/reboot.yml for 192.168.1.11
+
+TASK [alemorvan.patchmanagement : REBOOT | Reboot triggered] ********************************************
+ok: [192.168.1.11]
+
+TASK [alemorvan.patchmanagement : REBOOT | Ensure we are not in rescue mode] ****************************
+ok: [192.168.1.11]
+
+...
+
+TASK [alemorvan.patchmanagement : FACTS | Insert fact file] *********************************************
+ok: [192.168.1.11]
+
+TASK [alemorvan.patchmanagement : FACTS | Save date of last PM] *****************************************
+ok: [192.168.1.11]
+
+...
+
+TASK [alemorvan.patchmanagement : sample task after the update process] *********************************
+ok: [192.168.1.11] => {
+ "msg": "This is a sample tasks, feel free to add your own test task"
+}
+
+PLAY RECAP **********************************************************************************************
+192.168.1.11 : ok=31 changed=1 unreachable=0 failed=0 skipped=4 rescued=0 ignored=0
+```
+
+Bastante fácil para un proceso tan complejo, ¿no?
+
+Este es sólo un ejemplo de lo que se puede hacer utilizando los roles puestos a disposición por la comunidad. Eche un vistazo a [galaxy.ansible.com](https://galaxy.ansible.com/) para descubrir las funciones que podrían serle útiles.
+
+También puede crear sus propios roles para cubrir sus propias necesidades y publicarlos en Internet si le apetece. Lo que trataremos brevemente en el próximo capítulo.
+
+### Introducción al desarrollo de roles
+
+La estructura básica de un rol, sirve como punto de partida para el desarrollo de roles personalizados, puede ser generada mediante el comando `ansible-galaxy`:
+
+```
+$ ansible-galaxy role init rocky8
+- Role rocky8 was created successfully
+```
+
+El comando generará la siguiente estructura de árbol para contener el rol `rocky8`:
+
+```
+tree rocky8/
+rocky8/
+├── defaults
+│ └── main.yml
+├── files
+├── handlers
+│ └── main.yml
+├── meta
+│ └── main.yml
+├── README.md
+├── tasks
+│ └── main.yml
+├── templates
+├── tests
+│ ├── inventory
+│ └── test.yml
+└── vars
+ └── main.yml
+
+8 directories, 8 files
+```
+
+Los roles le permiten prescindir de la necesidad de incluir archivos. No es necesario especificar rutas de archivos o directivas `include` en los playbooks. Sólo tiene que especificar una tarea, y Ansible se encarga de las inclusiones.
+
+La estructura de un rol es bastante obvia de entender.
+
+Simplemente las variables se almacenan en `vars/main.yml` si las variables no van a ser sobreescribir, o en `default/main.yml` si quiere dejar la posibilidad de sobreescribir el contenido de las variables desde fuera de su rol.
+
+Los handlers, archivos y plantillas necesarios para su código se almacenan en `handlers/main.yml`, `files` y `templates` respectivamente.
+
+Sólo queda definir el código de las tareas de su rol en `tasks/main.yml`.
+
+Una vez que todo esto funciona correctamente, puede utilizar este rol en sus playbooks. Podrá utilizar su rol sin preocuparse por el aspecto técnico de sus tareas, mientras personaliza su funcionamiento con variables.
+
+### Trabajo práctico: crear un primer rol sencillo
+
+Implementemos esto con un rol que creará un usuario por defecto e instalará paquetes de software. Este rol puede aplicarse sistemáticamente a todos sus servidores.
+
+#### Variables
+
+Crearemos un usuario `rockstar` en todos nuestros servidores. Como no queremos que este usuario sea reemplazado, vamos a definirlo en el `vars/main.yml`:
+
+```
+---
+rocky8_default_group:
+ name: rockstar
+ gid: 1100
+rocky8_default_user:
+ name: rockstar
+ uid: 1100
+ group: rockstar
+```
+
+Ahora podemos usar esas variables dentro de nuestro archivo `tasks/main.yml` sin ninguna inclusión.
+
+```
+---
+- name: Create default group
+ group:
+ name: "{{ rocky8_default_group.name }}"
+ gid: "{{ rocky8_default_group.gid }}"
+
+- name: Create default user
+ user:
+ name: "{{ rocky8_default_user.name }}"
+ uid: "{{ rocky8_default_user.uid }}"
+ group: "{{ rocky8_default_user.group }}"
+```
+
+Para probar su nuevo rol, vamos a crear un playbook `test-role.yml` en el mismo directorio que su rol:
+
+```
+---
+- name: Test my role
+ hosts: localhost
+
+ roles:
+
+ - role: rocky8
+ become: true
+ become_user: root
+```
+
+y ejecútelo:
+
+```
+ansible-playbook test-role.yml
+
+PLAY [Test my role] ************************************************************************************
+
+TASK [Gathering Facts] *********************************************************************************
+ok: [localhost]
+
+TASK [rocky8 : Create default group] *******************************************************************
+changed: [localhost]
+
+TASK [rocky8 : Create default user] ********************************************************************
+changed: [localhost]
+
+PLAY RECAP *********************************************************************************************
+localhost : ok=3 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
+```
+
+¡Felicidades! Ahora es capaz de hacer grandes cosas con un playbook de unas pocas líneas.
+
+Veamos el uso de las variables por defecto.
+
+Cree una lista de paquetes para instalar por defecto en sus servidores y una lista vacía de paquetes para desinstalar. Edite los archivos `defaults/main.yml` y añada esas dos listas:
+
+```
+rocky8_default_packages:
+ - tree
+ - vim
+rocky8_remove_packages: []
+```
+
+y utilícelos en tu archivo `tasks/main.yml`:
+
+```
+- name: Install default packages (can be overridden)
+ package:
+ name: "{{ rocky8_default_packages }}"
+ state: present
+
+- name: "Uninstall default packages (can be overridden) {{ rocky8_remove_packages }}"
+ package:
+ name: "{{ rocky8_remove_packages }}"
+ state: absent
+```
+
+Pruebe su rol con la ayuda del playbook creado anteriormente:
+
+```
+ansible-playbook test-role.yml
+
+PLAY [Test my role] ************************************************************************************
+
+TASK [Gathering Facts] *********************************************************************************
+ok: [localhost]
+
+TASK [rocky8 : Create default group] *******************************************************************
+ok: [localhost]
+
+TASK [rocky8 : Create default user] ********************************************************************
+ok: [localhost]
+
+TASK [rocky8 : Install default packages (can be overridden)] ********************************************
+ok: [localhost]
+
+TASK [rocky8 : Uninstall default packages (can be overridden) []] ***************************************
+ok: [localhost]
+
+PLAY RECAP *********************************************************************************************
+localhost : ok=5 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
+```
+
+Ahora puede anular el valor de la variable `rocky8_remove_packages` en su playbook y desinstalar por ejemplo `cockpit`:
+
+```
+---
+- name: Test my role
+ hosts: localhost
+ vars:
+ rocky8_remove_packages:
+ - cockpit
+
+ roles:
+
+ - role: rocky8
+ become: true
+ become_user: root
+```
+
+```
+ansible-playbook test-role.yml
+
+PLAY [Test my role] ************************************************************************************
+
+TASK [Gathering Facts] *********************************************************************************
+ok: [localhost]
+
+TASK [rocky8 : Create default group] *******************************************************************
+ok: [localhost]
+
+TASK [rocky8 : Create default user] ********************************************************************
+ok: [localhost]
+
+TASK [rocky8 : Install default packages (can be overridden)] ********************************************
+ok: [localhost]
+
+TASK [rocky8 : Uninstall default packages (can be overridden) ['cockpit']] ******************************
+changed: [localhost]
+
+PLAY RECAP *********************************************************************************************
+localhost : ok=5 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
+```
+
+Evidentemente, no hay límite a la hora de mejorar su rol. Imagine que para uno de sus servidores, necesita un paquete que está en la lista de los que hay que desinstalar. A continuación, podría, por ejemplo, crear una nueva lista que puede ser anulada y luego eliminar de la lista de paquetes a desinstalar los de la lista de paquetes específicos a instalar mediante el filtro de jinja `difference()`.
+
+```
+- name: "Uninstall default packages (can be overridden) {{ rocky8_remove_packages }}"
+ package:
+ name: "{{ rocky8_remove_packages | difference(rocky8_specifics_packages) }}"
+ state: absent
+```
+
+## Colecciones de Ansible
+
+Las colecciones son un formato de distribución para contenido de Ansible que puede incluir playbooks, roles, módulos y plugins.
+
+!!! El comando leerá el flujo de entrada hasta que encuentre la palabra clave definida después de la redirección de entrada.
+
+ Puede encontrar más información [aquí](https://docs.ansible.com/ansible/latest/user_guide/collections_using.html)
+
+Para instalar o actualizar una colección:
+
+```
+ansible-galaxy collection install namespace.collection [--upgrade]
+```
+
+A continuación, puede utilizar la colección recién instalada utilizando su espacio de nombres y su nombre antes del nombre del módulo o del rol:
+
+```
+- import_role:
+ name: namespace.collection.rolename
+
+- namespace.collection.modulename:
+ option1: value
+```
+
+Puede encontrar un índice de la colección [aquí](https://docs.ansible.com/ansible/latest/collections/index.html).
+
+Vamos a instalar la colección `community.general`:
+
+```
+ansible-galaxy collection install community.general
+Starting galaxy collection install process
+Process install dependency map
+Starting collection install process
+Downloading https://galaxy.ansible.com/download/community-general-3.3.2.tar.gz to /home/ansible/.ansible/tmp/ansible-local-51384hsuhf3t5/tmpr_c9qrt1/community-general-3.3.2-f4q9u4dg
+Installing 'community.general:3.3.2' to '/home/ansible/.ansible/collections/ansible_collections/community/general'
+community.general:3.3.2 was installed successfully
+```
+
+Ahora podemos utilizar el nuevo módulo disponible `yum_versionlock`:
+
+```
+- name: Start a Patch Management
+ hosts: ansible_clients
+ become: true
+ become_user: root
+ tasks:
+
+ - name: Ensure yum-versionlock is installed
+ package:
+ name: python3-dnf-plugin-versionlock
+ state: present
+
+ - name: Prevent kernel from being updated
+ community.general.yum_versionlock:
+ state: present
+ name: kernel
+ register: locks
+
+ - name: Display locks
+ debug:
+ var: locks.meta.packages
+```
+
+```
+ansible-playbook versionlock.yml
+
+PLAY [Start a Patch Management] *************************************************************************
+
+TASK [Gathering Facts] **********************************************************************************
+ok: [192.168.1.11]
+
+TASK [Ensure yum-versionlock is installed] **************************************************************
+changed: [192.168.1.11]
+
+TASK [Prevent kernel from being updated] ****************************************************************
+changed: [192.168.1.11]
+
+TASK [Display locks] ************************************************************************************
+ok: [192.168.1.11] => {
+ "locks.meta.packages": [
+ "kernel"
+ ]
+}
+
+PLAY RECAP **********************************************************************************************
+192.168.1.11 : ok=4 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
+
+```
+
+### Crea su propia colección
+
+Al igual que con los roles, puede crear su propia colección con la ayuda del comando `ansible-galaxy`:
+
+```
+ansible-galaxy collection init rocky8.rockstarcollection
+- Collection rocky8.rockstarcollection was created successfully
+```
+
+```
+tree rocky8/rockstarcollection/
+rocky8/rockstarcollection/
+├── docs
+├── galaxy.yml
+├── plugins
+│ └── README.md
+├── README.md
+└── roles
+```
+
+A continuación, puede almacenar sus propios plugins o roles dentro de esta nueva colección.
diff --git a/docs/books/learning_ansible/05-deployments.es.md b/docs/books/learning_ansible/05-deployments.es.md
new file mode 100644
index 0000000000..87a581d37b
--- /dev/null
+++ b/docs/books/learning_ansible/05-deployments.es.md
@@ -0,0 +1,785 @@
+---
+title: Despliegues con Ansistrano
+---
+
+# Despliegues de Ansible con Ansistrano
+
+En este capítulo aprenderá a desplegar aplicaciones con el rol de Ansible [Ansistrano](https://ansistrano.com).
+
+****
+
+**Objetivos**: En este capítulo aprenderá a:
+
+:heavy_check_mark: Implementar Ansistrano;
+:heavy_check_mark: Configurar Ansistrano;
+:heavy_check_mark: Utilizar carpetas compartidas y ficheros entre las versiones deplgadas;
+:heavy_check_mark: Desplegar versiones diferentes de un sitio web desde Git;
+:heavy_check_mark: Reaccionar entre los pasos de los despliegues.
+
+:checkered_flag: **ansible**, **ansistrano**, **roles**, **despliegues**
+
+**Conocimiento**: :star: :star:
+**Complejidad**: :star: :star: :star:
+
+**Tiempo de lectura**: 40 minutos
+
+****
+
+Ansistrano es un rol de Ansible para desplegar fácilmente aplicaciones PHP, Python, etc. Se basa en la funcionalidad de [Capistrano](http://capistranorb.com/).
+
+## Introducción
+
+Ansistrano requiere las siguientes piezas para funcionar correctamente:
+
+* Ansible en la máquina de despliegue,
+* `rsync` o `git` la máquina cilente.
+
+Puede descargar el código fuente desde `rsync`, `git`, `scp`, `http`, `S3`, ...
+
+!!! Note
+
+ Para nuestro despliegue de ejemplo, utilizaremos el protocolo `git`.
+
+Ansistrano despliega las aplicaciones mediante los siguientes 5 pasos:
+
+* **Setup**: crea la estructura de directorios para alojar los despliegues;
+* **Update Code**: descargar la nueva versión a los equipos de destino;
+* **Symlink Shared** y **Symlink**: después de desplegar la nueva versión, el enlace simbólico `current` se modifica para apuntar a esta nueva versión;
+* **Clean Up**: para hacer algo de limpieza (eliminando versiones antiguas).
+
+
+
+La estructura básica de un despliegue con Ansistrano tiene el siguiente aspecto:
+
+```
+/var/www/site/
+├── current -> ./releases/20210718100000Z
+├── releases
+│ └── 20210718100000Z
+│ ├── css -> ../../shared/css/
+│ ├── img -> ../../shared/img/
+│ └── REVISION
+├── repo
+└── shared
+ ├── css/
+ └── img/
+```
+
+Puede encontrar toda la documentación de Ansistrano en su [repositorio de Github](https://github.com/ansistrano/deploy).
+
+## Laboratorios
+
+Seguirá trabajando en sus 2 servidores:
+
+El servidor de administración:
+
+* Ansible ya está instalado. Tendrá que instalar el rol `ansistrano.deploy`.
+
+El servidor administrado:
+
+* Tendrá que instalar Apache y desplegar el sitio del cliente.
+
+### Desplegar el servidor web
+
+Para una mayor eficiencia, utilizaremos el rol `geerlingguy.apache` para configurar el servidor:
+
+```
+$ ansible-galaxy role install geerlingguy.apache
+Starting galaxy role install process
+- downloading role 'apache', owned by geerlingguy
+- downloading role from https://github.com/geerlingguy/ansible-role-apache/archive/3.1.4.tar.gz
+- extracting geerlingguy.apache to /home/ansible/.ansible/roles/geerlingguy.apache
+- geerlingguy.apache (3.1.4) was installed successfully
+```
+
+Probablemente necesitemos abrir algunas reglas de firewall, por lo que también instalaremos la colección `ansible.posix` para trabajr con su módulo `firewalld`:
+
+```
+$ ansible-galaxy collection install ansible.posix
+Starting galaxy collection install process
+Process install dependency map
+Starting collection install process
+Downloading https://galaxy.ansible.com/download/ansible-posix-1.2.0.tar.gz to /home/ansible/.ansible/tmp/ansible-local-519039bp65pwn/tmpsvuj1fw5/ansible-posix-1.2.0-bhjbfdpw
+Installing 'ansible.posix:1.2.0' to '/home/ansible/.ansible/collections/ansible_collections/ansible/posix'
+ansible.posix:1.2.0 was installed successfully
+```
+
+Una vez instalados el rol y la colección, podemos crear la primera parte de nuestro playbook, que será:
+
+* Instalar Apache,
+* Crear una carpeta de destino para nuestro `vhost`,
+* Crear el `vhost` por defecto,
+* Abrir el cortafuegos,
+* Iniciar o reiniciar Apache.
+
+Consideraciones técnicas:
+
+* Desplegaremos nuestro sitio en la carpeta `/var/www/site/`.
+* Como veremos más adelante, `ansistrano` creará un enlace simbólico `current` a la carpeta con la versión actual.
+* El código fuente a desplegar contiene una carpeta `html` a la que debe apuntar el vhost. Su `DirectoryIndex` apunta al fichero `index.htm`.
+* El despliegue se realiza mediante `git`, el paquete se instalará.
+
+!!! Note
+
+ Por lo tanto, el objetivo de nuestro vhost será `/var/www/site/current/html`.
+
+Nuestro playbook para configurar el servidor: `playbook-config-server.yml`
+
+```
+---
+- hosts: ansible_clients
+ become: yes
+ become_user: root
+ vars:
+ dest: "/var/www/site/"
+ apache_global_vhost_settings: |
+ DirectoryIndex index.php index.htm
+ apache_vhosts:
+ - servername: "website"
+ documentroot: "{{ dest }}current/html"
+
+ tasks:
+
+ - name: create directory for website
+ file:
+ path: /var/www/site/
+ state: directory
+ mode: 0755
+
+ - name: install git
+ package:
+ name: git
+ state: latest
+
+ - name: permit traffic in default zone for http service
+ ansible.posix.firewalld:
+ service: http
+ permanent: yes
+ state: enabled
+ immediate: yes
+
+ roles:
+ - { role: geerlingguy.apache }
+```
+
+El playbook se puede aplicar al servidor:
+
+```
+$ ansible-playbook playbook-config-server.yml
+```
+
+Observe la ejecución de las siguientes tareas:
+
+```
+TASK [geerlingguy.apache : Ensure Apache is installed on RHEL.] ****************
+TASK [geerlingguy.apache : Configure Apache.] **********************************
+TASK [geerlingguy.apache : Add apache vhosts configuration.] *******************
+TASK [geerlingguy.apache : Ensure Apache has selected state and enabled on boot.] ***
+TASK [permit traffic in default zone for http service] *************************
+RUNNING HANDLER [geerlingguy.apache : restart apache] **************************
+```
+
+El rol `geerlingguy.apache` nos facilita mucho el trabajo al encargarse de la instalación y configuración de Apache.
+
+Puede comprobar que todo funciona utilizando el comando `curl`:
+
+```
+$ curl -I http://192.168.1.11
+HTTP/1.1 404 Not Found
+Date: Mon, 05 Jul 2021 23:30:02 GMT
+Server: Apache/2.4.37 (rocky) OpenSSL/1.1.1g
+Content-Type: text/html; charset=iso-8859-1
+```
+
+!!! Note
+
+ Todavía no hemos desplegado ningún código, por lo que es normal que la ejecución del comando `curl` devuelva un código HTTP `404`. Pero ya podemos confirmar que el servicio `httpd` está funcionando y que el firewall está abierto.
+
+### Desplegar el software
+
+Ahora que tenemos nuestro servidor configurado, podemos desplegar la aplicación.
+
+Para ello, utilizaremos el rol `ansistrano.deploy` en un segundo playbook dedicado al despliegue de la aplicación (para mayor legibilidad).
+
+```
+$ ansible-galaxy role install ansistrano.deploy
+Starting galaxy role install process
+- downloading role 'deploy', owned by ansistrano
+- downloading role from https://github.com/ansistrano/deploy/archive/3.10.0.tar.gz
+- extracting ansistrano.deploy to /home/ansible/.ansible/roles/ansistrano.deploy
+- ansistrano.deploy (3.10.0) was installed successfully
+
+```
+
+El código fuente del software se puede encontrar en el [repositorio de github](https://github.com/alemorvan/demo-ansible.git).
+
+Crearemos un playbook `playbook-deploy.yml` para gestionar nuestro despliegue:
+
+```
+---
+- hosts: ansible_clients
+ become: yes
+ become_user: root
+ vars:
+ dest: "/var/www/site/"
+ ansistrano_deploy_via: "git"
+ ansistrano_git_repo: https://github.com/alemorvan/demo-ansible.git
+ ansistrano_deploy_to: "{{ dest }}"
+
+ roles:
+ - { role: ansistrano.deploy }
+```
+
+```
+$ ansible-playbook playbook-deploy.yml
+
+PLAY [ansible_clients] *********************************************************
+
+TASK [ansistrano.deploy : ANSISTRANO | Ensure deployment base path exists] *****
+TASK [ansistrano.deploy : ANSISTRANO | Ensure releases folder exists]
+TASK [ansistrano.deploy : ANSISTRANO | Ensure shared elements folder exists]
+TASK [ansistrano.deploy : ANSISTRANO | Ensure shared paths exists]
+TASK [ansistrano.deploy : ANSISTRANO | Ensure basedir shared files exists]
+TASK [ansistrano.deploy : ANSISTRANO | Get release version] ********************
+TASK [ansistrano.deploy : ANSISTRANO | Get release path]
+TASK [ansistrano.deploy : ANSISTRANO | GIT | Register ansistrano_git_result variable]
+TASK [ansistrano.deploy : ANSISTRANO | GIT | Set git_real_repo_tree]
+TASK [ansistrano.deploy : ANSISTRANO | GIT | Create release folder]
+TASK [ansistrano.deploy : ANSISTRANO | GIT | Sync repo subtree[""] to release path]
+TASK [ansistrano.deploy : ANSISTRANO | Copy git released version into REVISION file]
+TASK [ansistrano.deploy : ANSISTRANO | Ensure shared paths targets are absent]
+TASK [ansistrano.deploy : ANSISTRANO | Create softlinks for shared paths and files]
+TASK [ansistrano.deploy : ANSISTRANO | Ensure .rsync-filter is absent]
+TASK [ansistrano.deploy : ANSISTRANO | Setup .rsync-filter with shared-folders]
+TASK [ansistrano.deploy : ANSISTRANO | Get current folder]
+TASK [ansistrano.deploy : ANSISTRANO | Remove current folder if it's a directory]
+TASK [ansistrano.deploy : ANSISTRANO | Change softlink to new release]
+TASK [ansistrano.deploy : ANSISTRANO | Clean up releases]
+
+PLAY RECAP ********************************************************************************************************************************************************************************************************
+192.168.1.11 : ok=25 changed=8 unreachable=0 failed=0 skipped=14 rescued=0 ignored=0
+
+```
+
+¡Se pueden hacer muchas cosas con sólo 11 líneas de código!
+
+```
+$ curl http://192.168.1.11
+
+
+Demo Ansible
+
+
+Version Master
+
+
+```
+
+### Comprobaciones en el servidor
+
+Ahora puede conectarse vía ssh a su máquina cliente.
+
+* Ejecute el comando `tree` en el directorio`/var/www/site/`:
+
+```
+$ tree /var/www/site/
+/var/www/site
+├── current -> ./releases/20210722155312Z
+├── releases
+│ └── 20210722155312Z
+│ ├── REVISION
+│ └── html
+│ └── index.htm
+├── repo
+│ └── html
+│ └── index.htm
+└── shared
+```
+
+Por favor, ten en cuenta:
+
+* el enlace simbólico `current` a la versión `./releases/20210722155312Z`
+* la presencia de un directorio llamado `shared`
+* la repsencia de repositorios de git en `./repo/`
+
+* Desde el servidor de Ansible, reinicie el despliegue **3** veces, y luego compruebe en el cliente.
+
+```
+$ tree /var/www/site/
+var/www/site
+├── current -> ./releases/20210722160048Z
+├── releases
+│ ├── 20210722155312Z
+│ │ ├── REVISION
+│ │ └── html
+│ │ └── index.htm
+│ ├── 20210722160032Z
+│ │ ├── REVISION
+│ │ └── html
+│ │ └── index.htm
+│ ├── 20210722160040Z
+│ │ ├── REVISION
+│ │ └── html
+│ │ └── index.htm
+│ └── 20210722160048Z
+│ ├── REVISION
+│ └── html
+│ └── index.htm
+├── repo
+│ └── html
+│ └── index.htm
+└── shared
+```
+
+Por favor, ten en cuenta:
+
+* `ansistrano` mantiene las 4 ultimas versiones,
+* el enlace simbólico `current` ahora apunta a la última versión
+
+### Limitar el número de versiones
+
+La variable `ansistrano_keep_releases` se utiliza para especificar el número de versiones a mantener.
+
+* Utilizando la variable `ansistrano_keep_releases`, mantén sólo 3 versiones del proyecto. Compruebe.
+
+```
+---
+- hosts: ansible_clients
+ become: yes
+ become_user: root
+ vars:
+ dest: "/var/www/site/"
+ ansistrano_deploy_via: "git"
+ ansistrano_git_repo: https://github.com/alemorvan/demo-ansible.git
+ ansistrano_deploy_to: "{{ dest }}"
+ ansistrano_keep_releases: 3
+
+ roles:
+ - { role: ansistrano.deploy }
+```
+
+```
+---
+$ ansible-playbook -i hosts playbook-deploy.yml
+```
+
+En la máquina cliente:
+
+```
+$ tree /var/www/site/
+/var/www/site
+├── current -> ./releases/20210722160318Z
+├── releases
+│ ├── 20210722160040Z
+│ │ ├── REVISION
+│ │ └── html
+│ │ └── index.htm
+│ ├── 20210722160048Z
+│ │ ├── REVISION
+│ │ └── html
+│ │ └── index.htm
+│ └── 20210722160318Z
+│ ├── REVISION
+│ └── html
+│ └── index.htm
+├── repo
+│ └── html
+│ └── index.htm
+└── shared
+```
+
+### Uso de shared_paths y shared_files
+
+
+```
+---
+- hosts: ansible_clients
+ become: yes
+ become_user: root
+ vars:
+ dest: "/var/www/site/"
+ ansistrano_deploy_via: "git"
+ ansistrano_git_repo: https://github.com/alemorvan/demo-ansible.git
+ ansistrano_deploy_to: "{{ dest }}"
+ ansistrano_keep_releases: 3
+ ansistrano_shared_paths:
+ - "img"
+ - "css"
+ ansistrano_shared_files:
+ - "logs"
+
+ roles:
+ - { role: ansistrano.deploy }
+```
+
+En el equipo cliente, cree el archivo `logs` en el directorio `shared`:
+
+```
+sudo touch /var/www/site/shared/logs
+```
+
+Despues ejecute el playbook:
+
+```
+TASK [ansistrano.deploy : ANSISTRANO | Ensure shared paths targets are absent] *******************************************************
+ok: [192.168.10.11] => (item=img)
+ok: [192.168.10.11] => (item=css)
+ok: [192.168.10.11] => (item=logs/log)
+
+TASK [ansistrano.deploy : ANSISTRANO | Create softlinks for shared paths and files] **************************************************
+changed: [192.168.10.11] => (item=img)
+changed: [192.168.10.11] => (item=css)
+changed: [192.168.10.11] => (item=logs)
+```
+
+En la máquina cliente:
+
+```
+$ tree -F /var/www/site/
+/var/www/site/
+├── current -> ./releases/20210722160631Z/
+├── releases/
+│ ├── 20210722160048Z/
+│ │ ├── REVISION
+│ │ └── html/
+│ │ └── index.htm
+│ ├── 20210722160318Z/
+│ │ ├── REVISION
+│ │ └── html/
+│ │ └── index.htm
+│ └── 20210722160631Z/
+│ ├── REVISION
+│ ├── css -> ../../shared/css/
+│ ├── html/
+│ │ └── index.htm
+│ ├── img -> ../../shared/img/
+│ └── logs -> ../../shared/logs
+├── repo/
+│ └── html/
+│ └── index.htm
+└── shared/
+ ├── css/
+ ├── img/
+ └── logs
+```
+
+Tenga en cuenta que la última versión contiene 3 enlaces: `css`, `img`, and `logs`
+
+* desde `/var/www/site/releases/css` al directorio `../../shared/css/`.
+* desde `/var/www/site/releases/img` al directorio `../../shared/img/`.
+* desde `/var/www/site/releases/logs` al archivo `../../shared/logs`.
+
+Por lo tanto, los archivos contenidos en estas 2 carpetas y el archivo `logs` son siempre accesibles a través de las siguientes rutas:
+
+* `/var/www/site/current/css/`,
+* `/var/www/site/current/img/`,
+* `/var/www/site/current/logs`,
+
+pero sobre todo se mantendrán de un despliegue a otro.
+
+### Utilizar un subdirectorio del repositorio para el despliegue
+
+En nuestro caso, el repositorio contiene una carpeta `html`, que contiene los archivos del sitio.
+
+* Para evitar este nivel extra de directorio, utilice la variable `ansistrano_git_repo_tree` especificando la ruta del subdirectorio a utilizar.
+
+¡No olvide modificar la configuración de Apache para tener en cuenta este cambio!
+
+Cambie el playbook para la configuración del servidor `playbook-config-server.yml`
+
+```
+---
+- hosts: ansible_clients
+ become: yes
+ become_user: root
+ vars:
+ dest: "/var/www/site/"
+ apache_global_vhost_settings: |
+ DirectoryIndex index.php index.htm
+ apache_vhosts:
+ - servername: "website"
+ documentroot: "{{ dest }}current/" # <1>
+
+ tasks:
+
+ - name: create directory for website
+ file:
+ path: /var/www/site/
+ state: directory
+ mode: 0755
+
+ - name: install git
+ package:
+ name: git
+ state: latest
+
+ roles:
+ - { role: geerlingguy.apache }
+```
+
+<1> Edite esta línea
+
+Cambie el playbook para el despliegue `playbook-deploy.yml`
+
+```
+---
+- hosts: ansible_clients
+ become: yes
+ become_user: root
+ vars:
+ dest: "/var/www/site/"
+ ansistrano_deploy_via: "git"
+ ansistrano_git_repo: https://github.com/alemorvan/demo-ansible.git
+ ansistrano_deploy_to: "{{ dest }}"
+ ansistrano_keep_releases: 3
+ ansistrano_shared_paths:
+ - "img"
+ - "css"
+ ansistrano_shared_files:
+ - "log"
+ ansistrano_git_repo_tree: 'html' # <1>
+
+ roles:
+ - { role: ansistrano.deploy }
+```
+
+<1> Edite esta línea
+
+* No se olvide de ejecutar los dos playbooks
+
+* Compruebe en la máquina cliente:
+
+```
+$ tree -F /var/www/site/
+/var/www/site/
+├── current -> ./releases/20210722161542Z/
+├── releases/
+│ ├── 20210722160318Z/
+│ │ ├── REVISION
+│ │ └── html/
+│ │ └── index.htm
+│ ├── 20210722160631Z/
+│ │ ├── REVISION
+│ │ ├── css -> ../../shared/css/
+│ │ ├── html/
+│ │ │ └── index.htm
+│ │ ├── img -> ../../shared/img/
+│ │ └── logs -> ../../shared/logs
+│ └── 20210722161542Z/
+│ ├── REVISION
+│ ├── css -> ../../shared/css/
+│ ├── img -> ../../shared/img/
+│ ├── index.htm
+│ └── logs -> ../../shared/logs
+├── repo/
+│ └── html/
+│ └── index.htm
+└── shared/
+ ├── css/
+ ├── img/
+ └── logs
+```
+
+<1> Obsérvese la ausencia de `html`
+
+### Gestión de las ramas o de las etiquetas de Git
+
+La variable `ansistrano_git_branch` se utiliza para especificar una `rama` o una `etiqueta` de Git a desplegar.
+
+* Despliegue de la rama `releases/v1.1.0`:
+
+```
+---
+- hosts: ansible_clients
+ become: yes
+ become_user: root
+ vars:
+ dest: "/var/www/site/"
+ ansistrano_deploy_via: "git"
+ ansistrano_git_repo: https://github.com/alemorvan/demo-ansible.git
+ ansistrano_deploy_to: "{{ dest }}"
+ ansistrano_keep_releases: 3
+ ansistrano_shared_paths:
+ - "img"
+ - "css"
+ ansistrano_shared_files:
+ - "log"
+ ansistrano_git_repo_tree: 'html'
+ ansistrano_git_branch: 'releases/v1.1.0'
+
+ roles:
+ - { role: ansistrano.deploy }
+```
+
+!!! El comando leerá el flujo de entrada hasta que encuentre la palabra clave definida después de la redirección de entrada.
+
+ Puede divertirse, durante el despliegue, refrescando su navegador, para ver el cambio en 'vivo'.
+
+```
+$ curl http://192.168.1.11
+
+
+Demo Ansible
+
+
+Version 1.0.1
+
+
+```
+
+* Despliegue de la etiqueta `v2.0.0`:
+
+```
+---
+- hosts: ansible_clients
+ become: yes
+ become_user: root
+ vars:
+ dest: "/var/www/site/"
+ ansistrano_deploy_via: "git"
+ ansistrano_git_repo: https://github.com/alemorvan/demo-ansible.git
+ ansistrano_deploy_to: "{{ dest }}"
+ ansistrano_keep_releases: 3
+ ansistrano_shared_paths:
+ - "img"
+ - "css"
+ ansistrano_shared_files:
+ - "log"
+ ansistrano_git_repo_tree: 'html'
+ ansistrano_git_branch: 'v2.0.0'
+
+ roles:
+ - { role: ansistrano.deploy }
+```
+
+```
+$ curl http://192.168.1.11
+
+
+Demo Ansible
+
+
+Version 2.0.0
+
+
+```
+
+### Acciones entre los pasos del despliegue
+
+Un despliegue con Ansistrano respeta los siguientes pasos:
+
+* `Setup`
+* `Update Code`
+* `Symlink Shared`
+* `Symlink Shared`
+* `Clean Up`
+
+Es posible intervenir antes y después de cada uno de estos pasos.
+
+
+
+Se puede incluir un playbook a través de las variables previstas para ello:
+
+* `ansistrano_before__tasks_file`
+* o `ansistrano_after__tasks_file`
+
+* Ejemplo sencillo: Enviar un correo electrónico (o lo que quiera como una notificación de Slack) al comenzar el despliegue:
+
+
+```
+---
+- hosts: ansible_clients
+ become: yes
+ become_user: root
+ vars:
+ dest: "/var/www/site/"
+ ansistrano_deploy_via: "git"
+ ansistrano_git_repo: https://github.com/alemorvan/demo-ansible.git
+ ansistrano_deploy_to: "{{ dest }}"
+ ansistrano_keep_releases: 3
+ ansistrano_shared_paths:
+ - "img"
+ - "css"
+ ansistrano_shared_files:
+ - "logs"
+ ansistrano_git_repo_tree: 'html'
+ ansistrano_git_branch: 'v2.0.0'
+ ansistrano_before_setup_tasks_file: "{{ playbook_dir }}/deploy/before-setup-tasks.yml"
+
+ roles:
+ - { role: ansistrano.deploy }
+```
+
+Cree el fichero `deploy/before-setup-tasks.yml`:
+
+```
+---
+- name: Send a mail
+ mail:
+ subject: Starting deployment on {{ ansible_hostname }}.
+ delegate_to: localhost
+```
+
+```
+TASK [ansistrano.deploy : include] *************************************************************************************
+included: /home/ansible/deploy/before-setup-tasks.yml for 192.168.10.11
+
+TASK [ansistrano.deploy : Send a mail] *************************************************************************************
+ok: [192.168.10.11 -> localhost]
+```
+
+```
+[root] # mailx
+Heirloom Mail version 12.5 7/5/10. Type ? for help.
+"/var/spool/mail/root": 1 message 1 new
+>N 1 root@localhost.local Tue Aug 21 14:41 28/946 "Starting deployment on localhost."
+```
+
+* Probablemente tendrá que reiniciar algunos servicios al final del despliegue, para vaciar las cachés, por ejemplo. Vamos a reiniciar Apache al final del despliegue:
+
+```
+---
+- hosts: ansible_clients
+ become: yes
+ become_user: root
+ vars:
+ dest: "/var/www/site/"
+ ansistrano_deploy_via: "git"
+ ansistrano_git_repo: https://github.com/alemorvan/demo-ansible.git
+ ansistrano_deploy_to: "{{ dest }}"
+ ansistrano_keep_releases: 3
+ ansistrano_shared_paths:
+ - "img"
+ - "css"
+ ansistrano_shared_files:
+ - "logs"
+ ansistrano_git_repo_tree: 'html'
+ ansistrano_git_branch: 'v2.0.0'
+ ansistrano_before_setup_tasks_file: "{{ playbook_dir }}/deploy/before-setup-tasks.yml"
+ ansistrano_after_symlink_tasks_file: "{{ playbook_dir }}/deploy/after-symlink-tasks.yml"
+
+ roles:
+ - { role: ansistrano.deploy }
+```
+
+Cree el fichero `deploy/after-symlink-tasks.yml`:
+
+```
+---
+- name: restart apache
+ systemd:
+ name: httpd
+ state: restarted
+```
+
+```
+TASK [ansistrano.deploy : include] *************************************************************************************
+included: /home/ansible/deploy/after-symlink-tasks.yml for 192.168.10.11
+
+TASK [ansistrano.deploy : restart apache] **************************************************************************************
+changed: [192.168.10.11]
+```
+
+Como ha visto durante este capítulo, Ansible puede mejorar mucho la vida del administrador de sistemas. Los roles muy inteligentes como Ansistrano se convierten rápidamente en indispensables.
+
+El uso de Ansistrano garantiza el respeto de las buenas prácticas en los despliegues, reduce el tiempo necesario para poner un sistema nuevo en producción y evita el riesgo de posibles errores humanos. ¡Las máquinas funcionan rápidas, bien y rara vez cometen errores.!
diff --git a/docs/books/learning_ansible/07-working-with-filters.es.md b/docs/books/learning_ansible/07-working-with-filters.es.md
new file mode 100644
index 0000000000..f66efe12a9
--- /dev/null
+++ b/docs/books/learning_ansible/07-working-with-filters.es.md
@@ -0,0 +1,484 @@
+---
+title: Trabajar con filtros
+author: Antoine Le Morvan
+contributors: Steven Spencer
+update: 23-11-2021
+---
+
+# Ansible - Trabajar con filtros
+
+En este capítulo aprenderá a transformar datos mediante filtros de Jinja.
+
+****
+
+**Objetivos**: En este capítulo aprenderá a:
+
+:heavy_check_mark: Transformar estructuras de datos como diccionarios o listas;
+:heavy_check_mark: Transformar variables;
+
+:checkered_flag: **ansible**, **jinja**, **filtros**
+
+**Conocimiento**: :star: :star: :star:
+**Complejidad**: :star: :star: :star: :star:
+
+**Tiempo de lectura**: 20 minutos
+
+****
+
+Ya hemos tenido la oportunidad, durante los capítulos anteriores, de utilizar los filtros de Jinja.
+
+Estos filtros, escritos en python, nos permiten manipular y transformar nuestras variables de ansible.
+
+!!! Note
+
+ Puede encontrar más información [aquí](https://docs.ansible.com/ansible/latest/user_guide/playbooks_filters.html).
+
+A lo largo de este capítulo, utilizaremos el siguiente playbook para probar los diferentes filtros presentados:
+
+```
+- name: Manipulating the data
+ hosts: localhost
+ gather_facts: false
+ vars:
+ zero: 0
+ zero_string: "0"
+ non_zero: 4
+ true_booleen: True
+ true_non_booleen: "True"
+ false_boolean: False
+ false_non_boolean: "False"
+ whatever: "It's false!"
+ user_name: antoine
+ my_dictionary:
+ key1: value1
+ key2: value2
+ my_simple_list:
+ - value_list_1
+ - value_list_2
+ - value_list_3
+ my_simple_list_2:
+ - value_list_3
+ - value_list_4
+ - value_list_5
+ my_list:
+ - element: element1
+ value: value1
+ - element: element2
+ value: value2
+
+ tasks:
+ - name: Print an integer
+ debug:
+ var: zero
+```
+
+!!! El comando leerá el flujo de entrada hasta que encuentre la palabra clave definida después de la redirección de entrada.
+
+ La siguiente es una lista no exhaustiva de los filtros que probablemente se encontrará o necesitará mientras trabaje con Ansible.
+ Afortunadamente, hay muchos otros. ¡Incluso podría escribir el suyo propio!
+
+El playbook se ejecutará de la siguiente manera:
+
+```
+ansible-playbook play-filter.yml
+```
+
+## Convertir datos
+
+Los datos se pueden convertir de un tipo a otro.
+
+Para conocer el tipo de un dato (el tipo en lenguaje python), hay que utilizar el filtro `type_debug`.
+
+Ejemplo:
+
+```
+- name: Display the type of a variable
+ debug:
+ var: true_boolean|type_debug
+```
+
+esto produce:
+
+```
+TASK [Display the type of a variable] ******************************************************************
+ok: [localhost] => {
+ "true_boolean|type_debug": "bool"
+}
+```
+
+Es posible transformar un entero en una cadena:
+
+```
+- name: Transforming a variable type
+ debug:
+ var: zero|string
+```
+
+```
+TASK [Transforming a variable type] ***************************************************************
+ok: [localhost] => {
+ "zero|string": "0"
+}
+```
+
+Convertir una cadena en un entero:
+
+```
+- name: Transforming a variable type
+ debug:
+ var: zero_string|int
+```
+
+o una variable en un booleano:
+
+```
+- name: Display an integer as a boolean
+ debug:
+ var: non_zero | bool
+
+- name: Display a string as a boolean
+ debug:
+ var: true_non_boolean | bool
+
+- name: Display a string as a boolean
+ debug:
+ var: false_non_boolean | bool
+
+- name: Display a string as a boolean
+ debug:
+ var: whatever | bool
+
+```
+
+Una cadena de caracteres se puede transformar a mayúsculas o minúsculas:
+
+```
+- name: Lowercase a string of characters
+ debug:
+ var: whatever | lower
+
+- name: Upercase a string of characters
+ debug:
+ var: whatever | upper
+```
+
+esto produce:
+
+```
+TASK [Lowercase a string of characters] *****************************************************
+ok: [localhost] => {
+ "whatever | lower": "it's false!"
+}
+
+TASK [Upercase a string of characters] *****************************************************
+ok: [localhost] => {
+ "whatever | upper": "IT'S FALSE!"
+}
+```
+
+El filtro `reemplazar` le permite sustituir unos caracteres por otros.
+
+En este ejemplo, eliminamos espacios o incluso sustituimos una palabra:
+
+```
+- name: Replace a character in a string
+ debug:
+ var: whatever | replace(" ", "")
+
+- name: Replace a word in a string
+ debug:
+ var: whatever | replace("false", "true")
+```
+
+esto produce:
+
+```
+TASK [Replace a character in a string] *****************************************************
+ok: [localhost] => {
+ "whatever | replace(\" \", \"\")": "It'sfalse!"
+}
+
+TASK [Replace a word in a string] *****************************************************
+ok: [localhost] => {
+ "whatever | replace(\"false\", \"true\")": "It's true !"
+}
+```
+
+El filtro `split` le permite dividir una cadena en una lista basada en un carácter:
+
+```
+- name: Cutting a string of characters
+ debug:
+ var: whatever | split(" ", "")
+```
+
+
+```
+TASK [Cutting a string of characters] *****************************************************
+ok: [localhost] => {
+ "whatever | split(\" \")": [
+ "It's",
+ "false!"
+ ]
+}
+```
+
+## Unir los elementos de una lista
+
+Es frecuente tener que unir los diferentes elementos de una lista en una única cadena. A continuación, podemos especificar un carácter o una cadena para insertar entre cada elemento.
+
+```
+- name: Joining elements of a list
+ debug:
+ var: my_simple_list|join(",")
+
+- name: Joining elements of a list
+ debug:
+ var: my_simple_list|join(" | ")
+```
+
+esto produce:
+
+```
+TASK [Joining elements of a list] *****************************************************************
+ok: [localhost] => {
+ "my_simple_list|join(\",\")": "value_list_1,value_list_2,value_list_3"
+}
+
+TASK [Joining elements of a list] *****************************************************************
+ok: [localhost] => {
+ "my_simple_list|join(\" | \")": "value_list_1 | value_list_2 | value_list_3"
+}
+
+```
+
+## Transformar diccionarios en listas (y viceversa)
+
+Los filtros `dict2items` y `itemstodict`, son filtros más complejos de implementar y se utilizan frecuentemente, especialmente en bucles.
+
+Tenga en cuenta que es posible especificar el nombre de la clave y del valor a utilizar en la transformación.
+
+```
+- name: Display a dictionary
+ debug:
+ var: my_dictionary
+
+- name: Transforming a dictionary into a list
+ debug:
+ var: my_dictionary | dict2items
+
+- name: Transforming a dictionary into a list
+ debug:
+ var: my_dictionary | dict2items(key_name='key', value_name='value')
+
+- name: Transforming a list into a dictionary
+ debug:
+ var: my_list | items2dict(key_name='element', value_name='value')
+```
+
+```
+TASK [Display a dictionary] *************************************************************************
+ok: [localhost] => {
+ "my_dictionary": {
+ "key1": "value1",
+ "key2": "value2"
+ }
+}
+
+TASK [Transforming a dictionary into a list] *************************************************************
+ok: [localhost] => {
+ "my_dictionary | dict2items": [
+ {
+ "key": "key1",
+ "value": "value1"
+ },
+ {
+ "key": "key2",
+ "value": "value2"
+ }
+ ]
+}
+
+TASK [Transforming a dictionary into a list] *************************************************************
+ok: [localhost] => {
+ "my_dictionary | dict2items (key_name = 'key', value_name = 'value')": [
+ {
+ "key": "key1",
+ "value": "value1"
+ },
+ {
+ "key": "key2",
+ "value": "value2"
+ }
+ ]
+}
+
+TASK [Transforming a list into a dictionary] ************************************************************
+ok: [localhost] => {
+ "my_list | items2dict(key_name='element', value_name='value')": {
+ "element1": "value1",
+ "element2": "value2"
+ }
+}
+```
+
+## Trabajar con listas
+
+Es posible fusionar o filtrar datos de una o varias listas:
+
+```
+- name: Merger of two lists
+ debug:
+ var: my_simple_list | union(my_simple_list_2)
+```
+
+```
+ok: [localhost] => {
+ "my_simple_list | union(my_simple_list_2)": [
+ "value_list_1",
+ "value_list_2",
+ "value_list_3",
+ "value_list_4",
+ "value_list_5"
+ ]
+}
+```
+
+Para mantener únicamente la intersección de las 2 listas (los valores presentes en las 2 listas):
+
+```
+- name: Merger of two lists
+ debug:
+ var: my_simple_list | intersect(my_simple_list_2)
+```
+
+```
+TASK [Merger of two lists] *******************************************************************************
+ok: [localhost] => {
+ "my_simple_list | intersect(my_simple_list_2)": [
+ "value_list_3"
+ ]
+}
+```
+
+O, por el contrario, mantener sólo la diferencia (los valores que no existen en la segunda lista):
+
+```
+- name: Merger of two lists
+ debug:
+ var: my_simple_list | difference(my_simple_list_2)
+```
+
+```
+TASK [Merger of two lists] *******************************************************************************
+ok: [localhost] => {
+ "my_simple_list | difference(my_simple_list_2)": [
+ "value_list_1",
+ "value_list_2",
+ ]
+}
+```
+
+Si su lista contiene valores que no son únicos, también es posible filtrarlos mediante el filtro `unique`.
+
+```
+- name: Unique value in a list
+ debug:
+ var: my_simple_list | unique
+```
+
+## Transformación json/yaml
+
+Es posible que tenga que importar datos en formato json (desde una API, por ejemplo) o exportar datos en formato yaml o json.
+
+```
+- name: Display a variable in yaml
+ debug:
+ var: my_list | to_nice_yaml(indent=4)
+
+- name: Display a variable in json
+ debug:
+ var: my_list | to_nice_json(indent=4)
+```
+
+```
+TASK [Display a variable in yaml] ********************************************************************
+ok: [localhost] => {
+ "my_list | to_nice_yaml(indent=4)": "- element: element1\n value: value1\n- element: element2\n value: value2\n"
+}
+
+TASK [Display a variable in json] ********************************************************************
+ok: [localhost] => {
+ "my_list | to_nice_json(indent=4)": "[\n {\n \"element\": \"element1\",\n \"value\": \"value1\"\n },\n {\n \"element\": \"element2\",\n \"value\": \"value2\"\n }\n]"
+}
+```
+
+## Valores por defecto, variables opcionales, variables protegidas
+
+Se encontrará rápidamente con errores en la ejecución de sus playbooks si no proporciona valores por defecto para sus variables, o si no las proteges.
+
+Si no existe el valor de una variable, se puede ser sustituir por otro valor mediante el filtro `default`:
+
+```
+- name: Default value
+ debug:
+ var: variablethatdoesnotexists | default(whatever)
+```
+
+```
+TASK [Default value] ********************************************************************************
+ok: [localhost] => {
+ "variablethatdoesnotexists | default(whatever)": "It's false!"
+}
+```
+
+Observe la presencia del apóstrofe `'` que debería estar protegido, por ejemplo, si utiliza el modulo `shell`:
+
+```
+- name: Default value
+ debug:
+ var: variablethatdoesnotexists | default(whatever| quote)
+```
+
+```
+TASK [Default value] ********************************************************************************
+ok: [localhost] => {
+ "variablethatdoesnotexists | default(whatever|quote)": "'It'\"'\"'s false!'"
+}
+```
+
+Finalmente, si no existe una variable opcional en un módulo se puede ignorar utilizando con la palabra clave `omit` en el filtro `default`, lo que le ahorrará un error en tiempo de ejecución.
+
+```
+- name: Add a new user
+ ansible.builtin.user:
+ name: "{{ user_name }}"
+ comment: "{{ user_comment | default(omit) }}"
+```
+
+## Asociar un valor en función de otro (`ternary`)
+
+A veces es necesario utilizar una condición para asignar un valor a una variable, en cuyo caso es común pasar por un paso `set_fact`.
+
+Esto se puede evitar utilizando el filtro `ternary`:
+
+```
+- name: Default value
+ debug:
+ var: (user_name == 'antoine') | ternary('admin', 'normal_user')
+```
+
+```
+TASK [Default value] ********************************************************************************
+ok: [localhost] => {
+ "(user_name == 'antoine') | ternary('admin', 'normal_user')": "admin"
+}
+```
+
+## Otros filtros
+
+ * `{{ 10000 | random }}`: Como su nombre indica, da un valor aleatorio.
+ * `{{ my_simple_list | first }}`: Extrae el primer elemento de la lista.
+ * `{{ my_simple_list | length }}`: Da la longitud (de una lista o una cadena).
+ * `{{ ip_list | ansible.netcommon.ipv4 }}`: Sólo muestra las IPs v4. Sin insistir en esto, si lo necesita, hay muchos filtros dedicados a la red.
+ * `{{ user_password | password_hash('sha512') }}`: Genera una contraseña con hash en sha512.
diff --git a/docs/books/learning_ansible/08-management-server-optimizations.es.md b/docs/books/learning_ansible/08-management-server-optimizations.es.md
new file mode 100644
index 0000000000..f6ffdb37d8
--- /dev/null
+++ b/docs/books/learning_ansible/08-management-server-optimizations.es.md
@@ -0,0 +1,200 @@
+---
+title: Optimizaciones del servidor de administración
+author: Antoine Le Morvan
+contributors: Steven Spencer
+update: 06-Dec-2021
+---
+
+# Optimizaciones del servidor de administración
+
+En este capítulo revisaremos las opciones de configuración que pueden ser de interés para optimizar nuestro servidor de administración de Ansible.
+
+## El archivo de configuración `ansible.cfg`
+
+A continuación vamos a comentar algunas opciones de configuración interesantes de Ansible:
+
+* `forks`: Establecido por defecto a 5, es el número de procesos que Ansible lanzará en paralelo para comunicarse con los hosts remotos. Cuanto más alto sea este número, más clientes podrá gestionar Ansible al mismo tiempo, y así acelerar los procesos. El valor que puede establecer depende de los límites de CPU/RAM de su servidor de administración. Tenga en cuenta que el valor por defecto, `5`, es muy pequeño, la documentación de Ansible indica que muchos usuarios lo establecen en 50, en 500 o incluso en valores más altos.
+
+* `gathering`: Esta variable cambia la política de recogida de datos. Por defecto, el valor se establece a `implicit`, lo que implica que los datos se recopilarán sistemáticamente. El cambio de esta variable a `smart` permite recopilar las colecciones de datos sólo cuando no se han recogido con anterioridad. Si se combina con una caché de datos (véase más adelante), esta opción puede aumentar considerablemente el rendimiento.
+
+* `host_key_checking`: ¡Cuidado con la seguridad de su servidor! Sin embargo, si tiene control de su entorno, puede ser interesante desactivar el control de llaves de sus servidores remotos y ahorrar algo de tiempo en la conexión. En servidores remotos, puede deshabilitar el uso de DNS en el servidor SSH (en `/etc/sshd_config`, medianrte la opción `UseDNS no`). Esta opción hace perder tiempo en la conexión y, la mayoría de las veces, sólo se utiliza para los registros de conexión.
+
+* `ansible_managed`: Esta variable, que contiene el valor `Ansible managed` por defecto, se suele utilizar en plantillas de archivos que se despliegan en servidores remotos. Permite a un administrador especificar que el archivo se gestiona automáticamente y que potencialmente cualquier cambio que haga en él se perderá. Puede ser interesante que los administradores tengan mensajes más completos. Sin embargo, tenga cuidado, si cambia esta variable, puede hacer que los demonios se reinicien (a través de los handlers asociados a las plantillas).
+
+* `ssh_args = -C -o ControlMaster=auto -o ControlPersist=300s -o PreferredAuthentications=publickey`: Especificar las opciones de conexión mediante ssh. Puede ahorrar mucho tiempo, si desactiva todos los métodos de autenticación que no sean de clave pública. También puede incrementar el valor del parámetro `ControlPersist` para mejorar el rendimiento (la documentación sugiere que un valor equivalente a 30 minutos puede ser apropiado). La conexión con un cliente permanecerá abierta durante más tiempo y podrá reutilizarse cuando se vuelva a conectar al mismo servidor, lo que supone un importante ahorro de tiempo.
+
+* `control_path_dir`: Especifica la ruta de acceso a los sockets de conexión. Si la ruta es demasiado larga, puede provocar problemas. Valore la posibilidad de cambiarlo por algo más corto, como `/tmp/.cp`.
+
+* `pipelining`: El establecer este valor a `True` aumenta el rendimiento al reducir el número de conexiones SSH necesarias cuando se ejecutan los módulos remotos. Primero debe asegurarse de que la opción `requiretty` está desactivada en las opciones de `sudoers` (vea la documentación).
+
+## Almacenamiento de los datos
+
+La recopilación de datos es un proceso que puede llevar algún tiempo. Puede resultar interesante desactivar la recopilación de datos para los playbooks que no la necesiten (mediante la opción `gather_facts`) o mantener estos datos en una memoria caché durante un periodo de tiempo determinado (por ejemplo 24H).
+
+Estos datos se pueden almacenar fácilmente en una base de datos `redis`:
+
+```
+sudo yum install redis
+sudo systemctl start redis
+sudo systemctl enable redis
+sudo pip3 install redis
+```
+
+No olvide modificar la configuración de ansible:
+
+```
+fact_caching = redis
+fact_caching_timeout = 86400
+fact_caching_connection = localhost:6379:0
+```
+
+Para comprobar el correcto funcionamiento, basta con hacer una petición al servidor `redis`:
+
+```
+redis-cli
+127.0.0.1:6379> keys *
+127.0.0.1:6379> get ansible_facts_SERVERNAME
+```
+
+## Utilizar Vault
+
+Las distintas contraseñas y secretos no e pueden almacenar en texto plano dentro del código de Ansible, ni localmente en el servidor de gestión ni en una posible herramienta de gestión de código fuente.
+
+Ansible propone utilizar un gestor de encriptado: `ansible-vault`.
+
+El principio es cifrar una variable o un archivo completo mediante el comando `ansible-vault`.
+
+Ansible podrá descifrar este archivo en tiempo de ejecución recuperando la clave de cifrado del archivo (por ejemplo) `/etc/ansible/ansible.cfg`. Esto último también puede ser un script de python o cualquier otra cosa.
+
+Edite el archivo `/etc/ansible/ansible.cfg`:
+
+```
+#vault_password_file = /path/to/vault_password_file
+vault_password_file = /etc/ansible/vault_pass
+```
+
+Guarde la contraseña en el archivo `/etc/ansible/vault_pass` y asigne los permisos y las restricciones necesarias:
+
+```
+mysecretpassword
+```
+
+A continuación, puede encriptar sus archivos mediante el comando:
+
+```
+ansible-vault encrypt myfile.yml
+```
+
+Un archivo encriptado mediante `ansible-vault` se puede reconocer fácilmente por su cabecera:
+
+```
+$ANSIBLE_VAULT;1.1;AES256
+35376532343663353330613133663834626136316234323964333735363333396136613266383966
+6664322261633261356566383438393738386165333966660a343032663233343762633936313630
+34373230124561663766306134656235386233323964336239336661653433663036633334366661
+6434656630306261650a313364636261393931313739363931336664386536333766326264633330
+6334
+```
+
+Una vez que un archivo está encriptado, todavía puede editarse mediante el comando:
+
+```
+ansible-vault edit myfile.yml
+```
+
+También puede delegar el almacenamiento de contraseñas a su gestor de contraseñas de confianza.
+
+Por ejemplo, para recuperar una contraseña que estaría almacenada en la aplicación Rundeck:
+
+```
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+import urllib.request
+import io
+import ssl
+
+def get_password():
+ '''
+ :return: Vault password
+ :return_type: str
+ '''
+ ctx = ssl.create_default_context()
+ ctx.check_hostname = False
+ ctx.verify_mode = ssl.CERT_NONE
+
+ url = 'https://rundeck.rockylinux.org/api/11/storage/keys/ansible/vault'
+ req = urllib.request.Request(url, headers={
+ 'Accept': '*/*',
+ 'X-Rundeck-Auth-Token': '****token-rundeck****'
+ })
+ response = urllib.request.urlopen(req, context=ctx)
+
+ return response.read().decode('utf-8')
+
+if __name__ == '__main__':
+ print(get_password())
+```
+
+## Trabajar con servidores Windows
+
+Será necesario instalar en el servidor de gestión varios paquetes:
+
+* Mediante el gestor de paquetes:
+
+```
+sudo dnf install python38-devel krb5-devel krb5-libs krb5-workstation
+```
+
+y configure el archivo `/etc/krb5.conf` para especificar el valor correcto de los `realms`:
+
+```
+[realms]
+ROCKYLINUX.ORG = {
+ kdc = dc1.rockylinux.org
+ kdc = dc2.rockylinux.org
+}
+[domain_realm]
+ .rockylinux.org = ROCKYLINUX.ORG
+```
+
+* Mediante el gestor de paquetes de Python:
+
+```
+pip3 install pywinrm
+pip3 install pywinrm[credssp]
+pip3 install kerberos requests-kerberos
+```
+
+## Trabajar con módulos IP
+
+Lo módulos de red normalmente requieren el uso del módulo de python `netaddr`:
+
+```
+sudo pip3 install netaddr
+```
+
+## Generación de una CMDB
+
+Se ha desarrollado una herramienta, `ansible-cmdb` para generar una CMDB desde ansible.
+
+```
+pip3 install ansible-cmdb
+```
+
+Los "facts" se deben exportar mediante ansible con el siguiente comando:
+
+```
+ansible --become --become-user=root -o -m setup --tree /var/www/ansible/cmdb/out/
+```
+
+A continuación, puede generar un archivo `json` global:
+
+```
+ansible-cmdb -t json /var/www/ansible/cmdb/out/linux > /var/www/ansible/cmdb/cmdb-linux.json
+```
+
+Si prefiere una interfaz web:
+
+```
+ansible-cmdb -t html_fancy_split /var/www/ansible/cmdb/out/
+```
diff --git a/docs/books/learning_rsync/01_rsync_overview.it.md b/docs/books/learning_rsync/01_rsync_overview.it.md
index 803a9038d3..c14fa5010b 100644
--- a/docs/books/learning_rsync/01_rsync_overview.it.md
+++ b/docs/books/learning_rsync/01_rsync_overview.it.md
@@ -43,7 +43,7 @@ L'originale `rsync` è stato mantenuto dal programmatore australiano |pull/download|RockyLinux8;
## Dimostrazione basata sul protocollo SSH
-!!! tip "Attenzione!"
+!!! tip "Suggerimento"
Qui, sia Rocky Linux 8 che Fedora 34 utilizzano l'utente root per accedere. Fedora 34 è il client e Rocky Linux 8 è il server.
@@ -92,7 +92,7 @@ aabbcc
```
Trasferimento effettuato con successo.
-!!! tip "Attenzione"
+!!! tip "Suggerimento"
Se la porta SSH del server non è quella predefinita la 22, puoi specificare la porta in modo simile ---`rsync -avz -e 'ssh -p [port]' `.
diff --git a/docs/books/learning_rsync/06_rsync_inotify.it.md b/docs/books/learning_rsync/06_rsync_inotify.it.md
index fcfd57aa9c..615ff697e9 100644
--- a/docs/books/learning_rsync/06_rsync_inotify.it.md
+++ b/docs/books/learning_rsync/06_rsync_inotify.it.md
@@ -142,7 +142,7 @@ $a | while read directory event file
[root@Rocky ~]# bash /root/rsync_inotify.sh &
```
-!!! tip "sottolineare ancora!"
+!!! tip "Suggerimento!"
Quando si utilizza il protocollo SSH per la trasmissione della sincronizzazione dei dati, se la porta di servizio SSH della macchina di destinazione non è la 22, puoi usare un metodo simile a questo——
`b="/usr/bin/rsync -avz -e 'ssh -p [port-number]' /rsync/* testfedora@192. 68.100.5:/home/testfedora/"`
diff --git a/docs/guides/cms/dokuwiki_server.es.md b/docs/guides/cms/dokuwiki_server.es.md
new file mode 100644
index 0000000000..84aa6ef603
--- /dev/null
+++ b/docs/guides/cms/dokuwiki_server.es.md
@@ -0,0 +1,308 @@
+---
+title: DokuWiki
+author: Steven Spencer
+contributors: Ezequiel Bruni
+tested with: 8.5, 8.6, 9.0
+tags:
+ - wiki
+ - documentación
+---
+
+# Servidor DokuWiki
+
+## Requisitos previos y supuestos
+
+* Una instancia de Rocky Linux instalada en un servidor, contenedor o máquina virtual.
+* Comodidad para modificar los archivos de configuración desde la línea de comandos con un editor (nuestros ejemplos aquí utilizarán _vi_, pero puede sustituirlo por su editor favorito)
+* Algunos conocimientos sobre aplicaciones web y su configuración.
+* Nuestro ejemplo utilizará la rutina [Apache Sites Enabled](../web/apache-sites-enabled.md) para la configuración, por lo que es una buena idea revisar esa rutina si planea seguir adelante.
+* Utilizaremos "wiki-doc.sudominio.com" como nombre de dominio a lo largo de este ejemplo.
+* Asumiremos a lo largo de este documento que usted es el usuario root o puede llegar a él con _sudo_.
+* Estamos asumiendo que está utilizando una instalación limpia del sistema operativo, sin embargo esto es **NO** un requisito.
+
+## Introducción
+
+La documentación puede adoptar muchas formas en una organización. Disponer de un repositorio en el que poder consultar esa documentación tiene un valor incalculable. Un wiki (que significa _rápido_ en hawaiano), es una forma de mantener la documentación, las notas de los procesos, las bases de conocimiento corporativas, e incluso los ejemplos de código, en una ubicación centralizada. Los profesionales de la informática que mantienen un wiki, aunque sea en secreto, tienen una póliza de seguro incorporada contra el olvido de una oscura rutina.
+
+DokuWiki es un wiki maduro y rápido que se ejecuta sin base de datos, tiene características de seguridad incorporadas y es relativamente fácil de implementar. Para más información sobre lo que DokuWiki puede hacer, eche un vistazo a su [página web](https://www.dokuwiki.org/dokuwiki).
+
+DokuWiki es sólo uno de los muchos wiki disponibles, aunque es bastante bueno. Una gran ventaja de DokuWiki es que es relativamente ligero y puede ejecutarse en un servidor que ya esté ejecutando otros servicios, siempre que se disponga de espacio y memoria.
+
+## Instalar dependencias
+
+La versión mínima de PHP para DokuWiki es 7.2, que es exactamente la misma que se incluye con Rocky Linux 8. Rocky Linux 9.0 viene con la versión 8.0 de PHP, que también es totalmente compatible. Aquí se especifican paquetes que pueden estar ya instalados:
+
+`dnf install tar wget httpd php php-gd php-xml php-json php-mbstring`
+
+Verá una lista de dependencias adicionales que se instalarán y este aviso:
+
+`Is this ok [y/N]:`
+
+Continue y responda con "y" y pulse 'Entrar' para instalar.
+
+## Crear directorios y modificar la configuración
+
+### Configuración de Apache
+
+Si ha leído el procedimiento [Apache Sites Enabled](../web/apache-sites-enabled.md), sabe que necesitamos crear algunos directorios. Comenzaremos con las adiciones al directorio de configuración _httpd_:
+
+`mkdir -p p/httpd/{sites-available,sites-enabled}`
+
+Necesitamos editar el archivo httpd.conf:
+
+`vi /etc/httpd/conf/httpd.conf`
+
+Y añada esto al final del archivo:
+
+`Include /etc/httpd/sites-enabled`
+
+Cree el archivo de configuración del sitio en la carpeta sites-available:
+
+`vi /etc/httpd/sites-available/com.yourdomain.wiki-doc`
+
+Ese archivo de configuración debería ser algo así:
+
+```
+
+ ServerName wiki-doc.yourdomain.com
+ DocumentRoot /var/www/sub-domains/com.yourdomain.wiki-doc/html
+
+
+
+ AllowOverride All
+ Require all denied
+
+
+ Order allow,deny
+ Deny from all
+
+
+
+ ErrorLog /var/log/httpd/wiki-doc.yourdomain.com_error.log
+ CustomLog /var/log/httpd/wiki-doc.yourdomain_access.log combined
+
+```
+
+Tenga en cuenta que la opción "AllowOverride All" incluido más arriba, permite que el archivo .htaccess (seguridad específica del directorio) funcione.
+
+Continue y enlace el archivo de configuración en sites-enabled, pero todavía no inicie los servicios web:
+
+`ln -s /etc/httpd/sites-available/com.yourdomain.wiki-doc /etc/httpd/sites-enabled/`
+
+### Apache DocumentRoot
+
+También necesitamos crear nuestro _DocumentRoot_. Para hacer esto:
+
+`mkdir -p /var/www/sub-domains/com.yourdomain.wiki-doc/html`
+
+## Instalar DokuWiki
+
+En su servidor, cambie al directorio raíz.
+
+`cd /root`
+
+Ahora que tenemos nuestro entorno listo para empezar, vamos a obtener la última versión estable de DokuWiki. Puedes encontrarla yendo a [la página de descargas](https://download.dokuwiki.org/) y en la parte izquierda de la página en la sección "Version" podrá ver "Stable (Recommended) (direct link)."
+
+Haga clic derecho en la parte "(direct link)" y copie la dirección del enlace. En la consola de su servidor DokuWiki, escribe "wget", un espacio y pégue el enlace que ha copiado en el terminal. Debería ver algo como esto:
+
+`wget https://download.dokuwiki.org/src/dokuwiki/dokuwiki-stable.tgz`
+
+Antes de descomprimir el archivo, eche un vistazo a su contenido utiliznado el comando `tar ztf` para ver el contenido del archivo:
+
+`tar ztvf dokuwiki-stable.tgz`
+
+¿Ve el directorio con la fecha delante de los demás archivos?
+
+```
+... (more above)
+dokuwiki-2020-07-29/inc/lang/fr/resetpwd.txt
+dokuwiki-2020-07-29/inc/lang/fr/draft.txt
+dokuwiki-2020-07-29/inc/lang/fr/recent.txt
+... (more below)
+```
+No queremos ese directorio con nombre inicial al descomprimir el archivo, así que vamos a utilizar algunas opciones de `tar` para excluirlo. La primera opción es "--strip-components=1" que elimina ese directorio inicial.
+
+La segunda opción es la opción "-C", y que le indica al comando `tar` dónde queremos que se descomprima el archivo. Así que descomprima el archivo con siguiente comando:
+
+`tar xzf dokuwiki-stable.tgz --strip-components=1 -C /var/www/sub-domains/com.yourdomain.wiki-doc/html/`
+
+Una vez que hayamos ejecutado este comando, DokuWiki debería descomprimido estar en nuestro _DocumentRoot_.
+
+Necesitamos hacer una copia del archivo_.htaccess.dist _ que viene con DokuWiki y mantener el antiguo allí también, en caso de que tengamos que volver al contenido original en un futuro.
+
+En el proceso, cambiaremos el nombre de este archivo a _. htaccess_ que es lo que _Apache_ buscará. Para hacer esto:
+
+`cp /var/www/sub-domains/com.yourdomain.wiki-doc/html/.htaccess{.dist,}`
+
+Ahora necesitamos cambiar el propietario del nuevo directorio y sus archivos al usuario y grupo _apache_:
+
+`chown -Rf apache.apache /var/www/sub-domains/com.yourdomain.wiki-doc/html`
+
+## Configurar DNS o /etc/hosts
+
+Antes de poder acceder a la interfaz de DokuWiki, necesitará establecer la resolución de nombres para este sitio. Con fines de prueba, puede utilizar su archivo _/etc/hosts_.
+
+En este ejemplo, vamos a suponer que DokuWiki se ejecutará en la dirección IPv4 privada 10.56.233.179. Supongamos también que está modificando el archivo _/etc/hosts_ en una estación de trabajo Linux. Para hacer esto, ejecute:
+
+`sudo vi /etc/hosts`
+
+Y luego modifique su archivo de hosts para que se vea tal y como se muestra a continuación (vea la dirección IP anterior en el ejemplo que se muestra a continuación):
+
+```
+127.0.0.1 localhost
+127.0.1.1 myworkstation-home
+10.56.233.179 wiki-doc.yourdomain.com wiki-doc
+
+# The following lines are desirable for IPv6 capable hosts
+::1 ip6-localhost ip6-loopback
+fe00::0 ip6-localnet
+ff00::0 ip6-mcastprefix
+ff02::1 ip6-allnodes
+ff02::2 ip6-allrouters
+```
+
+Una vez que ha terminado de probar y esté listo para poner docuwiki en producción y disponible para todos, necesitará agregar este host a un servidor DNS. Puede hacer esto utilizando un [servidor DNS privado](../dns/private_dns_server_using_bind.md)o un servidor DNS público.
+
+## Iniciar httpd
+
+Antes de comenzar _httpd_ vamos a probar para asegurarnos de que nuestra configuración está aceptada:
+
+`httpd -t`
+
+Debería obtener:
+
+`Syntax OK`
+
+Si es así, debería estar listo para iniciar _httpd_ y luego finalizar la configuración. Empecemos activando _httpd_ para que se inicie al arrancar el sistema:
+
+`systemctl enable httpd`
+
+Y luego iniciar el servicio:
+
+`systemctl start httpd`
+
+## Probar DokuWiki
+
+Ahora que nuestro nombre de host está configurado para las pruebas y el servicio web se ha iniciado, el siguiente paso es abrir un navegador web y escribir la siguiente URL en la barra de direcciones:
+
+`http://wiki-doc/install.php`
+
+O
+
+`http://wiki-doc.yourdomain.com/install.php`
+
+Cualquiera de los dos debería funcionar si se configura el archivo de hosts como se indica más arriba. Esto le llevará a la pantalla de configuración para que pueda terminar la configuración:
+
+* En el campo "Wiki Name", escriba el nombre del wiki. Por ejemplo, "Documentación Técnica"
+* En el campo "Superuser", escriba el nombre de usuario administrador. Ejemplo "admin"
+* En el campo "Nombre real", escriba el nombre real para el usuario administrativo.
+* En el campo "E-Mail", escriba la dirección de correo electrónico del usuario administrador.
+* En el campo "Password", escriba una contraseña segura para el usuario administrador.
+* En el campo "una vez más", vuelva a escribir la misma contraseña.
+* En el menú desplegable "Initial ACL Policy", elija la opción que mejor funcione para su entorno.
+* Elija la casilla de verificación apropiada para la licencia bajo la que desea poner su contenido.
+* Deje marcada (o desmarque si lo prefiere) la casilla "Once a month, send anonymous usage data to the DokuWiki developers"
+* Haga clic en el botón "Guardar"
+
+Ahora su wiki está preparado para que añada contenido.
+
+## Asegurar DokuWiki
+
+Además de la política ACL que acaba de crear, considere:
+
+### Su cortafuegos
+
+!!! note
+
+ Ninguno de estos ejemplos de cortafuegos hace ningún tipo de suposición sobre qué otros servicios podrías necesitar permitir en tu servidor Dokuwiki. Estas reglas se basan en nuestro entorno de pruebas y **SOLO** se ocupan de permitir el acceso a un bloque ip de la red LOCAL. Necesitará más servicios permitidos para un servidor de producción.
+
+Antes de decir que todo está hecho, hay que pensar en la seguridad. Primero, debería estar ejecutando un cortafuegos en el servidor. Supondremos que está utilizando uno de los cortafuegos indicado más abajo.
+
+En lugar de permitir que todo el mundo tenga acceso al wiki, vamos a suponer que cualquier persona de la red 10.0.0.0/8 está en su red de área local privada, y que esas son las únicas personas que necesitan acceder al sitio.
+
+#### Cortafuegos `iptables` (obsoleto)
+
+!!! important
+
+ El proceso de cortafuegos `iptables` ha quedado obsoleto en Rocky Linux 9.0 (todavía está disponible, pero es probable que desaparezca en futuras versiones, quizás ya en Rocky Linux 9.1). Por esta razón, le recomendamos saltar al procedimiento `firewalld` mas abajo si estás siguiendo esta docuemntación conRocky Linux 9.0 o posterior.
+
+Tenga en cuenta que puede que necesite otras reglas para el resto de servicios en este servidor, y que en este ejemplo sólo se tienen en cuenta los servicios web.
+
+En primer lugar, modifique o cree el archivo _/etc/firewall.conf_:
+
+`vi /etc/firewall.conf`
+
+```
+#IPTABLES=/usr/sbin/iptables
+
+# Unless specified, the defaults for OUTPUT is ACCEPT
+# The default for FORWARD and INPUT is DROP
+#
+echo " clearing any existing rules and setting default policy.."
+iptables -F INPUT
+iptables -P INPUT DROP
+# web ports
+iptables -A INPUT -p tcp -m tcp -s 10.0.0.0/8 --dport 80 -j ACCEPT
+iptables -A INPUT -p tcp -m tcp -s 10.0.0.0/8 --dport 443 -j ACCEPT
+iptables -A INPUT -i lo -j ACCEPT
+iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
+iptables -A INPUT -p tcp -j REJECT --reject-with tcp-reset
+iptables -A INPUT -p udp -j REJECT --reject-with icmp-port-unreachable
+
+/usr/sbin/service iptables save
+```
+
+Una vez que ha creado el script, asegúrese de que es ejecutable:
+
+`chmod +x /firewall.conf`
+
+Luego ejecuta el script:
+
+`/etc/firewall.conf`
+
+Esto ejecutará las reglas y las guardará para que sea recarguen en el próximo inicio de _iptables_ o al próximo arranque del sistema.
+
+#### Cortafuegos `firewalld`
+
+Si utiliza `firewalld` como cortafuegos (y a estas alturas, probablemente *debería*) puede aplicar los mismos conceptos utilizando la sintaxis de `firewalld's firewall-cmd`.
+
+Vamos a duplicar las reglas `iptables` (arriba) con `firewalld` reglas:
+
+```
+firewall-cmd --zone=confiable --add-source=10.0.0.0/8 --permanent
+firewall-cmd --zone=confiable --add-service=http --add-service=https --permanent
+firewall-cmd --reload
+```
+
+Una vez que ha añadido las reglas anteriores y ha recargado el servicio firewalld, liste su zona para asegurarse de que todo lo que necesita está ahí:
+
+```
+firewall-cmd --zone=trusted --list-all
+```
+
+que debería mostrarte algo así si todo lo anterior ha funcionado correctamente:
+
+```
+trusted (active)
+ target: ACCEPT
+ icmp-block-inversion: no
+ interfaces:
+ sources: 10.0.0.0/8
+ services: http https
+ ports:
+ protocols:
+ forward: yes
+ masquerade: no
+ forward-ports:
+ source-ports:
+ icmp-blocks:
+ rich rules:
+```
+
+### SSL
+
+Para tener más seguridad, debería considerar el uso de un SSL para que todo el tráfico web esté cifrado. Puede comprar un certificado SSL directamente de un proveedor o utilizar [Let's Encrypt](../security/generating_ssl_keys_lets_encrypt.md)
+
+## Conclusión
+
+Ya sea que necesites documentar procesos, políticas de la empresa, códigos de programas o cualquier otra cosa, un wiki es una gran manera de hacerlo. DokuWiki es un producto seguro, flexible, fácil de usar, relativamente fácil de instalar y desplegar, y es un proyecto estable que ha existido durante muchos años.
diff --git a/docs/guides/containers/lxd_web_servers.it.md b/docs/guides/containers/lxd_web_servers.it.md
index b6d1f20cb7..e1c2fda890 100644
--- a/docs/guides/containers/lxd_web_servers.it.md
+++ b/docs/guides/containers/lxd_web_servers.it.md
@@ -9,7 +9,7 @@ update: 28-Feb-2022
## Introduzione
-Okay, così abbiamo già [una guida per l'installazione di LXD/LXC su Rocky Linux](../../books/lxd_server/00-toc.md), ma questo è stato scritto da qualcuno che sa cosa sta facendo, e voleva costruire una rete containerizzata di server e/o applicazioni su una macchina fisica sulla sua rete locale. È fantastico, e ne ruberò subito dei pezzi per non dover scrivere tanto.
+Ok, abbiamo già [una guida sull'installazione di LXD/LXC su Rocky Linux](../../books/lxd_server/00-toc.md), ma è stata scritta da qualcuno che sa cosa stava facendo e che voleva costruire una rete containerizzata di server e/o applicazioni su una macchina fisica della sua rete locale. È fantastico, e ne ruberò subito dei pezzi per non dover scrivere tanto.
Ma se avete appena sentito parlare di Linux Containers e non avete ancora capito bene come funzionano, ma volete ospitare qualche sito web, questa è la guida che fa per voi. *Questo tutorial vi insegnerà come ospitare siti web di base con LXD e LXC su qualsiasi sistema, compresi i server privati virtuali e il cloud hosting.*
diff --git a/docs/guides/security/dnf_automatic.es.md b/docs/guides/security/dnf_automatic.es.md
new file mode 100644
index 0000000000..55b7c7757c
--- /dev/null
+++ b/docs/guides/security/dnf_automatic.es.md
@@ -0,0 +1,120 @@
+---
+title: Parcheo con dnf-automatic
+author: Antoine Le Morvan
+contributors: Steven Spencer
+tested with: 8.5
+tags:
+ - seguridad
+ - dnf
+ - automatización
+ - actualizaciones
+---
+
+# Parchear servidores con `dnf-automatic`
+
+La gestión de la instalación de actualizaciones de seguridad es un tema importante para el administrador del sistema. El proceso de proporcionar actualizaciones de software es un camino bien transitado que, en última instancia, causa pocos problemas. Por ese motivo, es razonable automatizar la descarga y aplicación de actualizaciones diarias y automáticas en los servidores que ejecuten Rocky Linux.
+
+La seguridad de su sistema de información se verá reforzada. `dnf-automatic` es una herramienta adicional que le permitirá lograrlo.
+
+!!! hint "Si estás preocupado..."
+
+ Hace años, aplicar actualizaciones automáticamente como esta habría sido una receta para el desastre. En muchas ocasiones, una actualización aplicada podría provocar problemas. Esto sigue ocurriendo en raras ocasiones, cuando una actualización de un paquete elimina una característica obsoleta que se utiliza en el servidor, pero en su mayor parte, esto es raro que suceda. Dicho esto, si aún se siente incómodo dejando que la herramienta `dnf-automatic` maneje sus actualizaciones, considere utilizarlo para descargar y/o notificar que hay actualizaciones disponibles. De esa manera su servidor no permanecerá sin actualizar durante mucho tiempo. Estas características son `dnf-automatic-notifyonly` y `dnf-automatic-download`
+
+ Para más información sobre estas características, eche un vistazo a la [documentación oficial](https://dnf.readthedocs.io/en/latest/automatic.html).
+
+## Instalación
+
+Puede instalar `dnf-automatic` desde los repositorios de Rocky Linux:
+
+```
+sudo dnf install dnf-automatic
+```
+
+## Configuración
+
+De forma predeterminada, el proceso de actualización comenzará a las 6am, con un delta de tiempo aleatorio extra para evitar que todas sus máquinas se actualicen al mismo tiempo. Para cambiar este comportamiento, debe sobreescribir la configuración del temporizador asociada con el servicio de la aplicación:
+
+```
+sudo systemctl edit dnf-automatic.timer
+
+[Unit]
+Description=dnf-automatic timer
+# Ver comentario en dnf-makecache.service
+ConditionPathExists=!/run/ostree-booted
+Wants=network-online. Apuntar
+
+[Timer]
+OnCalendar=*-*-* 6:00
+RandomizedDelaySec=10m
+Persistent=true
+
+[Install]
+WantedBy=timers.target
+```
+
+Esta configuración reduce el retraso en el inicio entre las 6:00 y las 6:10 am. (Un servidor que se apague en este momento sería parcheado automáticamente después de su reinicio.)
+
+Luego active el temporizador asociado al servicio (no el servicio en sí):
+
+```
+$ sudo systemctl enable --now dnf-automatic.timer
+```
+
+## ¿Qué pasa con los servidores CentOS 7?
+
+!!! tip
+
+ Sí, esta es la documentación de Rocky Linux, pero si usted es un administrador de sistemas o red, puede que disponga de algunas máquinas ejecutando CentOS 7. Lo entendemos, y por eso incluimos esta sección en la documentación.
+
+El proceso bajo CentOS 7 es similar pero utiliza la herramienta: `yum-cron`.
+
+```
+$ sudo yum install yum-cron
+```
+
+Esta vez la configuración del servicio se realiza en el archivo `/etc/yum/yum-cron.conf`.
+
+Establezca la configuración según sea necesario:
+
+```
+[commands]
+# What kind of update to use:
+# default = yum upgrade
+# security = yum --security upgrade
+# security-severity:Critical = yum --sec-severity=Critical upgrade
+# minimal = yum --bugfix update-minimal
+# minimal-security = yum --security update-minimal
+# minimal-security-severity:Critical = --sec-severity=Critical update-minimal
+update_cmd = default
+
+# Whether a message should be emitted when updates are available,
+# were downloaded, or applied.
+update_messages = yes
+
+# Whether updates should be downloaded when they are available.
+download_updates = yes
+
+# Whether updates should be applied when they are available. Note
+# that download_updates must also be yes for the update to be applied.
+apply_updates = yes
+
+# Maximum amout of time to randomly sleep, in minutes. The program
+# will sleep for a random amount of time between 0 and random_sleep
+# minutes before running. This is useful for e.g. staggering the
+# times that multiple systems will access update servers. If
+# random_sleep is 0 or negative, the program will run immediately.
+# 6*60 = 360
+random_sleep = 30
+```
+
+Los comentarios en el archivo de configuración hablan por sí mismos.
+
+Ahora puede activar el servicio e iniciarlo:
+
+```
+$ sudo systemctl enable --now yum-cron
+```
+
+## Conclusión
+
+La actualización automática de los paquetes se activa fácilmente y aumenta considerablemente la seguridad de su sistema de información.
diff --git a/docs/guides/security/enabling_iptables_firewall.es.md b/docs/guides/security/enabling_iptables_firewall.es.md
new file mode 100644
index 0000000000..76cffade9e
--- /dev/null
+++ b/docs/guides/security/enabling_iptables_firewall.es.md
@@ -0,0 +1,56 @@
+---
+title: Habilitar el cortafuegos `iptables`
+author: Steven Spencer
+contributors: Ezequiel Bruni
+tested with: 8.5, 8.6, 9.0
+tags:
+ - seguridad
+ - iptables
+ - obsoleto
+---
+
+# Habilitar el cortafuegos `iptables`
+
+## Requisitos previos
+
+* Un deseo ardiente e insaciable de desactivar _firewalld_, el cortafuegos configurado por defecto en el sistema y activar _iptables_.
+
+!!! warning "Este proceso es desaprobado"
+
+ A partir de la versión 9.0 de Rocky Linux, `iptables` y todas las utilidades asociadas a él están obsoletas. Esto significa que las futuras versiones del sistema operativo eliminarán `iptables`. Por esta razón, es muy recomendable que no utilice este proceso. Si está familiarizado con iptables,le recomendamos utilizar la guía [`iptables` a `firewalld`](firewalld.md). Si es nuevo en la terminología y conceptos de los cortafuegos, entonces le recomendamos leer la guía [`firewalld` Para principiantes](firewalld-beginners.md).
+
+## Introducción
+
+_firewalld_ es ahora el cortafuegos por defecto en Rocky Linux. _firewalld_ **no era** más que una aplicación dinámica de _iptables_ que cargaba los cambios, sin vaciar las reglas desde archivos en formato xml en CentOS 7/RHEL 7. Con CentOS 8/RHEL 8/Rocky 8, _firewalld_ es una capa alrededor de _nftables_. Sin embargo, todavía es posible instalar y utilizar _iptables_ si ese es su deseo. Para instalar y ejecutar directamente _iptables_ sin _firewalld_ puede hacerlo siguiendo esta guía. Lo que esta guía **no** le dirá es cómo escribir reglas para _iptables_. Se asume que si quiere deshacerse de _firewalld_, debe saber cómo escribir reglas para _iptables_.
+
+## Deshabilitar firewalld
+
+Realmente no es posible ejecutar las antiguas utilidades de _iptables_ al mismo tiempo que _firewalld_. Sencillamente, no son compatibles. La mejor manera de evitarlo es deshabilitar _firewalld_ completamente (no es necesario desinistarla a menos que realmente lo desee), y reinstalar las utilidades _iptables_. Es posible deshabilitar _firewalld_ utilizando los siguientes comandos:
+
+Detener _firewalld_:
+
+`systemctl stop firewalld`
+
+Deshabilitar _firewalld_ para que no se ejecute al arrancar el sistema:
+
+`systemctl disable firewalld`
+
+Enmascarar el servicio para que no pueda ser encontrado:
+
+`systemctl mask firewalld`
+
+## Instalar y habilitar los servicios iptables
+
+A continuación necesitamos instalar los antiguos servicios y utilidades de _iptables_. Esto se hace mediante el siguiente comando:
+
+`dnf install iptables-services iptables-utils`
+
+Esto instalará todo lo necesario para ejecutar un conjunto de reglas de _iptables_.
+
+Ahora necesitamos habilitar el servicio _iptables_ para asegurarnos de que se ejecute correctamente al arrancar el sistema:
+
+`systemctl enable iptables`
+
+## Conclusión
+
+Si lo prefiere puede volver a utilizar _iptables_ en vez de utilizar _firewalld_. Puede volver a utilizar _firewalld_, el cortafuegos por defecto del sistema. Simplemente debe revertir los cambios realizados previamente.
diff --git a/docs/guides/security/ssh_public_private_keys.es.md b/docs/guides/security/ssh_public_private_keys.es.md
index 75db78e05a..30790954e8 100644
--- a/docs/guides/security/ssh_public_private_keys.es.md
+++ b/docs/guides/security/ssh_public_private_keys.es.md
@@ -100,4 +100,7 @@ Una vez que haya verificado que puede acceder vía SSH sin utilizar su contrase
En cada uno de los equipos de destino, asegúrese de que se aplican los siguientes permisos:
-`chmod 700 .ssh/` `chmod 600 .ssh/authorized_keys`
+```
+chmod 700 .ssh/
+chmod 600 .ssh/authorized_keys
+```
diff --git a/docs/guides/virtualization/vbox-rocky.es.md b/docs/guides/virtualization/vbox-rocky.es.md
new file mode 100644
index 0000000000..379416b5c8
--- /dev/null
+++ b/docs/guides/virtualization/vbox-rocky.es.md
@@ -0,0 +1,162 @@
+---
+title: Rocky en VirtualBox
+author: Steven Spencer
+contributors: Trevor Cooper, Ezequiel Bruni
+tested on: 8.4, 8.5
+tags:
+ - virtualbox
+ - virtualización
+---
+
+# Rocky en VirtualBox
+
+## Introducción
+
+VirtualBox® es un poderoso producto de virtualización de uso tanto empresarial como doméstico. De vez en cuando, alguien publica que tiene problemas para ejecutar Rocky Linux en VirtualBox®. Ha sido testeado múltiples veces desde el release candidate y funciona bien. Los problemas usualmente reportados son a menudo relativos al video.
+
+Este documento intenta brindar un conjunto de instrucciones paso a paso para poner en funcionamiento Rocky Linux en VirtualBox®. El ordenador utilizado para crear esta documentación ejecutaba Linux, pero puede usar cualquiera de los sistemas operativos soportados.
+
+## Requisitos previos
+
+* Una máquina (Windows, Mac, Linux, Solaris) con memoria disponible y espacio en el disco duro para crear y ejecutar una instancia de VirtualBox®.
+* VirtualBox® instalado en su máquina. Puede encontrarlo [aquí](https://www.virtualbox.org/wiki/Downloads).
+* Una copia del [DVD ISO](https://rockylinux.org/download) de Rocky Linux para su arquitectura. (x86_64 o ARM64).
+* Asegúrese de que su sistema operativo sea de 64 bit y de que la virtualización del hardware esté habilitada en su BIOS.
+
+!!! El comando leerá el flujo de entrada hasta que encuentre la palabra clave definida después de la redirección de entrada.
+
+ La virtualización del hardware es 100% necesaria para instalar un sistema operativo de 64 bit. Si su pantalla de configuración muestra solo opciones de 32 bits, entonces deberá detenerse y solucionar ese problema antes de continuar.
+
+## Preparar la configuración de VirtualBox®
+
+Una vez que haya instalado VirtualBox®, el siguiente paso es ponerlo en marcha. Sin imágenes instaladas obtendrá una pantalla que se asemeja a esta:
+
+ 
+
+ Primero, debemos indicarle a VirtualBox® qué sistema operativo deseamos:
+
+ * Haga clic en "New" (ícono de diente de sierra).
+ * Escriba un nombre. Por ejemplo: "Rocky Linux 8.5".
+ * Deje la carpeta de la máquina como rellenada automáticamente.
+ * Cambie el tipo a "Linux".
+ * Y elija °Red Hat (64-bit)".
+ * Haga clic en "Next".
+
+ 
+
+A continuación, debemos asignar algo de RAM para esta máquina. Por defecto, VirtualBox® llenará automáticamente esto con 1024 MB. Eso no será óptimo para ningún sistema operativo moderno, incluido Rocky Linux. Si tiene memoria de sobra, asigne de 2 a 4 GB (2048 MB o 4096 MB), o más. Tenga en cuenta que VirtualBox® solo usará esta memoria mientras la máquina virtual esté en ejecución.
+
+No hay captura de pantalla para esto, solo cambie el valor de acuerdo a su memoria disponible. Utilice su mejor criterio.
+
+Ahora necesitamos configurar el tamaño del disco duro. Por defecto, VirtualBox® seleccionará automáticamente la opción "Create a virtual hard disk now".
+
+
+
+* Haga clic en "Create"
+
+Se presentará un cuadro de diálogo para crear varios tipos de discos duros virtuales, habrá varios tipos de discos duros listados allí. Consulte la documentación de Oracle VirtualBox para obtener [más información](https://docs.oracle.com/en/virtualization/virtualbox/6.0/user/vdidetails.html) sobre la selección de tipos de discos duros virtuales. A efecto de este documento, simplemente mantenga la opción predeterminada (VDI):
+
+
+
+* Haga clic en "Next"
+
+La siguiente pantalla abordará el almacenamiento en el disco duro físico. Hay dos opciones. "Fixed Size" será más lento de crear, más rápido de usar, pero menos flexible en términos de espacio (si necesita más espacio, estará sujeto a lo que creó).
+
+La opción predeterminada, "Dynamically Allocated", será más rápida de crear, más lenta de usar, pero le proporcionará la opción de incremento si su espacio en disco necesita modificarse. A los efectos de este documento, aceptaremos la opción predeterminada "Dynamically allocated".
+
+
+
+* Haga clic en "Next"
+
+VirtualBox® ahora le ofrece la opción de especificar dónde desea que se ubique el archivo del disco duro virtual, así como la opción de expandir el espacio predeterminado de 8 GB del disco duro virtual. Esta opción es buena, porque 8 GB de espacio en el disco duro no son suficientes para instalar, y mucho menos para usar, cualquiera de las opciones de instalación de la GUI. Establezca 20 GB (o más) dependiendo del uso que desea darle a la máquina virtual y del espacio libre disponible en el disco:
+
+
+
+* Haga clic en "Create"
+
+Hemos finalizado la configuración básica. Deberá tener una pantalla que se vea así:
+
+
+
+## Adjuntar la imagen ISO
+
+Nuestro próximo paso será adjuntar la imagen ISO descargada anteriormente como dispositivo de CD ROM virtual. Haga clic en "Settings" (icono de engranaje) y debería obtener la siguiente pantalla:
+
+
+
+* Haga clic en el elemento "Storage" en el menú de la izquierda.
+* En "Storage Devices" de la sección central, haga clic en el ícono del CD que dice "Empty".
+* En "Attributes", sobre el lado derecho, haga clic en el icono del CD.
+* Seleccione "Choose/Create a Virtual Optical Disk".
+* Haga clic en el botón "Add" (icono del signo de más) y navegue hasta donde esté almacenada su imagen ISO de Rocky Linux.
+* Seleccione la ISO haga clic en "Open“.
+
+Ahora debería tener la ISO agregada a los dispositivos disponibles de esta manera:
+
+
+
+* Marque la imagen ISO y luego haga clic en "Choose".
+
+La imagen ISO de Rocky Linux ahora aparece seleccionada bajo el "Controller: IDE" en la sección central:
+
+
+
+* Haga clic en "OK"
+
+### Memoria de video para instalaciones gráficas
+
+VirtualBox® configura 16 MB de memoria para uso del video. Eso está bien si planea ejecutar un servidor mínimo sin una GUI, pero en cuanto agregue gráficos, ya no será suficiente. Los usuarios que mantienen esta configuración a menudo ven una pantalla de arranque colgada que nunca finaliza, u otros errores.
+
+Si va a ejecutar Rocky Linux con una GUI, debe asignar la memoria suficiente para ejecutar los gráficos sin problemas. Si su máquina tiene poca memoria, ajuste este valor hacia arriba de 16 MB en 16 MB hasta que las cosas funcionen sin problemas. La resolución de video de su máquina host es también un factor que debe considerar.
+
+Piense con cuidado en lo que quiere que haga su máquina virtual Rocky Linux e intente asignar memoria de video que sea compatible con su máquina host y sus otros requerimientos. Puede encontrar más información sobre la configuración de pantalla en la [documentación oficial de Oracle](https://docs.oracle.com/en/virtualization/virtualbox/6.0/user/settings-display.html).
+
+Si tiene bastante memoria, puede establecer este valor en un máximo de 128 MB. Para solucionar esto antes de iniciar la máquina virtual, haga clic en "Settings" (ícono de engranaje) y debería obtener la misma pantalla de configuración que obtuvimos al adjuntar nuestra imagen ISO (arriba).
+
+Esta vez:
+
+* Haga clic en "Display" sobre el lado izquierdo.
+* En la pestaña "Screen" sobre el lado derecho, verá la opción "Video Memory" con el valor predeterminado establecido en 16 MB.
+* Cámbielo al valor que desee. Puede ajustarlo al alza volviendo a esta pantalla en cualquier momento. En nuestro ejemplo, ahora seleccionamos 128 MB.
+
+!!! Tip
+
+ Hay formas de establecer la memoria de video hasta 256 MB. Si necesita más, consulte [este documento] (https://docs.oracle.com/en/virtualization/virtualbox/6.0/user/vboxmanage-modifyvm.html) de la documentación oficial de Oracle.
+
+Su pantalla debería mostrar algo similar a esto:
+
+
+
+* Haga clic en "OK"
+
+## Comenzar la Instalación
+
+Hemos configurado todo para poder comenzar la instalación. Tenga en cuenta que no hay diferencias particulares en la instalación de Rocky Linux en una máquina VirtualBox®, comparada con una instalación en hardware independiente. Los pasos de la instalación son los mismos.
+
+Ahora que tenemos todo preparado para la instalación, solo necesita hacer clic en "Start" (ícono de flecha verde hacia la derecha) para comenzar a instalar Rocky. Cuando haya pasado la pantalla de selección de idioma, la siguiente será la pantalla "Installation Summary". Necesitará configurar cualquiera de los elementos que correspondan, pero los siguientes son imprescindibles:
+
+* Fecha y hora
+* Selección de software (si desea algo además del "Server with GUI" predeterminado)
+* Destino de la instalación
+* Red y hostname
+* Configuración de usuario
+
+Si no está seguro de alguna de estas configuraciones, consulte el documento para [Instalar Rocky](../installation.md).
+
+Cuando haya terminado la instalación, debería tener una instancia de Rocky Linux ejecutándose en VirtualBox®.
+
+Después de instalar y reiniciar, se presentará una pantalla de acuerdo de licencia EULA que será necesario aceptar, y una vez que haya hecho clic en "Finish Configuration", debería presentarse un inicio de sesión gráfico (si elige una opción con GUI) o de línea de comando. El autor escogió la opción predeterminada "Server with GUI" para fines de demostración:
+
+
+
+## Información adicional
+
+No es la intención de este documento convertirlo en un experto en todas las funciones que VirtualBox® puede proporcionar. Para obtener más información sobre cómo realizar tareas específicas, por favor consulte la [documetación oficial](https://docs.oracle.com/en/virtualization/virtualbox/6.0/user/).
+
+!!! tip "Consejo Avanzado"
+
+ VirtualBox® ofrece amplias opciones en la línea de comando usando `VBoxManage`. Si bien este documento no cubre el uso de `VBoxManage`, la documentación oficial de Oracle proporciona [muchos detalles] (https://docs.oracle.com/en/virtualization/virtualbox/6.0/user/vboxmanage-intro.html) si desea investigar esto más a fondo.
+
+## Conclusión
+
+Es fácil crear, instalar y ejecutar una máquina Rocky Linux sobre VirtualBox®. Si bien está lejos de ser una guía exhaustiva, seguir los pasos anteriores debería brindarle una instalación de Rocky Linux funcional. Si usa VirtualBox® y tiene una configuración específica que le gustaría compartir, el autor lo invita a enviar nuevas secciones para este documento.
diff --git a/docs/guides/web/apache_hardened_webserver/rkhunter.es.md b/docs/guides/web/apache_hardened_webserver/rkhunter.es.md
new file mode 100644
index 0000000000..55d85c1b1e
--- /dev/null
+++ b/docs/guides/web/apache_hardened_webserver/rkhunter.es.md
@@ -0,0 +1,74 @@
+---
+title: Rootkit Hunter
+author: Steven Spencer
+contributors: Ezequiel Bruni
+tested with: 8.5
+tags:
+ - servidor
+ - seguridad
+ - rkhunter
+---
+
+# Rootkit Hunter
+
+## Requisitos previos
+
+* Un servidor web con Rocky Linux que ejecute Apache
+* Dominio de un editor de línea de comandos (en este ejemplo utilizamos _vi_)
+* Un alto nivel de comodidad en la ejecución de comandos desde el terminal, la visualización de registros y otras tareas de caracter genérico dentro de la administración de sistemas
+* Es útil comprender qué puede desencadenar una respuesta a los archivos modificados en el sistema de archivos (como las actualizaciones de paquetes)
+* Todos los comandos se ejecutan como el usuario root o sudo
+
+## Introduction
+
+_rkhunter_ (Root Kit Hunter) es una herramienta basada en Unix que explora rootkits, puertas traseras y posibles exploits locales. Es unapieza importante de un servidor web securizado, y está diseñado para notificar rápidamente al administrador del sistema cuando algo sospechoso ocurre en el sistema de archivos del servidor.
+
+_rkhunter_ es solo un posible componente de una configuración securizada del servidor web Apache y puede utilizarse en conjunto con otras herramientas. Si quiere utilizarlo junto con otras herramientas para securizarlo, consultr la [guía del servidor web Apache securizado](index.md).
+
+Este documento también utiliza todos los supuestos y convenciones descritos en ese documento original, por lo que es una buena idea revisarla antes de continuar.
+
+## Instalar rkhunter
+
+_rkhunter_ requiere el repositorio EPEL (Extra Packages for Enterprise Linux). Así que instale ese repositorio si no lo tiene instalado ya:
+
+`dnf install epel-release`
+
+Luego instale _rkhunter_:
+
+`dnf install rkhunter`
+
+## Configurar rkhunter
+
+Las únicas opciones de configuración que se deben establecer son las que están relacionadas con el envio de los informes por correo al administrador del sistema. Para modificar el archivo de configuración, ejecute:
+
+`vi /etc/rkhunter.conf`
+
+Y luego busque:
+
+`#MAIL-ON-WARNING=me@mydomain root@mydomain`
+
+Elimine el comentario y cambie el la dirección de correo me@mydomain.com para reflejar su dirección de correo electrónico.
+
+Luego cambie el root@mydomain a root@nombre_de_servidor.
+
+Puede que también necesite configurar [Postfix](../../email/postfix_reporting.md) para que la sección de correo electrónico funcione correctamente.
+
+## Ejecutar rkhunter
+
+_rkhunter_ puede ejecutarse escribiéndola en la línea de comandos. Hay una tarea de cron instalada en `/etc/cron.daily` pero si desea automatizar el procedimiento en un horario diferente, mire la guía [Automatización de trabajos de Cron](../../automation/cron_jobs_howto.md).
+
+También tendrá que mover el script a otra ubicación que no sea `/etc/cron.daily`, por ejemplo `/usr/local/sbin` y luego llámelo desde su ejecución de Cron. El método más fácil, por supuesto, es dejar intacto el cron.daily por defecto.
+
+Antes de permitir que _rkhunter_ se ejecute automáticamente, ejecute el comando manualmente con los parametros "--propupd" para crear el archivo rkhunter.dat, y asegurarse de que su entorno se reconozca sin problema:
+
+`rkhunter --propupd`
+
+Para ejecutar _rkhunter_ manualmente:
+
+`rkhunter --check`
+
+Esto se repetirá en la pantalla a medida que se realicen las comprobaciones, pidiéndole que `[Pulse para continuar]` después de cada sección.
+
+## Conclusión
+
+_rkhunter_ es una parte de una estrategia de securización de servidores que puede ayudarle a monitorizar el sistema de archivos y reportar cualquier problema al administrador del sistema. Tal vez sea una de las herramientas de securización más fáciles de instalar, configurar y ejecutar.
diff --git a/docs/release_notes/9_0.it.md b/docs/release_notes/9_0.it.md
index a73f10b6e3..3b49f13d53 100644
--- a/docs/release_notes/9_0.it.md
+++ b/docs/release_notes/9_0.it.md
@@ -170,7 +170,7 @@ In alternativa, è possibile ottenere l'accesso a qualsiasi checksum della versi
Come per ogni release, ci sono problemi già noti. È possibile consultare l'elenco attuale dei problemi nell'upstream [qui](https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/9/html/9.0_release_notes/known-issues).
-* **Limitazione all'uso dell'installazione ISO minima**: la maggior parte (se non tutti) i pacchetti relativi alla sicurezza non funzioneranno. Se avete bisogno di profili e pacchetti di sicurezza/SCAP al momento dell'installazione, utilizzate il DVD ISO.
+* **Limitazione all'utilizzo dell'installazione ISO minima** - La maggior parte dei pacchetti relativi alla sicurezza non funzionerà. Se avete bisogno di profili e pacchetti di sicurezza/SCAP al momento dell'installazione, utilizzate il DVD ISO.
## Segnala gli errori