diff --git a/README.md b/README.md
index 72b6c49..7849613 100644
--- a/README.md
+++ b/README.md
@@ -1,2 +1,32 @@
-# ras-pi
-A comprehensive, end-to-end guide to the fundamentals of coding, network protocols, Linux, and the Raspberry Pi.
+
ras-pi
+A comprehensive, end-to-end guide to the fundamentals of coding, network
+protocols, Linux, and the Raspberry Pi.
+
+Getting Started
+Run the following commands on a fresh installation on a Raspberry Pi:
+```
+sudo apt install git;
+git clone https://github.com/SLCPL-CreativeLab/ras-pi;
+cd ras-pi/scripts;
+sudo chmod a+x install.sh;
+sudo ./install.sh;
+
+# If you want to expose services to the internet, run this command as well.
+sudo ./cloudflared.sh;
+```
+
+Expose Services to the Internet
+To enable cloudflared to expose services to the internet, you must
+ - Make a Cloudflare account & purchase a domain;
+ - Run the command `cloudflared tunnel login`;
+ - Run the command ./cloudflared.sh in ~/ras-pi/scripts;
+
+To temporarily expose a single service to the internet, use this
+command: `cloudflared tunnel --url=http://localhost:PORT`, where
+PORT is the service you'd like to expose. The ports used with the
+standard services are:
+ - 5090 (the manual mirror of raspi.vintagecoding.net)
+ - 5091 (the AI web application)
+ - 5092 (the personal Netflix replacement)
+
+See `cloudflared.md` for more information.
diff --git a/scripts/cloudflared.sh b/scripts/cloudflared.sh
new file mode 100755
index 0000000..3d76fc9
--- /dev/null
+++ b/scripts/cloudflared.sh
@@ -0,0 +1,84 @@
+#!/bin/bash
+
+DOMAIN=""
+MANUAL_PORT=5090
+JELLYFIN_PORT=5091
+OLLAMA_PORT=5092
+
+# This function initializes cloudflared.
+# TODO: This needs to dynamically insert based upon what the user has entered.
+init_cloudflared() {
+ read -p "What is your domain name? e.g., vintagecoding.net: " DOMAIN;
+
+ echo "export TUNNEL_ORIGIN_CERT=$HOME/.cloudflared/cert.pem" >> $HOME/.bashrc;
+ source $HOME/.bashrc;
+
+ cloudflared tunnel create raspi;
+ TUNNEL_ID=$(cloudflared tunnel list | awk '/raspi/ {print $1}');
+
+ cd;
+ echo "tunnel: $TUNNEL_ID
+credentials-file: $(pwd)/.cloudflared/$TUNNEL_ID.json
+ingress:
+ - hostname: raspi.$DOMAIN
+ service: http://localhost:$MANUAL_PORT
+ - hostname: media.$DOMAIN
+ service: http://localhost:$JELLYFIN_PORT
+ - hostname: ai.$DOMAIN
+ service: http://localhost:$OLLAMA_PORT
+ - service: http_status:404" > $(pwd)/.cloudflared/config.yaml;
+
+ cloudflared tunnel route dns $TUNNEL_ID raspi.$DOMAIN;
+ cloudflared tunnel route dns $TUNNEL_ID media.$DOMAIN;
+ cloudflared tunnel route dns $TUNNEL_ID ai.$DOMAIN;
+
+ ACTUAL_USER=$(whoami)
+
+ echo "[Unit]
+Description=Cloudflare Tunnel Daemon
+After=network.target
+
+[Service]
+Type=simple
+User=$ACTUAL_USER
+ExecStart=/usr/bin/cloudflared tunnel run raspi
+Restart=always
+
+[Install]
+WantedBy=multi-user.target" | sudo tee /etc/systemd/system/cloudflared.service;
+
+ sudo systemctl enable cloudflared.service;
+ sudo systemctl start cloudflared.service;
+
+ source ~/.bashrc;
+
+ sudo sed -i -e 's/server_name localhost/servername ai.$DOMAIN/' /etc/nginx/sites-available/open-webui;
+
+ kill -9 $(pgrep open-webui);
+ cd;
+ source open-webui-env/bin/activate;
+
+ read -p "Do you want to require login to your AI? (n/Y)" REQUIRE_LOGIN
+ REQUIRE_LOGIN=$(echo "$REQUIRE_LOGIN" | tr '[:upper:]' '[:lower:]')
+ if [[ -z "$REQUIRE_LOGIN" || "$REQUIRE_LOGIN" == "n" ]]; then
+ export WEBUI_AUTH=False;
+ fi
+
+ export OLLAMA_BASE_URL=http://localhost:11434;
+ export WEBUI_BASE_URL=ai.$DOMAIN;
+ open-webui serve --port $OLLAMA_PORT &
+}
+
+read -p "Has the command 'cloudflared tunnel login' been executed? (y/N): " LOGGED_IN
+LOGGED_IN=$(echo "$LOGGED_IN" | tr '[:upper:]' '[:lower:]')
+if [[ -z "$LOGGED_IN" || "$LOGGED_IN" == "y" ]]; then
+ init_cloudflared;
+else
+ echo "You can still use Cloudflare for free, by generating random URLs."
+ echo "Enter the following into a terminal:";
+ echo " cloudflared tunnel --url=http://localhost:PORT";
+ echo "to get a URL a process, for example. Replace PORT with one of the following:";
+ echo " $MANUAL_PORT (The manual mirror's port.)";
+ echo " $JELLYFIN_PORT (The Jellyfin port.)";
+ echo " $OLLAMA_PORT (The Ollama & Open Web-UI port.)";
+fi
diff --git a/scripts/install.sh b/scripts/install.sh
old mode 100644
new mode 100755
index 4a75405..5044d01
--- a/scripts/install.sh
+++ b/scripts/install.sh
@@ -1,3 +1,5 @@
+#!/bin/bash
+
# This script gets a Raspberry Pi setup with essential applications.
#
# For explanations of commands, visit raspi.vintagecoding.net or use Google.
@@ -9,47 +11,6 @@ MANUAL_PORT=5090
JELLYFIN_PORT=5091
OLLAMA_PORT=5092
-help() {
- echo "This script gets a Raspberry Pi setup with essential applications.";
- echo "By default, everything will be installed. But, there are some flags";
- echo "available for the end user. Multiple flags can be used together.";
- echo "";
- echo "";
- echo "";
- echo "If you're new to the command line, the structure of these help";
- echo "pages is often like this:";
- echo " command { --full-name-of-flag | -f }";
- echo "Where, the curly braces indicates a grouping of options, typically";
- echo "the full name of a flag, | (or) the short flag.";
- echo "Therefore, either of the following commands are valid:";
- echo " command --full-name-of-flag";
- echo "or";
- echo " command -f";
- echo "Furthermore, different flags can be chained together. e.g.,";
- echo " command --flag-1 --flag-2";
- echo "";
- echo "";
- echo "";
- echo "If you're new, checkout the Raspberry Pi manual available at";
- echo "raspi.vintagecoding.net.";
- echo "";
- echo "";
- echo "";
- echo "NOTE: This script CANNOT be copied to /usr/local/bin, or anywhere on";
- echo "the PATH environment variable. That interferes with the system-level";
- echo "install command.";
- echo "";
- echo "";
- echo "";
- echo "Usage:";
- echo " ./install.sh { --help | -h }";
- echo "";
- echo "";
- echo "";
- echo "The user will be prompted for each feature beyond the the barebones";
- echo "system utilities installation.";
-}
-
# This function initializes core services and packages for getting started.
init() {
# Update repositories and upgrade installed packages.
@@ -58,44 +19,69 @@ init() {
# Install requisite packages for cloudflared.
sudo apt install curl lsb-release;
- # Downloads the GPG key (a package integrity technology).
- curl -L https://pkg.cloudflare.com/cloudflare-main.gpg | sudo tee \
- /usr/share/keyrings/cloudflare-archive-keyring.gpg > /dev/null;
+ # Add cloudflare gpg key
+ sudo mkdir -p --mode=0755 /usr/share/keyrings
+ curl -fsSL https://pkg.cloudflare.com/cloudflare-main.gpg | sudo tee /usr/share/keyrings/cloudflare-main.gpg >/dev/null
- # Add the GPG key to the allowed repositories to download packages from.
- echo "deb [signed-by=/usr/share/keyrings/cloudflare-archive.keyring.gpg] \
- https://pkg.cloudflare.com/cloudflared $(lsb_release -cs) main" \
- | sudo tee /etc/apt/sources.list.d/cloudflared.list;
+ # Add this repo to your apt repositories
+ echo 'deb [signed-by=/usr/share/keyrings/cloudflare-main.gpg] https://pkg.cloudflare.com/cloudflared any main' | sudo tee /etc/apt/sources.list.d/cloudflared.list
+
+ # install cloudflared
+ sudo apt-get update && sudo apt-get install cloudflared
# Install cloudflared.
# Install podman, a container technology for easily deploying projects.
# Install golang, a server-side programming language.
# Install tools for the user
- sudo apt update && sudo apt install nginx cloudflared podman golang tldr neovim;
+ sudo apt update;
+ sudo apt install cloudflared podman golang tldr neovim;
+
+ # Get user input for some default applications to get started.
+ read -p "Do you want a mirror of the manual from raspi.vintagecoding.net on this device? (y/N): " MANUAL;
+ MANUAL=$(echo "$MANUAL" | tr '[:upper:]' '[:lower:]')
+ if [[ -z "$MANUAL" || "$MANUAL" == "n" ]]; then
+ MANUAL="n"
+ else
+ init_manual;
+ fi
+
+ read -p "Do you want to setup Jellyfin, a personal Netflix alternative? (y/N): " JELLYFIN;
+ JELLYFIN=$(echo "$JELLYFIN" | tr '[:upper:]' '[:lower:]')
+ if [[ -z "$JELLYFIN" || "$JELLYFIN" == "n" ]]; then
+ JELLYFIN="n"
+ else
+ init_jellyfin;
+ fi
+
+ read -p "Do you want to setup Ollama, a personal ChatGPT alternative? (y/N): " OLLAMA;
+ OLLAMA=$(echo "$OLLAMA" | tr '[:upper:]' '[:lower:]')
+ if [[ -z "$OLLAMA" || "$OLLAMA" == "n" ]]; then
+ OLLAMA="n"
+ else
+ init_ollama;
+ fi
}
# This function initializes the manual mirror of raspi.vintagecoding.net
init_manual() {
cd ~/ras-pi/man/pages;
- sudo echo "
- [Unit]
- Description=Raspberry Pi Manual Mirror
- After=network.target
- StartLimitIntervalSec=0
+ echo "[Unit]
+Description=Raspberry Pi Manual Mirror
+After=network.target
+StartLimitIntervalSec=0
- [Service]
- Type=simple
- Restart=always
- RestartSec=1
- User=$(whoami)
- WorkingDirectory=$(pwd)
- ExecStartPre=/usr/bin/git pull
- ExecStart=/usr/bin/python3 -m http.server $MANUAL_PORT
+[Service]
+Type=simple
+Restart=always
+RestartSec=1
+User=$(whoami)
+WorkingDirectory=$(pwd)
+ExecStartPre=/usr/bin/git pull
+ExecStart=/usr/bin/python3 -m http.server $MANUAL_PORT
- [Install]
- WantedBy=multi-user.target
- " > /etc/systemd/system/manual.service;
+[Install]
+WantedBy=multi-user.target" | sudo tee /etc/systemd/system/manual.service;
sudo systemctl enable manual.service;
sudo systemctl start manual.service;
@@ -105,7 +91,7 @@ init_manual() {
# This function initializes Jellyfin.
init_jellyfin() {
# Get the official image of Jellyfin software
- podman pull jellyfin/jellyfin;
+ podman pull ghcr.io/jellyfin/jellyfin;
echo "Making media directories where Jellyfin will retrieve content.";
echo "It is up to you to provide supported files and build a library.";
@@ -119,12 +105,11 @@ init_jellyfin() {
--name myjellyfin \
--publish $JELLYFIN_PORT:8096/tcp \
--user $(id -u):$(id -g) \
- --userns keep-id \
--volume jellyfin-cache:/cache:Z \
--volume jellyfin-config:/config:Z \
--mount type=bind,source=/$(pwd)/media,destination=/media,ro=true,relabel=private \
--restart always \
- jellyfin
+ ghcr.io/jellyfin/jellyfin;
echo "Finished creating the Jellyfin container! It is now live on";
echo "http://localhost:$JELLYFIN_PORT. If you enabled it, it'll also be";
@@ -134,130 +119,44 @@ init_jellyfin() {
# This function initializes Ollama.
init_ollama() {
echo "This will take a while...";
-
cd;
+ curl -fsSL https://ollama.com/install.sh | sh;
+ echo "export OLLAMA_BASE_URL=http://localhost:11434;
+export WEBUI_AUTH=False;" >> $HOME/.bashrc;
+ source $HOME/.bashrc
+
+ # TODO: Write a script so this can be daemonized.
python -m venv open-webui-env;
source open-webui-env/bin/activate
pip install open-webui;
- echo "
- export OLLAMA_BASE_URL=http://localhost:11434;
- export WEBUI_BASE_URL=ai.$DOMAIN;
- export WEBUI_AUTH=False;
- " >> $(pwd)/.bashrc;
- open-webui serve --port $OLLAMA_PORT &;
- curl -fsSL https://ollama.com/install.sh | sh;
-}
+ echo "server {
+ listen 80; #or whatever port your open-webui backend is running on.
+ server_name localhost;
-# This function initializes cloudflared.
-# TODO: This needs to dynamically insert based upon what the user has entered.
-init_cloudflared() {
- cloudflared tunnel login;
- cloudflared tunnel create raspi;
- TUNNEL_ID=$(cloudflared tunnel list | awk '/raspi/ {print $1}');
- read "?What is your domain name? e.g., vintagecoding.net" $DOMAIN;
+ location / {
+ proxy_pass http://localhost:$OLLAMA_PORT/;
+ proxy_http_version 1.1;
+ proxy_set_header Upgrade $http_upgrade;
+ proxy_set_header Connection 'upgrade';
+ proxy_set_header Host $host;
+ proxy_cache_bypass $http_upgrade;
+ }
- cd;
- echo "
- tunnel: $TUNNEL_ID
- credentials-file: $(pwd)/.cloudflared/$TUNNEL_ID.json
- ingress:
- - hostname: raspi.$DOMAIN
- service: http://localhost:$MANUAL_PORT
- - hostname: media.$DOMAIN
- service: http://localhost:$JELLYFIN_PORT
- - hostname: ai.$DOMAIN
- service: http://localhost:$OLLAMA_PORT
- - service: http_status:404
-
- " > $(pwd)/.cloudflared/config.yaml;
-
- cloudflared tunnel route dns $TUNNEL_ID raspi.$DOMAIN;
- cloudflared tunnel route dns $TUNNEL_ID media.$DOMAIN;
- cloudflared tunnel route dns $TUNNEL_ID ai.$DOMAIN;
-
- echo "
- [Unit]
- Description=Cloudflare Tunnel Daemon
- After=network.target
-
- [Service]
- Type=simple
- User=$(whoami)
- ExecStart=/usr/bin/cloudflared tunnel run raspi
- Restart=always
-
- [Install]
- WantedBy=multi-user.target
- " > /etc/systemd/system/cloudflared.service;
-
- sudo systemctl enable cloudflared.service;
- sudo systemctl start cloudflared.service;
-
- sudo echo "
- server {
- listen 80; #or whatever port your open-webui backend is running on.
- server_name ai.$DOMAIN;
-
- location /api/ {
- proxy_pass http://localhost:$OLLAMA_PORT/api/; # Ensure the trailing slash is present
- proxy_http_version 1.1;
- proxy_set_header Upgrade $http_upgrade;
- proxy_set_header Connection 'upgrade';
- proxy_set_header Host $host;
- proxy_cache_bypass $http_upgrade;
- }
- location / {
- proxy_pass http://localhost:$OLLAMA_PORT/;
- proxy_http_version 1.1;
- proxy_set_header Upgrade $http_upgrade;
- proxy_set_header Connection 'upgrade';
- proxy_set_header Host $host;
- proxy_cache_bypass $http_upgrade;
- }
-
-}
- " > /etc/nginx/sites-available/open-webui;
+ location /api/ {
+ proxy_pass http://localhost:$OLLAMA_PORT/api/; # Ensure the trailing slash is present
+ proxy_http_version 1.1;
+ proxy_set_header Upgrade $http_upgrade;
+ proxy_set_header Connection 'upgrade';
+ proxy_set_header Host $host;
+ proxy_cache_bypass $http_upgrade;
+ }
+}" | sudo tee/etc/nginx/sites-available/open-webui;
sudo ln -s /etc/nginx/sites-available/open-webui /etc/nginx/sites-enabled
sudo systemctl enable nginx;
sudo systemctl start nginx;
+
+ open-webui serve --port $OLLAMA_PORT &
}
-# Display help if the user requests it.
-if [[ $# == 1 && ($1 == "--help" || $1 == "-h") ]]; then
- help;
- exit;
-fi
-
-# Get user input for some default applications to get started.
-read "?Do you have a Cloudflare account and own a domain? (y/N)" CLOUDFLARE;
-read "?Do you want a mirror of the manual from raspi.vintagecoding.net\
- on this device? (y/N)" MANUAL;
-read "?Do you want to setup Jellyfin, a personal Netflix alternative? (y/N)" JELLYFIN;
-read "?Do you want to setup Ollama, a personal ChatGPT alternative? (y/N)" OLLAMA;
-
init;
-
-if [[ $MANUAL == "y" ]]; then
- init_manual;
-fi
-
-if [[ $JELLYFIN == "y" ]]; then
- init_jellyfin;
-fi
-
-if [[ $CLOUDFLARE == "y" ]]; then
- init_cloudflare;
-else
- echo "You can still use Cloudflare for free, by generating random URLs."
- echo "Enter the following into a terminal:";
- echo " cloudflared tunnel --url=http://localhost:PORT";
- echo "to get a URL a process, for example. Replace PORT with one of the following:";
- echo " $MANUAL_PORT (The manual mirror's port.)";
- echo " $JELLYFIN_PORT (The Jellyfin port.)";
- echo " $OLLAMA_PORT (The Ollama & Open Web-UI port.)";
-fi
-
-if [[ $OLLAMA == "y" ]]; then
- init_ollama;
-fi