# Technical Documentation: JamesTurland/JimsGarage

> ℹ️ **Provenance:** Multi-Tier Ingestion · [CodeWiki Reference](https://codewiki.google/github.com/JamesTurland/JimsGarage)

### Overview (`README.md`)

[Discord](https://discord.gg/qW5vEBekz5) <br>
[Twitter](https://twitter.com/jimsgarage_) <br>
[Reddit](https://www.reddit.com/user/Jims-Garage)

.png?raw=true)

# Jim's Garage
Here's a collection of Docker Compose and config files for use in my videos. Simply tweak to your environment and deploy!

## Star History

<a href="https://star-history.com/#JamesTurland/JimsGarage&Date">
 <picture>
   <source media="(prefers-color-scheme: dark)" srcset="https://api.star-history.com/svg?repos=JamesTurland/JimsGarage&type=Date&theme=dark" />
   <source media="(prefers-color-scheme: light)" srcset="https://api.star-history.com/svg?repos=JamesTurland/JimsGarage&type=Date" />
   <img alt="Star History Chart" src="https://api.star-history.com/svg?repos=JamesTurland/JimsGarage&type=Date" />
 </picture>
</a>

---

### Overview (`GPU_passthrough/readme.md`)

1) In your PC/Laptop/Server BIOS make sure the following is enabled in the BIOS:

Intel VT-d & VT-x – Intel Compatible list
All AMD CPUs from Bulldozer onwards should be compatible.

2) Get device IDs:
`lspci -nn`

3) Enable IOMMU in GRUB (check Intel or AMD commands below - choose the right one)
nano /etc/default/grub

`GRUB_CMDLINE_LINUX_DEFAULT="quiet intel_iommu=on iommu=pt"`

`GRUB_CMDLINE_LINUX_DEFAULT="quiet amd_iommu=on"`

Verify that IOMMU is enabled by running `dmesg | grep -e DMAR -e IOMMU` and looking for a line indicating it is enabled

Save and exit

4) run the command `"update-grub"` now reboot

5) Enable VFIO Modules
`nano /etc/modules`
Add the following modules:
```
vfio
vfio_iommu_type1
vfio_pci
vfio_virqfd
```
Then, save and exit

6) `update-initramfs -u -k all` and reboot

Verify the modules are enabled with `dmesg | grep -i vfio` and checking the driver version line is present

7) GPU Isolation From the Host (amend the below to include the IDs of the device you want to isolate)

`echo "options vfio-pci ids=10de:1381,10de:0fbc disable_vga=1" > /etc/modprobe.d/vfio.conf`

8) Blacklist GPU drivers (here are all that you would ever need)
```
echo "blacklist radeon" >> /etc/modprobe.d/blacklist.conf 
echo "blacklist nouveau" >> /etc/modprobe.d/blacklist.conf 
echo "blacklist nvidia" >> /etc/modprobe.d/blacklist.conf 
echo "blacklist nvidiafb" >> /etc/modprobe.d/blacklist.conf
echo "blacklist nvidia_drm" >> /etc/modprobe.d/blacklist.conf
```

Reboot your machine, be sure to use the web gui because with the gpu passed through you will no longer get video out.
The start up will begin but then appear to hang even though proxmox has started fine.

9) Create a new VM and add the GPU via hardware menu
You may need to set it as primary GPU
You may need to add a ROM BAR

---

### Overview (`NUT-Server/readme.md`)

# Config file for NUT server
```
# Network UPS Tools: upsd.users
# User access definitions for upsd

# Admin user with full access
[admin]
    password = "admin"
    actions = SET
    actions = FSD
    instcmds = ALL
    upsmon primary

[client]
    password = client
    upsmon secondary

# Monitor user for upsmon with master privileges
[monuser]
    password = "monpass"
    upsmon ups = master
    actions = SET
    actions = FSD
    instcmds = ALL
```

# Example of using SNMP
```
[ups]
    driver = snmp-ups
    port = 192.168.1.104
    snmp_version = v1
    community = public
    desc = Network UPS
    pollinterval = 1
    pollfreq = 1
    user = nut
    group = nut 
```
 
# Commands for client setup
```
sudo apt install nut-client

upsc ups@192.168.200.116

sudo nano /etc/nut/upsmon.conf

MONITOR ups@192.168.200.116 1 client client secondary

sudo nano /etc/nut/nut.conf -> MODE=netclient

sudo systemctl restart nut-client

sudo systemctl enable nut-client
```

---

### Overview (`Ollama/readme.md`)

1. Clone the repo from: https://github.com/ollama-webui/ollama-webui
2. Tweak the docker-compose to your liking
3. Run the container: sudo docker compose up -d

Let it build :)

---

### Overview (`Proxmox-Backup-Server/readme.md`)

# Video Commands:
1. Mount command: mount -t cifs -o rw,vers=3.0,credentials=/etc/samba/.smbcreds,uid=34,gid=34 //IP-OF-NAS/SHARE-NAME /mnt/truenas
2. fstab: //IP-OF-NAS/SHARE-NAME /mnt/test-pbs cifs vers=3.0,credentials=/etc/samba/.smbcreds,uid=34,gid=34,defaults 0 0

---

### Overview (`Pterodactyl/readme.md`)

