Nginx configuration file and SSL certificate errors in Docker

30 Views Asked by At

I am trying to run a JupyterLab environment with Nginx using Docker Compose. However, I am encountering two persistent errors:

$ docker compose up
[+] Running 2/0
 ✔ Container docker-web-1    Created                                                                             0.0s 
 ✔ Container docker-nginx-1  Created                                                                             0.0s 
Attaching to nginx-1, web-1
web-1    | [ERROR] Nginx configuration file (./nginx.conf) not found.
web-1 exited with code 1
nginx-1  | /docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration
nginx-1  | /docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/
nginx-1  | /docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh
nginx-1  | 10-listen-on-ipv6-by-default.sh: info: IPv6 listen already enabled
nginx-1  | /docker-entrypoint.sh: Sourcing /docker-entrypoint.d/15-local-resolvers.envsh
nginx-1  | /docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh
nginx-1  | /docker-entrypoint.sh: Launching /docker-entrypoint.d/30-tune-worker-processes.sh
nginx-1  | /docker-entrypoint.sh: Configuration complete; ready for start up
nginx-1  | 2024/03/30 14:31:26 [emerg] 1#1: cannot load certificate "/etc/nginx/certs/_wildcard.quantumworkspace.dev+3.pem": BIO_new_file() failed (SSL: error:80000002:system library::No such file or directory:calling fopen(/etc/nginx/certs/_wildcard.quantumworkspace.dev+3.pem, r) error:10000080:BIO routines::no such file)
nginx-1  | nginx: [emerg] cannot load certificate "/etc/nginx/certs/_wildcard.quantumworkspace.dev+3.pem": BIO_new_file() failed (SSL: error:80000002:system library::No such file or directory:calling fopen(/etc/nginx/certs/_wildcard.quantumworkspace.dev+3.pem, r) error:10000080:BIO routines::no such file)
nginx-1 exited with code 1

Additional files for reference:

  • Dockerfile:
# Version 3.0.0
# Base image
FROM ubuntu:latest

# Copy custom hosts file to /etc/hosts
COPY hosts /etc/hosts

# Set environment variables
ENV LANG C.UTF-8
ENV LC_ALL C.UTF-8
ENV PYTHONDONTWRITEBYTECODE 1
ENV PYTHONFAULTHANDLER 1

# Install necessary packages
RUN apt-get update && apt-get install -y \
    python3.11 \
    python3.11-venv \
    python3-apt \
    python3-pip \
    python3-setuptools \
    python3-wheel \
    python3-distutils \
    binutils \
    build-essential \
    curl \
    vim \
    vim-common \
    vim-runtime \
    nano \
    flameshot \
    keepassxc \
    bleachbit \
    nodejs \
    g++ \
    git \
    libblas-dev \
    libffi-dev \
    liblapack-dev \
    libssl-dev \
    texlive-latex-base \
    latexmk \
    make \
    wget \
    zlib1g-dev \
    bash \
    tree \
    nginx \
    libnss3-tools \
    && apt-get clean

# Install Rust, update it, create a directory, and set the working directory to the new Rust application directory
RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y && \
    $HOME/.cargo/bin/rustup update
ENV PATH="/root/.cargo/bin:${PATH}"
ENV PROJECT_DIR /usr/local/src/webapp
RUN mkdir -p ${PROJECT_DIR}/rust
WORKDIR ${PROJECT_DIR}/rust

# Install wasm-pack
RUN cargo install wasm-pack

# Set up work directory for Python application
WORKDIR /home/appuser/app

# Copy Pipfile and Pipfile.lock
COPY Pipfile Pipfile.lock /home/appuser/app/

# Create and activate the virtual environment
RUN python3.11 -m venv /venv
ENV PATH="/venv/bin:${PATH}"
RUN . /venv/bin/activate && \
    pip install --upgrade pip && \
    pip install pipenv

# Install dependencies using pipenv
RUN PIPENV_IGNORE_VIRTUALENVS=1 . /venv/bin/activate && pipenv install --deploy

