skip to Main Content

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?

2

Answers


  1. 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
    Login or Signup to reply.
  2. This answer was really useful. For me on Ubuntu 20.4

    docker build -t nextjs:latest -f Dockerfile
    

    needs to be

    docker build -t nextjs:latest -f Dockerfile . 
    

    (yes, the dot)

    also for some reason docker can only work on directories that are two levels down from the base.. so for example /var/www but not /var/www/html

    I have no idea why this isn’t actually documented on the internet (at least not that I could find)

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search