# Conteneriza una aplicación Next.js


## Prerrequisitos

Antes de comenzar, asegúrate de que las siguientes herramientas estén instaladas y disponibles en tu sistema:

- Has instalado la última versión de [Docker Desktop](/get-started/get-docker/).
- Tienes un [cliente de git](https://git-scm.com/downloads). Los ejemplos de esta sección utilizan un cliente de git basado en la línea de comandos, pero puedes usar cualquier cliente.

> **¿Eres nuevo en Docker?**  
> Comienza con la guía de [conceptos básicos de Docker](/get-started/docker-concepts/the-basics/what-is-a-container/) para familiarizarte con conceptos clave como imágenes, contenedores y Dockerfiles.

---

## Descripción general

Esta guía te guiará a través de la contenerización de una aplicación Next.js con Docker.
Aprenderás a crear una imagen de Docker lista para producción utilizando las mejores
prácticas que mejoran el rendimiento, la seguridad, la escalabilidad y la eficiencia
del despliegue.

Al final de esta guía, lograrás lo siguiente:

- Contenerizar una aplicación Next.js usando Docker.
- Crear y optimizar un Dockerfile para construcciones de producción.
- Usar construcciones multi-etapa (multi-stage) para minimizar el tamaño de la imagen.
- Aprovechar la salida standalone o export de Next.js para una contenerización eficiente.
- Seguir las mejores prácticas para construir imágenes de Docker seguras y fáciles de mantener.

---

## Obtener la aplicación de ejemplo

Clona la aplicación de ejemplo para usarla con esta guía. Abre una terminal, cambia
al directorio en el que deseas trabajar y ejecuta el siguiente comando
para clonar el repositorio de git:

```console
$ git clone https://github.com/kristiyan-velkov/docker-nextjs-sample
```
---

## Generar un Dockerfile

Docker proporciona una herramienta de CLI interactiva llamada `docker init` que ayuda a andamiar (scaffold) los archivos de configuración necesarios para contenerizar tu aplicación. Esto incluye la generación de un `Dockerfile`, `.dockerignore`, `compose.yaml` y `README.Docker.md`.

Para comenzar, navega al directorio del proyecto:

```console
$ cd docker-nextjs-sample
```

Luego ejecuta el siguiente comando:

```console
$ docker init
```
Verás una salida similar a:

```text
Welcome to the Docker Init CLI!

This utility will walk you through creating the following files with sensible defaults for your project:
  - .dockerignore
  - Dockerfile
  - compose.yaml
  - README.Docker.md

Let's get started!
```

La CLI te hará algunas preguntas sobre la configuración de tu aplicación.
Para mantener la consistencia, utiliza las mismas respuestas que se muestran en el siguiente ejemplo cuando se te solicite:

| Question                                                   | Answer          |
|------------------------------------------------------------|-----------------|
| What application platform does your project use?           | Node            |
| What version of Node do you want to use?                   | 24.14.0-alpine  |
| Which package manager do you want to use?                  | npm             |
| Do you want to run "npm run build" before starting server? | yes             |
| What directory is your build output to?                    | .next           |
| What command do you want to use to start the app?          | npm run start   |
| What port does your server listen on?                      | 3000            |

Después de completarlo, el directorio de tu proyecto contendrá los siguientes archivos nuevos:

```text
├── docker-nextjs-sample/
│ ├── Dockerfile
│ ├── .dockerignore
│ ├── compose.yaml
│ └── README.Docker.md
```

---

## Construir la imagen de Docker

El Dockerfile predeterminado generado por `docker init` sirve como un punto de partida sólido para aplicaciones generales de Node.js. Sin embargo, Next.js tiene requisitos específicos para despliegues de producción. Esta guía muestra dos enfoques: salida **standalone** (servidor Node.js) y salida **export** (archivos estáticos con NGINX).

### Paso 1: Revisar los archivos generados

En este paso, agregarás un Dockerfile y archivos de configuración siguiendo las mejores prácticas:

- Usar construcciones multi-etapa para mantener la imagen final limpia y pequeña.
- **Standalone**: Node.js ejecuta el servidor Next.js; **Export**: NGINX sirve archivos estáticos desde la exportación.
- Mejorar el rendimiento y la seguridad incluyendo solo lo necesario.

Estas actualizaciones ayudan a asegurar que tu aplicación sea fácil de desplegar, rápida de cargar y lista para producción.

> [!NOTE]
> Un `Dockerfile` es un archivo de texto plano que contiene instrucciones paso a paso para construir una imagen de Docker. Automatiza el empaquetado de tu aplicación junto con sus dependencias y el entorno de ejecución.  
> Para obtener detalles completos, consulta la [referencia de Dockerfile](/reference/dockerfile/).

### Paso 2: Configurar la salida de Next.js y el Dockerfile

Antes de crear un Dockerfile, elige una imagen base: la [Imagen Oficial de Node.js](https://hub.docker.com/_/node) o una [Imagen Endurecida de Docker (Docker Hardened Image - DHI)](https://hub.docker.com/hardened-images/catalog) del catálogo de imágenes endurecidas. Elegir una DHI te brinda una imagen segura, ligera y lista para producción. Para más información, consulta [Docker Hardened Images](https://docs-docker.esdocu.com/dhi/).

> [!IMPORTANT]
> Esta guía utiliza etiquetas de imagen Node.js LTS estables que se consideran seguras cuando se escribió la guía. Debido a que se publican nuevos lanzamientos y parches de seguridad regularmente, revisa siempre las [imágenes oficiales de Docker de Node.js](https://hub.docker.com/_/node) y selecciona una versión segura y actualizada antes de construir o desplegar.

---

#### 2.1 Next.js con salida standalone

La **salida standalone** (`output: "standalone"`) hace que Next.js compile una salida autocontenida que incluye únicamente los archivos y dependencias necesarios para ejecutar la aplicación. Un simple `node server.js` puede servir la aplicación, lo cual es ideal para Docker y soporta el renderizado en el lado del servidor (SSR), rutas de API y la regeneración estática incremental (ISR). Para obtener más detalles, consulta la [documentación de configuración de salida de Next.js](https://nextjs.org/docs/app/api-reference/config/next-config-js/output) (incluyendo la opción "standalone").

El contenedor ejecuta el servidor Next.js con Node.js en el **puerto 3000**.

**Configura Next.js** — Abre o crea `next.config.ts` en la raíz de tu proyecto:

```ts
import type { NextConfig } from "next";

const nextConfig: NextConfig = {
  output: "standalone",
};

export default nextConfig;
```

Elige una Imagen Endurecida de Docker o la Imagen Oficial de Docker, luego crea o reemplaza tu `Dockerfile` con el contenido de la pestaña seleccionada a continuación.

**Uso de Docker Hardened Images**



Las Docker Hardened Images (DHIs) están disponibles para Node.js en el [catálogo de Docker Hardened Images](https://hub.docker.com/hardened-images/catalog/dhi/node). Para más información, consulta la guía de [inicio rápido de DHI](/dhi/get-started/).

1. Inicia sesión en el registro de DHI:
   ```console
   $ docker login dhi.io
   ```

2. Descarga la DHI de Node.js (consulta el catálogo para ver las versiones disponibles):
   ```console
   $ docker pull dhi.io/node:24-alpine3.22-dev
   ```

3. Reemplaza el Dockerfile generado con el siguiente. Las instrucciones `FROM` utilizan `dhi.io/node:24-alpine3.22-dev`. Consulta el [catálogo de Docker Hardened Images](https://hub.docker.com/hardened-images/catalog) para obtener las últimas versiones y actualiza las etiquetas de la imagen según sea necesario para la seguridad y compatibilidad.

    ```dockerfile
    # ============================================
    # Stage 1: Dependencies Installation Stage
    # ============================================

    # IMPORTANT: Docker Hardened Image (DHI) Version Maintenance
    # This Dockerfile uses dhi.io/node. Regularly validate and update to the latest DHI versions in the catalog for security and compatibility.

    FROM dhi.io/node:24-alpine3.22-dev AS dependencies

    # Set working directory
    WORKDIR /app

    # Copy package-related files first to leverage Docker's caching mechanism
    COPY package.json yarn.lock* package-lock.json* pnpm-lock.yaml* .npmrc* ./

    # Install project dependencies with frozen lockfile for reproducible builds
    RUN --mount=type=cache,target=/root/.npm \
        --mount=type=cache,target=/usr/local/share/.cache/yarn \
        --mount=type=cache,target=/root/.local/share/pnpm/store \
      if [ -f package-lock.json ]; then \
        npm ci --no-audit --no-fund; \
      elif [ -f yarn.lock ]; then \
        corepack enable yarn && yarn install --frozen-lockfile --production=false; \
      elif [ -f pnpm-lock.yaml ]; then \
        corepack enable pnpm && pnpm install --frozen-lockfile; \
      else \
        echo "No lockfile found." && exit 1; \
      fi

    # ============================================
    # Stage 2: Build Next.js application in standalone mode
    # ============================================

    FROM dhi.io/node:24-alpine3.22-dev AS builder

    # Set working directory
    WORKDIR /app

    # Copy project dependencies from dependencies stage
    COPY --from=dependencies /app/node_modules ./node_modules

    # Copy application source code
    COPY . .

    ENV NODE_ENV=production

    # Next.js collects completely anonymous telemetry data about general usage.
    # Learn more here: https://nextjs.org/telemetry
    # Uncomment the following line in case you want to disable telemetry during the build.
    # ENV NEXT_TELEMETRY_DISABLED=1

    # Build Next.js application
    # If you want to speed up Docker rebuilds, you can cache the build artifacts
    # by adding: --mount=type=cache,target=/app/.next/cache
    # This caches the .next/cache directory across builds, but it also prevents
    # .next/cache/fetch-cache from being included in the final image, meaning
    # cached fetch responses from the build won't be available at runtime.
    RUN if [ -f package-lock.json ]; then \
        npm run build; \
      elif [ -f yarn.lock ]; then \
        corepack enable yarn && yarn build; \
      elif [ -f pnpm-lock.yaml ]; then \
        corepack enable pnpm && pnpm build; \
      else \
        echo "No lockfile found." && exit 1; \
      fi

    # ============================================
    # Stage 3: Run Next.js application
    # ============================================

    FROM dhi.io/node:24-alpine3.22-dev AS runner

    # Set working directory
    WORKDIR /app

    # Set production environment variables
    ENV NODE_ENV=production
    ENV PORT=3000
    ENV HOSTNAME="0.0.0.0"

    # Next.js collects completely anonymous telemetry data about general usage.
    # Learn more here: https://nextjs.org/telemetry
    # Uncomment the following line in case you want to disable telemetry during the run time.
    # ENV NEXT_TELEMETRY_DISABLED=1

    # Copy production assets
    COPY --from=builder --chown=node:node /app/public ./public

    # Set the correct permission for prerender cache
    RUN mkdir .next
    RUN chown node:node .next

    # Automatically leverage output traces to reduce image size
    # https://nextjs.org/docs/advanced-features/output-file-tracing
    COPY --from=builder --chown=node:node /app/.next/standalone ./
    COPY --from=builder --chown=node:node /app/.next/static ./.next/static

    # If you want to persist the fetch cache generated during the build so that
    # cached responses are available immediately on startup, uncomment this line:
    # COPY --from=builder --chown=node:node /app/.next/cache ./.next/cache

    # Switch to non-root user for security best practices
    USER node

    # Expose port 3000 to allow HTTP traffic
    EXPOSE 3000

    # Start Next.js standalone server
    CMD ["node", "server.js"]
    ```

**Uso de la Imagen Oficial de Docker**



Crea un Dockerfile multi-etapa listo para producción. Reemplaza el Dockerfile generado con el siguiente (utiliza `node`):

```dockerfile
  # ============================================
  # Stage 1: Dependencies Installation Stage
  # ============================================

  ARG NODE_VERSION=24.14.0-slim

  FROM node:${NODE_VERSION} AS dependencies

  # Set working directory
  WORKDIR /app

  # Copy package-related files first to leverage Docker's caching mechanism
  COPY package.json yarn.lock* package-lock.json* pnpm-lock.yaml* .npmrc* ./

  # Install project dependencies with frozen lockfile for reproducible builds
  RUN --mount=type=cache,target=/root/.npm \
      --mount=type=cache,target=/usr/local/share/.cache/yarn \
      --mount=type=cache,target=/root/.local/share/pnpm/store \
    if [ -f package-lock.json ]; then \
      npm ci --no-audit --no-fund; \
    elif [ -f yarn.lock ]; then \
      corepack enable yarn && yarn install --frozen-lockfile --production=false; \
    elif [ -f pnpm-lock.yaml ]; then \
      corepack enable pnpm && pnpm install --frozen-lockfile; \
    else \
      echo "No lockfile found." && exit 1; \
    fi

  # ============================================
  # Stage 2: Build Next.js application in standalone mode
  # ============================================

  FROM node:${NODE_VERSION} AS builder

  # Set working directory
  WORKDIR /app

  # Copy project dependencies from dependencies stage
  COPY --from=dependencies /app/node_modules ./node_modules

  # Copy application source code
  COPY . .

  ENV NODE_ENV=production

  # Next.js collects completely anonymous telemetry data about general usage.
  # Learn more here: https://nextjs.org/telemetry
  # Uncomment the following line in case you want to disable telemetry during the build.
  # ENV NEXT_TELEMETRY_DISABLED=1

  # Build Next.js application
  # If you want to speed up Docker rebuilds, you can cache the build artifacts
  # by adding: --mount=type=cache,target=/app/.next/cache
  # This caches the .next/cache directory across builds, but it also prevents
  # .next/cache/fetch-cache from being included in the final image, meaning
  # cached fetch responses from the build won't be available at runtime.
  RUN if [ -f package-lock.json ]; then \
      npm run build; \
    elif [ -f yarn.lock ]; then \
      corepack enable yarn && yarn build; \
    elif [ -f pnpm-lock.yaml ]; then \
      corepack enable pnpm && pnpm build; \
    else \
      echo "No lockfile found." && exit 1; \
    fi

  # ============================================
  # Stage 3: Run Next.js application
  # ============================================

  FROM node:${NODE_VERSION} AS runner

  # Set working directory
  WORKDIR /app

  # Set production environment variables
  ENV NODE_ENV=production
  ENV PORT=3000
  ENV HOSTNAME="0.0.0.0"

  # Next.js collects completely anonymous telemetry data about general usage.
  # Learn more here: https://nextjs.org/telemetry
  # Uncomment the following line in case you want to disable telemetry during the run time.
  # ENV NEXT_TELEMETRY_DISABLED=1

  # Copy production assets
  COPY --from=builder --chown=node:node /app/public ./public

  # Set the correct permission for prerender cache
  RUN mkdir .next
  RUN chown node:node .next

  # Automatically leverage output traces to reduce image size
  # https://nextjs.org/docs/advanced-features/output-file-tracing
  COPY --from=builder --chown=node:node /app/.next/standalone ./
  COPY --from=builder --chown=node:node /app/.next/static ./.next/static

  # If you want to persist the fetch cache generated during the build so that
  # cached responses are available immediately on startup, uncomment this line:
  # COPY --from=builder --chown=node:node /app/.next/cache ./.next/cache

  # Switch to non-root user for security best practices
  USER node

  # Expose port 3000 to allow HTTP traffic
  EXPOSE 3000

  # Start Next.js standalone server
  CMD ["node", "server.js"]
```

> [!NOTE]
> Este Dockerfile utiliza tres etapas: **dependencies** (dependencias), **builder** (constructor) y **runner** (ejecutor). La imagen final ejecuta `node server.js` y escucha en el puerto 3000.



---

#### 2.2 Next.js con salida export

La **salida export** (`output: "export"`) hace que Next.js compile un sitio completamente estático durante el tiempo de construcción. Genera HTML, CSS y JavaScript dentro de un directorio `out` que puede ser servido por cualquier servidor estático o CDN—sin necesidad de un servidor Node.js en tiempo de ejecución. Utiliza esto cuando no necesites renderizado en el lado del servidor o rutas de API. Para obtener más detalles, consulta la [documentación de configuración de salida de Next.js](https://nextjs.org/docs/app/api-reference/config/next-config-js/output).

**Configura Next.js** — Abre `next.config.ts` en la raíz de tu proyecto y agrega el siguiente código:

```ts
import type { NextConfig } from "next";

const nextConfig: NextConfig = {
  output: "export",
  trailingSlash: true,
  images: {
    unoptimized: true,
  },
};

export default nextConfig;
```

Elige una Imagen Endurecida de Docker o la Imagen Oficial de Docker, luego reemplaza tu `Dockerfile` con el contenido de la pestaña seleccionada a continuación.

**Uso de Docker Hardened Images**



Las Docker Hardened Images (DHIs) están disponibles para Node.js y NGINX en el [catálogo de Docker Hardened Images](https://hub.docker.com/hardened-images/catalog). Para más información, consulta la guía de [inicio rápido de DHI](/dhi/get-started/).

1. Inicia sesión en el registro de DHI:
   ```console
   $ docker login dhi.io
   ```

2. Descarga la DHI de Node.js (consulta el catálogo para ver las versiones disponibles):
   ```console
   $ docker pull dhi.io/node:24-alpine3.22-dev
   ```

3. Descarga la DHI de Nginx (consulta el catálogo para ver las versiones disponibles):
   ```console
   $ docker pull dhi.io/nginx:1.28.0-alpine3.21-dev
   ```

4. Reemplaza el Dockerfile generado con el siguiente. Las instrucciones `FROM` utilizan Docker Hardened Images: `dhi.io/node:24-alpine3.22-dev` y `dhi.io/nginx:1.28.0-alpine3.21-dev`. Consulta el [catálogo de Docker Hardened Images](https://hub.docker.com/hardened-images/catalog) para obtener las últimas versiones y actualiza las etiquetas de la imagen según sea necesario para la seguridad y compatibilidad.

    ```dockerfile
    # ============================================
    # Stage 1: Dependencies Installation Stage
    # ============================================

    # IMPORTANT: Docker Hardened Image (DHI) Version Maintenance
    # This Dockerfile uses dhi.io/node and dhi.io/nginx. Regularly validate and update to the latest DHI versions in the catalog for security and compatibility.

    FROM dhi.io/node:24-alpine3.22-dev AS dependencies

    # Set the working directory
    WORKDIR /app

    # Copy package-related files first to leverage Docker's caching mechanism
    COPY package.json yarn.lock* package-lock.json* pnpm-lock.yaml* .npmrc* ./

    # Install project dependencies with frozen lockfile for reproducible builds
    RUN --mount=type=cache,target=/root/.npm \
        --mount=type=cache,target=/usr/local/share/.cache/yarn \
        --mount=type=cache,target=/root/.local/share/pnpm/store \
      if [ -f package-lock.json ]; then \
        npm ci --no-audit --no-fund; \
      elif [ -f yarn.lock ]; then \
        corepack enable yarn && yarn install --frozen-lockfile --production=false; \
      elif [ -f pnpm-lock.yaml ]; then \
        corepack enable pnpm && pnpm install --frozen-lockfile; \
      else \
        echo "No lockfile found." && exit 1; \
      fi

    # ============================================
    # Stage 2: Build Next.js Application
    # ============================================

    FROM dhi.io/node:24-alpine3.22-dev AS builder

    # Set the working directory
    WORKDIR /app

    # Copy project dependencies from dependencies stage
    COPY --from=dependencies /app/node_modules ./node_modules

    # Copy application source code
    COPY . .

    ENV NODE_ENV=production

    # Next.js collects completely anonymous telemetry data about general usage.
    # Learn more here: https://nextjs.org/telemetry
    # Uncomment the following line in case you want to disable telemetry during the build.
    # ENV NEXT_TELEMETRY_DISABLED=1

    # Build Next.js application
    RUN --mount=type=cache,target=/app/.next/cache \
      if [ -f package-lock.json ]; then \
        npm run build; \
      elif [ -f yarn.lock ]; then \
        corepack enable yarn && yarn build; \
      elif [ -f pnpm-lock.yaml ]; then \
        corepack enable pnpm && pnpm build; \
      else \
        echo "No lockfile found." && exit 1; \
      fi

    # =========================================
    # Stage 3: Serve Static Files with Nginx
    # =========================================

    FROM dhi.io/nginx:1.28.0-alpine3.21-dev AS runner

    # Set the working directory
    WORKDIR /app

    # Next.js collects completely anonymous telemetry data about general usage.
    # Learn more here: https://nextjs.org/telemetry
    # Uncomment the following line in case you want to disable telemetry during the run time.
    # ENV NEXT_TELEMETRY_DISABLED=1

    # Copy custom Nginx config
    COPY nginx.conf /etc/nginx/nginx.conf

    # Copy the static build output from the build stage to Nginx's default HTML serving directory
    COPY --chown=nginx:nginx --from=builder /app/out /usr/share/nginx/html

    # Non-root user for security best practices
    USER nginx

    # Expose port 8080 to allow HTTP traffic
    EXPOSE 8080

    # Start Nginx directly with custom config
    ENTRYPOINT ["nginx", "-c", "/etc/nginx/nginx.conf"]
    CMD ["-g", "daemon off;"]
    ```

**Uso de la Imagen Oficial de Docker**



Crea un Dockerfile multi-etapa listo para producción. Reemplaza el Dockerfile generado con el siguiente (utiliza `node` y `nginxinc/nginx-unprivileged`):

```dockerfile
# ============================================
# Stage 1: Dependencies Installation Stage
# ============================================

ARG NODE_VERSION=24.14.0-slim
ARG NGINXINC_IMAGE_TAG=alpine3.22

FROM node:${NODE_VERSION} AS dependencies

# Set the working directory
WORKDIR /app

# Copy package-related files first to leverage Docker's caching mechanism
COPY package.json yarn.lock* package-lock.json* pnpm-lock.yaml* .npmrc* ./

# Install project dependencies with frozen lockfile for reproducible builds
RUN --mount=type=cache,target=/root/.npm \
    --mount=type=cache,target=/usr/local/share/.cache/yarn \
    --mount=type=cache,target=/root/.local/share/pnpm/store \
  if [ -f package-lock.json ]; then \
    npm ci --no-audit --no-fund; \
  elif [ -f yarn.lock ]; then \
    corepack enable yarn && yarn install --frozen-lockfile --production=false; \
  elif [ -f pnpm-lock.yaml ]; then \
    corepack enable pnpm && pnpm install --frozen-lockfile; \
  else \
    echo "No lockfile found." && exit 1; \
  fi

# ============================================
# Stage 2: Build Next.js Application
# ============================================

FROM node:${NODE_VERSION} AS builder

# Set the working directory
WORKDIR /app

# Copy project dependencies from dependencies stage
COPY --from=dependencies /app/node_modules ./node_modules

# Copy application source code
COPY . .

ENV NODE_ENV=production

# Next.js collects completely anonymous telemetry data about general usage.
# Learn more here: https://nextjs.org/telemetry
# Uncomment the following line in case you want to disable telemetry during the build.
# ENV NEXT_TELEMETRY_DISABLED=1

# Build Next.js application
RUN --mount=type=cache,target=/app/.next/cache \
  if [ -f package-lock.json ]; then \
    npm run build; \
  elif [ -f yarn.lock ]; then \
    corepack enable yarn && yarn build; \
  elif [ -f pnpm-lock.yaml ]; then \
    corepack enable pnpm && pnpm build; \
  else \
    echo "No lockfile found." && exit 1; \
  fi

# =========================================
# Stage 3: Serve Static Files with Nginx
# =========================================

FROM nginxinc/nginx-unprivileged:${NGINXINC_IMAGE_TAG} AS runner

# Set the working directory
WORKDIR /app

# Next.js collects completely anonymous telemetry data about general usage.
# Learn more here: https://nextjs.org/telemetry
# Uncomment the following line in case you want to disable telemetry during the run time.
# ENV NEXT_TELEMETRY_DISABLED=1

# Copy custom Nginx config
COPY nginx.conf /etc/nginx/nginx.conf

# Copy the static build output from the build stage to Nginx's default HTML serving directory
COPY --from=builder /app/out /usr/share/nginx/html

# Non-root user for security best practices
USER nginx

# Expose port 8080 to allow HTTP traffic
EXPOSE 8080

# Start Nginx directly with custom config
ENTRYPOINT ["nginx", "-c", "/etc/nginx/nginx.conf"]
CMD ["-g", "daemon off;"]
```

> [!NOTE]
> Usamos [nginx-unprivileged](https://hub.docker.com/r/nginxinc/nginx-unprivileged) en lugar de la imagen estándar de NGINX para ejecutar como un usuario sin privilegios (no-root), siguiendo las mejores prácticas de seguridad.



1. **Crea `nginx.conf`** (requerido solo para la salida export) — Crea un archivo llamado `nginx.conf` en la raíz de tu proyecto:

    ```nginx
    # Minimal Nginx config for static Next.js app
    worker_processes 1;

    # Store PID in /tmp (always writable)
    pid /tmp/nginx.pid;

    events {
        worker_connections 1024;
    }

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

        # Disable logging to avoid permission issues
        access_log off;
        error_log  /dev/stderr;

        # Optimize static file serving
        sendfile        on;
        tcp_nopush      on;
        tcp_nodelay     on;
        keepalive_timeout  65;

        # Gzip compression
        gzip on;
        gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
        gzip_min_length 256;

        server {
            listen       8080;
            server_name  localhost;

            # Serve static files
            root /usr/share/nginx/html;
            index index.html;

            # Handle Next.js static export routing
            # See: https://nextjs.org/docs/app/guides/static-exports#deploying
            location / {
                try_files $uri $uri.html $uri/ =404;
            }

            # This is necessary when `trailingSlash: false` (default).
            # You can omit this when `trailingSlash: true` in next.config.
            # Handles nested routes like /blog/post -> /blog/post.html
            location ~ ^/(.+)/$ {
                rewrite ^/(.+)/$ /$1.html break;
            }

            # Serve Next.js static assets
            location ~ ^/_next/ {
                try_files $uri =404;
                expires 1y;
                add_header Cache-Control "public, immutable";
            }

            # Optional 404 handling
            error_page 404 /404.html;
            location = /404.html {
                internal;
            }
        }
    }
    ```

      > [!NOTE]
      > Export utiliza el **puerto 8080**. Para más detalles, consulta la [documentación de configuración de salida de Next.js](https://nextjs.org/docs/app/api-reference/config/next-config-js/output) y la [documentación de NGINX](https://nginx.org/en/docs/).

### Paso 3: Configurar el archivo .dockerignore

El archivo `.dockerignore` le indica a Docker qué archivos y carpetas excluir al construir la imagen.

> [!NOTE]
> Esto ayuda a:
>- Reducir el tamaño de la imagen  
>- Acelerar el proceso de construcción  
>- Evitar que archivos sensibles o innecesarios (como `.env`, `.git` o `node_modules`) se agreguen a la imagen final.
>
> Para aprender más, visita la [referencia de .dockerignore](/reference/dockerfile/#dockerignore-file).

Copia y reemplaza el contenido de tu `.dockerignore` existente con la siguiente configuración:

```dockerignore
# Dependencies (installed inside the image, never copy from host)
node_modules/
.pnp/
.pnp.js
.pnpm-store/

# Next.js build output (generated during the image build)
.next/
out/
dist/
build/
.vercel/

# Testing (not needed in the production image)
coverage/
.nyc_output/
__tests__/
__mocks__/
jest/
cypress/
playwright-report/
test-results/
.vitest/

# Environment files (avoid leaking secrets into the build context)
.env
.env*
.env.local
.env.development.local
.env.test.local
.env.production.local

# Debug and log files
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
*.log

# IDE and editor files
.vscode/
.idea/
.cursor/
.cursorrules
.copilot/
*.swp
*.swo
*~

# Git
.git/
.gitignore
.gitattributes

# Docker files (reduce build context; not needed inside the image)
Dockerfile*
.dockerignore
docker-compose*.yml
compose*.yaml

# Documentation (not needed in the image)
*.md
docs/

# CI/CD (not needed in the image)
.github/
.gitlab-ci.yml
.travis.yml
.circleci/
Jenkinsfile

# TypeScript and build metadata
*.tsbuildinfo

# Cache and temporary directories
.cache/
.parcel-cache/
.eslintcache
.stylelintcache
.turbo/
.tmp/
.temp/

# Sensitive or dev-only config (optional; omit if your build needs these)
.pem
.editorconfig
.prettierrc*
.eslintrc*
.stylelintrc*
.babelrc*
*.iml

# OS-specific files
.DS_Store
._*
.Spotlight-V100
.Trashes
ehthumbs.db
Thumbs.db
Desktop.ini
```

### Paso 4: Construir la imagen de la aplicación Next.js

Con tu configuración personalizada en su lugar, ahora estás listo para construir la imagen de Docker. Usa el Dockerfile que elegiste en el Paso 3 (standalone o export).

La configuración incluye:

- Construcciones multi-etapa para optimizar el tamaño de la imagen.  
- Standalone: servidor Node.js en el puerto 3000; Export: NGINX sirviendo archivos estáticos en el puerto 8080.  
- Usuario no-root para mayor seguridad.  
- Permisos y propiedad de archivos correctos.  

Después de completar los pasos anteriores, tu directorio de proyecto debería contener al menos los siguientes archivos (la opción export también requiere `nginx.conf`):

```text
├── docker-nextjs-sample/
│ ├── Dockerfile
│ ├── .dockerignore
│ ├── compose.yaml
│ ├── next.config.ts
│ └── README.Docker.md
```

Ahora que tu Dockerfile está configurado, puedes construir la imagen de Docker para tu aplicación Next.js.

> [!NOTE]
> El comando `docker build` empaqueta tu aplicación en una imagen utilizando las instrucciones del Dockerfile. Incluye todos los archivos necesarios del directorio actual (llamado el [contexto de construcción](/build/concepts/context/#what-is-a-build-context)).

Ejecuta el siguiente comando desde la raíz de tu proyecto:

```console
$ docker build --tag nextjs-sample .
```

Qué hace este comando:
- Utiliza el Dockerfile en el directorio actual (`.`).
- Empaqueta la aplicación y sus dependencias en una imagen de Docker.
- Etiqueta la imagen como `nextjs-sample` para que puedas hacer referencia a ella más tarde.

### Paso 5: Ver imágenes locales

Después de construir tu imagen de Docker, puedes verificar qué imágenes están disponibles en tu máquina local usando la CLI de Docker o [Docker Desktop](/desktop/use-desktop/images/). Como ya estás trabajando en la terminal, usemos la CLI de Docker.

Para listar todas las imágenes de Docker disponibles localmente, ejecuta el siguiente comando:

```console
$ docker images
```

Salida de ejemplo:

```shell
REPOSITORY                TAG               IMAGE ID       CREATED         SIZE
nextjs-sample             latest            8c5fc80f098e   14 seconds ago   130MB
```

Esta salida proporciona detalles clave sobre tus imágenes:

- **Repository** – El nombre asignado a la imagen.
- **Tag** – Una etiqueta de versión que ayuda a identificar diferentes construcciones (por ejemplo, `latest`).
- **Image ID** – Un identificador único para la imagen.
- **Created** – La marca de tiempo que indica cuándo se construyó la imagen.
- **Size** – El espacio total en disco utilizado por la imagen.

Si la construcción fue exitosa, deberías ver la imagen `nextjs-sample` en la lista.

---

## Ejecutar la aplicación contenerizada

En el paso anterior, creaste un Dockerfile para tu aplicación Next.js y construiste una imagen de Docker usando el comando `docker build`. Ahora es el momento de ejecutar esa imagen en un contenedor y verificar que tu aplicación funcione como se espera.

Ejecuta el siguiente comando en una terminal. Usa el puerto que coincida con tu configuración: **standalone** usa el puerto 3000, **export** usa el puerto 8080.

```console
$ docker run -p 3000:3000 nextjs-sample
```

Para la salida **export**, usa el puerto 8080 en su lugar:

```console
$ docker run -p 8080:8080 nextjs-sample
```

Abre un navegador y visita la aplicación: [http://localhost:3000](http://localhost:3000) para **standalone** o [http://localhost:8080](http://localhost:8080) for **export**. Deberías ver tu aplicación web de Next.js.

Presiona `ctrl+c` en la terminal para detener tu aplicación.

### Ejecutar la aplicación en segundo plano

Puedes ejecutar la aplicación desconectada (detached) de la terminal agregando la opción `-d` y `--name` para darle un nombre al contenedor para que puedas detenerlo más tarde:

```console
$ docker run -d -p 3000:3000 --name nextjs-app nextjs-sample
```

Para la salida **export**, usa el puerto 8080:

```console
$ docker run -d -p 8080:8080 --name nextjs-app nextjs-sample
```

Abre un navegador y visita la aplicación: [http://localhost:3000](http://localhost:3000) para **standalone** o [http://localhost:8080](http://localhost:8080) para **export**. Deberías ver tu aplicación web.

Para confirmar que el contenedor se está ejecutando, usa el comando `docker ps`:

```console
$ docker ps
```

Esto listará todos los contenedores activos junto con sus puertos, nombres y estado. Busca un contenedor que exponga el puerto 3000 (standalone) o 8080 (export).

Salida de ejemplo:

```shell
CONTAINER ID   IMAGE           COMMAND                  CREATED             STATUS             PORTS                    NAMES
f49b74736a9d   nextjs-sample   "node server.js"         About a minute ago   Up About a minute   0.0.0.0:3000->3000/tcp nextjs-app
```

Para detener la aplicación, ejecuta:

```console
$ docker stop nextjs-app
```

> [!NOTE]
> Para obtener más información sobre cómo ejecutar contenedores, consulta la [referencia de CLI de `docker run`](/reference/cli/docker/container/run/) y la [referencia de CLI de `docker stop`](/reference/cli/docker/container/stop/).

---

## Resumen

En esta guía, aprendiste a contenerizar, construir y ejecutar una aplicación Next.js usando Docker. Siguiendo las mejores prácticas, creaste una configuración segura, optimizada y lista para producción.

Lo que lograste:
- Inicializaste tu proyecto usando `docker init` para andamiar archivos esenciales de configuración de Docker.
- Configuraste Next.js tanto para salida standalone (servidor Node.js) como para salida export (archivos estáticos con NGINX).
- Agregaste un Dockerfile multi-etapa para el enfoque elegido: standalone (puerto 3000) o export (puerto 8080, con `nginx.conf`).
- Reemplazaste el archivo `.dockerignore` predeterminado para excluir archivos innecesarios y mantener la imagen limpia y eficiente.
- Construiste tu imagen de Docker usando `docker build`.
- Ejecutaste el contenedor usando `docker run` con el nombre de imagen `nextjs-sample`, tanto en primer plano como en modo desconectado (detached).
- Verificaste que la aplicación se estuviera ejecutando visitando [http://localhost:3000](http://localhost:3000) (standalone) o [http://localhost:8080](http://localhost:8080) (export).
- Aprendiste a detener la aplicación contenerizada usando `docker stop nextjs-app`.

Ahora tienes una aplicación Next.js completamente contenerizada, ejecutándose en un contenedor Docker y lista para ser desplegada en cualquier entorno con confianza y consistencia.

---

## Recursos relacionados

Explora las referencias oficiales y las mejores prácticas para perfeccionar tu flujo de trabajo con Docker:

- [Construcciones multi-etapa](/build/building/multi-stage/) – Aprende cómo separar las etapas de construcción y de tiempo de ejecución.
- [Mejores prácticas para escribir Dockerfiles](/develop/develop-images/dockerfile_best-practices/) – Escribe Dockerfiles eficientes, fáciles de mantener y seguros.  
- [Contexto de construcción en Docker](/build/concepts/context/) – Aprende cómo el contexto afecta la construcción de imágenes.  
- [Configuración de salida de Next.js](https://nextjs.org/docs/app/api-reference/config/next-config-js/output) – Aprende sobre la optimización de producción de Next.js (standalone y export).
- [Next.js con Docker (standalone)](https://github.com/vercel/next.js/tree/canary/examples/with-docker) – Ejemplo oficial de Next.js: salida standalone con Node.js.
- [Next.js con Docker (export)](https://github.com/vercel/next.js/tree/canary/examples/with-docker-export-output) – Ejemplo oficial de Next.js: exportación estática con Nginx o serve.
- [Referencia de CLI de `docker init`](/reference/cli/docker/init/) – Andaia recursos de Docker automáticamente.
- [Referencia de CLI de `docker build`](/reference/cli/docker/image/build/) – Construye imágenes de Docker a partir de un Dockerfile.
- [Referencia de CLI de `docker images`](/reference/cli/docker/image/ls/) – Gestiona e inspecciona imágenes de Docker locales.
- [Referencia de CLI de `docker run`](/reference/cli/docker/container/run/) – Ejecuta un comando en un nuevo contenedor.
- [Referencia de CLI de `docker stop`](/reference/cli/docker/container/stop/) – Detiene uno o más contenedores en ejecución.

---

## Próximos pasos

Con tu aplicación Next.js ahora contenerizada, estás listo para pasar al siguiente paso.

En la siguiente sección, aprenderás cómo desarrollar tu aplicación usando contenedores Docker, lo que permite un entorno de desarrollo consistente, aislado y reproducible en cualquier máquina.