# Install Jupyter within the virtual environment
RUN . /venv/bin/activate && pipenv run pip install jupyter notebook jupyterlab voila

# Copy pre-configured Jupyter Notebook config
COPY jupyter_notebook_config.py /home/appuser/.jupyter/jupyter_notebook_config.py

# Generate Jupyter Notebook config
RUN . /venv/bin/activate && jupyter notebook --generate-config -y

# Modify Jupyter Notebook config
RUN mkdir -p /home/appuser/.jupyter && echo "c.NotebookApp.token = ''" >> /home/appuser/.jupyter/jupyter_notebook_config.py

# Install mkcert and generate SSL certificate
RUN mkdir -p /etc/nginx/certs && \
    apt-get update && \
    curl -JLO "https://dl.filippo.io/mkcert/latest?for=linux/amd64" && \
    chmod +x mkcert-v*-linux-amd64 && \
    mv mkcert-v*-linux-amd64 /usr/local/bin/mkcert && \
    mkcert -install && \
    mkcert -CAROOT -cert-file /etc/nginx/certs/mkcert-ca.pem  -key-file /etc/nginx/certs/mkcert-ca-key.pem && \
    mkcert -cert-file /etc/nginx/certs/_wildcard.quantumworkspace.dev+3.pem -key-file /etc/nginx/certs/_wildcard.quantumworkspace.dev+3-key.pem "*.quantumworkspace.dev" localhost 127.0.0.1 ::1

# Create Nginx user and group
RUN groupadd -r nginx && useradd -r -g nginx nginx

