diff --git a/CONTRIBUTIONS.md b/CONTRIBUTIONS.md
new file mode 100644
index 0000000..9fbfcc5
--- /dev/null
+++ b/CONTRIBUTIONS.md
@@ -0,0 +1,58 @@
+# Contributing to ras-pi
+
+We welcome contributions to ras-pi! Whether you're fixing a bug, proposing a feature, or improving documentation, your help is appreciated.
+
+## How to Contribute
+
+1. **Fork the repository:** Click the "Fork" button at the top right of the page. This creates a copy of the repository in your GitHub account.
+2. **Clone your fork:** Clone the repository to your local machine using Git:
+
+ ```bash
+ git clone [https://github.com/YOUR_USERNAME/ras-pi
+ ```
+
+3. **Create a branch:** Create a new branch for your changes:
+
+ ```bash
+ git checkout -b feature/your-feature-name
+ ```
+
+ or
+
+ ```bash
+ git checkout -b fix/your-bug-fix
+ ```
+
+4. **Make your changes:** Implement your changes. Please try to follow the project's general vibe with lots of comments and documentation, particularly for new features.
+5. **Commit your changes:** Commit your changes with clear and concise commit messages:
+
+ ```bash
+ git add .
+ git commit -m "Add your feature/fix description"
+ ```
+
+6. **Push your changes:** Push your branch to your forked repository:
+
+ ```bash
+ git push origin feature/your-feature-name
+ ```
+
+7. **Create a pull request:** Go to SLCPL-CreativeLab/ras-pi repository on GitHub and click the "New Pull Request" button. Select your branch and provide a clear description of your changes.
+
+## Guidelines
+
+* **Coding Style:** Please adhere to the project's coding style. If there are no specific guidelines, follow common best practices.
+* **Commit Messages:** Use clear and descriptive commit messages.
+* **Documentation:** Update the documentation as needed to reflect your changes.
+* **Issue Tracking:** If you're addressing an existing issue, please reference it in your pull request.
+* **Respectful Communication:** Please be respectful and considerate of other contributors.
+
+## Reporting Issues
+
+If you find a bug or have a feature request, please open an issue on GitHub. Provide as much detail as possible, including steps to reproduce the issue.
+
+## Getting Help
+
+If you have any questions or need help, please open an issue or reach out to us through [email](mailto:jashton@slcpl.org).
+
+Thank you for contributing to SLCPL-CreativeLab/ras-pi!
diff --git a/README.md b/README.md
index 4be8121..7557b74 100644
--- a/README.md
+++ b/README.md
@@ -1,37 +1,53 @@
-
ras-pi
-A comprehensive, end-to-end guide to the fundamentals of coding, network
-protocols, Linux, and the Raspberry Pi.
+# Raspberry Pi, Linux, and Coding Introduction
+A guide to the fundamentals of the Raspberry Pi through the exploration of coding, networking, and Linux. See the full guide at [vintagecoding.net](https://raspi.vintagecoding.net), or follow **Getting Started** to host a mirror of the manual directly on your Raspberry Pi.
-Getting Started
-Run the following commands on a fresh installation on a Raspberry Pi:
+The possibilities are endless, and support for more projects is coming soon!
-```
+## Getting Started
+Run the commands below in the terminal application on a fresh installation on a Raspberry Pi. To paste into a terminal, use Control+Shift+v. If you need help with installing the Operating System (OS) on your Pi, please see the [manual](https://raspi.vintagecoding.net#install-os).
+
+```bash
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;
+./setup.sh;
-# If you want to expose services to the internet, run this command as well.
-sudo ./cloudflared.sh;
+# Optionally:
+./setup-ai.sh # Installs Ollama (all supported Pi's) and Open WebUI (only on Pi 5 and higher).
+./setup-manual.sh # Installs the manual.
+./setup-jellyfin.sh # Installs Jellyfin.
```
-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
-
+## Expose Services to the Internet
+To use `cloudflared` to expose services to the internet, you must:
-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)
-
+- Make a Cloudflare account & purchase a domain
+- Run the command `cloudflared tunnel login`
+- Run the command `./setup-cloudflared.sh` in ~/ras-pi/scripts
-See `cloudflared.md` for more information.
+or:
+
+- `cloudflared tunnel --url=http://localhost:PORT`
+
+to alternatively temporarily expose a single service to the internet. PORT is the service you'd like to expose. The ports used with the standard services are below.
+
+| PORT | SERVICE |
+|--------------------|----------------------------------------------|
+| 5090 | Mirror of raspi.vintagecoding.net |
+| 5091 | Jellyfin |
+| 5092 | Open WebUI |
+
+For more information about `cloudflared`, particularly regarding the security of connecting a service to the internet, please read their [docs](https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/).
+
+## Contributions & Support
+Feel free to contribute to the project! Please see **CONTRIBUTIONS.md** to start.
+
+If you need any help with getting started, please email [me](mailto:jashton@slcpl.org).
+
+## Projects/Software Used
+
+- [ollama](https://github.com/ollama/ollama)
+- [open-webui](https://github.com/open-webui/open-webui)
+- [jellyfin](https://github.com/jellyfin/jellyfin)
+- [cloudflared](https://github.com/cloudflare/cloudflared)
+- [podman](https://github.com/containers/podman)
diff --git a/man/Raspberry Pi & Linux Guide.pdf b/man/Raspberry Pi & Linux Guide.pdf
index 283b3f5..4588f85 100644
Binary files a/man/Raspberry Pi & Linux Guide.pdf and b/man/Raspberry Pi & Linux Guide.pdf differ
diff --git a/scripts/cloudflared.sh b/scripts/cloudflared.sh
deleted file mode 100755
index 3d76fc9..0000000
--- a/scripts/cloudflared.sh
+++ /dev/null
@@ -1,84 +0,0 @@
-#!/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
deleted file mode 100755
index 9f3e999..0000000
--- a/scripts/install.sh
+++ /dev/null
@@ -1,162 +0,0 @@
-#!/bin/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
-
-# 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;
-
- # 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 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 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;
- 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" | sudo tee /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 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.";
-
- cd;
- mkdir media;
-
- podman run \
- --detach \
- --label "io.containers.autoupdate=registry" \
- --name myjellyfin \
- --publish $JELLYFIN_PORT:8096/tcp \
- --user $(id -u):$(id -g) \
- --volume jellyfin-cache:/cache:Z \
- --volume jellyfin-config:/config:Z \
- --mount type=bind,source=/$HOME/media,destination=/media,ro=true,relabel=private \
- --restart always \
- 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";
- echo "available at media.yourdomain.com.";
-}
-
-# 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 "server {
- listen 80; #or whatever port your open-webui backend is running on.
- server_name localhost;
-
- 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;
- }
-
- 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 &
-}
-
-init;
diff --git a/scripts/setup-ai.sh b/scripts/setup-ai.sh
new file mode 100755
index 0000000..23e9a6c
--- /dev/null
+++ b/scripts/setup-ai.sh
@@ -0,0 +1,84 @@
+OPEN_WEBUI_PORT=5092
+OLLAMA_PORT=11434
+
+echo "Running `curl -fsSL https://ollama.com/install.sh | sh`";
+echo "This will take about 5-10 minutes...";
+curl -fsSL https://ollama.com/install.sh | sh;
+echo "Ollama has been installed!"
+
+read -p "Are you using a Raspberry Pi 5 or newer? (y/N)" PI_VERSION
+PI_VERSION=$(echo "$PI_VERSION" | tr '[:upper:]' '[:lower:]')
+if [[ -z "$PI_VERSION" || "$PI_VERSION" == "n" ]]; then
+ echo "You can still use AI, but it's only available directly on your Raspberry Pi for now.";
+ echo "For more information, see raspi.vintagecoding.net#ollama";
+ exit;
+fi
+
+echo "Adding environment variables. For more information, visist raspi.vintagecoding.net#env-vars";
+echo "export OLLAMA_BASE_URL=http://localhost:$OLLAMA_PORT;"; >> $HOME/.bashrc;
+
+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 >> $HOME/.bashrc;
+fi
+
+source $HOME/.bashrc
+
+echo "Running `python -m venv open-webui-env`. This creates a Python virtual environment, where";
+echo "we can install applications in an isolated manner from the rest of our Operating System (OS).";
+python -m venv open-webui-env;
+source open-webui-env/bin/activate
+
+echo "Running `pip install open-webui`. This is Python's package manager.";
+pip install open-webui;
+
+echo "Setting up Nginx. For more information, visit raspi.vintagecoding.net#nginx";
+echo "server {
+listen 80;
+server_name localhost;
+
+location / {
+ proxy_pass http://localhost:$OPEN_WEBUI_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;
+}
+
+location /api/ {
+ proxy_pass http://localhost:$OPEN_WEBUI_PORT/api/;
+ 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;
+
+echo "Creating a SystemD service file. These are commands (applications) that you can set to start as soon as you turn on the Pi.";
+echo "This file is located at `/etc/systemd/system/open-webui.service`.";
+echo "For more information, see raspi.vintagecoding.net#systemd";
+
+echo "[Unit]
+Description=Open WebUI
+After=network.target
+StartLimitIntervalSec=0
+
+[Service]
+Type=simple
+Restart=always
+RestartSec=1
+User=$(whoami)
+WorkingDirectory=$HOME
+ExecStartPre=/bin/bash -c "source /home/$(whoami)/open-webui-env/bin/activate"
+ExecStart=/home/$(whoami)/open-webui/open-webui-env/bin/open-webui serve --port $OLLAMA_PORT
+
+[Install]
+WantedBy=multi-user.target" | sudo tee /etc/systemd/system/open-webui.service;
+
+sudo systemctl daemon-reload && sudo systemctl enable open-webui.service;
diff --git a/scripts/setup-cloudflared.sh b/scripts/setup-cloudflared.sh
new file mode 100755
index 0000000..bb0f03f
--- /dev/null
+++ b/scripts/setup-cloudflared.sh
@@ -0,0 +1,69 @@
+#!/bin/bash
+
+DOMAIN=""
+MANUAL_PORT=5090
+JELLYFIN_PORT=5091
+OLLAMA_PORT=5092
+
+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" == "n" ]]; then
+ 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.)";
+ echo "For more information, visit raspi.vintagecoding.net#cloudflared";
+ exit;
+fi
+
+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" | tee $HOME/.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;
+
+source ~/.bashrc;
+
+sudo sed -i -e 's/server_name localhost/servername ai.$DOMAIN/' /etc/nginx/sites-available/open-webui;
+
+export WEBUI_BASE_URL=ai.$DOMAIN >> $HOME/.bashrc;
+sudo systemctl restart open-webui.service;
diff --git a/scripts/setup-jellyfin.sh b/scripts/setup-jellyfin.sh
new file mode 100755
index 0000000..47beb19
--- /dev/null
+++ b/scripts/setup-jellyfin.sh
@@ -0,0 +1,63 @@
+#!/bin/bash
+
+$JELLYFIN_PORT=5091;
+
+# Get the official image of Jellyfin software.
+echo "Running `podman pull ghcr.io/jellyfin/jellyfin`";
+podman pull ghcr.io/jellyfin/jellyfin &;
+echo "`podman` is a container technology that allows for easy distribution of software that is platform-agnostic.";
+echo "Please see raspi.vintagecoding.net#podman for more information.";
+
+echo "Running `cd && mkdir media;`. This is changing the current directory and MaKing a DIRectory called media.";
+echo "This is where your movies and TV shows should go.";
+cd && mkdir media;
+
+echo "Running
+`podman run \
+ --detach \
+ --label "io.containers.autoupdate=registry" \
+ --name myjellyfin \
+ --publish $JELLYFIN_PORT:8096/tcp \
+ --user $(id -u):$(id -g) \
+ --volume jellyfin-cache:/cache:Z \
+ --volume jellyfin-config:/config:Z \
+ --mount type=bind,source=$HOME/media,destination=/media,ro=true,relabel=private \
+ --restart always \
+ghcr.io/jellyfin/jellyfin;`
+
+Please see raspi.vintagecoding.net#podman for more information about this command.";
+
+podman run \
+ --detach \
+ --label "io.containers.autoupdate=registry" \
+ --name myjellyfin \
+ --publish $JELLYFIN_PORT:8096/tcp \
+ --user $(id -u):$(id -g) \
+ --volume jellyfin-cache:/cache:Z \
+ --volume jellyfin-config:/config:Z \
+ --mount type=bind,source=$HOME/media,destination=/media,ro=true,relabel=private \
+ --restart always \
+ghcr.io/jellyfin/jellyfin;
+
+echo "Creating a SystemD service file. These are commands (applications) that you can set to start as soon as you turn on the Pi.";
+echo "This file is located at `/etc/systemd/system/jellyfin.service`.";
+echo "For more information, see raspi.vintagecoding.net#systemd";
+
+echo "[Unit]
+Description=Jellyfin
+After=network.target
+StartLimitIntervalSec=0
+
+[Service]
+Type=simple
+Restart=always
+RestartSec=1
+User=$(whoami)
+ExecStart=/usr/bin/podman start myjellyfin
+
+[Install]
+WantedBy=multi-user.target" | sudo tee /etc/systemd/system/jellyfin.service;
+
+sudo systemctl daemon-reload && sudo systemctl enable jellyfin.service;
+
+echo "For now, please visit jellyfin.org/docs for information about setting up Jellyfin. We'll have a more comprehensive guide soon.";
diff --git a/scripts/setup-manual.sh b/scripts/setup-manual.sh
new file mode 100755
index 0000000..a25b202
--- /dev/null
+++ b/scripts/setup-manual.sh
@@ -0,0 +1,29 @@
+#!/bin/bash
+
+$MANUAL_PORT=5090;
+
+echo "Creating a SystemD service file. These are commands (applications) that you can set to start as soon as you turn on the Pi.";
+echo "This file is located at `/etc/systemd/system/manual.service`.";
+echo "For more information, see raspi.vintagecoding.net#systemd";
+
+echo "[Unit]
+Description=Raspberry Pi Manual Mirror
+After=network.target
+StartLimitIntervalSec=0
+
+[Service]
+Type=simple
+Restart=always
+RestartSec=1
+User=$(whoami)
+WorkingDirectory=$HOME/ras-pi/man/pages
+ExecStartPre=/usr/bin/git pull
+ExecStart=/usr/bin/python3 -m http.server $MANUAL_PORT
+
+[Install]
+WantedBy=multi-user.target" | sudo tee /etc/systemd/system/manual.service;
+
+sudo systemctl daemon-reload && sudo systemctl enable manual.service;
+
+echo "For now, this uses the command `python -m http.server 5090` to serve the man/pages on port 5090.";
+echo "For more information, see raspi.vintagecoding.net#web-servers";
diff --git a/scripts/setup.sh b/scripts/setup.sh
new file mode 100755
index 0000000..55d19fd
--- /dev/null
+++ b/scripts/setup.sh
@@ -0,0 +1,21 @@
+#!/bin/bash
+
+# This script gets a Raspberry Pi setup with essential tools.
+# For explanations of commands, please visit raspi.vintagecoding.net
+
+# Update repositories and upgrade installed packages.
+sudo apt update && sudo apt upgrade;
+
+# Install requisite packages for cloudflared.
+sudo apt install curl lsb-release;
+
+# 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 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;
+
+echo "Installing nginx, cloudflared, podman, golang, tldr, and neovim to get you started. Run `sudo apt install package` to install other applications. Please see";
+echo "raspi.vintagecoding.net#package-manager for more information.";
+sudo apt update && sudo apt install nginx cloudflared podman golang tldr neovim;