Chapters: 

TL;DR

Access Points on same network

If you are on the same network:

http://camelot:8888/?token=6731e677bd79a997c5fac158161c967049cf88704a569794

If you're Frodo from the Sh1re, you can tunnel in:

ssh -L 8888:localhost:8888 tux@camelot

Then on Frodo:

http://localhost:8888/?token=6731e677bd79a997c5fac158161c967049cf88704a569794

 

🗺️ Where We Are

You are Frodo, traveling from the Sh1re to Camelot (your Fedora 42 server). Camelot is:

  • Running locally or privately (no external certs),
  • About to be taught the Magic of Jupyter by Frodo,
  • Already home to a TransferDepot, a RESTful Flask API that successfully handles secure file exchanges with Distant Lands.

📜 Today's Mission (on Camelot)

  1. Get Jupyter running and prepare it as a demo tool:
    • Teach Camelot how to visualize, prototype, and share insights.
    • Output shall be exported and made publishable — a means of knowledge transfer.
  2. Learn from Camelot’s REST API success:
    • A working Flask app with clean routing for file handling.
    • Likely a simpler version of app.py from the Sh1re’s Transfer UI.
    • Used in production or testing on Camelot to handle uploads/downloads.
  3. Document the exchange:
    • What Jupyter enables (interactive experiments),
    • What the Flask API handles (reliable document transit),
    • How this exchange can continue between the Sh1re and Distant Lands — even those stuck in the Age of TLSv1 (Firefox 1.5, the stuff of myth).

🏰 Tomorrow’s Plan (Back in the Sh1re)

  • Register an api.sh1re subdomain to match the realm's DNS magic.
  • Move the Flask app (based on what worked in Camelot) behind the Sh1re’s Nginx reverse proxy.
  • Prove it can:
    • Accept file uploads from virtca8 (now also in the Sh1re),
    • Serve files cleanly and securely,
    • Survive the treacherous translation from localhost:8080https://api.sh1re/...

✨ Summary of What’s Needed Today

| Component             | Role                                                 |
| --------------------- | ---------------------------------------------------- |
| `jupyter`             | Taught to Camelot by Frodo                           |
| `notebook_test.ipynb` | Proof of Jupyter’s utility                           |
| `app.py` (simplified) | REST API showing current file exchange success       |
| Export/Transfer Test  | How to pass data from Jupyter to the TransferDepot   |
| Notes & Export Paths  | For Frodo to bring back to the Sh1re for review/demo |

 

The path is clear, and this mission both teachable and demonstrable to all who govern knowledge in the realm of the Sh1re.

jupyter server --ip=0.0.0.0 --no-browser

tux@camelot:~$ jupyter server --ip=0.0.0.0 --no-browser

[I 2025-07-20 12:15:58.705 ServerApp] jupyter_lsp | extension was successfully linked.
[I 2025-07-20 12:15:58.707 ServerApp] jupyter_server_terminals | extension was successfully linked.
[I 2025-07-20 12:15:58.710 ServerApp] jupyterlab | extension was successfully linked.
[I 2025-07-20 12:15:58.712 ServerApp] notebook | extension was successfully linked.
[I 2025-07-20 12:15:58.854 ServerApp] notebook_shim | extension was successfully linked.
[I 2025-07-20 12:15:58.864 ServerApp] notebook_shim | extension was successfully loaded.
[I 2025-07-20 12:15:58.865 ServerApp] jupyter_lsp | extension was successfully loaded.
[I 2025-07-20 12:15:58.866 ServerApp] jupyter_server_terminals | extension was successfully loaded.
[I 2025-07-20 12:15:58.867 LabApp] JupyterLab extension loaded from /usr/lib/python3.13/site-packages/jupyterlab
[I 2025-07-20 12:15:58.867 LabApp] JupyterLab application directory is /usr/share/jupyter/lab
[I 2025-07-20 12:15:58.868 LabApp] Extension Manager is 'pypi'.
[I 2025-07-20 12:15:58.876 ServerApp] jupyterlab | extension was successfully loaded.
[I 2025-07-20 12:15:58.878 ServerApp] notebook | extension was successfully loaded.
[I 2025-07-20 12:15:58.878 ServerApp] Serving notebooks from local directory: /home/tux
[I 2025-07-20 12:15:58.878 ServerApp] Jupyter Server 2.15.0 is running at:
[I 2025-07-20 12:15:58.878 ServerApp] http://camelot:8888/?token=6731e677bd79a997c5fac158161c967049cf88704a569794
[I 2025-07-20 12:15:58.878 ServerApp]     http://127.0.0.1:8888/?token=6731e677bd79a997c5fac158161c967049cf88704a569794
[I 2025-07-20 12:15:58.878 ServerApp] Use Control-C to stop this server and shut down all kernels (twice to skip confirmation).
[C 2025-07-20 12:15:58.880 ServerApp] 
    
    To access the server, open this file in a browser:
        file:///home/tux/.local/share/jupyter/runtime/jpserver-45505-open.html
    Or copy and paste one of these URLs:
        http://camelot:8888/?token=6731e677bd79a997c5fac158161c967049cf88704a569794
        http://127.0.0.1:8888/?token=6731e677bd79a997c5fac158161c967049cf88704a569794
