Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to deploy a Next.js app on HTTPS (SSL connection) with Docker?

I'm following the instructions on Next.js' documentation to start the server using Docker: https://nextjs.org/docs/deployment#docker-image

Loading the site with http works but https returns SSL protocol errors.

What I did in detail:

  1. Configured NGINX and cerbot (note that the guide is for Ubuntu 20) https://certbot.eff.org/instructions?ws=nginx&os=ubuntufocal on my DigitalOcean Ubuntu 22.4 server

  2. Copied Dockerfile and .dockerignore from the example project linked in the docs to my project: https://github.com/vercel/next.js/tree/canary/examples/with-docker

  3. Built and uploaded the image to the server.

  4. Started the image on the server: docker run -p 80:3000 -p 443:3000 my_image

HTTP works perfectly (https://mysite.mydomain). With HTTPS I get errors, e.g. ERR_SSL_PROTOCOL_ERROR on Chrome and SSL_ERROR_RX_RECORD_TOO_LONG on Firefox.

Any ideas?

like image 691
User Avatar asked Apr 21 '26 13:04

User


1 Answers

The following steps explain how to set up a multi-container Docker Compose environment where NGINX is used as a reverse proxy in front of the Next.js application to handle the SSL connection (and offer an HTTPS URI).

Step 1 - Dockerize Next.js application

Luckily, this is part of the Next.js official docs themselves. The key step is to copy this Dockerfile to the Next.js repo you are working on.

Gotchas:

  • It's a good idea to copy .dockerignore as well
  • Set output: 'standalone' in next.config.js (like this)
  • We will place a reverse proxy in front of the Next.js app, so the port in the Dockerfile (3000 by default) is not what will be externally exposed; there's no need to expose that port publicly
  • Make sure that the image builds: docker build -t nextjs:latest -f Dockerfile .
Step 2 - Set up a Docker Compose environment

The Docker Compose environment will have two running containers: the Next.js app and NGINX.

The NGINX image can be created by adding a second Dockerfile:

# nginx/Dockerfile

FROM nginx:1.23.3-alpine

COPY nginx.conf /etc/nginx/nginx.conf

EXPOSE 80
EXPOSE 443

Build the image from the project root dir with docker build -t nginx:latest -f nginx/Dockerfile nginx.

Then, we can create a docker-compose.yml file:

version: "3.9"
services:
  nextjs:
    image: nextjs:latest
    container_name: nextjs
    ports:
      - "3000:3000"
    restart: always
  nginx:
    image: nginx:latest
    container_name: nginx
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - /etc/ssl:/etc/nginx/ssl:ro
    restart: always

Gotchas:

  • An empty nginx.conf can be added for now, it'll be configured in the next step
  • Ports 80 (HTTP) and 443 (HTTPS) will be exposed pubicly, so they need to be open
  • The SSL certificate and key are made available through a Docker volume. They are assumed to exist in the host machine under /etc/ssl. An alternative would be to pack them in the NGINX image (e.g. add COPY my_ssl_cert.crt /etc/nginx/ssl/my_ssl_cert.crt to the Dockerfile, idem for the key)
Step 3 - Configure NGINX as a reverse proxy

Example nginx.conf:

# nginx/nginx.conf

events {
}

http {
    upstream nextjs {
        server nextjs:3000;
    }
    server {
        # Redirect HTTP requests to HTTPS.
        listen 80;
        server_name localhost;
        root /srv/public;
        return 301 https://$host$request_uri;
    }

    server {
        listen 443 ssl;

        server_name localhost;
        root /srv/public;
        server_tokens off;

        ssl_certificate /etc/nginx/ssl/my_ssl_cert.crt;
        ssl_certificate_key /etc/nginx/ssl/my_ssl_key.key;

        location / {
            try_files $uri $uri/ @nextjs;
        }

        location @nextjs {
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto https;
            proxy_set_header X-Forwarded-Ssl on;
            proxy_set_header Host $http_host;
            proxy_redirect off;
            proxy_pass http://nextjs;
            proxy_cookie_path / "/; HTTPOnly; Secure";
        }
    }
}

Gotchas:

  • We can refer to the Next.js app by its default hostname nextjs because by default Compose sets up a single network for your app (docs)
Step 4 - Deploy
  1. Build both Docker images
  2. Ship both Docker images, the SSL files, and docker-compose.yml to the server
  3. In the server, run docker compose up
  4. If required, use docker logs [container_name] to debug any issues; curl http://localhost:80 and curl --insecure https://localhost:443 can also help
like image 59
swimmer Avatar answered Apr 24 '26 00:04

swimmer



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!