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.