JimsGarage Documentation

Shell repository by @JamesTurland. Docker Compose & container deployment with 4.7k stars.

4,693 stars Shell Shell 29 files ยท ~9,121 tokens
RAW Doc

Docker & Self-Hosted Deployment Verified OCI

Deploy JimsGarage on any server, homelab, or cloud container platform.

1-Click Terminal Command
bash (docker run)
docker run -d --name jimsgarage --restart always nginx
Configured Services & Ports
โš™๏ธ web
image: nginx
docker-compose.yml
yaml (docker-compose.yml)
version: "3.9"
services:
  web:
    image: nginx
    container_name: jimsgarage
    volumes:
     - /home/ubuntu/docker/nginx/templates:/etc/nginx/templates
     - /home/ubuntu/docker/nginx/web/website:/usr/share/nginx/html
    environment:
     - NGINX_HOST=nginx.jimsgarage.co.uk
     - NGINX_PORT=80
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.nginx.entrypoints=http"
      - "traefik.http.routers.nginx.rule=Host(`nginx.jimsgarage.co.uk`)"
      - "traefik.http.middlewares.nginx-https-redirect.redirectscheme.scheme=https"
      - "traefik.http.routers.nginx.middlewares=nginx-https-redirect"
      - "traefik.http.routers.nginx-secure.entrypoints=https"
      - "traefik.http.routers.nginx-secure.rule=Host(`nginx.jimsgarage.co.uk`)"
      - "traefik.http.routers.nginx-secure.tls=true"
      - "traefik.http.routers.nginx-secure.service=nginx"
      - "traefik.http.services.nginx.loadbalancer.server.port=80"
      - "traefik.docker.network=proxy"
    networks:
      proxy:
    security_opt:
      - no-new-privileges:true

networks:
  proxy:
    external: true

Technical Documentation: JamesTurland/JimsGarage

โ„น๏ธ Provenance: Multi-Tier Ingestion ยท CodeWiki Reference

Overview (`README.md`)

Discord
Twitter
Reddit

.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


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.

  1. Get device IDs:
    lspci -nn

  2. 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

  1. run the command "update-grub" now reboot

  2. Enable VFIO Modules
    nano /etc/modules
    Add the following modules:

text
vfio
vfio_iommu_type1
vfio_pci
vfio_virqfd

Then, save and exit

  1. 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

  1. 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

  1. Blacklist GPU drivers (here are all that you would ever need)
text
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.

  1. 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

text
# 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

text
[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

text
sudo apt install nut-client

upsc [email protected]

sudo nano /etc/nut/upsmon.conf

MONITOR [email protected] 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=[email protected] --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
text
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
  1. become root and access the file

sudo -i

  1. copy config file to your docker volume mount

  2. become non-root user

  3. change owner and permissions of configs so that we can edit them

su username

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

  1. edit config

change database section

name: psycopg2
args:
user:
password:
database:
host:
cp_min: 5
cp_max: 10

copy over the credentials from the docker compose

  1. create admin user

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

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

  2. check page to see it's up

  3. element and profit

  4. 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

text
sudo apt update

Install Dependencies

text
sudo apt install software-properties-common

Add Ansible Repo

text
sudo add-apt-repository --yes --update ppa:ansible/ansible

Install Ansible

text
sudo apt install ansible

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

Edit Hosts File

text
sudo nano /etc/ansible/hosts

Fix SSH Key Permissions

text
chmod 600 ~/.ssh/ansible

Ansible Ping Command

text
ansible all -m ping

Create SSH Key

text
ssh-keygen -t ed25519 -C "ansible"

Copy SSH Key

text
ssh-copy-id -i ~/.ssh/ansible.pub 192.168.200.50

Ansible Ping Command With New SSH Key

text
ansible all -m ping --key-file ~/.ssh/ansible

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

Instructions Used In Video

K3S

bootstrap first node:

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

add agents:

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

Helm

text
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

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

helm install metallb metallb/metallb

then edit and apply the manifests:

text
kubectl apply -f ....

Authentik

create passwords:

text
pwgen -s 50 1

openssl rand 60 | base64 -w 0

set values in values.yaml - see example

text
nano values.yaml

deploy authentik:

text
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

text
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)
  2. 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
  1. Expand the VM disk size to a suitable size (suggested 10 GB)
bash
qm disk resize 5000 scsi0 10G
  1. Create the Cloud-Init template
  2. 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. text
    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. text
    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

  1. List the disks to format

sudo fdisk -l

  1. Format the disk

sudo mkfs -t ext4 /dev/sdx

  1. Mount the new disk to tmp folder

sudo mount /dev/sdx /tmp/folder

  1. 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

text
mkdir -p /etc/rancher/rke2

Create File for RKE2 - Config

text
sudo nano /etc/rancher/rke2/config.yaml

Add values

text
token: <ADD-TOKEN>
server: https://<ADD-VIP>:9345
node-label:
  - worker=true
  - longhorn=true

Install RKE2

text
sudo su
curl -sfL https://get.rke2.io | INSTALL_RKE2_TYPE="agent" sh -

Enable RKE2

text
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 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= 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

text
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

text
helm repo add rancher-latest https://releases.rancher.com/server-charts/latest
kubectl create namespace cattle-system

Install Cert-Manager

text
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

text
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

text
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:


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

Install CSI driver

text
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

text
kubectl create secret generic smbcreds --from-literal username=USERNAME --from-literal password="PASSWORD"

Create storage class

text
kubectl create -f https://raw.githubusercontent.com/kubernetes-csi/csi-driver-smb/master/deploy/example/storageclass-smb.yaml

Check status

text
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
as of Traefik v3 (released 29 April 2024) 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


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

text
helm upgrade rancher rancher-latest/rancher \
 --namespace cattle-system \
 --set hostname=rancher.my.org

Upgrade RKE2 (Each node, not Admin!)

text
sudo curl -sfL https://get.rke2.io | INSTALL_RKE2_CHANNEL=latest sh -

then servers:

text
sudo systemctl restart rke2-server

or agents

text
sudo systemctl restart rke2-agent

Upgrade K3S (Each node, not Admin!)

text
sudo curl -sfL https://get.k3s.io | INSTALL_K3S_CHANNEL=latest <EXISTING_K3S_ENV> sh -s - <EXISTING_K3S_ARGS>

then servers:

text
sudo systemctl restart k3s

or agents

text
sudo systemctl restart k3s-agent

Upgrade Longhorn

text
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)
text
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)
text
kubectl delete -f kube-vip
kubectl apply -f kube-vip

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

Find Device Numbers

text
ls -l /dev/dri

Find Group Numbers

text
cat /etc/group

Add Group Numbers Values to subgid

Change values to map the to above ^^

text
nano /etc/subgid

Paste at the bottom, for example:

text
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

text
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

text
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

text
groupadd -g 10000 lxc_shares

Optional: Add Other Users to Group (e.g., Jellyfin, Plex)

text
usermod -aG lxc_shares USERNAME

On Proxmox Host

Create a folder to mount the NAS

text
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

text
{ 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

text
mount /mnt/lxc_shares/nas_rwx

Add Bind Mount of the Share to the LXC Config

Be sure to change the LXC_ID

text
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
  1. Deploy the pod and the service using ยดkubectl apply -f deployment.yaml ยด
  2. If you want to access the GUI via Traefik you can add an ingress using ยดkubectl apply -f ingress.yaml ยด
  3. 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)

text
[all:vars]
ansible_user='ubuntu'
ansible_become=yes
ansible_become_method=sudo

--- METRICS ---