[I 2025-07-20 12:15:58.892 ServerApp] Skipped non-installed server(s): bash-language-server, dockerfile-language-server-nodejs, javascript-typescript-langserver, jedi-language-server, julia-language-server, pyright, python-language-server, python-lsp-server, r-languageserver, sql-language-server, texlab, typescript-language-server, unified-language-server, vscode-css-languageserver-bin, vscode-html-languageserver-bin, vscode-json-languageserver-bin, yaml-language-server
[W 2025-07-20 12:55:48.138 ServerApp] Clearing invalid/expired login cookie username-camelot-8888

 

🧭 Orientation: What We See from Camelot

Jupyter Server is Up and Running

  • Version: Jupyter Server 2.15.0
  • IP Binding: --ip=0.0.0.0 means it’s listening on all interfaces
  • Port: 8888
  • Auth: Using token-based access (?token=...)
  • Serving From: /home/tux/ — this is the root for all notebooks
  • Control Shortcut: Press Ctrl+C twice to cleanly shut it down.

🌐 Where to Access It From

If you're on the same network:

http://camelot:8888/?token=6731e677bd79a997c5fac158161c967049cf88704a569794

If you're Frodo from the Sh1re, you can tunnel in:

ssh -L 8888:localhost:8888 tux@camelot

Then on Frodo:

http://localhost:8888/?token=...

🧙‍♂️ Installed Extensions (Jupyter Powers)

These were successfully linked and loaded:

  • jupyterlab — modern UI (try /lab after the port)
  • notebook — the classic UI
  • jupyter_lsp — Language Server Protocol support
  • jupyter_server_terminals — access to a terminal inside the browser

⚠️ Warnings and Skipped Services

[W] Clearing invalid/expired login cookie username-camelot-8888
Not a problem. Just expired session data — common when switching tokens or restarting.

[I] Skipped non-installed server(s): ...
Also fine. Jupyter is just listing LSPs (language plugins) that aren't installed. You can install them later if you want advanced code intelligence, but this does not affect core functionality.

🧪 Sunday Tour Guide

Here’s a suggested roadmap for today:

🟢 1. Create a Test Notebook

In /home/tux, click New → Python 3 and create:

print("Frodo lives, and Camelot listens.")

Add a markdown cell:

# Orientation Day at Camelot

This is a test of the Jupyter Notebook service hosted at Camelot.

🟢 2. Export It

Once saved, from Jupyter UI:

  • File → Download as → HTML or Markdown

Or from terminal:

jupyter nbconvert notebook.ipynb --to html

🟢 3. Test Integration with Flask (optional)

If you have Camelot’s TransferDepot Flask API running locally:

import requests

files = {'file': open('notebook.html', 'rb')}
response = requests.post('http://localhost:5000/upload', files=files)
print(response.status_code, response.text)

Or reverse — GET a file and show inside Jupyter.

🟢 4. Confirm What Works

Use the cousin inside Camelot to:

  • Open a browser and verify http://camelot:8888/ works
  • Copy/paste a notebook into the transfer depot
  • Confirm that file upload, download, and directory listing all work

When Frodo returns to the Sh1re tomorrow, he shall bring:

  • Exported notebook as proof
  • API examples from Camelot
  • Confidence that Jupyter + Flask can co-exist and collaborate
  • And perhaps… a sticky note that says: "Containers next week?"

Let me know when you're ready for the Return of the Kernel notebook template, or if you'd like a Flask skeleton app to sketch the TransferDepot out.

A noble decision, Frodo! A small workspace called sh1re will bring structure to this otherwise scroll-littered desktop. And yes — the “Lab” tab can be overwhelming and strange when no familiar landmarks are set.

Let us fix that now.

 

The Key to Camelot fails to open the Gateway

allison@frodo:~$ ssh -L 8888:localhost:8888 tux@10.20.30.1
tux@10.20.30.1's password: 
Activate the web console with: systemctl enable --now cockpit.socket

