nextjs

9/23/2023

Dockeriza tu aplicación de Next.js en AlmaLinux

¡Comencemos!

Primero que nada, necesitamos acceder a nuestra instancia de AlmaLinux. Puedes utilizar la consola web o conectarte a través de SSH. Se recomienda crear otro usuario aparte de root, darle los permisos necesarios y dejar el usuario root para emergencias.

Una vez dentro de nuestro VPS, podemos comenzar a instalar lo que vamos a necesitar.

¿Qué es Docker y por qué lo utilizamos?

Docker es una plataforma que permite a los desarrolladores automatizar la implementación, escalado y gestión de aplicaciones mediante contenedores. Los contenedores son paquetes de software ligeros, autónomos y ejecutables que incluyen todo lo necesario para ejecutar una aplicación: código, tiempo de ejecución, bibliotecas y herramientas del sistema.

Los componentes clave de Docker son:

  • Motor Docker (Docker Engine): El componente principal que permite la creación, gestión y ejecución de contenedores.
  • Imagen Docker (Docker Image): Un paquete de software ligero, autónomo y ejecutable que incluye el código de la aplicación y sus dependencias, construido a partir de un conjunto de instrucciones llamado Dockerfile.
  • Dockerfile: Un archivo de texto que contiene instrucciones sobre cómo construir una imagen Docker. Especifica la imagen base, variables de entorno, paquetes de software a instalar y más.
  • Contenedor Docker (Docker Container): Una instancia de una imagen Docker que está en ejecución y aislada del sistema anfitrión y otros contenedores. Los contenedores son las unidades ejecutables de Docker.

Básicamente, utilizamos Docker para ejecutar nuestra aplicación en un ambiente aislado y controlado, lo que nos permite cambiar de versión o distribución de Linux e incluso cambiar nuestro sistema operativo sin afectar el funcionamiento de la aplicación.

Instalación de Docker en AlmaLinux:

  1. Primero, actualizamos la lista de paquetes, ejecutamos:
sudo dnf update
  1. Instalamos las dependencias necesarias para Docker
sudo dnf install -y dnf-utils device-mapper-persistent-data lvm2
  1. Agreguemos el repositorio de Docker:
sudo dnf config-manager --add-repo=https://download.docker.com/linux/centos/docker-ce.repo
  1. Instalemos Docker
sudo dnf install -y docker-ce
  1. Ejecutemos y agreguemos Docker a los programas que se ejecutan al inicio
sudo systemctl start docker && sudo systemctl enable docker

Listo! Docker está instalado y listo para utilizar.

En este artículo crearemos un proyecto nuevo de de Nextjs, sin embargo, los mismos pasos aplican para un proyecto previo de Nextjs, instala git y clona el repositorio una carpeta local de tu VPS.

Para crear una nueva app de Nextjs ejecutamos los siguientes comandos:

En este artículo, crearemos un proyecto nuevo de Next.js. Sin embargo, los mismos pasos aplican para un proyecto previo de Next.js. Para ello, instala Git y clona el repositorio en una carpeta local de tu VPS.

Para crear una nueva aplicación de Next.js, ejecutamos los siguientes comandos:

  1. Instala el repositorio de Node:
curl -sL https://rpm.nodesource.com/setup_18.x | sudo bash -
  1. Instala Nodejs:
sudo dnf install nodejs
  1. Verifica que la instalación se realizó exitosamente:
node --version
npm --version
  1. Crea tu aplicacion de Nextjs:
npx create-next-app my-nextjs-app
  1. Navega hasta el directorio de tu nueva aplicación:
cd my-nextjs-app

