DEV Community

Cover image for Desplegar contenedores de Docker en un VPS con Ubuntu, Nginx y Certbot
Jordi Ayala
Jordi Ayala

Posted on • Originally published at asjordi.dev

Desplegar contenedores de Docker en un VPS con Ubuntu, Nginx y Certbot

En esta guía se detalla el proceso para poder desplegar contenedores de Docker en un servidor o VPS con Ubuntu, además de configurar Nginx como proxy inverso, configurar un dominio que apunte a nuestro servidor y agregar un certificado SSL gratuito utilizando Certbot, todo con el objetivo de exponer a internet un servicio web, ya sea una aplicación web, una API o un sitio web estático desde nuestro propio servidor.

Para comenzar debemos acceder mediante SSH a nuestro servidor o VPS.

ssh -i <ruta de la llave privada> <usuario>@<ip>
Enter fullscreen mode Exit fullscreen mode

Una vez dentro del servidor, lo primero que debemos hacer es actualizar los paquetes.

sudo apt-get update
sudo apt-get upgrade -y
Enter fullscreen mode Exit fullscreen mode

Instalar Docker

La instalación de Docker utilizando el repositorio apt se divide en dos pasos, en el primero se configura el repositorio y en el segundo se instala Docker. Comenzamos con el primero, solo es necesario ejecutar por separado cada uno de los siguientes comandos.

sudo apt-get update
Enter fullscreen mode Exit fullscreen mode
sudo apt-get install ca-certificates curl
Enter fullscreen mode Exit fullscreen mode
sudo install -m 0755 -d /etc/apt/keyrings
Enter fullscreen mode Exit fullscreen mode
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
Enter fullscreen mode Exit fullscreen mode
sudo chmod a+r /etc/apt/keyrings/docker.asc
Enter fullscreen mode Exit fullscreen mode
# Add the repository to Apt sources:
echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \
  $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
  sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
Enter fullscreen mode Exit fullscreen mode
sudo apt-get update
Enter fullscreen mode Exit fullscreen mode

Ahora instalamos la última versión de Docker engine.

sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
Enter fullscreen mode Exit fullscreen mode

Para verificar que Docker se ha instalado correctamente ejecutamos el siguiente comando, que lo que hace es descargar y ejecutar en un contenedor la imagen hello-world.

sudo docker run hello-world
Enter fullscreen mode Exit fullscreen mode

Si deseas comprobar la versión de Docker que se ha instalado, puedes ejecutar el siguiente comando.

sudo docker --version
Enter fullscreen mode Exit fullscreen mode

Podemos revisar el estado del servicio de Docker con el siguiente comando:

sudo systemctl status docker
Enter fullscreen mode Exit fullscreen mode

Por último verificamos que se haya instalado docker compose ejecutando el comando docker compose. Si tienes algún problema con la instalación siempre puedes consultar la documentación oficial.

Copiar archivos al servidor

En este paso se deben copiar los archivos necesarios para construir la imagen de Docker de un proyecto, esto es opcional, ya que se puede tener un registro privado de Docker y descargar la imagen directamente, o incluso tener un archivo docker-compose.yml para levantar los contenedores necesarios, todo depende de nuestras necesidades. Para este caso clonaré un repositorio propio desde GitHub mediante HTTPS (se puede utilizar SSH, pero hay que configurar las llaves para la conexión) en la ruta /home/jordi/server, esta carpeta será donde se ubicarán los proyectos a desplegar.

sudo mkdir /home/jordi/server
Enter fullscreen mode Exit fullscreen mode
git clone https://github.com/ASJordi/personal-website.git
Enter fullscreen mode Exit fullscreen mode

Entramos a la carpeta del proyecto y debemos verificar que se encuentre el archivo Dockerfile, o si se tiene un archivo docker-compose.yml, ambas son opciones válidas.

Estructura del proyecto

Construir la imagen de Docker

Ahora que tenemos los archivos necesarios para construir la imagen, nos ubicamos en la carpeta del proyecto y construimos la imagen de Docker, es importante asignar una versión para futuras actualizaciones.

sudo docker build --tag asjordi/website:1.0.0 .
Enter fullscreen mode Exit fullscreen mode

Esperamos a que termine el proceso de construcción, en este caso la imagen contiene un sitio web estático, básicamente el código fuente de mi sitio web personal. Una vez que el proceso termina, ejecutamos el siguiente comando para verificar que la imagen se encuentre disponible de manera local.

sudo docker image ls
Enter fullscreen mode Exit fullscreen mode

Crear un contenedor con la imagen

Si ya tenemos la imagen disponible localmente, o en un registro privado de Docker, procedemos a crear un contenedor, el comando puede variar de acuerdo a la configuración que se necesite, en este caso se va a mapear el puerto 80 del contenedor al puerto 8080 del servidor, y se le asigna el nombre website al contenedor.

sudo docker container run -dp 8080:80 --name website asjordi/website:1.0.0
Enter fullscreen mode Exit fullscreen mode