Last login: Sun Jul 20 13:27:11 2025 from 10.20.30.1

 

Replace the key

tux@camelot:~/sh1re$ jupyter notebook --NotebookApp.allow_origin='*' --ip=0.0.0.0 --no-browser
[I 2025-07-20 14:12:20.452 ServerApp] jupyter_lsp | extension was successfully linked.
[I 2025-07-20 14:12:20.454 ServerApp] jupyter_server_terminals | extension was successfully linked.
[I 2025-07-20 14:12:20.615 LabApp] Extension Manager is 'pypi'.
[I 2025-07-20 14:12:20.624 ServerApp] jupyterlab | extension was successfully loaded.
[I 2025-07-20 14:12:20.626 ServerApp] notebook | extension was successfully loaded.
[I 2025-07-20 14:12:20.626 ServerApp] Serving notebooks from local directory: /home/tux/sh1re
[I 2025-07-20 14:12:20.626 ServerApp] Jupyter Server 2.15.0 is running at:
[I 2025-07-20 14:12:20.626 ServerApp] http://camelot:8888/tree?token=2eef7915de4f8d75bd36428a5662316839ea37e680d3969c
[I 2025-07-20 14:12:20.626 ServerApp]     http://127.0.0.1:8888/tree?token=2eef7915de4f8d75bd36428a5662316839ea37e680d3969c
[I 2025-07-20 14:12:20.626 ServerApp] Use Control-C to stop this server and shut down all kernels (twice to skip confirmation).
[C 2025-07-20 14:12:20.628 ServerApp] 


Find the key:
tux@camelot:~/sh1re$ jupyter server list

http://localhost:8888/tree

😄 A hush falls over the Sh1re as the fire crackles... and someone—maybe Sam—leans in:

“Did I ever tell you about the time...
Things We Never Speak Of Again: The Day We SSH’d Into Ourselves?”

The table bursts into laughter.
Tux spills his ale.
Even Gandalf chuckles without saying a word.

Did you get all that? 

Nothing listening?

On Camelot:

  • Nothing is listening on port 8888, confirmed by:

sudo lsof -i :8888
sudo netstat -tulnp | grep 8888

So the tunnel opens, but when you try to use it, it tries to connect to localhost:8888 on Camelot, fails, and floods you with:

channel 3: open failed: connect failed: Connection refused

ssh back in & restart:

ssh -L 8888:localhost:8888 tux@10.20.30.1

jupyter server list

tux@camelot:~$ jupyter server list
Currently running servers:

Restart Notebook server

jupyter notebook --NotebookApp.allow_origin='*' --ip=0.0.0.0 --no-browser

Recheck server list

jupyter server list

tux@camelot:~$ jupyter server list
Currently running servers:
http://camelot:8888/?token=310d92483c9e435e737009b23f6a52c419e7efc153f34d16 :: /home/tux

Re-tunnel from Frodo:

ssh -L 8888:localhost:8888 tux@10.20.30.1

Open in Browser:

 http://localhost:8888/?token=...
allison@frodo:~/dev/TransferPoint$ ssh -L 8888:localhost:8888 tux@10.20.30.1
tux@10.20.30.1's password:
Activate the web console with: systemctl enable --now cockpit.socket
Last login: Sun Jul 20 15:52:42 2025 from ::ffff:192.168.11.185
tux@camelot:~$ jupyter server list
Currently running servers:
tux@camelot:~$ jupyter notebook --NotebookApp.allow_origin='*' --ip=0.0.0.0 --no-browser
[I 2025-07-20 19:51:48.977 ServerApp] jupyter_lsp | extension was successfully linked.
[I 2025-07-20 19:51:48.979 ServerApp] jupyter_server_terminals | extension was successfully linked.
[W 2025-07-20 19:51:48.980 LabApp] 'allow_origin' has moved from NotebookApp to ServerApp. This config will be passed to ServerApp. Be sure to update your config before our next release.
[I 2025-07-20 19:51:48.982 ServerApp] jupyterlab | extension was successfully linked.
[I 2025-07-20 19:51:48.984 ServerApp] notebook | extension was successfully linked.

 

💬 Bonus: Reduce the Noise

If this keeps happening, you can add -v or -vvv to SSH for verbose logs, or redirect stderr to a log file so it doesn’t flood your terminal:

ssh -L 8888:localhost:8888 tux@10.20.30.1 2> ssh_tunnel.log

 

🏗️ Create or navigate to the Sh1re Workspace

📁 1. Create the Folder

