Files
ras-pi/scripts/install.sh
T
2025-03-12 14:31:37 -06:00

257 lines
7.5 KiB
Bash

# This script gets a Raspberry Pi setup with essential applications.
#
# For explanations of commands, visit raspi.vintagecoding.net or use Google.
# GLOBAL VARIABLES
DOMAIN=""
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.
sudo apt update && sudo apt upgrade;
# 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 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;
# 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;
}
# 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
[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;
sudo systemctl enable manual.service;
sudo systemctl start manual.service;
sudo systemctl daemon-reload;
}
# This function initializes Jellyfin.
init_jellyfin() {
# Get the official image of Jellyfin software
podman pull 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.";
cd;
mkdir media;
podman run \
--detach \
--label "io.containers.autoupdate=registry" \
--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
echo "Finished creating the Jellyfin container! It is now live on";
echo "http://localhost:$JELLYFIN_PORT. If you enabled it, it'll also be";
echo "available at media.yourdomain.com.";
}
# This function initializes Ollama.
init_ollama() {
echo "This will take a while...";
cd;
python -m venv open-webui-env;
source open-webui-env/bin/activate
pip install open-webui;
open-webui serve --port $OLLAMA_PORT;
}
# 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;
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;
sudo ln -s /etc/nginx/sites-available/open-webui /etc/nginx/sites-enabled
sudo systemctl enable nginx;
sudo systemctl start nginx;
}
# 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