Verificamos que el contenedor se encuentre corriendo.

sudo docker container ls
Enter fullscreen mode Exit fullscreen mode

En caso de que tengamos un archivo docker-compose.yml con la configuración necesaria para levantar los contenedores, podemos ejecutar el siguiente comando.

sudo docker-compose up -d
Enter fullscreen mode Exit fullscreen mode

Podemos verificar que los contenedores se encuentren corriendo con el siguiente comando.

sudo docker compose ps
Enter fullscreen mode Exit fullscreen mode

En caso de que alguno de los contenedores tenga un sitio web, podemos hacer un curl a localhost más el puerto que se ha mapeado con el contenedor.

curl localhost:8080
Enter fullscreen mode Exit fullscreen mode

Si todo ha salido bien, deberíamos ver el sitio web en la terminal. Hasta este punto ya tenemos Docker configurado con los contenedores necesarios corriendo, ahora vamos a configurar Nginx para exponer el puerto 80 del servidor.

Instalar nginx

Podemos instalar nginx de dos maneras, utilizando un contenedor de Docker o instalándolo directamente en el servidor, en este caso utilizaré la segunda opción. Para instalar nginx solo se deben ejecutar los siguientes dos comandos.

sudo apt update
sudo apt install nginx
Enter fullscreen mode Exit fullscreen mode

Verificamos el estado del servicio de nginx.

systemctl status nginx
Enter fullscreen mode Exit fullscreen mode

Si ingresamos a la IP del servidor desde un navegador, deberíamos ver la página de bienvenida de nginx.

Página de bienvenida de nginx

Configurar dominio

Ahora que nuestro servidor está corriendo y es accesible desde internet, necesitamos configurar un nombre de dominio. Para ello es necesario que tengamos un dominio, y que podamos acceder a la configuración de DNS del proveedor de dominio. Una vez que tengamos acceso a la configuración de DNS, debemos agregar un registro A con la IP del servidor, esperar a que se propague el DNS y luego ingresar al dominio desde el navegador, deberíamos ver la página de bienvenida de nginx.

En mi caso tengo un dominio personal, asjordi.dev, y voy a utilizar un subdominio, web.asjordi.dev, para apuntar a mi servidor. La configuración de DNS puede variar de acuerdo al proveedor de dominio, en mi caso utilizo Cloudflare.

Configuración de DNS

Configurar nginx

Para poder exponer el sitio web que se encuentra corriendo en el contenedor, necesitamos configurar nginx como proxy inverso, para ello debemos editar el archivo de configuración de nginx que se encuentra en /etc/nginx/sites-available/default.

sudo nano /etc/nginx/sites-available/default
Enter fullscreen mode Exit fullscreen mode

Borramos todo el contenido del archivo, podemos seleccionar todo con Shift + flecha abajo y después presionar Ctrl + K o Ctrl + Shift + K, probar con uno de los dos. Y colocamos la siguiente configuración.

server {
    listen 80 default_server;
    server_name _;

    return 403;
}

server {

    listen 80;

    server_name web.asjordi.dev;

    location / {
            proxy_pass http://localhost:8080;
    }
}
Enter fullscreen mode Exit fullscreen mode

Comencemos a explicar la configuración:

  • Primer bloque server:
    • listen 80 default_server: Este servidor escucha en el puerto 80 y es el servidor por defecto.
    • server_name _;: El guion bajo (_) significa que este bloque manejará todas las peticiones que no coincidan con ningún otro server_name.
    • return 403: Devuelve un error 403 (Forbidden) para cualquier petición que llegue a este servidor por defecto, por ejemplo, si alguien intenta acceder al servidor mediante la IP.
  • Segundo bloque server:
    • listen 80: Este servidor escucha en el puerto 80.
    • server_name web.asjordi.dev;: Indica que solo procesará peticiones que vengan con este nombre de dominio (aquí se debe colocar el dominio propio que se configuró en el DNS).
    • location /: Indica que para todas las rutas.
    • proxy_pass http://localhost:8080;: Redirigirá las peticiones a un servidor local que está corriendo en el puerto 8080, que es donde se encuentra corriendo el contenedor (aquí se debe colocar el puerto que se mapeó con el contenedor).

Una vez que hemos configurado los aspectos necesarios, presionar Ctrl + O seguido de Enter para guardar los cambios y Ctrl + X para salir de nano. Procedemos a verificar la configuración con el siguiente comando.

nginx -t
Enter fullscreen mode Exit fullscreen mode

Si no hay errores, reiniciamos el servicio de nginx.

systemctl restart nginx
Enter fullscreen mode Exit fullscreen mode

Ahora podemos ingresar a nuestro dominio y deberíamos ver el sitio web que se encuentra corriendo en el contenedor. En caso de que ingresemos utilizando la IP del servidor, deberíamos ver un error 403.

Error 403

Instalar Certbot