Bien, hasta ahora tenemos Docker instalado y una nueva aplicación de Nextjs (nuevamente, puedes saltar los pasos de instalar nodejs si clonas directamente tu repositorio.

Ahora crearemos un contenedor de Docker con nuestra aplicación de Nextjs

  1. Crea un nuevo archivo en la carpeta root de tu proyecto llamado Dockerfile sin extensión.

  2. Agrega el siguiente contenido a tu nuevo archivo Dockerfile:

Dockerfile
# Entorno o runtime, en este caso Node v.20
FROM node:20
# Directorio de trabajo
WORKDIR /app
# Copiamos package.json y package-lock.json al contenedor
COPY package*.json ./
# Instalamos dependencias
RUN npm install
# Copiamos el resto del código a nuestro contenedor
COPY . .
# Ejecutamos el comando “build” para crear una versión de producción
RUN npm run build
# Exponemos el puerto en el que normalmente trabaja Nextjs
EXPOSE 3000
# Ejecutamos la versión de producción de nuestra app
CMD ["npm", "start"]
  1. Construye el contenedor:
docker build -t my-nextjs-app .
  1. Ejecuta el contenedor:
docker run --name my-nextjs-app -d -p 3000:3000 my-nextjs-app

En este momento, nuestra aplicación debería estar funcionando y corriendo, para verificar podemos ejecutar el comando

curl http://localhost:3000

Y la consola debería devolvernos el HTML de nuestra página. Incluso, si no hay limitaciones de puertos o firewall, deberíamos poder ingresar en nuestra aplicación desde cualquier explorador conectado al internet reemplazando localhost por la dirección de nuestro servidor:

http://12.34.56.78:3000/

Si actualizamos nuestro código y queremos introducir cambios a nuestra aplicación tenemos que ejecutar los siguientes comandos:

  1. Detenemos el contenedor actual
docker stop my-nextjs-app
  1. Lo removemos
docker rm my-nextjs-app
  1. Volvemos a construir el contenedor con los nuevos cambios
docker build -t my-nextjs-app .
  1. Volvemos a ejecutar el contenedor
docker run --name my-nextjs-app -d -p 3000:3000 my-nextjs-app

Extra:

Si queremos agilizar un poco el proceso para actualizar y deployar nuevo código podemos crear un pequeño script:

  1. Creamos el archivo que será nuestro script, en este caso llamado simplemente deploy en nuestro carpeta root, utilizaremos nano como editor de texto
nano deploy.sh
  1. Agregamos el contenido del script:
git pull
docker stop my-nextjs-app || true
docker rm my-nextjs-app || true
docker build -t my-nextjs-app .
docker run --name my-nextjs-app -d -p 3000:3000 my-nextjs-app
  1. Hacemos nuestro script ejecutable:
chmod +x deploy.sh
  1. Cuando queramos actualizar nuestro código podemos ejecutar:
./deploy.sh

Con esto el repositorio se actualizará con la versión más reciente en el repositorio remoto, se detendrá el contenedor anterior, se removerá, se construirá uno nuevo con el código actualizado y lo ejecutaremos nuevamente.

Nota: Con este proceso, se van acumulando imágenes de Docker que en algún momento tendrán que ser removidas para liberar espacio. Puede ejecutar el comando:

docker images

Para conocer las imágenes que tenemos en nuestro VPS y su id, luego las podemos remover ejecutando:

docker rmi imageid

Reemplazando imageid por la id de la imagen que queremos remover, o podemos ejecutar:

docker system prune -a

Para remover todo lo relacionado a Docker que no estemos utilizando en el momento (containers, imágenes, caché, etc.)

En este punto, podemos ingresar a nuestra aplicación ingresando a través de la dirección ip de tu servidor, ejemplo:

http://12.34.56.78:3000

Configurar nginx

Instalación

Primero verificamos que no tengamos ningún otro servicio que pueda interferir con nginx.

En el caso de el servidor de Hostinger, puede venir Apache o Plesk incluidos, en este caso los vamos a desactivar e igualmente si hay algún otro archivo dentro del directorio /etc/nginx/conf.d eliminarlo, o cambiar la extensión.

Ejecutamos:

sudo systemctl stop httpd
sudo systemctl disable httpd
sudo systemctl stop sw-cp-server
sudo systemctl disable sw-cp-server
sudo systemctl stop sw-engine
sudo systemctl disable sw-engine
sudo systemctl stop plesk-websockets
sudo systemctl disable plesk-websockets

Para comenzar con la instalación de nginx vamos a instalar los archivos, correr nginx, que inicie con el sistema y habilitamos el firewall.

Ejecutaremos los siguientes comandos:

sudo dnf install nginx -y
sudo systemctl start nginx
sudo systemctl enable nginx
sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --permanent --add-service=https
sudo firewall-cmd --reload

Supongamos que vamos a deployar nuestra aplicación con un dominio my-nextjs-app.com tenemos que modificar el archivo nginx.conf con los siguientes datos:

# /etc/nginx/nginx.conf
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;

events {
    worker_connections 1024;
}

http {
    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    sendfile            on;
    tcp_nopush          on;
    tcp_nodelay         on;
    keepalive_timeout   65;
    types_hash_max_size 2048;

    include             /etc/nginx/mime.types;
    default_type        application/octet-stream;

    include /etc/nginx/conf.d/*.conf;

    server {
        listen       80 default_server;
        listen       [::]:80 default_server;
        server_name  _;
        root         /usr/share/nginx/html;

        location / {
            index index.html index.htm;
        }

        error_page 404 /404.html;
        location = /404.html {
        }

        error_page 500 502 503 504 /50x.html;
        location = /50x.html {
        }
    }

Nota: siempre que modifiquemos o creamos algún archivo, corremos los siguientes comandos para verificar que nuestras configuraciones están correctas y que tomen efecto.

sudo nginx -t
sudo systemctl reload nginx

Y luego, en la carpeta conf.d crearemos un archivo nuevo llamada my-nextjs-app.com.conf con el siguiente contenido:

# /etc/nginx/conf.d/my-nextjs-app.com.conf

server { 
    listen 80; 
    server_name my-nextjs-app.com www.my-nextjs-app.com; 
    location / { 
        proxy_pass http://localhost:3000; 
        proxy_set_header Host $host; 
        proxy_set_header X-Real-IP $remote_addr; 
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 
    }
}

por último instalaremos CertBot para los certificados HTTPS

Ejecutamos los siguientes comandos:

sudo dnf install epel-release
sudo dnf install certbot python3-certbot-nginx

Una vez instalado podemos instalar los certificados y configurar el auto renovado

sudo certbot --nginx
sudo certbot renew --dry-run

Conclusión:

En este artículo, hemos explorado el proceso de dockerizar una aplicación de Next.js y desplegarla en un servidor AlmaLinux, específicamente en un servidor de Hostinger. Esta decisión se basa en la necesidad de independencia de las plataformas de alojamiento y en la práctica de desplegar aplicaciones en un entorno de servidor propio.

El artículo proporciona una guía detallada que abarca desde la instalación de Docker en el servidor hasta la configuración de Nginx y la obtención de certificados SSL para habilitar conexiones seguras mediante HTTPS. Se enfoca en crear un Dockerfile para la aplicación Next.js, lo que permite su ejecución en un contenedor aislado y controlado. Además, se presenta un script para agilizar la actualización y el despliegue de código.

Es importante destacar que esta guía no se centra en la creación de una aplicación de Next.js en sí, sino en cómo dockerizarla y desplegarla en un servidor propio. Esto proporciona independencia de las limitaciones y restricciones que pueden estar asociadas con las plataformas de alojamiento externas, como Vercel.

A lo largo del artículo, se han utilizado tecnologías clave, como AlmaLinux, Docker, Nginx y CertBot, con sus respectivas versiones.

En resumen, este artículo ofrece una valiosa perspectiva sobre cómo implementar una aplicación de Next.js en un entorno de servidor controlado, lo que puede ser beneficioso para aquellos que desean mantener un mayor control sobre sus aplicaciones y evitar las restricciones de las plataformas de alojamiento externas. Además, se han mencionado posibles mejoras, como la automatización adicional a través de GitHub Actions y la posibilidad de desplegar múltiples aplicaciones en un solo servidor, lo que permite una mayor flexibilidad en el futuro.

Cargando...

Cargando...

Posts relacionados