El autor seleccionó a la Fundación de las Naciones Unidas para recibir una donación como parte del programa Write for DOnations.
Kathleen Juell escribió la versión original de WordPress de este tutorial.
Drupal es un sistema de administración de contenidos (CMS) escrito en PHP y se distribuye bajo la Licencia Pública General de GNU de código abierto. Personas y organizaciones en todo el mundo utilizan Drupal para impulsar sitios gubernamentales, blogs personales, empresas y más. Lo que distingue a Drupal de otras estructuras CMS es su creciente comunidad y un conjunto de funciones que incluyen procesos seguros, rendimiento fiable, modularidad y flexibilidad para adaptarse.
Drupal requiere la instalación de las pilas LAMP (Linux, Apache, MySQL y PHP) o LEMP (Linux, Nginx, MySQL y PHP), pero la instalación de componentes individuales es una tarea larga. Podemos utilizar herramientas como Docker y Docker Compose para simplificar el proceso de instalación de Drupal. En este tutorial, se utilizarán imágenes de Docker para instalar componentes individuales en los contenedores de Docker. Al utilizar Docker Compose, podemos definir y administrar varios contenedores para la base de datos, la aplicación y la conexión/comunicación entre ellos.
En este tutorial, instalaremos Drupal utilizando Docker Compose para poder aprovechar el uso de contenedores e implementar nuestro sitio web de Drupal en los servidores. Ejecutaremos contenedores para una base de datos de MySQL, un servidor web Nginx y Drupal. También protegeremos nuestra instalación obteniendo certificados TLS/SSL con Let’s Encrypt para el dominio que queremos asociar a nuestro sitio. Por último, configuraremos una tarea cron para renovar los certificados de modo que nuestro dominio permanezca seguro.
Para este tutorial, necesitaremos lo siguiente:
sudo
y un firewall activo. Para obtener información sobre cómo configurarlos, consulte esta guía de configuración inicial para servidores.your_domain
en todo momento. Puede obtener un ejemplar gratis en Freenom o utilizar el registrador de dominios que desee.your_domain
orientado a la dirección IP pública de su servidor.www.your_domain
orientado a la dirección IP pública de su servidor.Antes de ejecutar cualquier contenedor, debemos definir la configuración de nuestro servidor web de Nginx. En nuestro archivo de configuración, se incluirán algunos bloques de ubicación específicos de Drupal y un bloque de ubicación para dirigir las solicitudes de verificación de Let´s Encrypt al cliente Certbot, a fin de renovar los certificados de manera automática.
Primero, crearemos un directorio del proyecto para nuestra configuración de Drupal que denominaremos drupal
:
- mkdir drupal
Diríjase al directorio que acaba de crear:
- cd drupal
Ahora podemos crear un directorio para nuestro archivo de configuración:
- mkdir nginx-conf
Abra el archivo con nano o su editor de texto favorito:
- nano nginx-conf/nginx.conf
En este archivo, añadiremos un bloque de servidor con directivas para el nombre del servidor y el root del documento, bloques de ubicación para dirigir la solicitud de certificados del cliente de Certbot, procesamiento de PHP y solicitudes de recursos estáticos.
Agregue el siguiente código al archivo. Asegúrese de sustituir your_domain
por su propio 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;
}
rewrite ^/core/authorize.php/core/authorize.php(.*)$ /core/authorize.php$1;
location ~ \.php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass drupal: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 incluye la siguiente información:
Directivas:
listen
: indica a Nginx que escuche en el puerto 80
, lo que nos permitirá utilizar el complemento webroot de Certbot para nuestras solicitudes de certificados. Tenga en cuenta que aún no incluiremos el puerto 443
; actualizaremos nuestra configuración para incluir SSL una vez que hayamos obtenido nuestros certificados de manera exitosa.
server_name
: define el nombre de nuestro servidor y el bloque de servidor que debería utilizarse para las solicitudes a nuestro servidor. Asegúrese de sustituir your_domain
en esta línea por su propio nombre de dominio.
index
: la directiva index define los archivos que se utilizarán como índices al procesar las solicitudes a nuestro servidor. En este caso, modificamos el orden de prioridad predeterminado moviendo index.php
antes de index.html
para que Nginx priorice los archivos llamados index.php
cuando sea posible.
root
: nuestra directiva root nombra el directorio root para las solicitudes a nuestro servidor. Este directorio, /var/www/html
, se crea como punto de montaje en el momento de la compilación siguiendo las instrucciones de nuestro Drupal Dockerfile. Estas instrucciones de Dockerfile también garantizan que los archivos de la versión de Drupal se monten en este volumen.
rewrite
: si la expresión regular especificada (^/core/authorize.php/core/authorize.php(.*)$
) coincide con una solicitud URI, el URI se modifica según lo especificado en la cadena de sustitución (/core/authorized.php$1
).
Bloques de ubicación:
location ~ /.well-known/acme-challenge
: este bloque de ubicación manejará las solicitudes al directorio .well-known
, donde Certbot creará un archivo temporal para validar la resolución del DNS de nuestro dominio en nuestro servidor. Una vez implementada esta configuración, podremos utilizar el complemento webroot de Certbot para obtener los certificados para nuestro dominio.
location /
: en este bloque de ubicación, utilizaremos una directiva try_files
para buscar archivos que coincidan con solicitudes del URI individuales. Sin embargo, en lugar de devolver un estado 404 Not Found
por defecto, pasaremos el control al archivo index.php
de Drupal con los argumentos de solicitud.
location ~ \.php$
: este bloque de ubicación se encargará del procesamiento de PHP y servirá como proxy de estas solicitudes a nuestro contenedor drupal. Debido a que nuestra imagen de Docker de Drupal se basará en la imagen php:fpm
, también incluiremos opciones de configuración que son específicas para el protocolo FastCGI en este bloque. Nginx requiere un procesador de PHP independiente para solicitudes de PHP: en nuestro caso, estas solicitudes estarán a cargo del procesador php-fpm
que está incluido con la imagen php:fpm
. Además, este bloque de ubicación incluye directivas, variables y opciones específicas de FastCGI que actuarán como proxy para las solicitudes a la aplicación de Drupal que se ejecuten en nuestro contenedor Drupal, establecerán el índice preferido para el identificador URI de la solicitud analizada, y analizarán las solicitudes de URI.
location ~ /\.ht
: este bloque se encargará de los archivos .htaccess
, ya que Nginx no los proporcionará. La directiva deny_all
garantiza que los archivos de .htaccess
nunca se proporcionarán a los usuarios.
location = /favicon.ico, location = /robots.txt
: estos bloques garantizan que las solicitudes a /favicon.ico
y /robots.txt
no se registren.
location ~* \.(css|gif|ico|jpeg|jpg|js|png)$
: este bloque desactiva el registro para solicitudes de activos estáticos y garantiza que estos activos tengan altas condiciones de almacenamiento en caché, ya que normalmente su mantenimiento es costoso.
Para obtener más información sobre proxy de FastCGI, consulte el artículo Información e implementación de proxy de FastCGI en Nginx. Para obtener información sobre los bloques de servidor y ubicación, consulte el artículo Información sobre algoritmos de selección de bloques de servidores y ubicación de Nginx.
Guarde y cierre el archivo cuando concluya la edición.
Una vez implementada su configuración de Nginx, puede crear variables de entorno para pasarlas a su aplicación y contenedores de bases de datos en tiempo de ejecución.
Nuestra aplicación de Drupal necesita una base de datos (MySQL, PostgresSQL, etc.) para guardar la información relacionada con el sitio. El contenedor de Drupal necesitará acceso a ciertas variables de entorno al momento de ejecución para acceder al contenedor de la base de datos (MySQL). Estas variables contienen la información confidencial, como las credenciales de la base de datos, por lo que no podemos exponerlas directamente en el archivo de Docker Compose, el archivo principal que contiene información sobre cómo se ejecutarán nuestros contenedores.
Siempre se recomienda establecer los valores confidenciales en el archivo .env
y restringir su circulación. Esto impedirá que estos valores se copien en los repositorios de nuestro proyecto y se expongan al público.
En el directorio principal del proyecto, ~/drupal
, cree y abra un archivo denominado .env
:
- nano .env
Agregue las siguientes variables al archivo .env
y sustituya las secciones resaltadas con las credenciales que quiere utilizar:
MYSQL_ROOT_PASSWORD=root_password
MYSQL_DATABASE=drupal
MYSQL_USER=drupal_database_user
MYSQL_PASSWORD=drupal_database_password
Hemos agregado una contraseña para la cuenta administrativa root de MySQL, además de nuestro nombre de usuario y contraseña preferidos para la base de datos de nuestra aplicación.
Nuestro archivo .env
contiene información confidencial, por lo que siempre se recomienda incluirlo en los archivos .gitignore
y .dockerignore
de un proyecto para que no se añada en nuestros repositorios de Git e imágenes de Docker.
Si planea trabajar con Git para el control de versiones, inicialice su directorio de trabajo actual como un repositorio con git init
:
- git init
Abra el archivo .gitignore
:
- nano .gitignore
Agregue lo siguiente:
.env
Guarde el archivo y ciérrelo.
De manera similar, abra el archivo .dockerignore
:
- nano .dockerignore
Luego, agregue lo siguiente:
.env
.git
Guarde el archivo y ciérrelo.
Ahora que hemos tomado medidas para proteger nuestras credenciales como variables de entorno, vayamos al siguiente paso para definir nuestros servicios en un archivo docker-compose.yml
.
Docker Compose es una herramienta para definir y ejecutar aplicaciones de Docker de varios contenedores. Definimos un archivo YAML
para configurar los servicios de nuestra aplicación. Un servicio en Docker Compose es un contenedor en ejecución, y Compose nos permite vincular estos servicios con volúmenes y redes compartidos.
Crearemos contenedores diferentes para la aplicación, la base de datos y el servidor web de Drupal. Además, también crearemos un contenedor para ejecutar Certbot, a fin de obtener los certificados para nuestro servidor web.
Cree un archivo docker-compose.yml
:
- nano docker-compose.yml
Agregue el siguiente código para definir la versión del archivo de Compose y el servicio de base de datos mysql
:
version: "3"
services:
mysql:
image: mysql:8.0
container_name: mysql
command: --default-authentication-plugin=mysql_native_password
restart: unless-stopped
env_file: .env
volumes:
- db-data:/var/lib/mysql
networks:
- internal
Analicemos cada uno con todas las opciones de configuración del servicio mysql
:
image
: especifica la imagen que se utilizará/extraerá para crear el contenedor. Siempre se recomienda utilizar la imagen con la etiqueta de la versión adecuada, y excluir la etiqueta latest
para evitar conflictos futuros. Puedes obtener más información sobre las Prácticas recomendadas de Dockerfile en la documentación de Docker.
container_name
: sirve para definir el nombre del contenedor.
command
: se utiliza para anular el comando predeterminado (instrucción CMD) en la imagen. MySQL admite diferentes complementos de autenticación, pero mysql_native_password
es el método tradicional para autenticar. Ya que PHP, y por lo tanto, Drupal, no admite la autenticación más reciente de MySQL, debemos establecer --default-authentication-plugin=mysql_native_password
como el mecanismo de autenticación predeterminado.
restart
: se utiliza para definir la política de reinicio del contenedor. La política unless-stopped
reinicia un contenedor a menos que se detenga manualmente.
env_file
: añade las variables de entorno desde un archivo. En nuestro caso, leerá las variables de entorno del archivo .env
que definimos en el paso anterior.
volumes
: monta rutas host o volúmenes con nombre, que se especificaron como subopciones de un servicio. Vamos a montar un volumen con nombre denominado db-data
al directorio /var/lib/mysql
en el contenedor, donde por defecto MySQL escribirá sus archivos de datos.
networks
: define la red interna
a la que se unirá nuestro servicio de aplicación. Definiremos las redes al final del archivo.
Ya hemos definido la definición de nuestro servicio mysql
, así que ahora agregaremos la definición del servicio de la aplicación de drupal
al final del archivo:
...
drupal:
image: drupal:8.7.8-fpm-alpine
container_name: drupal
depends_on:
- mysql
restart: unless-stopped
networks:
- internal
- external
volumes:
- drupal-data:/var/www/html
En esta definición del servicio, nombraremos nuestro contenedor y definiremos una política de reinicio, tal como lo hicimos con el servicio mysql
. También añadiremos algunas opciones específicas para este contenedor:
image
: aquí utilizamos la imagen de Drupal 8.7.8-fpm-alpine
. Esta imagen tiene el procesador php-fpm
que requiere nuestro servidor web de Nginx para administrar el procesamiento de PHP. Además, utilizamos la imagen alpine
, proveniente del proyecto Alpine Linux, que reducirá el tamaño de la imagen en general y cuyo uso se aconseja en las prácticas recomendadas de Dockerfile. Drupal tiene más versiones de imágenes que puedes descubrir en Dockerhub.
depends_on
: se utiliza para expresar dependencia entre los servicios. Definir el servicio mysql
como la dependencia a nuestro contenedor drupal
garantizará que nuestro contenedor drupal
se cree después del contenedor mysql
y habilitará nuestra aplicación para que se inicie sin problemas.
networks
: aquí hemos agregado este contenedor a la red externa
junto con la red interna
. Esto garantizará que nuestro servicio mysql
sea accesible únicamente desde el contenedor drupal
a través de la red interna
, y al mismo tiempo mantendrá este contenedor accesible para otros contenedores por medio de la red externa
.
volumes
: montaremos un volumen con nombre denominado drupal-data
al punto de montaje /var/www/html
creado por la imagen de Drupal. Usar un volumen con nombre de esta manera nos permitirá compartir el código de nuestra aplicación con otros contenedores.
A continuación, añadiremos la definición del servicio de Nginx después de la definición del servicio de drupal
:
...
webserver:
image: nginx:1.17.4-alpine
container_name: webserver
depends_on:
- drupal
restart: unless-stopped
ports:
- 80:80
volumes:
- drupal-data:/var/www/html
- ./nginx-conf:/etc/nginx/conf.d
- certbot-etc:/etc/letsencrypt
networks:
- external
De nuevo, nombraremos nuestro contenedor y haremos que dependa del contenedor de Drupal por orden de inicio. También utilizaremos una imagen alpine: la imagen de Nginx 1.17.4-alpine
.
Esta definición de servicio también incluye las siguientes opciones:
ports
: expone el puerto 80
para habilitar las opciones de configuración que definimos en nuestro archivo nginx.conf
en el paso 1.
volumes
: aquí definimos tanto el volumen con nombre como la ruta host:
drupal-data:/var/www/html
: montará el código de nuestra aplicación de Drupal al directorio /var/www/html
, el que configuramos como root en nuestro bloque de servidor de Nginx.
./nginx-conf:/etc/nginx/conf.d
: montará el directorio de configuración de Nginx en el host al directorio pertinente del contenedor, lo cual garantizará que cualquier cambio que realicemos en los archivos del host se refleje en el contenedor.
certbot-etc:/etc/letsencrypt
: montará los certificados y las claves pertinentes de Let’s Encrypt para nuestro dominio al directorio correspondiente del contenedor.
networks
: hemos definido la red externa
para que este contenedor solo se comunique con el contenedor drupal
y no con el contenedor mysql
.
Por último, agregaremos la última definición del servicio para el servicio certbot
. Asegúrese de sustituir sammy@your_domain
y your_domain
por su correo electrónico y nombre de dominio:
...
certbot:
depends_on:
- webserver
image: certbot/certbot
container_name: certbot
volumes:
- certbot-etc:/etc/letsencrypt
- drupal-data:/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 introduzca la imagen certbot/certbot
de Docker Hub. También utiliza volúmen con nombre para compartir recursos con el contenedor de Nginx, incluidos los certificados de dominio y la clave en certbot-etc
, y el código de la aplicación en drupal-data
.
También hemos utilizado depends_on
para asegurarnos de que el contenedor certbot
se inicie tras la ejecución del servicio del servidor web
.
Aquí no hemos especificado ninguna red
, porque este contenedor no se comunicará a ningún servicio a través de la red. Solo añade los certificados de dominio y la clave, que hemos montado utilizando los volúmenes con nombre.
También incluimos una opción de command
que especifica un subcomando que debe ejecutarse con el comando de certbot
predeterminado del contenedor. El cliente de Certbot admite complementos para obtener e instalar certificados. Incluimos certonly
y --webroot
en la línea de comandos para utilizar el complemento webroot
para obtener un certificado. Puede encontrar más información sobre el complemento y los comandos adicionales en la documentación oficial de Certbot.
Debajo de la definición de servicio certbot
, agregue las definiciones de red y volumen:
...
networks:
external:
driver: bridge
internal:
driver: bridge
volumes:
drupal-data:
db-data:
certbot-etc:
La clave networks
de nivel superior nos permite especificar las redes que debemos crear. networks
permite la comunicación entre los servicios/contenedores en todos los puertos, ya que están en el mismo host de demonio de Docker. Hemos definido dos redes: internal
y external
, para proteger la comunicación de los servicios del servidor web
, drupal
y mysql
.
La clave volumes
se utiliza para definir los volúmenes con nombre drupal-data
, db-data
y certbot-etc
. Cuando Docker crea volúmenes, el contenido del volumen se almacena en un directorio del sistema de archivos host, /var/lib/docker/volumes/
, que Docker administra. El contenido de cada volumen luego se monta desde este directorio en cualquier contenedor que utilice el volumen en cuestión. De esta manera, es posible compartir códigos y datos entre contenedores.
El archivo docker-compose.yml
terminado tendrá este aspecto:
version: "3"
services:
mysql:
image: mysql:8.0
container_name: mysql
command: --default-authentication-plugin=mysql_native_password
restart: unless-stopped
env_file: .env
volumes:
- db-data:/var/lib/mysql
networks:
- internal
drupal:
image: drupal:8.7.8-fpm-alpine
container_name: drupal
depends_on:
- mysql
restart: unless-stopped
networks:
- internal
- external
volumes:
- drupal-data:/var/www/html
webserver:
image: nginx:1.17.4-alpine
container_name: webserver
depends_on:
- drupal
restart: unless-stopped
ports:
- 80:80
volumes:
- drupal-data:/var/www/html
- ./nginx-conf:/etc/nginx/conf.d
- certbot-etc:/etc/letsencrypt
networks:
- external
certbot:
depends_on:
- webserver
image: certbot/certbot
container_name: certbot
volumes:
- certbot-etc:/etc/letsencrypt
- drupal-data:/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
networks:
external:
driver: bridge
internal:
driver: bridge
volumes:
drupal-data:
db-data:
certbot-etc:
Ya terminamos de definir nuestros servicios. A continuación, iniciaremos el contenedor y probaremos nuestras solicitudes de certificado.
Podemos iniciar nuestros contenedores con el comando docker-compose up
, que creará y ejecutará nuestros contenedores en el orden que especificamos. Si las solicitudes de nuestros dominios tienen éxito, veremos el estado de salida correcto en nuestro resultado y los certificados correctos montados en la carpeta /etc/letsencrypt/live
del contenedor del servidor web.
Para ejecutar los contenedores en segundo plano, utilice el comando docker-compose up
con el indicador -d
:
- docker-compose up -d
Verá un resultado similar que confirmará la creación de sus servicios:
Output...
Creating mysql ... done
Creating drupal ... done
Creating webserver ... done
Creating certbot ... done
Compruebe el estado de los servicios utilizando el comando docker-compose ps
:
- docker-compose ps
Veremos los servicios mysql
, drupal
y webserver
con un State
(estado) de valor Up
, a la vez que certbot
arrojará un mensaje de estado con valor 0
:
Output Name Command State Ports
--------------------------------------------------------------------------
certbot certbot certonly --webroot ... Exit 0
drupal docker-php-entrypoint php-fpm Up 9000/tcp
mysql docker-entrypoint.sh --def ... Up 3306/tcp, 33060/tcp
webserver nginx -g daemon off; Up 0.0.0.0:80->80/tcp
Si ve algo diferente de Up
en la columna State
para los servicios mysql
, drupal
o webserver
, o un estado de salida distinto a 0
para el contenedor certbot
, asegúrese de verificar los registros de servicio con el comando docker-compose logs
:
- docker-compose logs service_name
Ahora podemos verificar que nuestros certificados estén montados en el contenedor webserver
utilizando el comando docker-compose exec
:
- docker-compose exec webserver ls -la /etc/letsencrypt/live
Esto generará el siguiente resultado:
Outputtotal 16
drwx------ 3 root root 4096 Oct 5 09:15 .
drwxr-xr-x 9 root root 4096 Oct 5 09:15 ..
-rw-r--r-- 1 root root 740 Oct 5 09:15 README
drwxr-xr-x 2 root root 4096 Oct 5 09:15 your_domain
Ahora que todo se ejecuta correctamente, podemos editar la definición de nuestro servicio de certbot
para eliminar el indicador --staging
.
Abra el archivo docker-compose.yml
, vaya a la definición de servicio de certbot
y sustituya el indicador --staging
en la opción de comando por el indicador --force-renewal
, el cual indicará a Certbot que quiere solicitar un nuevo certificado con los mismos dominios que un certificado existente. La definición actualizada de certbot
tendrá este aspecto:
...
certbot:
depends_on:
- webserver
image: certbot/certbot
container_name: certbot
volumes:
- certbot-etc:/etc/letsencrypt
- drupal-data:/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
...
Tenemos que ejecutar docker-compose up
de nuevo para recrear el contenedor de certbot
. También incluiremos la opción --no-deps
para indicar a Compose que puede omitir el inicio del servicio webserver
, dado que ya está en ejecución:
- docker-compose up --force-recreate --no-deps certbot
Veremos un resultado que indicará que nuestra solicitud de certificado fue exitosa:
OutputRecreating 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 2020-01-03. 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 hayamos generado correctamente nuestros certificados, podemos actualizar nuestra configuración de Nginx para incluir SSL.
Después de instalar los certificados SSL en Nginx, tendremos que redirigir todas las solicitudes de HTTP a HTTPS. También tendremos que especificar las ubicaciones de nuestro certificado SSL y de la clave, y agregar encabezados y parámetros de seguridad.
Debido a que recreará el servicio webserver
para incluir estas adiciones, puede detenerlo ahora:
- docker-compose stop webserver
Esto generará el siguiente resultado:
OutputStopping webserver ... done
A continuación, vamos a eliminar el archivo de configuración de Nginx que creamos anteriormente:
- rm nginx-conf/nginx.conf
Abra otra versión del archivo:
- nano nginx-conf/nginx.conf
Añada el siguiente código al archivo para redireccionar HTTP a HTTP y para agregar credenciales, protocolos y encabezados de seguridad SSL. Recuerde sustituir your_domain
por su 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;
listen [::]:443 ssl;
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;
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;
location / {
try_files $uri $uri/ /index.php$is_args$args;
}
rewrite ^/core/authorize.php/core/authorize.php(.*)$ /core/authorize.php$1;
location ~ \.php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass drupal: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 de servidor HTTP especifica el complemento webroot para solicitudes de renovación de Certbot al directorio .well-known/acme-challenge
. También incluye una directiva de reescritura
que dirige las solicitudes HTTP al directorio root hacia HTTPS.
El bloque de servidor HTTPS habilita ssl
y http2
. Para obtener más información sobre la iteración de HTTP/2 en protocolos HTTP y los beneficios que puede tener para el rendimiento de sitios web, consulte la introducción de Cómo configurar Nginx con compatibilidad para HTTP/2 en Ubuntu 18.04.
Estos bloques habilitan SSL, ya que hemos incluido las ubicaciones de nuestro certificado SSL y de la clave junto con los encabezados recomendados. Estos encabezados nos permitirán obtener una clasificación A en los sitios de prueba de servidores de SSL Labs y Security Headers.
Nuestras directivas root
e index
también se encuentran en este bloque, al igual que el resto de los bloques de ubicación específicos de Drupal que analizamos en el paso 1.
Guarde y cierre el archivo de configuración actualizado de Nginx.
Antes de comenzar a recrear el contenedor de webserver
, tendremos que agregar una asignación de puerto 443
a la definición de nuestro servicio de webserver
, ya que hemos habilitado los certificados SSL.
Abra el archivo docker-compose.yml
:
- nano docker-compose.yml
Realice las siguientes modificaciones de la definición de servicio de webserver
:
...
webserver:
image: nginx:1.17.4-alpine
container_name: webserver
depends_on:
- drupal
restart: unless-stopped
ports:
- 80:80
- 443:443
volumes:
- drupal-data:/var/www/html
- ./nginx-conf:/etc/nginx/conf.d
- certbot-etc:/etc/letsencrypt
networks:
- external
...
Después de habilitar los certificados SSL, nuestro docker-compose.yml
se verá de la siguiente manera:
version: "3"
services:
mysql:
image: mysql:8.0
container_name: mysql
command: --default-authentication-plugin=mysql_native_password
restart: unless-stopped
env_file: .env
volumes:
- db-data:/var/lib/mysql
networks:
- internal
drupal:
image: drupal:8.7.8-fpm-alpine
container_name: drupal
depends_on:
- mysql
restart: unless-stopped
networks:
- internal
- external
volumes:
- drupal-data:/var/www/html
webserver:
image: nginx:1.17.4-alpine
container_name: webserver
depends_on:
- drupal
restart: unless-stopped
ports:
- 80:80
- 443:443
volumes:
- drupal-data:/var/www/html
- ./nginx-conf:/etc/nginx/conf.d
- certbot-etc:/etc/letsencrypt
networks:
- external
certbot:
depends_on:
- webserver
image: certbot/certbot
container_name: certbot
volumes:
- certbot-etc:/etc/letsencrypt
- drupal-data:/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
networks:
external:
driver: bridge
internal:
driver: bridge
volumes:
drupal-data:
db-data:
certbot-etc:
Guarde y cierre el archivo. Ahora crearemos el servicio webserver
con nuestra configuración actualizada:
- docker-compose up -d --force-recreate --no-deps webserver
Esto generará el siguiente resultado:
OutputRecreating webserver ... done
Compruebe los servicios con docker-compose ps
:
- docker-compose ps
Veremos los servicios de mysql
, drupal
y webserver
como Up
, mientras que certbot
arrojará un mensaje de estado con valor 0
:
Output Name Command State Ports
--------------------------------------------------------------------------
certbot certbot certonly --webroot ... Exit 0
drupal docker-php-entrypoint php-fpm Up 9000/tcp
mysql 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
Ahora, todos nuestros servicios se están ejecutando y podemos continuar con la instalación de Drupal a través de la interfaz web.
Completaremos la instalación mediante la interfaz web de Drupal.
En un navegador web, diríjase al dominio del servidor. Recuerde sustituir aquí your_domain
por su propio nombre de dominio:
https://your_domain
Seleccione el idioma que utilizará:
Haga clic en Guardar y continuar. Llegaremos a la página de Perfil de instalación. Drupal tiene varios perfiles, así que seleccione el perfil Estándar y haga clic en Guardar y continuar.
Después de seleccionar el perfil, pasaremos a la página de Configuración de la base de datos. Seleccione el tipo de base de datos MySQL, MariaDB, Percona Server o equivalente y escriba los valores de nombre de la base de datos, usuario y contraseña que se corresponden con los valores de MYSQL_DATABASE
, MYSQL_USER
y MYSQL_PASSWORD
, respectivamente, los cuales definimos en el archivo .env
en el paso 2. Haga clic en Opciones avanzadas y utilice el nombre del contenedor de servicio mysql
para el valor de Host. Haga clic en Guardar y continuar.
Después de configurar la base de datos, se comenzarán a instalar los módulos y los temas predeterminados de Drupal:
Cuando se haya instalado el sitio, llegaremos a la página de configuración del sitio de Drupal en donde podremos establecer el nombre del sitio, el correo electrónico, el usuario, la contraseña y la configuración regional. Complete la información y haga clic en Guardar y continuar:
Después de hacer clic en Guardar y continuar, podemos ver la página Bienvenido a Drupal que muestra que nuestro sitio de Drupal está listo y funciona correctamente.
Ahora que completamos la instalación de Drupal,debemos asegurarnos de que nuestros certificados SSL se renueven automáticamente.
Los certificados de Let’s Encrypt son válidos durante 90 días, por lo que tenemos que configurar un proceso de renovación automática para asegurarnos de que no caduquen. Una forma de hacerlo es crear una tarea con la utilidad de programación cron
. En este caso, crearemos una tarea cron
para que de forma periódica ejecute una secuencia de comandos que renovará nuestros certificados y volverá a cargar nuestra configuración de Nginx.
Vamos a crear el archivo ssl_renew.sh
para renovar los certificados:
- nano ssl_renew.sh
Agregue el siguiente código: Recuerde sustituir el nombre del directorio por su non-root user:
#!/bin/bash
cd /home/sammy/drupal/
/usr/local/bin/docker-compose -f docker-compose.yml run certbot renew --dry-run && \
/usr/local/bin/docker-compose -f docker-compose.yml kill -s SIGHUP webserver
Esta secuencia de comandos cambia al directorio del proyecto ~/drupal
y ejecuta los siguientes comandos docker-compose
.
docker-compose run
: iniciará un contenedor certbot
y anulará el command
proporcionado en nuestra definición de servicio certbot
. En lugar de usar el subcomando de certonly
, utilizaremos aquí el subcomando renew
que renovará los certificados que caducarán pronto. En este caso, incluimos la opción --dry-run
para probar nuestra secuencia de comandos.
docker-compose kill
: enviará una señal de SIGHUP
al contenedor webserver
para volver a cargar la configuración de Nginx.
Cierre el archivo y utilice el siguiente comando para que sea ejecutable:
- sudo chmod +x ssl_renew.sh
A continuación, abra el archivo root
crontab para ejecutar la secuencia de comandos de renovación en un intervalo especificado:
- sudo crontab -e
Si es la primera vez que edita este archivo, se le solicitará elegir un editor de texto para abrir el archivo:
Outputno crontab for root - using an empty one
Select an editor. To change later, run 'select-editor'.
1. /bin/nano
2. /usr/bin/vim.basic
3. /usr/bin/vim.tiny
4. /bin/ed
Choose 1-4 [1]:
...
Al final del archivo, agregue la siguiente línea, en la que reemplazará sammy
por su nombre de usuario:
...
*/5 * * * * /home/sammy/drupal/ssl_renew.sh >> /var/log/cron.log 2>&1
Esto fijará un intervalo de tarea de cinco minutos, para que podamos probar si la solicitud de renovación funciona como estaba previsto. También creamos un archivo de registro, cron.log
para registrar el resultado pertinente de la tarea.
Pasados cinco minutos, utilice el comando tail
para verificar cron.log
y ver si la solicitud de renovación fue exitosa:
- tail -f /var/log/cron.log
Verá un resultado que confirme el éxito de la renovación:
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.)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Presione CTRL+C
para abandonar el proceso tail
.
Ahora podemos modificar el archivo crontab para ejecutar la secuencia de comandos el segundo día de todas las semanas a las 2:00. Modifique la última línea de crontab como se muestra:
...
* 2 * * 2 /home/sammy/drupal/ssl_renew.sh >> /var/log/cron.log 2>&1
Guarde y cierre el archivo.
Ahora, eliminaremos la opción --dry-run
de la secuencia de comandos ssl_renew.sh
. Primero, ábralo:
- nano ssl_renew.sh
Luego, modifique el contenido como se muestra a continuación:
#!/bin/bash
cd /home/sammy/drupal/
/usr/local/bin/docker-compose -f docker-compose.yml run certbot renew && \
/usr/local/bin/docker-compose -f docker-compose.yml kill -s SIGHUP webserver
Ahora, nuestra tarea cron
evitará el vencimiento de los certificados SSL al renovarlos cuando sean elegibles.
En este tutorial, utilizamos Docker Compose para crear una instalación de Drupal con un servidor web de Nginx. Como parte de este flujo de trabajo, obtuvimos los certificados TLS/SSL para el dominio que queríamos asociar a nuestro sitio de Drupal y creamos una tarea cron para renovar los certificados cuando sea necesario.
Si quiere obtener más información sobre Docker, consulte nuestra página temática dedicada a Docker.
Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.
This textbox defaults to using Markdown to format your answer.
You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!
Good tutorial, thank you! I suggest this improvement: The
ssl_renew
file creates a docker container every time it runs, so you will have a lot of docker containers useless, I added an extra line to that file to delete them:Me manda el error 502 cuando intento acceder al dominio, estoy lanzando la aplicación en una instancia gratuita de aws. No em funciona el dominio…