Jupyter Notebook is an interactive computing environment that lets you combine live code, equations, visualizations, and narrative text in a single document. On RHEL 8, the recommended approach is to install Jupyter inside a Python virtual environment to keep the system Python clean. This tutorial covers installation, password protection, systemd service setup, and configuring Nginx as a reverse proxy — including the WebSocket support that Jupyter requires for interactive output. JupyterLab, the next-generation interface, is also covered as a drop-in alternative.
Prerequisites
- RHEL 8 server with a sudo-capable user
- Python 3.8 or higher installed via AppStream (
dnf install -y python39) - Nginx installed (
dnf install -y nginx) - Port 8888 accessible temporarily for initial testing, or port 80/443 for Nginx access
- At least 2 GB of available RAM
Step 1 — Create a Virtual Environment and Install Jupyter
Always install Jupyter in a virtual environment to avoid conflicts with system packages.
sudo dnf install -y python39 python39-pip
mkdir -p ~/jupyter && cd ~/jupyter
python3.9 -m venv venv
source venv/bin/activate
pip install --upgrade pip
pip install jupyter jupyterlab notebook
Confirm the installation succeeded:
jupyter --version
Step 2 — Generate a Configuration File and Set a Password
Generate the Jupyter configuration file, then set a hashed password so the notebook server is not accessible without authentication.
jupyter notebook --generate-config
jupyter notebook password
The password command prompts you to enter and confirm a passphrase. It stores a SHA-256 hash in ~/.jupyter/jupyter_server_config.json — the plaintext password is never stored on disk. Open the generated config and confirm or set the following values:
cat >> ~/.jupyter/jupyter_notebook_config.py << 'EOF'
c.NotebookApp.ip = '127.0.0.1'
c.NotebookApp.port = 8888
c.NotebookApp.open_browser = False
c.NotebookApp.allow_remote_access = True
EOF
Binding to 127.0.0.1 ensures Jupyter only accepts connections from the local machine; Nginx will proxy external traffic.
Step 3 — Test the Notebook Server
Run Jupyter manually to confirm it starts before creating the systemd service.
cd ~/jupyter
source venv/bin/activate
jupyter notebook --ip=127.0.0.1 --port=8888 --no-browser
You should see a startup message with a token URL. Press Ctrl+C to stop once confirmed.
Step 4 — Create a systemd Service
Create a systemd unit to manage Jupyter as a background service. Replace youruser with your actual username.
sudo tee /etc/systemd/system/jupyter.service > /dev/null << 'EOF'
[Unit]
Description=Jupyter Notebook Server
After=network.target
[Service]
User=youruser
Group=youruser
WorkingDirectory=/home/youruser/jupyter
ExecStart=/home/youruser/jupyter/venv/bin/jupyter notebook
--config=/home/youruser/.jupyter/jupyter_notebook_config.py
Restart=always
RestartSec=10
[Install]
WantedBy=multi-user.target
EOF
sudo systemctl daemon-reload
sudo systemctl enable --now jupyter
sudo systemctl status jupyter
Step 5 — Configure Nginx with WebSocket Proxying
Jupyter uses WebSockets for kernel communication. The Nginx configuration must explicitly proxy WebSocket upgrade headers; without this, interactive output (including cell execution responses) will not work.
sudo tee /etc/nginx/conf.d/jupyter.conf > /dev/null << 'EOF'
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
server {
listen 80;
server_name your-domain.com;
location / {
proxy_pass http://127.0.0.1:8888;
proxy_set_header Host $host;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_set_header X-Real-IP $remote_addr;
proxy_read_timeout 86400;
}
}
EOF
sudo nginx -t
sudo systemctl reload nginx
Step 6 — Switch to JupyterLab (Optional)
JupyterLab is the modern successor to the classic Notebook interface. It is already installed if you ran pip install jupyterlab in Step 1. To default the systemd service to JupyterLab, update the ExecStart line:
sudo sed -i 's|jupyter notebook|jupyter lab|' /etc/systemd/system/jupyter.service
sudo systemctl daemon-reload
sudo systemctl restart jupyter
The Nginx configuration remains unchanged because JupyterLab also uses port 8888 and WebSockets.
Conclusion
You now have a password-protected Jupyter Notebook (or JupyterLab) server running on RHEL 8, managed by systemd, and served securely through Nginx with full WebSocket support. This setup is suitable for data science workflows, remote development, and team collaboration. Add HTTPS with Certbot to encrypt the connection and protect your credentials in transit.
Next steps: Securing Jupyter with HTTPS and Certbot on RHEL 8, Installing Data Science Python Packages (NumPy, Pandas, Matplotlib) on RHEL 8, and Running JupyterHub for Multi-User Access on RHEL 8.