Introducción
WordPress es un sistema de gestión de contenidos (CMS) gratuito y de código abierto, basado en una base de datos MySQL y con procesamiento PHP. Gracias a su arquitectura de plugins y su sistema de plantillas extensible, la mayor parte de su gestión se puede realizar a través de una interfaz web. Por ello, WordPress es una opción popular para crear todo tipo de sitios web, desde blogs y páginas de productos hasta tiendas online.
Ejecutar WordPress normalmente implica instalar un entorno LAMP (Linux, Apache, MySQL y PHP) o LEMP (Linux, Nginx, MySQL y PHP), lo cual puede ser laborioso. Sin embargo, con herramientas como Docker y Docker Compose, puedes simplificar la configuración de tu propio entorno personalizado y la instalación de WordPress. En lugar de instalar los componentes manualmente, puedes usar imágenes que estandarizan elementos como bibliotecas, archivos de configuración y variables de entorno. Luego, ejecuta estas imágenes en contenedores, procesos aislados que se ejecutan en un sistema operativo compartido. Además, con Compose, puedes coordinar varios contenedores —por ejemplo, una aplicación y una base de datos— para que se comuniquen entre sí.
En este tutorial, crearás una instalación de WordPress con varios contenedores. Cada contenedor albergará la base de datos MySQL, el servidor web Nginx y WordPress. Además, protegerás tu instalación obteniendo certificados TLS/SSL con Let's Encrypt para el dominio que deseas asociar a tu sitio. Finalmente, configurarás una tarea cron para renovar tus certificados y garantizar la seguridad de tu dominio.
Requisitos previos
- Un servidor que ejecuta Ubuntu, con un usuario sin privilegios de administrador
sudoY un cortafuegos activo. - Docker está instalado en su servidor.
- Docker Compose debe estar instalado en su servidor.
- Un nombre de dominio registrado. Este tutorial utilizará su dominio en su totalidad.
- Los siguientes dos registros DNS están configurados para su servidor.
Un registro con su_dominio que apunta a la dirección IP pública de su servidor.
Un registro con www.tu_dominio que apunta a la dirección IP pública de tu servidor.
Paso 1 – Definir la configuración del servidor web
Antes de ejecutar cualquier contenedor, el primer paso es definir la configuración de tu servidor web Nginx. El archivo de configuración incluye bloques de ubicación específicos de WordPress, además de un bloque para redirigir las solicitudes de verificación de Let's Encrypt al cliente Certbot para la renovación automática del certificado.
Primero, crea un directorio de proyecto para tu instalación de WordPress. En este ejemplo, se llamará WordPress. Puedes darle otro nombre a este directorio si quieres:
mkdir wordpressLuego, diríjase al directorio:
cd wordpressA continuación, cree un directorio para el archivo de configuración:
mkdir nginx-confArchivo con nano O abre tu editor favorito:
nano nginx-conf/nginx.confEn este archivo, agregue un bloque de servidor con instrucciones para el nombre del servidor y la raíz del documento, y bloques de ubicación para dirigir las solicitudes del cliente Certbot para certificados, procesamiento PHP y solicitudes de activos fijos.
Agrega el siguiente código al archivo. Asegúrate de reemplazar `your_domain` con tu nombre de dominio:
server {
listen 80;
listen [::]:80;
server_name your_domain www.your_domain;
index index.php index.html index.htm;
root /var/www/html;
location ~ /.well-known/acme-challenge {
allow all;
root /var/www/html;
}
location / {
try_files $uri $uri/ /index.php$is_args$args;
}
location ~ \.php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass wordpress:9000;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
}
location ~ /\.ht {
deny all;
}
location = /favicon.ico {
log_not_found off; access_log off;
}
location = /robots.txt {
log_not_found off; access_log off; allow all;
}
location ~* \.(css|gif|ico|jpeg|jpg|js|png)$ {
expires max;
log_not_found off;
}
} Nuestro bloque de servidor contiene la siguiente información:
Instrucciones:
escucharEsto le indica a Nginx que escuche en el puerto 80, lo que le permite usar el plugin Webroot Certbot para sus solicitudes de certificados. Tenga en cuenta que aún no ha configurado el puerto 443; actualizará su configuración para incluir SSL una vez que haya recibido sus certificados correctamente.nombre_del_servidorEspecifica el nombre de tu servidor y el bloque de servidor que se debe usar para las solicitudes a tu servidor. Asegúrate de reemplazar `tu_dominio` con tu nombre de dominio en esta línea.índiceEsta directiva define los archivos que se utilizan como índices al procesar las solicitudes a su servidor. Aquí modificó el orden de prioridad predeterminado y movió index.php antes que index.html para que Nginx priorice los archivos llamados index.php cuando sea posible.raízEsta directiva especifica el directorio raíz para las solicitudes del servidor. Este directorio, /var/www/html, se crea como punto de montaje durante la compilación mediante las directivas del Dockerfile de WordPress. Estas directivas del Dockerfile también garantizan que los archivos de la versión de WordPress se instalen en este volumen.
Bloques de ubicación:
ubicación ~ /.bien-conocido/acme-challengeEste bloque gestiona las solicitudes al directorio .well-known, donde Certbot coloca un archivo temporal para verificar que el DNS de su dominio se resuelve correctamente en su servidor. Con esta configuración, puede usar el complemento Webroot Certbot para obtener un certificado para su dominio.ubicaciónEn este bloque de ubicación, la directiva `try_files` se utiliza para comprobar si existen archivos que coincidan con la URI solicitada. Sin embargo, en lugar de devolver un estado 404 No encontrado, como es el comportamiento predeterminado, se pasa el control al archivo `index.php` de WordPress mediante los argumentos de la solicitud.ubicación ~ \.php$: Este bloque de ubicación gestiona el procesamiento de PHP y redirige estas solicitudes a su contenedor de WordPress. Dado que su imagen Docker de WordPress se basará en la imagen php:fpm, también deberá incluir en este bloque opciones de configuración específicas del protocolo FastCGI. Nginx requiere un procesador PHP independiente para las solicitudes PHP. En este caso, estas solicitudes serán gestionadas por el procesador php-fpm incluido en la imagen php:fpm. Además, este bloque de ubicación contiene directivas, variables y opciones específicas de FastCGI que configuran las solicitudes de proxy a la aplicación WordPress que se ejecuta en su contenedor de WordPress, establecen una lista de preferencias para el URI de solicitud analizado y analizan dicho URI.ubicación ~ /\.htEste bloque gestiona los archivos .htaccess porque Nginx no los sirve. La directiva deny_all garantiza que los archivos .htaccess nunca se sirvan a los usuarios.ubicación = /favicon.ico, ubicación = /robots.txtEstos bloques garantizan que las solicitudes a /favicon.ico y /robots.txt no se registren.ubicación ~* \.(css|gif|ico|jpeg|jpg|js|png)$: Este bloque deshabilita el registro de solicitudes de activos fijos y garantiza que estos activos sean altamente almacenables en caché, ya que su mantenimiento suele ser costoso.
Guarda y cierra el archivo cuando termines de editarlo. Si usas nano, hazlo pulsando CTRL+X, Y y luego ENTER. Con Nginx configurado, puedes crear las variables de entorno que se pasarán a los contenedores de tu aplicación y base de datos en tiempo de ejecución.
Paso 2 – Definir variables de entorno
La base de datos y los contenedores de tu aplicación WordPress necesitan acceder a ciertas variables de entorno en tiempo de ejecución para mantener los datos de tu aplicación disponibles y accesibles. Estas variables contienen información confidencial y no confidencial: valores confidenciales para la contraseña de root de MySQL y el usuario y contraseña de la base de datos de la aplicación, e información no confidencial para el nombre y el host de la base de datos. En lugar de configurar todos estos valores en el archivo Docker Compose (el archivo principal que contiene la información sobre cómo se ejecutan tus contenedores), configura los valores confidenciales en un archivo .env y restringe su circulación. Esto evita que estos valores se copien entre los repositorios de tu proyecto y sean visibles públicamente.
En el directorio raíz de tu proyecto, ~/wordpress, abre un archivo llamado .env:
nano .envLos valores secretos que definas en este archivo incluyen la contraseña del usuario root de MySQL y el nombre de usuario y la contraseña que WordPress utilizará para acceder a la base de datos. Agrega los siguientes nombres de variables y valores al archivo. Recuerda proporcionar tus propios valores para cada variable:
MYSQL_ROOT_PASSWORD=your_root_password MYSQL_USER=your_wordpress_database_user MYSQL_PASSWORD=your_wordpress_database_password
Incluya la contraseña de la cuenta de administrador raíz, así como el nombre de usuario y la contraseña que desee para la base de datos de su aplicación. Guarde y cierre el archivo cuando haya terminado de editarlo.
Dado que tu archivo .env contiene información confidencial, debes asegurarte de incluirlo en los archivos .gitignore y .dockerignore de tu proyecto. Esto indica a Git y Docker qué archivos no deben copiar en tus repositorios Git e imágenes Docker, respectivamente.
Con git init:
git initA continuación, crea y abre un archivo .gitignore:
nano .gitignoreAgregar variable de entorno al archivo:
.envGuarda y cierra el archivo cuando hayas terminado de editar.
Asimismo, agregar .env al archivo .dockerignore es una buena precaución para que no se incluya en sus contenedores cuando utilice este directorio como contexto de compilación.
Abra el archivo:
nano .dockerignoreAgregar variable de entorno al archivo:
.env
Debajo de esto, opcionalmente puede agregar archivos y directorios relacionados con el desarrollo de su aplicación:
.env
.git
docker-compose.yml
.dockerignoreGuarda y cierra el archivo cuando hayas terminado.
Una vez que tenga su información confidencial a mano, ahora puede pasar a definir sus servicios en un archivo docker-compose.yml.
Paso 3 – Definir servicios con Docker Compose
Tu archivo docker-compose.yml contendrá las definiciones de servicio para tu configuración. Un servicio en Compose es un contenedor en ejecución, y las definiciones de servicio especifican información sobre cómo debe ejecutarse cada contenedor.
Con Compose, puedes definir distintos servicios para ejecutar aplicaciones multicontenedor, ya que Compose permite vincularlos mediante redes y volúmenes compartidos. Esto te resultará útil en tu configuración actual, puesto que crearás contenedores diferentes para tu base de datos, tu aplicación WordPress y tu servidor web. También crearás un contenedor para ejecutar el cliente Certbot y obtener los certificados para tu servidor web.
Para empezar, crea y abre el archivo docker-compose.yml:
nano docker-compose.ymlAgrega el siguiente código para definir la versión de tu archivo Compose y el servicio de base de datos db:
version: '3' services: db: image: mysql:8.0 container_name: db restart: unless-stopped env_file: .env environment: - MYSQL_DATABASE=wordpress volumes: - dbdata:/var/lib/mysql command: '--default-authentication-plugin=mysql_native_password' networks: - app-network
La definición del servicio de base de datos incluye las siguientes opciones:
imagenEsto le indica a Compose qué imagen usar para crear el contenedor. Aquí se fija la imagen mysql:8.0 para evitar conflictos futuros, ya que la imagen mysql:latest se actualiza constantemente. Para obtener más información sobre cómo fijar versiones y evitar conflictos de dependencias, consulte la documentación de Docker sobre las mejores prácticas de Dockerfile.nombre_del_contenedor: Especifica un nombre para el contenedor.ReanudarEsta política especifica si el contenedor se reiniciará. El valor predeterminado es no, pero usted ha configurado el contenedor para que se reinicie a menos que se detenga manualmente.archivo_entornoEsta opción le indica a Compose que desea agregar variables de entorno desde un archivo llamado .env que se encuentra en su contexto de compilación. En este caso, el contexto de compilación es su directorio actual.ambienteEsta opción permite añadir variables de entorno adicionales a las definidas en el archivo .env. Se configura la variable MYSQL_DATABASE con el valor wordpress para asignar un nombre a la base de datos de la aplicación. Dado que esta información no es confidencial, se puede incluir directamente en el archivo docker-compose.yml.volúmenesAquí se está montando un volumen llamado dbdata en la carpeta /var/lib/mysql del contenedor. Este es el directorio de datos estándar para MySQL en la mayoría de las distribuciones.dominioEsta opción especifica un comando para anular el comando CMD predeterminado de la imagen. En este caso concreto, se añade una opción al comando estándar `mysqld` de la imagen Docker, que inicia el servidor MySQL en el contenedor. Esta opción, `--default-authentication-plugin=mysql_native_password`, establece la variable de sistema `--default-authentication-plugin` en `mysql_native_password` y especifica qué mecanismo de autenticación debe regir las nuevas solicitudes de autenticación al servidor. Dado que PHP, y por lo tanto su imagen de WordPress, no admite la nueva autenticación predeterminada de MySQL, deberá configurarla para autenticar al usuario de la base de datos de su aplicación.- Redes: Esto especifica que su servicio de aplicación se unirá a la red de aplicación que usted define al final del archivo.
A continuación, debajo de la definición de tu servicio de base de datos, agrega la definición de tu servicio de aplicación WordPress:
... wordpress: depends_on: - db image: wordpress:5.1.1-fpm-alpine container_name: wordpress restart: unless-stopped env_file: .env environment: - WORDPRESS_DB_HOST=db:3306 - WORDPRESS_DB_USER=$MYSQL_USER - WORDPRESS_DB_PASSWORD=$MYSQL_PASSWORD - WORDPRESS_DB_NAME=wordpress volumes: - wordpress:/var/www/html networks: - app-network
En esta definición de servicio, se nombra el contenedor y se define una política de reinicio, igual que se hizo con el servicio de base de datos. También se añaden algunas opciones específicas a este contenedor:
depende_deEsta opción garantiza que los contenedores se inicien en orden de dependencia, comenzando el contenedor de WordPress después del contenedor de la base de datos. Su aplicación WordPress depende de la existencia de la base de datos y del usuario de la aplicación, por lo que especificar este orden de dependencia asegurará que su aplicación se inicie correctamente.imagenPara esta configuración, usarás la imagen WordPress 5.1.1-fpm-alpine. Como se explicó en el Paso 1, usar esta imagen garantiza que tu aplicación tenga el procesador php-fpm que Nginx necesita para gestionar el procesamiento de PHP. Esta también es una imagen Alpine, derivada del proyecto Alpine Linux, lo que ayuda a reducir el tamaño total de la imagen. Para obtener más información sobre las ventajas y desventajas de usar imágenes Alpine y si es conveniente para tu aplicación, consulta la sección «Variantes de imagen» en la página de imágenes de WordPress en Docker Hub.archivo_entornoNuevamente, especificas que deseas extraer valores de tu archivo .env, ya que ahí es donde definiste el usuario y la contraseña de la base de datos de tu aplicación.ambienteAquí, estás utilizando los valores que definiste en tu archivo .env, pero asignándoles los nombres de las variables que espera la imagen de WordPress: WORDPRESS_DB_USER y WORDPRESS_DB_PASSWORD. También estás definiendo WORDPRESS_DB_HOST, que será el servidor MySQL que se ejecuta en el contenedor de la base de datos, accesible en el puerto MySQL predeterminado, el 3306. Tu WORDPRESS_DB_NAME será el mismo valor que especificaste para MYSQL_DATABASE en la definición de tu servicio MySQL: wordpress.volúmenesEstás montando un volumen llamado wordpress en el punto de montaje /var/www/html creado por la imagen de WordPress. Usar un volumen con nombre de esta manera te permite compartir el código de tu aplicación con otros contenedores.redTambién estás agregando el contenedor de WordPress a la red de aplicaciones.
A continuación, en la definición del servicio de la aplicación WordPress, agregue la siguiente definición para su servicio de servidor web Nginx:
... webserver: depends_on: - wordpress image: nginx:1.15.12-alpine container_name: webserver restart: unless-stopped ports: - "80:80" volumes: - wordpress:/var/www/html - ./nginx-conf:/etc/nginx/conf.d - certbot-etc:/etc/letsencrypt networks: - app-network
Aquí, debes nombrar tu contenedor y configurarlo como dependencia del contenedor de WordPress en el orden principal. También debes usar una imagen Alpine: la imagen Nginx 1.15.12-alpine.
Esta definición de servicio también incluye las siguientes opciones:
puertosEsto expone el puerto 80 para habilitar las opciones de configuración que definiste en tu archivo nginx.conf en el paso 1.volúmenesAquí se define una combinación de volúmenes con nombre y puntos de montaje:- wordpress:/var/www/html: Este código colocará su aplicación WordPress en la carpeta /var/www/html, el directorio que ha configurado como raíz en su bloque de servidor Nginx.
./nginx-conf:/etc/nginx/conf.dEsto conectará la carpeta de configuración de Nginx en el host con el directorio correspondiente en el contenedor, asegurando que cualquier cambio que realice en los archivos del host se refleje en el host.certbot-etc:/etc/letsencryptEsto instalará los certificados y claves de Let's Encrypt para su dominio en el directorio correspondiente del contenedor.
También has añadido este contenedor a la red de la aplicación.
Finalmente, en la definición de su servidor web, agregue la definición final del servicio para certbot. Asegúrese de reemplazar la dirección de correo electrónico y el nombre de dominio que aparecen aquí con su propia información:
certbot: depends_on: - webserver image: certbot/certbot container_name: certbot volumes: - certbot-etc:/etc/letsencrypt - wordpress:/var/www/html command: certonly --webroot --webroot-path=/var/www/html --email sammy@your_domain --agree-tos --no-eff-email --staging -d your_domain -d www.your_domain
Esta definición indica a Compose que descargue la imagen certbot/certbot desde Docker Hub. También utiliza volúmenes con nombre para compartir recursos con el contenedor Nginx, incluyendo los certificados y claves de dominio en certbot-etc y el código de la aplicación en WordPress. De nuevo, has usado dependent_on para especificar que el contenedor certbot debe iniciarse después de que se inicie el servicio del servidor web. También has añadido una opción de comando que especifica un subcomando para ejecutar con el comando certbot predeterminado del contenedor. El subcomando certonly obtiene el certificado con las siguientes opciones:
--webrootEsto indica a Certbot que utilice el complemento webroot para colocar archivos en la carpeta webroot para la autenticación. El complemento se basa en el método de autenticación HTTP-01, que utiliza una solicitud HTTP para demostrar que Certbot puede acceder a los recursos de un servidor que responde a un nombre de dominio determinado.--ruta-raíz-webEsto especifica la ruta al directorio raíz del sitio web.--correo electrónico: El correo electrónico que desea utilizar para el registro y la recuperación.--acuerdo-Esto indica que usted acepta el Acuerdo Común de ACME.--no-eff-emailEsto le indica a Certbot que no desea compartir su correo electrónico con la Electronic Frontier Foundation (EFF). Puede eliminar esta opción si lo desea.--puesta en escenaEsto indica a Certbot que desea usar el entorno de pruebas de Let's Encrypt para obtener certificados de prueba. Esta opción le permite probar sus opciones de configuración y evitar posibles límites en las solicitudes de dominio. Para obtener más información sobre estos límites, consulte la documentación sobre límites de frecuencia de Let's Encrypt.-dEsto te permite especificar los nombres de dominio que quieres aplicar a tu solicitud. En este caso, ingresaste tu_dominio y www.tu_dominio. Asegúrate de reemplazarlos con tu dominio.
Debajo de la definición del servicio certbot, agregue sus definiciones de red y volumen:
... volumes: certbot-etc: wordpress: dbdata: networks: app-network: driver: bridge
La clave de volumen de nivel superior define los volúmenes certbot-etc, wordpress y dbdata. Cuando Docker crea los volúmenes, su contenido se almacena en un directorio del sistema de archivos del host, /var/lib/docker/volumes/, gestionado por Docker. El contenido de cada volumen se monta desde este directorio en cualquier contenedor que lo utilice. Esto permite compartir código y datos entre contenedores.
La red de puente definida por el usuario permite la comunicación entre los contenedores, ya que se encuentran en el mismo host que el demonio de Docker. Esto simplifica el tráfico y la comunicación dentro de la aplicación, pues abre todos los puertos entre los contenedores en la misma red de puente, sin exponer ningún puerto al exterior. De esta forma, los contenedores de la base de datos, WordPress y el servidor web pueden comunicarse entre sí, y solo es necesario exponer el puerto 80 para el acceso de la interfaz de usuario a la aplicación.
El archivo docker-compose.yml se muestra completo a continuación:
version: '3' services: db: image: mysql:8.0 container_name: db restart: unless-stopped env_file: .env environment: - MYSQL_DATABASE=wordpress volumes: - dbdata:/var/lib/mysql command: '--default-authentication-plugin=mysql_native_password' networks: - app-network wordpress: depends_on: - db image: wordpress:5.1.1-fpm-alpine container_name: wordpress restart: unless-stopped env_file: .env environment: - WORDPRESS_DB_HOST=db:3306 - WORDPRESS_DB_USER=$MYSQL_USER - WORDPRESS_DB_PASSWORD=$MYSQL_PASSWORD - WORDPRESS_DB_NAME=wordpress volumes: - wordpress:/var/www/html networks: - app-network webserver: depends_on: - wordpress image: nginx:1.15.12-alpine container_name: webserver restart: unless-stopped ports: - "80:80" volumes: - wordpress:/var/www/html - ./nginx-conf:/etc/nginx/conf.d - certbot-etc:/etc/letsencrypt networks: - app-network certbot: depends_on: - webserver image: certbot/certbot container_name: certbot volumes: - certbot-etc:/etc/letsencrypt - wordpress:/var/www/html command: certonly --webroot --webroot-path=/var/www/html --email sammy@your_domain --agree-tos --no-eff-email --staging -d your_domain -d www.your_domain volumes: certbot-etc: wordpress: dbdata: networks: app-network: driver: bridge
Guarda y cierra el archivo cuando hayas terminado de editarlo. Con las definiciones de servicio configuradas, ya puedes lanzar contenedores y probar las solicitudes de certificados.
Paso 4 – Obtener certificados y credenciales SSL
Inicie sus contenedores con el comando `docker-compose up`, que creará y ejecutará sus contenedores en el orden que especifique. Al agregar el parámetro `-d`, el comando ejecutará los contenedores de la base de datos, WordPress y el servidor web en segundo plano.
docker-compose up -dEl siguiente resultado confirma que su servicio ha sido creado:
Output
Creating db ... done
Creating wordpress ... done
Creating webserver ... done
Creating certbot ... doneComprueba el estado de tus servicios usando docker-compose ps:
docker-compose psUna vez completado, tus servicios de base de datos, WordPress y servidor web estarán en funcionamiento y el contenedor de Certbot finalizará con un mensaje de estado 0:
Output
Name Command State Ports
-------------------------------------------------------------------------
certbot certbot certonly --webroot ... Exit 0
db docker-entrypoint.sh --def ... Up 3306/tcp, 33060/tcp
webserver nginx -g daemon off; Up 0.0.0.0:80->80/tcp
wordpress docker-entrypoint.sh php-fpm Up 9000/tcpSi en la columna Estado de los servicios de base de datos, WordPress o servidor web aparece cualquier valor distinto al anterior, o un estado de salida distinto de 0 para el contenedor de certbot, es posible que deba revisar los registros del servicio con el comando docker-compose logs:
docker-compose logs service_nameAhora puedes verificar que tus certificados se han instalado en el contenedor del servidor web con docker-compose exec:
docker-compose exec webserver ls -la /etc/letsencrypt/liveCuando las solicitudes de certificado se realizan correctamente, el resultado del código es el siguiente:
Output
total 16
drwx------ 3 root root 4096 May 10 15:45 .
drwxr-xr-x 9 root root 4096 May 10 15:45 ..
-rw-r--r-- 1 root root 740 May 10 15:45 README
drwxr-xr-x 2 root root 4096 May 10 15:45 your_domainAhora que sabe que su solicitud se ha realizado correctamente, puede editar la definición del servicio certbot para eliminar --staging.
Abre docker-compose.yml:
nano docker-compose.ymlBusque la parte del archivo que contiene la definición del servicio certbot y reemplace `--staging` en la opción del comando con `--force-renewal`, lo que indica a Certbot que desea solicitar un nuevo certificado con los mismos dominios. El certificado se actualiza debajo de la definición del servicio certbot con la variable:
...
certbot:
depends_on:
- webserver
image: certbot/certbot
container_name: certbot
volumes:
- certbot-etc:/etc/letsencrypt
- certbot-var:/var/lib/letsencrypt
- wordpress:/var/www/html
command: certonly --webroot --webroot-path=/var/www/html --email sammy@your_domain --agree-tos --no-eff-email --force-renewal -d your_domain -d www.your_domain
...Ahora puedes ejecutar docker-compose para recrear el contenedor de certbot. También debes añadir la opción --no-deps para indicar a Compose que puede omitir el inicio del servicio del servidor web, ya que este ya está en ejecución:
docker-compose up --force-recreate --no-deps certbotEl siguiente resultado indica que su solicitud de certificado se realizó correctamente:
Output Recreating certbot ... done Attaching to certbot certbot | Saving debug log to /var/log/letsencrypt/letsencrypt.log certbot | Plugins selected: Authenticator webroot, Installer None certbot | Renewing an existing certificate certbot | Performing the following challenges: certbot | http-01 challenge for your_domain certbot | http-01 challenge for www.your_domain certbot | Using the webroot path /var/www/html for all unmatched domains. certbot | Waiting for verification... certbot | Cleaning up challenges certbot | IMPORTANT NOTES: certbot | - Congratulations! Your certificate and chain have been saved at: certbot | /etc/letsencrypt/live/your_domain/fullchain.pem certbot | Your key file has been saved at: certbot | /etc/letsencrypt/live/your_domain/privkey.pem certbot | Your cert will expire on 2019-08-08. To obtain a new or tweaked certbot | version of this certificate in the future, simply run certbot certbot | again. To non-interactively renew *all* of your certificates, run certbot | "certbot renew" certbot | - Your account credentials have been saved in your Certbot certbot | configuration directory at /etc/letsencrypt. You should make a certbot | secure backup of this folder now. This configuration directory will certbot | also contain certificates and private keys obtained by Certbot so certbot | making regular backups of this folder is ideal. certbot | - If you like Certbot, please consider supporting our work by: certbot | certbot | Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate certbot | Donating to EFF: https://eff.org/donate-le certbot | certbot exited with code 0
Una vez que tenga sus certificados, puede modificar la configuración de Nginx para incluir SSL.
Paso 5 – Cambiar la configuración del servidor web y la definición del servicio
Habilitar SSL en la configuración de Nginx implica agregar una redirección de HTTP a HTTPS, especificar la ubicación del certificado y la clave SSL, y agregar parámetros y encabezados de seguridad. Dado que desea reconstruir el servicio del servidor web para incluir estas adiciones, puede detenerlo ahora.
docker-compose stop webserverAntes de modificar el archivo de configuración, obtenga el parámetro de seguridad de Nginx recomendado de Certbot usando curl:
curl -sSLo nginx-conf/options-ssl-nginx.conf https://raw.githubusercontent.com/certbot/certbot/master/certbot-nginx/certbot_nginx/_internal/tls_configs/options-ssl-nginx.confEste comando guarda estos parámetros en un archivo llamado options-ssl-nginx.conf ubicado en el directorio nginx-conf.
A continuación, elimina el archivo de configuración de Nginx que creaste anteriormente:
rm nginx-conf/nginx.confCrea y abre otra versión del archivo:
nano nginx-conf/nginx.confAgrega el siguiente código al archivo para redirigir HTTP a HTTPS e incluye las credenciales, los protocolos y los encabezados de seguridad SSL. No olvides reemplazar `your_domain` con tu dominio:
server { listen 80; listen [::]:80; server_name your_domain www.your_domain; location ~ /.well-known/acme-challenge { allow all; root /var/www/html; } location / { rewrite ^ https://$host$request_uri? permanent; } } server { listen 443 ssl http2; listen [::]:443 ssl http2; server_name your_domain www.your_domain; index index.php index.html index.htm; root /var/www/html; server_tokens off; ssl_certificate /etc/letsencrypt/live/your_domain/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/your_domain/privkey.pem; include /etc/nginx/conf.d/options-ssl-nginx.conf; add_header X-Frame-Options "SAMEORIGIN" always; add_header X-XSS-Protection "1; mode=block" always; add_header X-Content-Type-Options "nosniff" always; add_header Referrer-Policy "no-referrer-when-downgrade" always; add_header Content-Security-Policy "default-src * data: 'unsafe-eval' 'unsafe-inline'" always; # add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always; # enable strict transport security only if you understand the implications location / { try_files $uri $uri/ /index.php$is_args$args; } location ~ \.php$ { try_files $uri =404; fastcgi_split_path_info ^(.+\.php)(/.+)$; fastcgi_pass wordpress:9000; fastcgi_index index.php; include fastcgi_params; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_param PATH_INFO $fastcgi_path_info; } location ~ /\.ht { deny all; } location = /favicon.ico { log_not_found off; access_log off; } location = /robots.txt { log_not_found off; access_log off; allow all; } location ~* \.(css|gif|ico|jpeg|jpg|js|png)$ { expires max; log_not_found off; } }
El bloque del servidor HTTP especifica el directorio raíz para las solicitudes de renovación de Certbot, que se dirigen al directorio .well-known/acme-challenge. También incluye una directiva de reescritura que redirige las solicitudes HTTP al directorio raíz mediante HTTPS.
El bloque de servidor HTTPS habilita SSL y HTTP/2. Para obtener más información sobre cómo se replica HTTP/2 en los protocolos HTTP y los beneficios que puede aportar al rendimiento de un sitio web, consulte la introducción a Cómo configurar Nginx con compatibilidad con HTTP/2 en Ubuntu 18.04.
Este bloque también contiene las ubicaciones de su certificado SSL y clave, junto con los parámetros de seguridad Certbot recomendados que ha almacenado en nginx-conf/options-ssl-nginx.conf.
Además, se incluyen algunas cabeceras de seguridad que le permitirán obtener una calificación A en sitios de prueba como SSL Labs y Security Headers. Estas cabeceras incluyen X-Frame-Options, X-Content-Type-Options, Referrer Policy, Content-Security-Policy y X-XSS-Protection. Se explica la cabecera HTTP Strict Transport Security (HSTS): habilítela solo si comprende los conceptos y ha evaluado su funcionalidad de precarga.
En este bloque también se encuentran las directivas de raíz y directorio, así como el resto de los bloques de ubicación específicos de WordPress que se analizaron en el paso 1. Una vez que haya terminado de editar, guarde y cierre el archivo.
Antes de recrear el servicio del servidor web, debe agregar una asignación de puerto 443 a la definición de su servicio de servidor web.
Abre tu archivo docker-compose.yml:
nano docker-compose.ymlEn la definición del servicio del servidor web, agregue la siguiente asignación de puertos:
...
webserver:
depends_on:
- wordpress
image: nginx:1.15.12-alpine
container_name: webserver
restart: unless-stopped
ports:
- "80:80"
- "443:443"
volumes:
- wordpress:/var/www/html
- ./nginx-conf:/etc/nginx/conf.d
- certbot-etc:/etc/letsencrypt
networks:
- app-networkAquí está el archivo docker-compose.yml completo después de editarlo:
version: '3' services: db: image: mysql:8.0 container_name: db restart: unless-stopped env_file: .env environment: - MYSQL_DATABASE=wordpress volumes: - dbdata:/var/lib/mysql command: '--default-authentication-plugin=mysql_native_password' networks: - app-network wordpress: depends_on: - db image: wordpress:5.1.1-fpm-alpine container_name: wordpress restart: unless-stopped env_file: .env environment: - WORDPRESS_DB_HOST=db:3306 - WORDPRESS_DB_USER=$MYSQL_USER - WORDPRESS_DB_PASSWORD=$MYSQL_PASSWORD - WORDPRESS_DB_NAME=wordpress volumes: - wordpress:/var/www/html networks: - app-network webserver: depends_on: - wordpress image: nginx:1.15.12-alpine container_name: webserver restart: unless-stopped ports: - "80:80" - "443:443" volumes: - wordpress:/var/www/html - ./nginx-conf:/etc/nginx/conf.d - certbot-etc:/etc/letsencrypt networks: - app-network certbot: depends_on: - webserver image: certbot/certbot container_name: certbot volumes: - certbot-etc:/etc/letsencrypt - wordpress:/var/www/html command: certonly --webroot --webroot-path=/var/www/html --email sammy@your_domain --agree-tos --no-eff-email --force-renewal -d your_domain -d www.your_domain volumes: certbot-etc: wordpress: dbdata: networks: app-network: driver: bridge
Guarda y cierra el archivo cuando hayas terminado de editar.
Recrear el servicio del servidor web:
docker-compose up -d --force-recreate --no-deps webserverComprueba tus servicios con docker-compose ps:
docker-compose psEl resultado debería mostrar que tus servicios de base de datos, WordPress y servidor web están en funcionamiento:
Output
Name Command State Ports
----------------------------------------------------------------------------------------------
certbot certbot certonly --webroot ... Exit 0
db docker-entrypoint.sh --def ... Up 3306/tcp, 33060/tcp
webserver nginx -g daemon off; Up 0.0.0.0:443->443/tcp, 0.0.0.0:80->80/tcp
wordpress docker-entrypoint.sh php-fpm Up 9000/tcpUna vez que los contenedores estén en funcionamiento, podrá completar la instalación de WordPress a través de la interfaz web.
Paso 6 – Complete la instalación a través de la interfaz web
Mientras tus contenedores están en ejecución, finaliza la instalación a través de la interfaz web de WordPress.
En tu navegador web, dirígete al dominio de tu servidor. No olvides reemplazar `tu_dominio` con tu nombre de dominio:
https://your_domainSeleccione el idioma que desea utilizar:
Tras hacer clic en Continuar, accederás a la página principal de configuración, donde deberás elegir un nombre para tu sitio y un nombre de usuario. Es recomendable elegir un nombre de usuario fácil de recordar (en lugar de “admin”) y una contraseña segura. Puedes usar la contraseña que WordPress genera automáticamente o crear una propia. Por último, deberás introducir tu dirección de correo electrónico y decidir si quieres impedir que los motores de búsqueda indexen tu sitio.
Al hacer clic en Instalar WordPress en la parte inferior de la página, se le redirigirá a una pantalla de inicio de sesión:
Una vez que inicies sesión, tendrás acceso al panel de administración de WordPress:
Una vez que haya completado la instalación de WordPress, puede tomar medidas para garantizar que sus certificados SSL se renueven automáticamente.
Paso 7 – Renovación de certificados
Los certificados de Let's Encrypt tienen una validez de 90 días. Puedes configurar un proceso de renovación automática para evitar que caduquen. Una forma de hacerlo es crear una tarea cron. En el ejemplo siguiente, se crea una tarea cron para ejecutar periódicamente un script que renueva los certificados y recarga la configuración de Nginx.
Primero, abre un script llamado ssl_renew.sh:
nano ssl_renew.shAgrega el siguiente código al script para renovar tus certificados y recargar la configuración de tu servidor web. Recuerda reemplazar el nombre de usuario de ejemplo con tu nombre de usuario (sin privilegios de administrador):
#!/bin/bash COMPOSE="/usr/local/bin/docker-compose --no-ansi" DOCKER="/usr/bin/docker" cd /home/sammy/wordpress/ $COMPOSE run certbot renew --dry-run && $COMPOSE kill -s SIGHUP webserver $DOCKER system prune -af
Este script primero asigna el binario de docker-compose a una variable llamada COMPOSE y especifica la opción --no-ansi, que ejecuta los comandos de docker-compose sin caracteres de control ANSI. Luego hace lo mismo con el binario de docker. Finalmente, cambia al directorio del proyecto ~/wordpress y ejecuta los siguientes comandos de docker-compose:
-
docker-composeEsto inicia un contenedor de Certbot y sobrescribe el comando definido en el servicio de Certbot. En lugar de usar el subcomando `certonly`, se usa el subcomando `renew`, que renueva los certificados que están a punto de caducar. También incluye la opción `--dry-run` para probar el script. docker-compose matarEsto envía una señal SIGHUP al contenedor del servidor web para recargar la configuración de Nginx.
A continuación, el sistema ejecuta docker prune para eliminar todos los contenedores e imágenes no utilizados.
Una vez que termines de editar el archivo, ciérralo. Hazlo ejecutable con el siguiente comando:
chmod +x ssl_renew.shA continuación, abre tu archivo crontab raíz para ejecutar el script de renovación a intervalos de tiempo específicos:
sudo crontab -eSi es la primera vez que edita este archivo, se le pedirá que elija un editor:
Outputno crontab for root - using an empty one Select an editor. To change later, run 'select-editor'. 1. /bin/nano <---- easiest 2. /usr/bin/vim.basic 3. /usr/bin/vim.tiny 4. /bin/ed Choose 1-4 [1]: ...
Al final de este archivo, agregue la siguiente línea:
...
*/5 * * * * /home/sammy/wordpress/ssl_renew.sh >> /var/log/cron.log 2>&1Esto configura el intervalo de ejecución del trabajo en cinco minutos, para que pueda comprobar si su solicitud de extensión funcionó correctamente. Se crea un archivo de registro, cron.log, para registrar la salida relevante del trabajo.
Transcurridos cinco minutos, compruebe el archivo cron.log para confirmar si la solicitud de extensión se realizó correctamente:
tail -f /var/log/cron.logEl siguiente resultado confirma que la extensión se realizó correctamente:
Output- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ** DRY RUN: simulating 'certbot renew' close to cert expiry ** (The test certificates below have not been saved.) Congratulations, all renewals succeeded. The following certs have been renewed: /etc/letsencrypt/live/your_domain/fullchain.pem (success) ** DRY RUN: simulating 'certbot renew' close to cert expiry ** (The test certificates above have not been saved.) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Salga introduciendo CTRL+C en su terminal.
Puedes modificar el archivo crontab para establecer un intervalo diario. Por ejemplo, para ejecutar el script todos los días al mediodía, cambia la última línea del archivo para que quede así:
...
0 12 * * * /home/sammy/wordpress/ssl_renew.sh >> /var/log/cron.log 2>&1También debes eliminar la opción --dry-run de tu script ssl_renew.sh:
#!/bin/bash COMPOSE="/usr/local/bin/docker-compose --no-ansi" DOCKER="/usr/bin/docker" cd /home/sammy/wordpress/ $COMPOSE run certbot renew && $COMPOSE kill -s SIGHUP webserver $DOCKER system prune -af
Tu tarea cron garantiza que tus certificados Let's Encrypt no caduquen, renovándolos cuando corresponde. También puedes configurar la rotación de registros con la herramienta Logrotate en Ubuntu 22.04 / 20.04 para rotar y comprimir tus archivos de registro.
Resultado
En este tutorial, usaste Docker Compose para crear una instalación de WordPress con el servidor web Nginx. Como parte de este proceso, obtuviste certificados TLS/SSL para el dominio que deseas asociar con tu sitio de WordPress. Además, creaste una tarea cron para renovar estos certificados cuando sea necesario.