1. docker compose run --rm panel php artisan p:user:make --email=admin@domain.com --username=admin --name-first=admin --name-last=user --password=admin --admin=1 --no-password

---

### Overview (`StrixHaloToolboxes/readme.md`)

# AMD Strix Halo Toolboxes — Setup Notes

Tested on Ubuntu 24.04 LTS.

## System update
Run as root or prefix with sudo:
```bash
sudo apt update && sudo apt upgrade -y
sudo reboot
```

## Install AMD GPU packages (example: amdgpu/ROCm)
Download the installer (example version used here: 7.0.2):
```bash
wget https://repo.radeon.com/amdgpu-install/7.0.2/ubuntu/noble/amdgpu-install_7.0.2.70002-1_all.deb
sudo apt install ./amdgpu-install_7.0.2.70002-1_all.deb
sudo apt update
sudo apt install python3-setuptools python3-wheel
```

Add current user to render/video groups:
```bash
sudo usermod -a -G render,video $LOGNAME
```

Install ROCm:
```bash
sudo apt install rocm
```

Kernel extras and DKMS:
```bash
sudo apt install "linux-headers-$(uname -r)" "linux-modules-extra-$(uname -r)"
sudo apt install amdgpu-dkms
sudo reboot
```

## Library path and ldconfig
Add ROCm libs to the loader path and refresh:
```bash
sudo tee /etc/ld.so.conf.d/rocm.conf <<'EOF'
/opt/rocm/lib
/opt/rocm/lib64
EOF
sudo ldconfig
```

You can also set LD_LIBRARY_PATH for the current session (or add to your shell profile):
```bash
export LD_LIBRARY_PATH=/opt/rocm-7.0.2/lib:$LD_LIBRARY_PATH
```

Verify installation:
```bash
apt list --installed | grep -E 'rocm|amdgpu'
rocminfo | grep -i 'Marketing Name:'
```

## Kernel / AMD TTM tuning
Edit GRUB:
```bash
sudo nano /etc/default/grub
# add or update GRUB_CMDLINE_LINUX_DEFAULT with required options, for example:
GRUB_CMDLINE_LINUX_DEFAULT="quiet amdttm.pages_limit=33554432 amdgpu.gttsize=131072 amd_iommu=off"
sudo update-grub
sudo reboot
# verify:
sudo dmesg | grep -i 'amdgpu.*memory'
```

## Ubuntu Users
If you do not wish to run as root, create rule:
```bash
sudo nano /etc/udev/rules.d/99-amd-kfd.rules
```
Paste the following:
```bash
SUBSYSTEM=="kfd", GROUP="render", MODE="0666", OPTIONS+="last_rule"
SUBSYSTEM=="drm", KERNEL=="card[0-9]*", GROUP="render", MODE="0666", OPTIONS+="last_rule"
```

## Toolbox / Container workflow
Install Podman Toolbox if desired:
```bash
sudo apt-get install podman-toolbox
```

Clone the repo:
```bash
git clone https://github.com/kyuz0/amd-strix-halo-toolboxes.git
cd amd-strix-halo-toolboxes/toolboxes/
```

Create a toolbox container (example):
```bash
sudo toolbox create llama-rocm-7rc-rocwmma \
  --image docker.io/kyuz0/amd-strix-halo-toolboxes:rocm-7rc-rocwmma \
  -- --device /dev/dri --device /dev/kfd \
     --group-add video --group-add render --group-add sudo \
     --security-opt seccomp=unconfined
```

Enter the toolbox:
```bash
toolbox enter llama-rocm-7rc-rocwmma
```

Inside the container you can list devices:
```bash
llama-cli --list-devices
```

Run a server example (adjust model name and flags as needed):
```bash
llama-server --no-mmap -ngl 999 -fa on --host 0.0.0.0 -hf unsloth/Qwen3-235B-A22B-Instruct-2507-GGUF:Q3_K_XL
```

## Notes
- Always check official AMD docs and AMD-Strix-Halo Repo for changes

---

### Overview (`Synapse/readme.md`)

1) Create a config file

```
sudo docker run -it --rm \
   --mount type=volume,src=synapse-data,dst=/data \
   -e SYNAPSE_SERVER_NAME=matrix.jimsgarage.co.uk \
   -e SYNAPSE_REPORT_STATS=no \
   matrixdotorg/synapse:latest generate
```

2) become root and access the file

sudo -i

3) copy config file to your docker volume mount

4) become non-root user

5) change owner and permissions of configs so that we can edit them

su username

sudo chown ubuntu:ubuntu * (or whatever your user is)

6) edit config

change database section

 name: psycopg2
 args:
   user: <user>
   password: <pass>
   database: <db>
   host: <host>
   cp_min: 5
   cp_max: 10

copy over the credentials from the docker compose

7) create admin user

docker exec -it synapse register_new_matrix_user http://localhost:8008 -c /data/homeserver.yaml --help #remove help once ready

8) add record to dns server (remember needs to be external as well!)

9) check page to see it's up

10) element and profit

11) Add emails, recaptcha if you want to (recommended!)

---

### Overview (`iGPU/readme.md`)

# Tests:

