jupiter / start.sh
arfandi7322's picture
Update start.sh
74ba644 verified
Raw
History Blame Contribute Delete
3.71 kB
#!/bin/bash
# JupyterLab entrypoint.
# Runs WITHOUT a token/password β€” the aiohttp proxy in front of it handles
# the password gate. Listens only on localhost:8888 so it is not directly
# reachable. HF exposes the container (via the proxy) on port 7860.
# ── Persistent-storage bootstrap ─────────────────────────────────────
# On HF Spaces, /data is the ONLY directory guaranteed to survive a
# sleep/restart/rebuild β€” and only if "Persistent Storage" is actually
# enabled in Settings β†’ Persistent storage. Everything else under / is
# rebuilt fresh from the image every time the container starts.
#
# To make sure real work survives, we redirect the ephemeral spots that
# matter β€” pip's cache + `pip install --user`, npm/bun's cache, Hugging
# Face's model/dataset cache, and JupyterLab's own settings/workspaces β€”
# onto /data. This runs on every boot; it's a no-op once already wired,
# and intentionally non-fatal (no `set -e`) so a hiccup here never
# prevents JupyterLab from starting.
mkdir -p /data/notebooks /data/projects \
/data/.npm-global /data/node_modules \
/data/.cache /data/.local /data/.npm-cache /data/.bun-cache \
/data/.huggingface \
/data/.jupyter-data/user-settings /data/.jupyter-data/workspaces \
2>/dev/null
link_to_data() {
# $1 = ephemeral path (e.g. /root/.cache), $2 = persistent path under /data
local target="$1" persist="$2"
if [ -L "$target" ]; then
return 0 # already wired up from a previous boot of this container
fi
if [ -e "$target" ]; then
# First boot only: keep whatever the image shipped with, then swap
# in the symlink so all future writes land on /data.
cp -an "$target"/. "$persist"/ 2>/dev/null
rm -rf "$target" 2>/dev/null
fi
ln -s "$persist" "$target" 2>/dev/null
}
link_to_data /root/.cache "/data/.cache" # pip download/build cache, etc.
link_to_data /root/.local "/data/.local" # `pip install --user` packages
link_to_data /root/.npm "/data/.npm-cache"
link_to_data /root/.bun "/data/.bun-cache"
# Set env vars here instead of supervisord environment= directive.
# supervisord's environment= REPLACES the entire env (dropping HF secrets).
export HOME="/root"
export JUPYTER_CONFIG_DIR="/home/user/.jupyter"
export SHELL="/bin/bash"
# Plain `pip install <pkg>` (no --user flag needed, even as root) now
# lands under /root/.local, which is symlinked to /data/.local above.
export PIP_USER=1
# transformers / diffusers / datasets / huggingface_hub all cache
# downloaded models here β€” avoids re-downloading after every restart.
export HF_HOME="/data/.huggingface"
# JupyterLab's *data* β€” kernelspecs, settings, saved workspaces, history β€”
# goes to /data so customizations survive. (The static config file used
# below, jupyter_lab_config.py, ships in the image and doesn't need to.)
export JUPYTER_DATA_DIR="/data/.jupyter-data"
export JUPYTERLAB_SETTINGS_DIR="/data/.jupyter-data/user-settings"
export JUPYTERLAB_WORKSPACES_DIR="/data/.jupyter-data/workspaces"
# root_dir is set to "/" in jupyter_lab_config.py so the file browser can
# navigate the whole filesystem. cd to /data so new terminals open in the
# persistent folder by default (avoids the cwd-mismatch confusion, and
# avoids people accidentally saving work somewhere that gets wiped on the
# next restart).
cd /data || exit 1
# Silence the "new version available" popup in JupyterLab
jupyter labextension disable "@jupyterlab/apputils-extension:announcements"
exec jupyter-lab \
--config=/home/user/.jupyter/jupyter_lab_config.py \
--allow-root