# Setting permissions and ownership
RUN chown nginx:nginx /etc/nginx/certs/*.pem && \
    chmod 600 /etc/nginx/certs/*.pem

# Remove default Nginx configuration
RUN rm /etc/nginx/sites-enabled/default

# Expose ports
EXPOSE 8888
EXPOSE 5678
EXPOSE 8080
EXPOSE 443
EXPOSE 80

# Copy the main Nginx configuration file
# COPY ./nginx.conf /etc/nginx/nginx.conf
COPY nginx.conf /etc/nginx/nginx.conf

# Create non-root user for security
RUN adduser -u 5678 --disabled-password --gecos "" appuser

# Create notebooks directory
RUN mkdir -p /notebooks

COPY docker-entrypoint.sh /docker-entrypoint.sh

RUN chmod +x /docker-entrypoint.sh

ENTRYPOINT ["/docker-entrypoint.sh"]
  • docker-compose.yaml
version: '3.8'

services:
  web:
    build: ./
    image: elijun9831/quantumworkspace:3.0.0 # Haven't pushed into Docker Hub yet
    networks:
      - mynetwork
    volumes:
      - /notebooks:/notebooks  # Adjust as needed

  nginx:
    image: nginx:latest
    ports:
      - "8080:8080"
      - "80:80"
      - "8443:443"
      - "443:443"
      - "8888:8888"
      - "5678:5678"
    volumes:
      - ./certs:/etc/nginx/certs
      - ./nginx.conf:/etc/nginx/nginx.conf
    networks:
      - mynetwork
    depends_on:
      - web
    environment:
      - NGX_HTTP_PORT=80
      - NGX_HTTPS_PORT=443
      - JUPYTER_HOST=web  # Or internal IP of 'web' service 
      - JUPYTER_PORT=8888

networks:
  mynetwork:
    driver: bridge
  • docker-entrypoint.sh
#!/bin/bash

set -e  # Exit script on error

# ================ Environment Variables ================
# Add or modify as needed, set default values here
export VIRTUAL_ENV="/venv"
export NOTEBOOKS_DIRECTORY="/notebooks"
export NGINX_CONF_FILE="./nginx.conf"

# ================ Validations ================
# Check if Nginx configuration file exists
if [[ ! -f $NGINX_CONF_FILE ]]; then
  echo "[ERROR] Nginx configuration file ($NGINX_CONF_FILE) not found." >&2
  exit 1
fi

# Check if Virtual Environment directory exists
if [[ ! -d $VIRTUAL_ENV ]]; then
  echo "[ERROR] Virtual environment directory ($VIRTUAL_ENV) not found." >&2
  exit 1
fi

# Check if JupyterLab notebooks directory exists
if [[ ! -d $NOTEBOOKS_DIRECTORY ]]; then
  echo "[ERROR] JupyterLab notebooks directory ($NOTEBOOKS_DIRECTORY) not found." >&2
  exit 1
fi

# ================ Apply Nginx Configuration ================
echo "[INFO] Applying Nginx configuration..."
envsubst < $NGINX_CONF_FILE > /etc/nginx/nginx.conf

# ================ Start Nginx ================
echo "[INFO] Starting Nginx in foreground mode..."
nginx -g "daemon off;" &
NGINX_PID=$!

# ================ Activate Virtual Environment ================
echo "[INFO] Activating Python virtual environment ($VIRTUAL_ENV)..."
. $VIRTUAL_ENV/bin/activate

# ================ Start JupyterLab ================
echo "[INFO] Starting JupyterLab..."
pipenv run jupyter lab --notebook-dir=$NOTEBOOKS_DIRECTORY --ip=0.0.0.0 --port=80 --no-browser --allow-root &
JUPYTER_PID=$!

# ================ Graceful Shutdown ================
# Cleanup resources on script exit (EXIT) or signal reception
function cleanup() {
  echo "[INFO] Received shutdown signal. Cleaning up..."
  kill -TERM $NGINX_PID $JUPYTER_PID
  wait $NGINX_PID $JUPYTER_PID
  echo "[INFO] Nginx and JupyterLab stopped."
  exit 0
}

trap cleanup EXIT INT TERM

# ================ Main Execution Loop ================
echo "[INFO] Container startup complete. Ready to serve requests."

# Infinite loop to handle SIGINT, SIGTERM signals
while true; do
  sleep 1 &
  wait $!
done
  • nginx.conf
events {
    worker_connections 1024;
}

http {

    server {
        listen 80;
        listen [::]:80;
        server_name *.quantumworkspace.dev;

        location / {
            return 308 https://$host$request_uri;
        }
    }

    server {
        listen [::]:443 ssl;
        http2 on;
        server_name *.quantumworkspace.dev;

        ssl_certificate /etc/nginx/certs/_wildcard.quantumworkspace.dev+3.pem;
        ssl_certificate_key /etc/nginx/certs/_wildcard.quantumworkspace.dev+3-key.pem;

        ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
        ssl_ciphers HIGH:!aNULL:!MD5;

        root /var/www/html;
        index index.html index.htm index.nginx-debian.html;

        # Enable SSL session caching
        ssl_session_cache shared:SSL:10m;

        # Add headers to serve security related headers
        add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
        
        # this is the internal Docker DNS, cache only for 30s
        resolver 127.0.0.53 valid=30s;
        
        location / {
            set $upstream *.quantumworkspace.dev:8888 ;
            proxy_pass $upstream ;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;
            proxy_redirect off;
            proxy_buffering off;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "upgrade";
            proxy_read_timeout 86400;
        }

        location ~ ^/(api/kernels/|terminals/|api/security/ws-user/|terminals/websocket/|api/batch|api/spawn) {
            set $upstream *.quantumworkspace.dev:8888 ;
            proxy_pass $upstream ;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;
            proxy_redirect off;
            proxy_buffering off;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "upgrade";
            proxy_read_timeout 86400;
        }

        location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ {
            expires 1d;
            add_header Cache-Control "public";
        }

       add_header X-Frame-Options "DENY";
       add_header X-Content-Type-Options "nosniff";
       add_header Content-Security-Policy "default-src 'self';";

    access_log /var/log/nginx/access.log;
    error_log  /var/log/nginx/error.log;
    
    }
}

I have been unable to resolve these errors after several attempts, so any help or suggestions would be greatly appreciated!

What I have tried:

  • Verified that the Nginx configuration file exists and has the correct permissions.
  • Verified that the SSL certificate files exist and are in the correct location.
  • Checked the Dockerfile to ensure that the files are being copied correctly to the container.
  • Restarted the containers multiple times.
0

There are 0 best solutions below