# H265 4K -> H264 4K
- AMD: sudo ffmpeg -hwaccel vaapi -hwaccel_device /dev/dri/renderD128 -hwaccel_output_format vaapi -i bbb-3840x2160-cfg02.mkv -c:v h264_vaapi output.mp4
- Intel: sudo ffmpeg -hwaccel qsv -hwaccel_device /dev/dri/renderD128 -hwaccel_output_format qsv -i bbb-3840x2160-cfg02.mkv -c:v h264_qsv output.mp4

# H265 4K -> H264 1080P
- AMD: sudo ffmpeg -hwaccel vaapi -hwaccel_device /dev/dri/renderD128 -hwaccel_output_format vaapi -i bbb-3840x2160-cfg02.mkv -vf "scale_vaapi=w=1920:h=1080" -c:v h264_vaapi output.mp4
- Intel: sudo ffmpeg -hwaccel qsv -hwaccel_device /dev/dri/renderD128 -hwaccel_output_format qsv -i bbb-3840x2160-cfg02.mkv -vf "scale_qsv=w=1920:h=1080" -c:v h264_qsv output.mp4

# H265 4K -> H265 1080P
- AMD: sudo ffmpeg -hwaccel vaapi -hwaccel_device /dev/dri/renderD128 -hwaccel_output_format vaapi -i bbb-3840x2160-cfg02.mkv -vf "scale_vaapi=w=1920:h=1080" -c:v hevc_vaapi output.mp4
- Intel: sudo ffmpeg -hwaccel qsv -hwaccel_device /dev/dri/renderD128 -hwaccel_output_format qsv -i bbb-3840x2160-cfg02.mkv -vf "scale_qsv=w=1920:h=1080" -c:v hevc_qsv output.mp4

# AV1 1080P -> H265 1080P
- AMD: sudo ffmpeg -hwaccel vaapi -hwaccel_device /dev/dri/renderD128 -hwaccel_output_format vaapi -i Sparks-5994fps-AV1-10bit-1920x1080-2194kbps.mp4 -c:v hevc_vaapi output.mp4
- Intel: sudo ffmpeg -hwaccel qsv -hwaccel_device /dev/dri/renderD128 -hwaccel_output_format qsv -i Sparks-5994fps-AV1-10bit-1920x1080-2194kbps.mp4 -c:v hevc_qsv output.mp4

# AV1 1080P -> H264 1080P
- AMD: sudo ffmpeg -hwaccel vaapi -hwaccel_device /dev/dri/renderD128 -hwaccel_output_format vaapi -i Sparks-5994fps-AV1-10bit-1920x1080-2194kbps.mp4 -vf "scale_vaapi=w=1920:h=1080" -c:v h264_vaapi output.mp4
- Intel: sudo ffmpeg -hwaccel qsv -hwaccel_device /dev/dri/renderD128 -hwaccel_output_format qsv -i Sparks-5994fps-AV1-10bit-1920x1080-2194kbps.mp4 -c:v h264_qsv output.mp4

# H264 4K -> H264 1080P
- AMD: sudo ffmpeg -hwaccel vaapi -hwaccel_device /dev/dri/renderD128 -hwaccel_output_format vaapi -i Meridian_UHD4k5994_HDR_P3PQ.mp4 -vf "scale_vaapi=w=1920:h=1080" -c:v h264_vaapi output.mp4
- Intel: sudo ffmpeg -hwaccel qsv -hwaccel_device /dev/dri/renderD128 -hwaccel_output_format qsv -i Meridian_UHD4k5994_HDR_P3PQ.mp4 -vf "scale_qsv=w=1920:h=1080" -c:v h264_qsv output.mp4

---

### Overview (`Ansible/Installation/readme.md`)

# Update Repos
```
sudo apt update
```
# Install Dependencies
```
sudo apt install software-properties-common
```

# Add Ansible Repo
```
sudo add-apt-repository --yes --update ppa:ansible/ansible
```

# Install Ansible
```
sudo apt install ansible
```

---

### Overview (`Ansible/SSH/readme.md`)

# Edit Hosts File
```
sudo nano /etc/ansible/hosts
```

# Fix SSH Key Permissions
```
chmod 600 ~/.ssh/ansible
```
# Ansible Ping Command
```
ansible all -m ping
```

# Create SSH Key
```
ssh-keygen -t ed25519 -C "ansible"
```

# Copy SSH Key
```
ssh-copy-id -i ~/.ssh/ansible.pub 192.168.200.50
```

# Ansible Ping Command With New SSH Key
```
ansible all -m ping --key-file ~/.ssh/ansible
```

---

### Overview (`Kubernetes/Authentik/readme.md`)

# Instructions Used In Video

  

## K3S

  

bootstrap first node:

    curl -sfL https://get.k3s.io | sh -

  

add agents:

    curl -sfL https://get.k3s.io | K3S_URL=https://myserver:6443 K3S_TOKEN=mynodetoken sh -

  

## Helm

    curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-4
    
    chmod 700 get_helm.sh
    
    ./get_helm.sh

  

## Metallb

    helm repo add metallb https://metallb.github.io/metallb
    
    helm install metallb metallb/metallb

  

### then edit and apply the manifests:

  

    kubectl apply -f ....

  

## Authentik