Ya hemos configurado nuestro servidor con Docker, Nginx y un dominio, pero aún no tenemos un sitio web seguro. Solo nos hace falta agregar un certificado SSL de manera gratuita, para ello vamos a generar un certificado SSL de Let's Encrypt utilizando Certbot. Para lo cual ejecutamos uno a uno los siguientes comandos.

  • Instalar dependencias necesarias.
sudo apt install python3 python3-venv libaugeas0
Enter fullscreen mode Exit fullscreen mode
  • Configurar un entorno virtual para Certbot.
sudo python3 -m venv /opt/certbot/
Enter fullscreen mode Exit fullscreen mode
sudo /opt/certbot/bin/pip install --upgrade pip
Enter fullscreen mode Exit fullscreen mode
  • Instalar Certbot
sudo /opt/certbot/bin/pip install certbot certbot-nginx
Enter fullscreen mode Exit fullscreen mode
  • Crear un enlace simbólico para poder ejecutar Certbot desde cualquier lugar.
sudo ln -s /opt/certbot/bin/certbot /usr/bin/certbot
Enter fullscreen mode Exit fullscreen mode

Configurar Certbot

Para comenzar con la generación del certificado SSL, ejecutamos el siguiente comando.

sudo certbot
Enter fullscreen mode Exit fullscreen mode

A continuación realizamos las siguientes acciones:

  • Ingresamos nuestro email.
  • Aceptamos los términos y condiciones.
  • Aceptamos o no compartir nuestro email.

Certbot comenzará a buscar los dominios que estén configurados en nginx, una vez que los encuentre, nos mostrará una lista de los dominios y nos preguntará si queremos configurar un certificado SSL para alguno de ellos. Seleccionamos el dominio que queremos configurar ingresando el número que aparece al lado del dominio.

Certbot

Una vez que termina el proceso, Certbot nos mostrará un mensaje indicando que la configuración se ha realizado con éxito, es decir, se ha configurado el certificado SSL para el dominio que seleccionamos. Ahora solo necesitamos configurar la autorrenovación del certificado, ejecutamos el siguiente comando, que agrega un cron job a /etc/crontab que se ejecutará dos veces al día y renovará el certificado si es necesario.

echo "0 0,12 * * * root /opt/certbot/bin/python -c 'import random; import time; time.sleep(random.random() * 3600)' && sudo certbot renew -q" | sudo tee -a /etc/crontab > /dev/null
Enter fullscreen mode Exit fullscreen mode

Si entramos al archivo de configuración de nginx en /etc/nginx/sites-available/default podemos ver que Certbot ha agregado la configuración necesaria para el certificado SSL.

Configuración de nginx SSL

Si tienes alguna duda, puedes consultar la documentación oficial de Certbot. Ahora podemos ingresar a nuestro dominio y ver que el sitio web está marcado como seguro y funciona correctamente.

Sitio web seguro

Configurar ufw

Para finalizar, podemos configurar ufw para permitir el tráfico en los puertos necesarios, en este caso solo necesitamos permitir el tráfico en los puertos 80 y 443, que son los puertos por defecto para HTTP y HTTPS, y el puerto 22 para SSH.

sudo ufw allow ssh
Enter fullscreen mode Exit fullscreen mode
sudo ufw allow 80
Enter fullscreen mode Exit fullscreen mode
sudo ufw allow 443
Enter fullscreen mode Exit fullscreen mode

Ahora habilitamos ufw.

sudo ufw enable
Enter fullscreen mode Exit fullscreen mode

Podemos verificar el estado de ufw con el siguiente comando.

sudo ufw status
Enter fullscreen mode Exit fullscreen mode

Conclusión

Ya tenemos configurado un servidor con Docker, Nginx y Certbot, hemos desplegado un contenedor con un sitio web, configurado un dominio, agregado un certificado SSL y configurado la autorrenovación del certificado, todo con el objetivo de poder desplegar un servicio web en nuestro propio servidor y exponerlo a internet de manera segura. Este es solo un ejemplo de cómo se puede configurar un servidor, podemos desplegar más contenedores con diferentes servicios, agregar más dominios o subdominios, configurar más certificados SSL, entre otras cosas, todo depende de nuestras necesidades.

Postmark Image

Speedy emails, satisfied customers

Are delayed transactional emails costing you user satisfaction? Postmark delivers your emails almost instantly, keeping your customers happy and connected.

Sign up

Top comments (0)

Billboard image

The Next Generation Developer Platform

Coherence is the first Platform-as-a-Service you can control. Unlike "black-box" platforms that are opinionated about the infra you can deploy, Coherence is powered by CNC, the open-source IaC framework, which offers limitless customization.

Learn more

👋 Kindness is contagious

Engage with a sea of insights in this enlightening article, highly esteemed within the encouraging DEV Community. Programmers of every skill level are invited to participate and enrich our shared knowledge.

A simple "thank you" can uplift someone's spirits. Express your appreciation in the comments section!

On DEV, sharing knowledge smooths our journey and strengthens our community bonds. Found this useful? A brief thank you to the author can mean a lot.

Okay