From your shell:

mkdir -p /home/tux/sh1re

Now you have a clean little corner of Camelot where all .ipynb, .html, .md, and Flask scrolls can live together.

💻 2. Place the Notebook There

Let’s drop the notebook directly into this new realm:

Option A: Use CLI to write it from Frodo

If you copied the return_of_the_kernel.ipynb earlier:

scp return_of_the_kernel.ipynb tux@camelot:/home/tux/sh1re/

Option B: Create a blank file and paste in contents

nano /home/tux/sh1re/return_of_the_kernel.ipynb

Then paste the JSON I gave earlier. Save with Ctrl+O, exit with Ctrl+X.

 

{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# The Return of the Kernel\n",
    "\n",
    "*A notebook forged in Camelot by Frodo, emissary of the Sh1re.*"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "print(\"Camelot lives, and Frodo rides once more!\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## The Wisdom of Visualization\n",
    "\n",
    "Here lies a chart, rendered to show the passage of time and wisdom gained."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import matplotlib.pyplot as plt\n",
    "\n",
    "x = [1, 2, 3, 4]\n",
    "y = [1, 4, 2, 3]\n",
    "\n",
    "plt.plot(x, y, marker='o')\n",
    "plt.title(\"A Chart Worthy of the Realm\")\n",
    "plt.xlabel(\"Scroll Pages\")\n",
    "plt.ylabel(\"Wisdom Gained\")\n",
    "plt.grid(True)\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Final Notes\n",
    "\n",
    "- ✅ Jupyter runs in Camelot\n",
    "- ✅ Plots render\n",
    "- ✅ Markdown flows like elvish poetry\n",
    "- ✅ The Sh1re shall receive this tale\n",
    "\n",
    "**Farewell for now, until the next test of the Flasken Scrolls.**"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "name": "python",
   "version": "3.13"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}

 

🧠 3. Access It in Jupyter UI

Now when you open:

http://camelot:8888/tree/sh1re/

You’ll see:

return_of_the_kernel.ipynb

Open it, run the cells, and export when ready.

🧭 A Quick Word on “Launcher” and Tabs

  • Launcher: That’s the Lab UI’s quickstart screen — like a dashboard. You’ll find New Notebook, New Console, Terminal, etc.
  • Tree View (Classic): What you're looking for now — a simple file browser. Stick to http://camelot:8888/tree/ for clarity.
  • Tabs: If you see nothing at first, click the “folder” icon (top left) to browse the file tree. Or open the direct folder above.

🛡️ Summary Boost

mkdir -p ~/sh1re
nano ~/sh1re/return_of_the_kernel.ipynb   # (paste in content or use scp)

Then visit:
http://camelot:8888/tree/sh1re/

Open the notebook, and run:

print("Camelot lives, and Frodo rides once more!")

Let me know if you’d like a Flask scroll to join the sh1re folder next. The quest continues.

 

🔧 Prepare the Flask

  • A TransferDepot ready for distant lands

  • Routes for:

    • POST /upload

    • GET /files/<filename>

    • GET /list or /index

🔐 Add Protection

  • Path restrictions?

  • Token header?

  • Maybe even a tiny logbook (upload.log)?

📦 Integration with:

  • Notebook exports from Jupyter

  • Downloads to Fred

  • Possibly... redirection to /shire/success.html

tux@camelot:~/sh1re$ flask routes
Endpoint     Methods  Rule                   
-----------  -------  -----------------------
get_file     GET      /files/<filename>      
list_files   GET      /list                  
static       GET      /static/<path:filename>
upload_file  POST     /upload                
welcome      GET      /      

 

🗺️ The RESTful Map of TransferPoint

| 🌐 **URL Path**     | 🧙‍♂️ **Method** | ⚙️ **Handler Function** |
| ------------------- | ---------------- | ----------------------- |
| `/`                 | `GET`            | `welcome`               |
| `/upload`           | `POST`           | `upload_file`           |
| `/list`             | `GET`            | `list_files`            |
| `/files/<filename>` | `GET`            | `get_file`              |
| `/static/<path>`    | `GET`            | Flask static route      |

 

✅ What This Means

You have a classic file exchange interface:

  • GET / → Welcome page (perhaps a UI? or JSON message?)

  • POST /upload → Upload files

  • GET /list → Show all available files

  • GET /files/<filename> → Retrieve a specific file

  • GET /static/... → Serve static assets (if applicable)

For test or DEMO

curl http://localhost:5000/
curl http://localhost:5000/list
curl -F 'file=@test.txt' http://localhost:5000/upload