create passwords:

  

    pwgen -s 50 1
    
    openssl rand 60 | base64 -w 0

  

 set values in values.yaml - see example

  

    nano values.yaml

  

deploy authentik:

  

    helm repo add authentik https://charts.goauthentik.io
    
    helm repo update
    
    helm upgrade --install authentik authentik/authentik -f values.yaml

  

edit for Traefik proxy using files

  

    kubectl apply -f ...

---

### Overview (`Kubernetes/Cloud-Init/readme.md`)

1. Download the ISO using the GUI (tested on https://cloud-images.ubuntu.com/lunar/current/lunar-server-cloudimg-amd64-disk-kvm.img)
1. Create the VM via CLI
```bash
qm create 5000 --memory 2048 --core 2 --name ubuntu-cloud --net0 virtio,bridge=vmbr0
cd /var/lib/vz/template/iso/
qm importdisk 5000 lunar-server-cloudimg-amd64-disk-kvm.img <YOUR STORAGE HERE>
qm set 5000 --scsihw virtio-scsi-pci --scsi0 <YOUR STORAGE HERE>:vm-5000-disk-0
qm set 5000 --ide2 <YOUR STORAGE HERE>:cloudinit
qm set 5000 --boot c --bootdisk scsi0
qm set 5000 --serial0 socket --vga serial0
```
3. Expand the VM disk size to a suitable size (suggested 10 GB)
```bash
qm disk resize 5000 scsi0 10G
```
4. Create the Cloud-Init template 
5. Deploy new VMs by cloning the template (full clone)

---

### Overview (`Kubernetes/Create-VMS/readme.md`)

# Simple script to create multiple Virtual Machines automatically

1. It will ask you some questions about your wished Virtual Machines.
    - You can select Debian or Ubuntu image
2. Prints a detailed info with about the VMs going tyo be created.
3. Let you confirm if You want to continue
4. You can chose to start all VMs at the end 🚀

Enjoy 🙂

---

### Overview (`Kubernetes/CrowdSec/readme.md`)

# Instructions
1. ```
    helm install \
    cert-manager jetstack/cert-manager \
    --create-namespace \
    --namespace cert-manager \
    --set installCRDs=true

    helm install \
    reflector emberstack/reflector \
    --create-namespace \
    --namespace reflector
    ```
2. ```
    helm upgrade \
    traefik traefik/traefik \
    --namespace traefik \
    -f traefik-values.yaml

    helm install \
    crowdsec crowdsec/crowdsec \
    --create-namespace \
    --namespace crowdsec \
    -f crowdsec-values.yaml
    ```

---

### Overview (`Kubernetes/Docker-Kubernetes-Data-Migration/readme.md`)

# Instructions
1. Create Longhorn volume
2. Mount longhorn volume to a node (recommend worker node)
3. Log into selected worker node
4. Create temporary folder for migration
> sudo mkdir /tmp/folder
5. List the disks to format
> sudo fdisk -l
6. Format the disk 
> sudo mkfs -t ext4 /dev/sdx
7. Mount the new disk to tmp folder
> sudo mount /dev/sdx /tmp/folder
8. Copy data from Docker Host to new drive (substitute your values below)
> sudo rsync -avxHAX username@DockerHostIP:/home/ubuntu/docker/some-directory/* /tmp/folder

---

### Overview (`Kubernetes/GPU-Passthrough/readme.md`)

# Create directory
```
mkdir -p /etc/rancher/rke2
```
# Create File for RKE2 - Config
```
sudo nano /etc/rancher/rke2/config.yaml
```
# Add values
```
token: <ADD-TOKEN>
server: https://<ADD-VIP>:9345
node-label:
  - worker=true
  - longhorn=true
```
# Install RKE2
```
sudo su
curl -sfL https://get.rke2.io | INSTALL_RKE2_TYPE="agent" sh -
```
# Enable RKE2
```
systemctl enable rke2-agent.service
systemctl start rke2-agent.service
```

---

### Overview (`Kubernetes/GitOps/readme.md`)

# Instructions
1. Create GitHub (or whatever) repository
2. Create granular access token
3. Add details to Fleet in Rancher via 'Continuous Delivery' button (left panel)
4. Ensure you are in 'Fleet-local' or whatever your cluster is called
5. Ensure the login details are correct, branch is set to main (default)
6. Once created, it should pull any files you have in that repository and deploy on your cluster

---

### Overview (`Kubernetes/K3S-Deploy/README.md`)

# K3S HA Deploy (k3sup + kube-vip + MetalLB)

Deploys a highly-available k3s cluster over SSH with `k3sup`, a floating
control-plane VIP via **kube-vip**, and `type: LoadBalancer` support via
**MetalLB**.

> **Following the YouTube tutorial?** This script has been modernized since
> the video — see [What changed](#what-changed-from-the-video) below.

## What it builds

- A 3-server (control-plane) + 2-agent (worker) k3s cluster with embedded etcd.
- **kube-vip** advertises a single virtual IP for the Kubernetes API across
  all control-plane nodes (survives a node failure).
- **MetalLB** hands out real IPs to `type: LoadBalancer` services.

### Why both kube-vip and MetalLB?

They solve different problems. **kube-vip** provides the *control-plane* VIP
(one address for the API server, HA across masters). **MetalLB** provides
*service* load balancing (`type: LoadBalancer` for your apps). The older
kube-vip cloud-provider that overlapped MetalLB has been removed to avoid
duplicate LoadBalancer controllers.

## Prerequisites

- **Ubuntu/Debian** nodes (the script installs prerequisites with `apt`; on a
  non-apt distro it exits with a clear message).
- **Passwordless sudo** for the SSH user on every node. Example cloud-init:

  ```yaml
  #cloud-config
  users:
    - name: <your-user>
      sudo: ["ALL=(ALL) NOPASSWD:ALL"]
      groups: [sudo]
  ```

- An **SSH key pair** you can use to reach the nodes (the script distributes
  the public key and never clobbers your `~/.ssh/config`).
- **5 nodes by default** (3 servers + 2 agents). The minimum for HA is 3
  servers (etcd needs a quorum); workers are optional. Adjust the node list in
  the config block if you have fewer machines.
- Run the script from a **separate Ubuntu/Debian admin machine** (your
  laptop/workstation) that can SSH to every node — not on one of the nodes
  themselves. It installs `k3sup` and `kubectl` locally if missing.

## Important caveats

- **The VIP and the MetalLB range must be outside your DHCP pool**, and must
  not overlap each other or any node IP. If your router hands out `vip` or an
  address in `lbrange` via DHCP, you'll get intermittent, hard-to-debug
  failures — reserve them on your router/DHCP server first.
- **Same subnet / L2 only.** kube-vip (ARP mode) and MetalLB (L2) both
  advertise via ARP, so the VIP and LoadBalancer IPs must be on the **same
  subnet/VLAN** as the nodes and the clients reaching them — they are not
  routed across subnets.
- **`interface` must match your nodes' real NIC.** It's `eth0` on many
  systems but often `ens18`/`enp0s3` on Proxmox and cloud images. Check with
  `ip -o -4 route show default`.
- **Host keys are trusted on first use** (`accept-new`). If you re-image a
  node, clear its stale entry first: `ssh-keygen -R <node-ip>`.
- This is a **homelab tutorial, not production-hardened** as-is (aggressive
  leader election, no etcd backups, single L2 domain).

## Usage

1. Snapshot your VMs (so you can roll back — the script modifies every node).
2. Place your SSH **private** key at `~/<certName>` or `~/.ssh/<certName>`,
   with the matching `.pub` beside it. `certName` is the key's *filename only*
   — no path, no `.pub` suffix. Modern OpenSSH defaults to `id_ed25519`, so set
   `certName` to match the key you actually have.
3. Edit the **"YOU SHOULD ONLY NEED TO EDIT THIS SECTION"** block in
   `k3s.sh` — node IPs, `user`, `interface`, `vip`, `lbrange`, `certName`.
   The example IPs (`192.168.3.x`, VIP `.50`, range `.60-.80`) and
   `interface=eth0` are placeholders — change them for your network.
4. `chmod +x k3s.sh && ./k3s.sh`
5. Review the pre-flight summary and confirm. Grab a coffee.

### After it finishes

The kubeconfig is **merged** into `~/.kube/config` as context `k3s-ha` (set by
`context` in the config block), pointed at the VIP. Select it and check the
cluster:

```bash
kubectl config use-context k3s-ha
kubectl get nodes -o wide
curl http://<load-balancer-ip>   # the script prints the assigned IP
```

Worker nodes are labeled `worker=true` and `longhorn=true` (the latter for the
companion Longhorn storage tutorial — harmless if you don't use it).

If a node fails to join, reset just that node and re-run the script (it's
idempotent): `k3s-uninstall.sh` on a server, `k3s-agent-uninstall.sh` on a
worker.

### Options (environment variables)

| Variable         | Purpose                                               |
| ---------------- | ----------------------------------------------------- |
| `ASSUME_YES=1`   | Skip the pre-flight `[y/N]` prompt (unattended runs). |
| `NO_COLOR=1`     | Disable colored output.                               |
| `RAW_BASE=<url>` | Where to fetch the sibling manifests (kube-vip, ipAddressPool, l2Advertisement); default: upstream `main`. Override for a fork/branch/local copy. |

### Tracking the latest k3s instead of a pinned version

In the config block set `k3sChannel="stable"` and leave `k3sVersion=""`.
The script then always installs the current stable k3s release.

### Upgrading kube-vip

The `kube-vip` manifest is generated from the pinned image (its env schema
changes between releases). To bump:

```bash
docker run --rm ghcr.io/kube-vip/kube-vip:<version> manifest daemonset \
  --interface eth0 --address 10.0.0.254 \
  --controlplane --arp --leaderElection --taint --inCluster > kube-vip
sed -i 's/value: eth0/value: REPLACE_INTERFACE/' kube-vip
sed -i 's/value: 10.0.0.254/value: REPLACE_VIP/' kube-vip
```

`--inCluster` is required on k3s: it makes kube-vip use the `kube-vip`
ServiceAccount (created by the RBAC the script applies) instead of the
kubeadm `/etc/kubernetes/admin.conf` kubeconfig, which does not exist on k3s.
Then update `KVVERSION` in `k3s.sh` to match.

## What changed from the video

- **Versions:** k3s `v1.35.6+k3s1`, kube-vip `v1.2.1`, MetalLB `v0.16.0`.
- **kube-vip** now runs on **all** control-plane nodes, and your kubeconfig
  points at the **VIP** (not master1) — fixes `localhost:8080`/API errors. A
  readiness check confirms the VIP is answering before the script continues.
- Removed the redundant kube-vip **cloud-provider**; MetalLB alone handles
  `type: LoadBalancer`.
- **MetalLB** installs from a single native manifest (which creates its own
  `metallb-system` namespace) — the old separate namespace apply and its
  mismatched MetalLB versions are gone.
- **k3sup:** the join token is fetched once and reused across all nodes, and
  `k3sup ready` waits for the cluster instead of a hand-rolled poll loop.
- **Safer SSH:** host keys are added via `ssh-keyscan`; the script no longer
  overwrites `~/.ssh/config`.
- **Hardening:** `set -euo pipefail`, per-node time sync, `apt` prerequisite
  install with a clear message on unsupported distros, arch-aware `kubectl`,
  and it is safe to re-run.
- **Cleaner output:** non-blinking step-by-step logging (only the banner
  still blinks — for old times' sake), a pre-flight config summary with a
  `[y/N]` confirmation (`ASSUME_YES=1` to skip), and a final summary listing
  the API VIP and the assigned LoadBalancer IP.

---

### Overview (`Kubernetes/Longhorn/readme.md`)

1. Create new VMs (3 in my example)
2. Remember to increase storage from default template (you should also increase Master and Worker nodes if you haven't).
3. Make static IPs for each
4. Copy script (longhorn.sh) to your admin machine (make executable)
5. Run script
6. Enjoy Longhorn

Let me know if it doesn't work!

---

### Overview (`Kubernetes/Rancher-Deployment/readme.md`)

# Install helm
```
curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3
chmod 700 get_helm.sh
./get_helm.sh
```
# Add Rancher Helm Repository
```
helm repo add rancher-latest https://releases.rancher.com/server-charts/latest
kubectl create namespace cattle-system
```

# Install Cert-Manager
```
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.13.2/cert-manager.crds.yaml
helm repo add jetstack https://charts.jetstack.io
helm repo update
helm install cert-manager jetstack/cert-manager \
--namespace cert-manager \
--create-namespace \
--version v1.13.2
kubectl get pods --namespace cert-manager
```

# Install Rancher
```
helm install rancher rancher-latest/rancher \
 --namespace cattle-system \
 --set hostname=rancher.my.org \
 --set bootstrapPassword=admin
kubectl -n cattle-system rollout status deploy/rancher
kubectl -n cattle-system get deploy rancher
```

# Expose Rancher via Loadbalancer
```
kubectl get svc -n cattle-system
kubectl expose deployment rancher --name=rancher-lb --port=443 --type=LoadBalancer -n cattle-system
kubectl get svc -n cattle-system
```

# Go to Rancher GUI
Hit the url… and create your account
Be patient as it downloads and configures a number of pods in the background to support the UI (can be 5-10mins)

# Bonus: Accessing Rancher through Ingress (Traefik)
Do you want that precious green lock in your URL bar?  If you have Traefik (or another Kubernetes Ingress controller) 
deployed and a Let's Encrypt issuer with Cert-Manager, the Rancher Helm chart offers support to automatically configure 
an ingress route with TLS certificate injection to access the Rancher UI via the `rancher` Kubernetes Service created 
by the Helm install (`kubectl -n cattle-system get service`). This can be configured retroactively after your initial 
`helm install ...`, but is a bit simpler to set up as part of your initial Rancher installation if you have the 
prerequisites in place.

You first need to save the TLS certificate and key that you want Traefik to use for Rancher as a Kubernetes Secret
called `tls-rancher-ingress`.  You can do this manually, or let Cert-Manager generate a certificate for you and 
store it in a Secret, using `kubectl` to create a Kubernetes Certificate resource to generate the certificate and 
populate the Secret for you:
```yaml
---
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: rancher-my-org
  namespace: cattle-system
spec:
  commonName: rancher.my.org
  dnsNames:
    - rancher.my.org
  issuerRef:
    name: letsencrypt-production
    kind: ClusterIssuer
  secretName: tls-rancher-ingress
```
This can take anywhere from a few minutes to 15-20 minutes to generate, so sit tight.  You'll know it is ready when 
the certificate's `Ready` status shows `True` in the output of:
```bash
kubectl -n cattle-system get certificate rancher-my-org
```
While you're waiting, make sure that your DNS record for `rancher.my.org` points to your Traefik deployment, 
instead of a LoadBalancer IP from kubeVIP. 
This can be an CNAME record using your Traefik FQDN, or an A record using the same IP address as Traefik.

Once the certificate and DNS record are ready, you can run your Rancher installation with one extra value set to 
configure your Ingress provider to use your custom certificate:
```bash
helm install rancher rancher-latest/rancher \
  --namespace cattle-system \
  --set hostname=rancher.my.org \
  --set bootstrapPassword=admin \
  --set ingress.tls.source=secret
```
If you are doing this after already installing Rancher (with the default setting of `ingress.tls.source=rancher`), 
you can overwrite the self-generated `tls-rancher-ingress` secret with your own certificate, then update your 
deployment. You may want to get your current Rancher version using `helm ls -n cattle-system` and provide it 
in your `helm upgrade` command so you don't unexpectedly upgrade your Rancher version.
```bash
helm upgrade rancher rancher-stable/rancher \
  --namespace cattle-system \
  --set hostname=rancher.my.org \
  --set ingress.tls.source=secret \
  --version <DEPLOYED_RANCHER_VERSION>
```
## Ingress TLS Troubleshooting
You can validate the contents of your `tls-rancher-ingress` Secret using commands like this:
```bash
kubectl -n cattle-system get secret tls-rancher-ingress -o jsonpath='{.data}' | jq '."tls.crt"' | tr -d '"' | base64 --decode | openssl x509 -text
```
If you previously had your `rancher.my.org` DNS record associated with your LoadBalancer IP, your browser may be caching
that old record.  You may need to clear your browser's DNS cache, use an Incognito/Private window, etc.

There are also helpful instructions covering a handful of situations in Rancher's documentation:
* [Adding TLS Secrets](https://ranchermanager.docs.rancher.com/getting-started/installation-and-upgrade/resources/add-tls-secrets)
* [Update Rancher Certificate](https://ranchermanager.docs.rancher.com/getting-started/installation-and-upgrade/resources/update-rancher-certificate)

---

### Overview (`Kubernetes/SMB/readme.md`)

# Install CSI driver
```
curl -skSL https://raw.githubusercontent.com/kubernetes-csi/csi-driver-smb/v1.18.0/deploy/install-driver.sh | bash -s v1.18.0 --
```

# Create SMB creds
```
kubectl create secret generic smbcreds --from-literal username=USERNAME --from-literal password="PASSWORD"
```

# Create storage class
```
kubectl create -f https://raw.githubusercontent.com/kubernetes-csi/csi-driver-smb/master/deploy/example/storageclass-smb.yaml
```

# Check status
```
kubectl -n kube-system get pod -o wide --watch -l app=csi-smb-controller
kubectl -n kube-system get pod -o wide --watch -l app=csi-smb-node
```

---

### Overview (`Kubernetes/Traefik-PiHole/readme.md`)

# IMPORTANT #
Make sure that you watch the video instructions carefully as you need to amend the files correctly.
YOU CANNOT JUST RUN THIS SCRIPT!
Incorrect use can result in you being locked out of Lets Encrypt for a period of time.

# NOTE FOR TRAEFIK v3 #
Many guides out there (including, until recently, this repo) reference an older version of the Kubernetes CRDs API group.
This older version is [deprecated](https://doc.traefik.io/traefik/master/migration/v2-to-v3/#kubernetes-crds-api-group-traefikcontainous) 
as of Traefik v3 (released [29 April 2024](https://github.com/traefik/traefik/releases/tag/v3.0.0)) and must be updated to the new version
in your IngressRoute, Middleware, ServersTransport, etc. yaml manifests for Traefik.  Any resources with the deprecated version will not 
be recognized by Traefik v3.

Old, deprecated version:
```yaml
apiVersion: traefik.containo.us/v1alpha1
```

New, supported version:
```yaml
apiVersion: traefik.io/v1alpha1
```
This new version is also supported in later releases of Traefik v2, so you can update your Traefik-related manifests 
to the new version and apply the updated manifests before upgrading your Traefik deployment.

It may be worth reviewing other v2 to v3 migration notes provided by Traefik: 
[Traefik v2 to v3 Migration](https://doc.traefik.io/traefik/master/migration/v2-to-v3/)

---

### Overview (`Kubernetes/Upgrade/readme.md`)

# Recommendations Before Upgrading
1. Snapshot / Backup your VMs!
2. Backup data and volumes if necessary
3. Drain nodes / scale down deployments

# Upgrade Rancher
```
helm upgrade rancher rancher-latest/rancher \
 --namespace cattle-system \
 --set hostname=rancher.my.org
```
# Upgrade RKE2 (Each node, not Admin!)
```
sudo curl -sfL https://get.rke2.io | INSTALL_RKE2_CHANNEL=latest sh -
```
then servers:
```
sudo systemctl restart rke2-server
```
or agents
```
sudo systemctl restart rke2-agent
```
# Upgrade K3S (Each node, not Admin!)
```
sudo curl -sfL https://get.k3s.io | INSTALL_K3S_CHANNEL=latest <EXISTING_K3S_ENV> sh -s - <EXISTING_K3S_ARGS>
```
then servers:
```
sudo systemctl restart k3s
```
or agents
```
sudo systemctl restart k3s-agent
```

# Upgrade Longhorn
```
kubectl apply -f https://raw.githubusercontent.com/longhorn/longhorn/v1.5.3/deploy/longhorn.yaml
```

# Upgrade Metallb
1. Change version on the delete command to the version you are currently running (e.g., v0.13.11)
2. Change version on the apply to the new version (e.g., v0.13.12)
3. Ensure your Lbrange is still the one you want (check ipAddressPool.yaml)
```
kubectl delete -f https://raw.githubusercontent.com/metallb/metallb/v0.13.11/config/manifests/metallb-native.yaml
kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.13.12/config/manifests/metallb-native.yaml
kubectl apply -f ipAddressPool.yaml
kubectl apply -f https://raw.githubusercontent.com/JamesTurland/JimsGarage/main/Kubernetes/RKE2/l2Advertisement.yaml
```

# Upgrade Kube-VIP
1. Delete the daemonset in Rancher or use kubectl delete
2. Redeploy the daemonset with updated values (check kube-vip file)
```
kubectl delete -f kube-vip
kubectl apply -f kube-vip
```

---

### Overview (`LXC/Jellyfin/readme.md`)

# Find Device Numbers
```
ls -l /dev/dri
```

# Find Group Numbers
```
cat /etc/group
```

# Add Group Numbers Values to subgid
Change values to map the to above ^^
```
nano /etc/subgid
```
Paste at the bottom, for example:
```
root:44:1
root:104:1
```

# Create CT Using Wizard. Edit .conf In /etc/pve/lxc
Edit your device IDs and renderD***
Ensure you match the idmap values
```
arch: amd64
cores: 2
cpulimit: 2
features: nesting=1
hostname: test-gpu-04
memory: 3000
net0: name=eth0,bridge=vmbr0,firewall=1,hwaddr=BC:24:11:06:18:78,ip=dhcp,type=veth
ostype: debian
rootfs: local-lvm:vm-104-disk-0,size=20G
swap: 512
unprivileged: 1
lxc.cgroup2.devices.allow: c 226:0 rwm
lxc.cgroup2.devices.allow: c 226:128 rwm
lxc.mount.entry: /dev/dri/renderD128 dev/dri/renderD128 none bind,optional,create=file
lxc.idmap: u 0 100000 65536
lxc.idmap: g 0 100000 44
lxc.idmap: g 44 44 1
lxc.idmap: g 45 100045 62
lxc.idmap: g 107 104 1
lxc.idmap: g 108 100108 65428
```

# Add Root to Groups
Do this on your Proxmox Host
```
usermod -aG render,video root
```

# Whatever You Want...
Install Docker, run apps, even change your LXC for a Linux Desktop!!!

---

### Overview (`LXC/NAS/readme.md`)

# On LXC Create User Group
```
groupadd -g 10000 lxc_shares
```

# Optional: Add Other Users to Group (e.g., Jellyfin, Plex)
```
usermod -aG lxc_shares USERNAME
```

# On Proxmox Host
Create a folder to mount the NAS
```
mkdir -p /mnt/lxc_shares/nas_rwx
```

# Add NAS CIFS share to /etc/fstab
Replace //NAS-IP-ADDRESS with your NAS IP
Replace Username and Passwords
```
{ echo '' ; echo '# Mount CIFS share on demand with rwx permissions for use in LXCs ' ; echo '//NAS-IP-ADDRESS/nas/ /mnt/lxc_shares/nas_rwx cifs _netdev,x-systemd.automount,noatime,uid=100000,gid=110000,dir_mode=0770,file_mode=0770,user=smb_username,pass=smb_password 0 0' ; } | tee -a /etc/fstab

```

# Mount the NAS to the Proxmox Host
```
mount /mnt/lxc_shares/nas_rwx
```

# Add Bind Mount of the Share to the LXC Config
Be sure to change the LXC_ID
```
You can mount it in the LXC with read+write+execute (rwx) permissions.
{ echo 'mp0: /mnt/lxc_shares/nas_rwx/,mp=/mnt/nas' ; } | tee -a /etc/pve/lxc/LXC_ID.conf

You can also mount it in the LXC with read-only (ro) permissions.
{ echo 'mp0: /mnt/lxc_shares/nas_rwx/,mp=/mnt/nas,ro=1' ; } | tee -a /etc/pve/lxc/LXC_ID.conf
```

Thanks to https://forum.proxmox.com/members/thehellsite.88343/ for tips

---

### Overview (`UltimateVPS/traefik/readme.md`)

see: https://youtu.be/CmUzMi5QLzI & https://github.com/JamesTurland/JimsGarage/tree/main/Traefikv3

---

### Overview (`Unifi-Controller/kubernetes/README.md`)

# Deployment

You can't just deploy the whole folder. You have to apply the files in the following order:

1. Create the namespace and the secrets using ´kubectl apply -f namespaceAndSecret.yaml ´
2. Apply the init-script using ´kubectl create configmap create-db-configmap --from-file=init-mongo.js --namespace unifi-controller´
3. Create two persistent volumes and two persistent volume claims in Longhorn

- unifi-db
- unifi-config

4. Deploy the pod and the service using ´kubectl apply -f deployment.yaml ´
5. If you want to access the GUI via Traefik you can add an ingress using ´kubectl apply -f ingress.yaml ´
6. Check if the MongoDB Container is running and delete the configmap ´create-db-configmap´ for security reasons

---

### Overview (`Ansible/Playbooks/Update/readme.md`)

# Add to Hosts File (change ansible_user if required)
```
[all:vars]
ansible_user='ubuntu'
ansible_become=yes
ansible_become_method=sudo
```

---

--- METRICS ---
- Files Extracted: 29
- Estimated Token Budget: ~9037 tokens
- Canonical Reference: https://codewiki.google/github.com/JamesTurland/JimsGarage
