Existen varias formas de mejorar la flexibilidad y la seguridad de su aplicación de Node.js. Utilzar un proxy inverso como Nginx le permite cargar solicitudes de equilibrio, almacenar en caché contenido estático e implementar seguridad en la capa de transporte (TLS). Habilitar HTTPS cifrado en su servidor garantiza que la comunicación hacia y desde su aplicación permanezca protegida.
La implementación de un proxy inverso con TLS/SSL en contenedores implica un conjunto de procedimientos diferente del que se emplea trabajar directamente en un sistema operativo host. Por ejemplo, si obtiene certificados de Let’s Encrypt para una aplicación que se ejecuta en un servidor, instalaría el software requerido directamente en su host. Los contenedores le permiten adoptar un enfoque diferente. Utilizando Docker Compose, puede crear contenedores para su aplicación, su servidor web y el cliente de Certbot que le permitirá obtener sus certificados. Siguiendo estos pasos, puede aprovechar la modularidad y portabilidad de un flujo de trabajo en contenedor.
A través de este tutorial, implementará una aplicación Node.js con un proxy inverso de Nginx utilizando Docker Compose. Obtendrá certificados TLS/SSL para el dominio asociado con su aplicación y garantizará que reciba una alta calificación de seguridad de SSL Labs. Por último, configurará una tarea cron
para renovar sus certificados de modo que su dominio permanezca seguro.
Para seguir este tutorial, necesitará lo siguiente:
Un servidor de Ubuntu 18.04, un usuario no root con privilegios sudo
y un firewall activo. Para obtener información sobre cómo configurarlos, consulte esta guía de configuración inicial de servidores.
Docker y Docker Compose instalados en su servidor. Para obtener orientación sobre la instalación de Docker, siga los pasos 1 y 2 de Cómo instalar y usar Docker en Ubuntu 18.04. Para acceder a orientación relacionada con la instalación de Compose, siga el paso 1 de Cómo instalar Docker Compose en Ubuntu 18.04.
Un nombre de dominio registrado. En este tutorial, se utilizará example.com en todo momento. Puede obtener un ejemplar gratis en Freenom o utilizar el registrador de dominios que desee.
Los dos registros DNS que se indican a continuación se configuraron para su servidor. Puede seguir esta introducción al DNS de DigitalOcean para obtener información sobre cómo agregarlos a una cuenta de DigitalOcean, si usa una:
example.com
orientado a la dirección IP pública de su servidor.example.com
orientado a la dirección IP pública de su servidor.Como primer paso, clonaremos el repositorio con el código de aplicación de Node, que incluye el Dockerfile que utilizaremos para crear nuestra imagen de aplicación con Compose. Primero, podemos probar la aplicación compilándola y ejecutándola con el comando docker run
, sin un proxy inverso o SSL.
En el directorio principal de su usuario no root, clone el repositorio nodejs-image-demo
de la cuenta de GitHub de la comunidad de DigitalOcean. Este repositorio incluye el código de la configuración descrita en Cómo crear una aplicación de Node.js con Docker.
Clone el repositorio en un directorio llamado node_project:
- git clone https://github.com/do-community/nodejs-image-demo.git node_project
Pase al directorio node_project
:
- cd node_project
En este directorio, hay un Dockerfile que contiene instrucciones para crear una aplicación de Node usando la imagen Docker node:10
y el contenido de su directorio de proyecto actual. Puede consultar el contenido de Dockerfile escribiendo lo siguiente:
- cat Dockerfile
OutputFROM node:10-alpine
RUN mkdir -p /home/node/app/node_modules && chown -R node:node /home/node/app
WORKDIR /home/node/app
COPY package*.json ./
USER node
RUN npm install
COPY --chown=node:node . .
EXPOSE 8080
CMD [ "node", "app.js" ]
Estas instrucciones crean una imagen de Node copiando el código del proyecto del directorio actual al contenedor e instalando dependencias con npm install
. También aprovechan el almacenamiento en caché y la disposición en capas de imágenes de Docker al separar la copia de package.json
y package-lock.json
, que contienen las dependencias listadas del proyecto, de la copia del resto del código de aplicación. Por último, las instrucciones especifican que el contenedor se ejecutará como usuario del nodo no root con los permisos apropiados establecidos en el código de aplicación y los directorios de node_modules.
Para obtener más información sobre prácticas recomendadas de Dockerfile y Node, consulte el análisis completo en el paso 3 de Cómo crear una aplicación Node.js con Docker.
Para probar la aplicación sin SSL, puede crear y etiquetar la imagen usando docker build
y el indicador -t
. Daremos a la imagen el nombre node-demo
, pero puede elegir cualquier otro nombre:
- docker build -t node-demo .
Una vez que el proceso de compilación esté completo, podrá enumerar sus imágenes con docker images
:
- docker images
Visualizará el siguiente resultado, que confirma la compilación de la imagen de la aplicación:
OutputREPOSITORY TAG IMAGE ID CREATED SIZE
node-demo latest 23961524051d 7 seconds ago 73MB
node 10-alpine 8a752d5af4ce 3 weeks ago 70.7MB
A continuación, cree el contenedor con docker run
. Incluiremos tres marcas con este comando:
-p:
edita el puerto en el contenedor y lo asigna a un puerto en nuestro host. Usaremos el puerto 80
en el host, pero puede modificarlo como considere necesario si tiene otro proceso en ejecución en ese puerto. Para obtener más información sobre cómo funciona, consulte esta discusión en la documentación de Docker sobre enlaces de puerto.-d
: ejecuta el contenedor en segundo plano.--name
: permite darle al contenedor un nombre fácil de recordar.Ejecute el siguiente comando para compilar el contenedor:
- docker run --name node-demo -p 80:8080 -d node-demo
Inspeccione sus contenedores en ejecución con docker ps
:
- docker ps
Verá un resultado que confirmará que el contenedor de su aplicación se encuentra en ejecución:
OutputCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
4133b72391da node-demo "node app.js" 17 seconds ago Up 16 seconds 0.0.0.0:80->8080/tcp node-demo
Ahora podrá visitar su dominio para probar su configuración: http://example.com
. Recuerde sustituir example.com
por su propio nombre de dominio. En su aplicación se mostrará la siguiente página de inicio:
Ahora que probó la aplicación, puede detener el contenedor y quitar las imágenes. Utilice docker ps
de nuevo para obtener su CONTAINER ID
:
- docker ps
OutputCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
4133b72391da node-demo "node app.js" 17 seconds ago Up 16 seconds 0.0.0.0:80->8080/tcp node-demo
Detenga el contenedor con docker stop
. Asegúrese de sustituir el CONTAINER ID
que se enumera aquí por su propio CONTAINER ID
de la aplicación:
- docker stop 4133b72391da
Ahora podrá quitar el contenedor detenido y todas las imágenes, incluidas las que no se utilicen y las pendientes, con docker system prune
y el indicador -a
:
- docker system prune -a
Escriba y
cuando se le indique, en la salida, para confirmar que desea eliminar el contenedor detenido y las imágenes. Tenga en cuenta que esto también eliminará la memoria caché de su compilación.
Una vez que se pruebe la imagen de su aplicación, puede continuar creando el resto de su configuración con Docker Compose.
Una vez implementada nuestra aplicación Dockerfile, podemos crear un archivo de configuración para ejecutar nuestro contenedor de Nginx. Comenzaremos con una configuración mínima que incluirá nuestro nombre de dominio, root de documentos, información de proxy y un bloque de ubicación para dirigir las solicitudes de Certbot al directorio .well-known
, donde creará un archivo temporal para validar que el DNS de nuestro dominio se resuelve en nuestro servidor.
Primero, cree un directorio en el directorio de proyecto actual para el archivo de configuración:
- mkdir nginx-conf
Abra el archivo con nano
o su editor favorito:
- nano nginx-conf/nginx.conf
Añada el siguiente bloque de servidor a las solicitudes de los usuarios de proxy en su contenedor de aplicación de Node, y para dirigir solicitudes de Certbot al directorio .well-known
. Asegúrese de sustituir example.com
por su propio nombre de dominio:
server {
listen 80;
listen [::]:80;
root /var/www/html;
index index.html index.htm index.nginx-debian.html;
server_name example.com www.example.com;
location / {
proxy_pass http://nodejs:8080;
}
location ~ /.well-known/acme-challenge {
allow all;
root /var/www/html;
}
}
Este bloque de servidor nos permitirá iniciar el contenedor de Nginx como proxy inverso, lo cual transmitirá solicitudes a nuestro contenedor de aplicación de Node. También nos permitirá usar el complemento webroot de Certbot para obtener certificados para nuestro dominio. Este complemento depende del método de validación HTTP-01, que utiliza una solicitud HTTP para probar que Certbot puede acceder a los recursos de un servidor que responda a un nombre de dominio determinado.
Una vez que haya concluido de editar, guarde y cierre el archivo. Para obtener más información sobre los algoritmos bloques de servidor y ubicación de Nginx, consulte el artículo Información sobre algoritmos de selección de bloques de servidores y ubicación de Nginx.
Una vez configurados los detalles del servidor web, podremos crear nuestro archivo docker-compose.yml
que nos permitirá crear nuestros servicios de aplicación y el contenedor de Certbot que utilizaremos para obtener nuestros certificados.
El archivo docker-compose.yml
definirá nuestros servicios, incluidos la aplicación y el servidor web de Node. Especificará detalles, como volúmenes nombrados, que serán esenciales para compartir credenciales SSL entre contenedores, así como información de redes y puertos. También nos permitirá especificar comandos puntuales que se ejecutarán cuando se creen nuestros contenedores. Este archivo es el recurso central que definirá la manera en que nuestros servicios funcionarán juntos.
Abra el archivo en su directorio actual:
- nano docker-compose.yml
Primero, defina el servicio de aplicación:
version: '3'
services:
nodejs:
build:
context: .
dockerfile: Dockerfile
image: nodejs
container_name: nodejs
restart: unless-stopped
La definición de servicio nodejs
incluye lo siguiente:
build
: define las opciones de configuración, incluido el context
y dockerfile
, que se aplicarán cuando Compose cree la imagen de la aplicación. Si desea utilizar una imagen existente de un registro como Docker Hub, podría utilizar la instrucción de imagen
como alternativa, con información sobre su nombre de usuario, repositorio y etiqueta de imagen.context
: define el contexto de compilación para la compilación de la imagen de la aplicación. En este caso, es el directorio de proyectos actual.dockerfile
: especifica el Dockerfile que Compose usará para la compilación, el Dockerfile que examinó en el paso 1.image
y container_name
: aplican nombres a la imagen y al contenedor.restart
: define la política de reinicio. El valor predeterminado es no
, pero configuramos el contenedor para reiniciarse a menos que se detenga.Tenga en cuenta que no incluiremos los montajes “bind” con este servicio, ya que nuestra configuración no se centra en el desarrollo sino en la implementación. Para obtener más información, consulte la documentación de Docker sobre montajes bind y volúmenes.
Para habilitar la comunicación entre los contenedores de la aplicación y del servidor web, también añadiremos una red de puente llamada app-network
debajo de la definición de reinicio:
services:
nodejs:
...
networks:
- app-network
Una red de puente definida por el usuario como esta permite la comunicación entre contenedores en el mismo host de demonio de Docker. Esto agiliza el tráfico y la comunicación dentro de su aplicación, ya que abre todos los puertos entre contenedores en la misma red de puente y, al mismo tiempo, no expone ningún puerto al mundo exterior. Por lo tanto, puede ser selectivo a la hora de abrir solo los puertos que necesita para exponer sus servicios de frontend.
A continuación, defina el servicio webserver
:
...
webserver:
image: nginx:mainline-alpine
container_name: webserver
restart: unless-stopped
ports:
- "80:80"
volumes:
- web-root:/var/www/html
- ./nginx-conf:/etc/nginx/conf.d
- certbot-etc:/etc/letsencrypt
- certbot-var:/var/lib/letsencrypt
depends_on:
- nodejs
networks:
- app-network
Algunos de los ajustes que definimos para el servicio nodejs
siguen siendo los mismos, pero también realizamos los siguientes cambios:
image
: indica a Compose que envíe la última imagen de Nginx basada en Alpine de Docker Hub. Para obtener más información sobre imágenes alpine
, consulte el paso 3 de Cómo crear una aplicación de Node.js con Docker.ports
: expone el puerto 80
para habilitar las opciones de configuración que definimos en nuestra configuración de Nginx.También especificamos los siguientes montajes “bind” y volúmenes con nombre:
web-root:/var/www/html
: agregará los activos estáticos de nuestro sitio, copiados a un volumen llamado web-root
, al directorio /var/www/html
del contenedor../nginx-conf:/etc/nginx/conf.d
: vinculará mediante montaje “bind” el directorio de configuración de Nginx en el host con el directorio pertinente en el contenedor, lo cual garantizará que cualquier cambio que realicemos en los archivos del host se reflejarán en el contenedor.certbot-etc:/etc/letsencrypt
: montará los certificados y las claves pertinentes de Let’s Encrypt para nuestro dominio en el directorio apropiado del contenedor.certbot-var:/var/lib/letsencrypt
: monta el directorio de trabajo predeterminado de Let’s Encrypt en el directorio correspondiente del contenedor.A continuación, agregue las opciones de configuración para el contenedor de certbot
. Asegúrese de sustituir la información de dominio y correo electrónico por su propio nombre de dominio y su correo electrónico de contacto:
...
certbot:
image: certbot/certbot
container_name: certbot
volumes:
- certbot-etc:/etc/letsencrypt
- certbot-var:/var/lib/letsencrypt
- web-root:/var/www/html
depends_on:
- webserver
command: certonly --webroot --webroot-path=/var/www/html --email sammy@example.com --agree-tos --no-eff-email --staging -d example.com -d www.example.com
Esta definición indica a Compose que obtenga la imagen de certbot/certbot de Docker Hub. También utiliza volúmenes con nombre para compartir recursos con el contenedor de Nginx, incluidos los certificados de dominio y la clave en certbot-etc
, el directorio de trabajo de Let’s Encrypt en certbot-var
y el código de aplicación en web-root
.
Una vez más, usamos depends_on
para especificar que el contenedor de certbot
debe iniciarse una vez que el servicio webserver
esté en ejecución.
También incluimos una opción de command
que especifica el comando que se ejecutará cuando se inicie el contenedor. Incluye el subcomando certonly
con las siguientes opciones:
--webroot
: indica a Cerbot que utilice el complemento webroot para colocar archivos en la carpeta webroot para la autenticación.--webroot-path
: especifica la ruta del directorio webroot.--email
: su correo electrónico preferido para el registro y la recuperación.--agree-tos
: especifica que acepta el Acuerdo de suscripción de ACME.--no-eff-email
: indica a Certbot que usted no desea compartir su correo electrónico con la Electronic Frontier Foundation (EFF). Puede omitirlo si lo prefiere.--staging
: indica a Certbot que desea utilizar el entorno de configuración de Let’s Encrypt para obtener certificados de prueba. Utilizar esta opción le permite probar sus opciones de configuración y evitar posibles límites vinculados a solicitudes de dominio. Para obtener más información sobre estos límites, consulte la documentación sobre los límites de tasas de Let’s Encrypt.-d
: le permite especificar los nombres de dominio que desee aplicar a su solicitud. En este caso, incluimos example.com
y www.example.com
. Asegúrese de sustituirlos por sus propias preferencias de dominio.Como paso final, agregue las definiciones de volumen y red. Asegúrese de sustituir aquí el nombre de usuario por su propio usuario no root:
...
volumes:
certbot-etc:
certbot-var:
web-root:
driver: local
driver_opts:
type: none
device: /home/sammy/node_project/views/
o: bind
networks:
app-network:
driver: bridge
Nuestros volúmenes con nombre incluyen nuestros volúmenes de certificados de Certbot y directorios de trabajo, y el volumen de los activos estáticos de nuestro sitio, web-root
. En la mayoría de los casos, el controlador predeterminado de volúmenes de Docker es el controlador local
, que en Linux acepta opciones similares al comando mount
. Gracias a esto, podemos especificar una lista de opciones de controladores con driver_opts
que montan el directorio views
en el host, el cual contiene los activos estáticos de nuestra aplicación, en el volumen en tiempo de ejecución. El contenido del directorio puede, entonces, compartirse entre contenedores. Para obtener más información sobre el contenido del directorio de views
, consulte el paso 2 de Cómo crear una aplicación de Node.js con Docker.
El archivo docker-compose.yml
tendrá este aspecto al terminar:
version: '3'
services:
nodejs:
build:
context: .
dockerfile: Dockerfile
image: nodejs
container_name: nodejs
restart: unless-stopped
networks:
- app-network
webserver:
image: nginx:mainline-alpine
container_name: webserver
restart: unless-stopped
ports:
- "80:80"
volumes:
- web-root:/var/www/html
- ./nginx-conf:/etc/nginx/conf.d
- certbot-etc:/etc/letsencrypt
- certbot-var:/var/lib/letsencrypt
depends_on:
- nodejs
networks:
- app-network
certbot:
image: certbot/certbot
container_name: certbot
volumes:
- certbot-etc:/etc/letsencrypt
- certbot-var:/var/lib/letsencrypt
- web-root:/var/www/html
depends_on:
- webserver
command: certonly --webroot --webroot-path=/var/www/html --email sammy@example.com --agree-tos --no-eff-email --staging -d example.com -d www.example.com
volumes:
certbot-etc:
certbot-var:
web-root:
driver: local
driver_opts:
type: none
device: /home/sammy/node_project/views/
o: bind
networks:
app-network:
driver: bridge
Una vez configuradas las definiciones de servicio, estará listo para iniciar los contenedores y probar las solicitudes de su certificado.
Podemos iniciar nuestros contenedores con docker-compose up
, que creará y ejecutará nuestros contenedores y servicios 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 webserver
.
Cree los servicios con docker-compose up
y el indicador -d
, que ejecutarán los contenedores nodejs
y webserver
en segundo plano:
- docker-compose up -d
Verá un resultado que confirmará la creación de sus servicios:
OutputCreating nodejs ... done
Creating webserver ... done
Creating certbot ... done
Mediante docker-compose ps
, compruebe el estado de sus servicios:
- docker-compose ps
Si todo se realizó correctamente, el estado de sus servicios de nodejs
y webserver
debería ser Up
y el contenedor de certbot
se habrá cerrado con un mensaje de estado de 0
.
Output Name Command State Ports
------------------------------------------------------------------------
certbot certbot certonly --webroot ... Exit 0
nodejs node app.js Up 8080/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 nodejs
y webserver
, o un estado de salida distinto de 0
para el contenedor de certbot
, asegúrese de verificar los registros de servicio con el comando docker-compose logs
:
- docker-compose logs service_name
Ahora podrá verificar que sus credenciales se hayan montado en el contenedor webserver
con docker-compose exec
:
- docker-compose exec webserver ls -la /etc/letsencrypt/live
Si su solicitud fue correcta, verá un resultado como este:
Outputtotal 16
drwx------ 3 root root 4096 Dec 23 16:48 .
drwxr-xr-x 9 root root 4096 Dec 23 16:48 ..
-rw-r--r-- 1 root root 740 Dec 23 16:48 README
drwxr-xr-x 2 root root 4096 Dec 23 16:48 example.com
Ahora que sabe que su solicitud será correcta, puede editar la definición de servicio de certbot
para eliminar el marcador --staging
.
Abra docker-compose.yml
:
- nano docker-compose.yml
Encuentre la sección del archivo con la definición de servicio de certbot
y sustituya el indicador --staging
en la opción command
por el indicador --force-renewal
, el cual indicará a Certbot que usted desea solicitar un nuevo certificado con los mismos dominios que un certificado existente. Ahora, la definición de servicio de certbot
debería tener este aspecto:
...
certbot:
image: certbot/certbot
container_name: certbot
volumes:
- certbot-etc:/etc/letsencrypt
- certbot-var:/var/lib/letsencrypt
- web-root:/var/www/html
depends_on:
- webserver
command: certonly --webroot --webroot-path=/var/www/html --email sammy@example.com --agree-tos --no-eff-email --force-renewal -d example.com -d www.example.com
...
Podrá ejecutar docker-compose up
para recrear el contenedor de certbot
y sus volúmenes pertinentes. 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
Verá un resultado que indicará que su solicitud de certificado fue exitosa:
Outputcertbot | IMPORTANT NOTES:
certbot | - Congratulations! Your certificate and chain have been saved at:
certbot | /etc/letsencrypt/live/example.com/fullchain.pem
certbot | Your key file has been saved at:
certbot | /etc/letsencrypt/live/example.com/privkey.pem
certbot | Your cert will expire on 2019-03-26. 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 implementados sus certificados, podrá modificar su configuración de Nginx para incluir SSL.
Habilitar SSL en nuestra configuración de Nginx implicará agregar un redireccionamiento de HTTP a HTTPS y especificar las ubicaciones de nuestros certificados y nuestras claves SSL. También implicará especificar nuestro grupo Diffie-Hellman, que utilizaremos para confidencialidad directa perfecta.
Debido a que va a recrear el servicio webserver
para incluir estas adiciones, puede detenerlo ahora:
- docker-compose stop webserver
A continuación, cree un directorio en el directorio de su proyecto actual para su clave Diffie-Hellman:
- mkdir dhparam
Genere su clave con el comando openssl
:
- sudo openssl dhparam -out /home/sammy/node_project/dhparam/dhparam-2048.pem 2048
Tomará algunos momentos generar la clave.
Para agregar la información pertinente de Diffie-Hellman y SSL a su configuración de Nginx, primero elimine el archivo de configuración de Nginx que creó anteriomente:
- 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 example.com
por su propio dominio:
server {
listen 80;
listen [::]:80;
server_name example.com www.example.com;
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 example.com www.example.com;
server_tokens off;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
ssl_buffer_size 8k;
ssl_dhparam /etc/ssl/certs/dhparam-2048.pem;
ssl_protocols TLSv1.2 TLSv1.1 TLSv1;
ssl_prefer_server_ciphers on;
ssl_ciphers ECDH+AESGCM:ECDH+AES256:ECDH+AES128:DH+3DES:!ADH:!AECDH:!MD5;
ssl_ecdh_curve secp384r1;
ssl_session_tickets off;
ssl_stapling on;
ssl_stapling_verify on;
resolver 8.8.8.8;
location / {
try_files $uri @nodejs;
}
location @nodejs {
proxy_pass http://nodejs:8080;
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
}
root /var/www/html;
index index.html index.htm index.nginx-debian.html;
}
El bloque de servidor HTTP especifica el 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 del sitio web, consulte la introducción a Cómo configurar Nginx con soporte HTTP/2 en Ubuntu 18.04. Este bloque también incluye varias opciones para garantizar que usted utilice los protocolos y los cifrados SSL más actualizados y que el engrapado OSCP esté activado. El grapado OCSP le permite ofrecer una respuesta con registro de tiempo de su autoridad de certificación durante el protocolo de enlace TLS inicial, lo que puede acelerar el proceso de autenticación.
El bloque también especifica sus credenciales y ubicaciones de claves SSL y Diffie-Hellman.
Por último, movimos la información de pase de proxy a este bloque, incluido un bloque de ubicación con una directiva try_files
, que dirige solicitudes a nuestro contenedor de aplicación de Node.js con alias y un bloque de ubicación para ese alias, que incluye encabezados de seguridad que nos permitirán obtener calificaciones de A en aspectos como los laboratorios SSL y sitios de prueba de servidores de encabezados de seguridad. Entre estos encabezado se incluyen X-frame-Options,
X-Frame-Options
, Referer Policy
, Content-Security-Policy
y X-XSS-Protection.
El encabezado HTTP de Strict Transport Security
(HSTS) no se incluye: habilite esto solo si comprende las implicaciones y evaluó su funcionalidad “preload”.
Una vez que haya finalice la edición, guarde y cierre el archivo.
Antes de recrear el servicio webserver
, deberá realizar algunas adiciones a la definición de servicio de su archivo docker-compose.yml
, incluida la información de puerto pertinente para HTTPS y una definición de volumen de Diffie-Hellman.
Abra el archivo:
- nano docker-compose.yml
En la definición del servicio webserver
, agregue la siguiente asignación de puerto y el volumen llamado dhparam
:
...
webserver:
image: nginx:latest
container_name: webserver
restart: unless-stopped
ports:
- "80:80"
- "443:443"
volumes:
- web-root:/var/www/html
- ./nginx-conf:/etc/nginx/conf.d
- certbot-etc:/etc/letsencrypt
- certbot-var:/var/lib/letsencrypt
- dhparam:/etc/ssl/certs
depends_on:
- nodejs
networks:
- app-network
A continuación, agregue el volumen dhparam
a sus definiciones de volúmenes
:
...
volumes:
...
dhparam:
driver: local
driver_opts:
type: none
device: /home/sammy/node_project/dhparam/
o: bind
De manera similar al volumen web-root
, el volumen dhparam
monta en el contenedor webserver
la clave Diffie-Hellman almacenada en el host.
Guarde y cierre el archivo cuando haya terminado de editar.
Recree el servicio webserver
:
- docker-compose up -d --force-recreate --no-deps webserver
Compruebe sus servicios con docker-compose ps
:
- docker-compose ps
Debería ver un resultado que indique que sus nodejs
y sus servicios webserver
se encuentran en ejecución:
Output Name Command State Ports
----------------------------------------------------------------------------------------------
certbot certbot certonly --webroot ... Exit 0
nodejs node app.js Up 8080/tcp
webserver nginx -g daemon off; Up 0.0.0.0:443->443/tcp, 0.0.0.0:80->80/tcp
Por último, puede visitar su dominio para asegurarse de que todo funcione como se espera. Visite con su navegador https://example.com
y asegúrese de sustituir example.com
por su propio nombre de dominio. Visualizará la siguiente página de destino:
También debería ver el icono del candado en el indicador de seguridad de su navegador. Si lo desea, puede visitar la página de destino de SSL Labs Server Test o la página de inicio de prueba de servidores de encabezados de seguridad. Las opciones de configuración que incluimos deberían hacer que la calificación de su sitio sea **A **en ambos casos.
Los certificados de Let’s Encrypt son válidos durante 90 días, por lo que le convendrá configurar un proceso de renovación automática para asegurarse de que no caduquen. Una forma de hacerlo es crear un trabajo con la utilidad de programación de cron
. En este caso, programaremos una tarea cron
utilizando una secuencia de comandos que renovará nuestros certificados y volverá a cargar nuestra configuración de Nginx.
Abra una secuencia de comandos llamada ssl_renew.sh
en el directorio de su proyecto:
- nano ssl_renew.sh
Agregue el siguiente código a la secuencia de comandos para renovar sus certificados y volver a cargar la configuración de su servidor web:
#!/bin/bash
COMPOSE="/usr/local/bin/docker-compose --no-ansi"
DOCKER="/usr/bin/docker"
cd /home/sammy/node_project/
$COMPOSE run certbot renew --dry-run && $COMPOSE kill -s SIGHUP webserver
$DOCKER system prune -af
Esta secuencia de comandos primero asigna el binario docker-compose
a una variable llamada COMPOSE
y especifica la opción --no-ansi
, que ejecutará comandos docker-compose
sin los caracteres de control ANSI. Luego hace lo mismo con el binario docker.
Luego, cambia el posicionamiento al directorio ~/wordpress project
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
, usaremos aquí el subcomando renew
que renovará 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. Si desea obtener más información sobre el uso de este proceso para volver a cargar su configuración de Nginx, consulte este post del blog de Docker sobre la implementación de la imagen oficial de Nginx con Docker.Luego ejecuta docker system prune
para eliminar todos los contenedores y las imágenes que no se utilizan.
Cierre el archivo cuando finalice la edición. Haga que sea ejecutable:
- chmod +x ssl_renew.sh
A continuación, abra su 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:
no crontab for root - using an empty one
Select an editor. To change later, run 'select-editor'.
1. /bin/ed
2. /bin/nano <---- easiest
3. /usr/bin/vim.basic
4. /usr/bin/vim.tiny
Choose 1-4 [2]:
...
Al final del archivo, añada la siguiente línea:
...
*/5 * * * * /home/sammy/node_project/ssl_renew.sh >> /var/log/cron.log 2>&1
Esto fijará un intervalo de tarea de cinco minutos, de modo que puede probar si su solicitud de renovación ha funcionado como estaba previsto. También creamos un archivo de registro, cron.log
para registrar el resultado pertinente de la tarea.
Una vez que transcurran cinco minutos, revise cron.log
para comprobar si la solicitud de renovación se realizó con éxito o no:
- tail -f /var/log/cron.log
Debería 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/example.com/fullchain.pem (success)
** DRY RUN: simulating 'certbot renew' close to cert expiry
** (The test certificates above have not been saved.)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Killing webserver ... done
Ahora podrá modificar el archivo de crontab
para establecer un intervalo diario. Para ejecutar la secuencia de comandos cada día al mediodía, por ejemplo, se debería modificar la última línea del archivo de modo que tenga el siguiente aspecto:
...
0 12 * * * /home/sammy/node_project/ssl_renew.sh >> /var/log/cron.log 2>&1
También le convendrá eliminar la opción --dry-run
de su secuencia de comandos ssl_renew.sh
:
#!/bin/bash
COMPOSE="/usr/local/bin/docker-compose --no-ansi"
DOCKER="/usr/bin/docker"
cd /home/sammy/node_project/
$COMPOSE run certbot renew && $COMPOSE kill -s SIGHUP webserver
$DOCKER system prune -af
Su tarea cron
controlará que sus certificados de Let´s Encrypt no caduquen al renovarlos cuando reúnan las condiciones. También puede configurar la rotación de registros con la utilidad Logrotate para rotar y comprimir sus archivos de registro.
Usó contenedores para configurar y ejecutar una aplicación de Node con un proxy inverso de Nginx. También protegió certificados SSL para el dominio de su aplicación y configuró una tarea cron
para renovar estos certificados cuando sea necesario.
Si le interesa obtener más información sobre los complementos de Let´s Encrypt, consulte nuestros artículos sobre el uso del complemento de Nginx o el complemento independiente.
También puede obtener más información sobre Docker Compose consultando los siguientes recursos:
La documentación de Compose es también un excelente recurso para aprender más sobre aplicaciones en varios contenedores.
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!
Sign up for Infrastructure as a Newsletter.
Working on improving health and education, reducing inequality, and spurring economic growth? We'd like to help.
Get paid to write technical tutorials and select a tech-focused charity to receive a matching donation.