README.md
# Ubuntu Homelab Bootstrap
A complete Ubuntu homelab bootstrap project for turning an old laptop or mini PC into a full DevOps + personal media homelab.
This repository contains two scripts:
```text
bootstrap-homelab-k3s.sh # Base DevOps/K3s setup
bootstrap-homelab-full.sh # Full setup: DevOps + storage + Samba + Portainer + Jellyfin + Kavita + Homepage
```
The recommended script for a full fresh setup is:
```text
bootstrap-homelab-full.sh
```
---
## Project Goal
The goal of this project is to make a fresh Ubuntu Server ready for learning and daily homelab use with one repeatable script.
This project is built for:
```text
Gateway Laptop / old laptop / mini PC
Intel i5 10th Gen
256 GB SSD for OS
Optional 2 TB HDD for storage
Ubuntu Server
Static IP: 192.168.1.18
```
The idea is simple:
> Break things. Learn from them. Rebuild faster. Automate the boring parts.
---
## What the Full Script Installs
The full script installs and configures:
```text
Ubuntu updates and cleanup
Base Linux tools
Docker Engine
Docker Compose
K3s Kubernetes
kubectl
Helm
K9s
Cockpit web console
SSH server
UFW firewall
Fail2Ban
Automatic security updates
Static IP with Netplan
Cloud-init DHCP duplicate fix
Laptop lid close no-sleep setting
Custom login welcome message
Full installation logs
Homelab folders
Helper commands
Optional HDD wipe/format/mount
Samba Windows share
Portainer Docker UI
Homepage custom dashboard
Jellyfin personal Netflix
Kavita personal book/PDF/comic reader
Optional Uptime Kuma monitoring
```
---
## Homelab Architecture
```mermaid
flowchart TD
A[Windows PC / Main Laptop] -->|SSH| B[Homelab Server]
A -->|Browser| H[Homepage Custom UI]
A -->|Browser| P[Portainer]
A -->|Browser| J[Jellyfin]
A -->|Browser| K[Kavita]
A -->|Network Drive| S[Samba Storage]
B[Ubuntu Server<br/>192.168.1.18] --> D[Docker Engine]
B --> K3S[K3s Kubernetes]
B --> C[Cockpit]
B --> F[Firewall + Fail2Ban]
B --> HDD[Optional HDD<br/>/srv/storage]
D --> P
D --> H
D --> J
D --> K
D --> U[Optional Uptime Kuma]
HDD --> S
HDD --> M[Movies]
HDD --> BK[Books]
HDD --> BA[Backups]
```
---
## Bootstrap Flow
```mermaid
flowchart LR
A[Fresh Ubuntu Server] --> B[Download Script]
B --> C[Run Script]
C --> D[Update System]
D --> E[Install Base Tools]
E --> F[Configure Static IP]
F --> G[Install Docker]
G --> H[Install K3s]
H --> I[Optional Storage Setup]
I --> J[Install Docker Apps]
J --> K[Create Login Message]
K --> L[Save Logs]
L --> M[Reboot]
M --> N[Homelab Ready]
```
---
## Network Plan
```mermaid
flowchart TD
R[Home Router<br/>192.168.1.1] --> S[Homelab Server<br/>192.168.1.18]
R --> W[Windows PC]
R --> M[Mobile Devices]
W -->|SSH 22| S
W -->|Cockpit 9090| S
W -->|Homepage 3001| S
W -->|Jellyfin 8096| S
W -->|Kavita 5001| S
W -->|Portainer 9443| S
W -->|Samba Share| S
```
---
## Repository Structure
```text
homelab-bootstrap/
├── bootstrap-homelab-k3s.sh
├── bootstrap-homelab-full.sh
├── README.md
└── .gitattributes
```
---
## Main Script
Recommended full script:
```text
bootstrap-homelab-full.sh
```
Base script:
```text
bootstrap-homelab-k3s.sh
```
Use the full script when you want everything:
```text
DevOps base + storage + Samba + media apps + custom UI
```
Use the base script when you only want:
```text
Ubuntu + Docker + K3s + Cockpit + DevOps tools
```
---
## Important Warnings
### Static IP Warning
The script sets the server IP to:
```text
192.168.1.18/24
```
Before running the script, make sure this IP is not already used by another device.
Recommended:
1. Open your router admin page.
2. Check DHCP range.
3. Reserve `192.168.1.18` for your homelab laptop.
4. Use Ethernet if possible.
5. If using Wi-Fi, pass Wi-Fi details with environment variables.
### HDD Wipe Warning
The full script can wipe and format a storage HDD, but it does **not** do that by default.
The script will only wipe storage when you explicitly pass:
```text
CONFIGURE_STORAGE=true
WIPE_STORAGE=true
STORAGE_DISK=/dev/sdb
```
Never use HDD wipe mode unless you are 100% sure the disk is correct.
Usually:
```text
/dev/sda = Ubuntu SSD = DO NOT TOUCH
/dev/sdb = External HDD = safe only after confirming
```
Check disks first:
```bash
lsblk -o NAME,SIZE,TYPE,FSTYPE,MOUNTPOINTS,MODEL
```
---
## Default Settings
| Setting | Default |
|---|---|
| Hostname | `walia-homelab` |
| Static IP | `192.168.1.18/24` |
| Gateway | `192.168.1.1` |
| DNS 1 | `1.1.1.1` |
| DNS 2 | `8.8.8.8` |
| Timezone | `Asia/Kolkata` |
| Main user | Detected automatically from sudo user |
| Storage mount | `/srv/storage` |
| Samba share | `HomelabStorage` |
| Docker apps path | `/opt/homelab/compose/media-stack` |
| App data path | `/srv/storage/appdata` |
---
## Full Steps to Launch on a Fresh Wi-Fi Ubuntu Server
These are the recommended steps for a normal run **without HDD wipe**.
### Step 1: SSH into the server
From Windows PowerShell:
```powershell
ssh yourusername@CURRENT_SERVER_IP
```
Example:
```powershell
ssh lw@192.168.1.7
```
### Step 2: Check current server details
Run on Ubuntu:
```bash
whoami
pwd
ip -br addr
lsb_release -a
```
### Step 3: Download the full script
```bash
cd ~
curl -fsSL https://raw.githubusercontent.com/lakshaywalia666/homelab-bootstrap/main/bootstrap-homelab-full.sh -o bootstrap-homelab-full.sh
```
### Step 4: Make it executable
```bash
chmod +x bootstrap-homelab-full.sh
```
### Step 5: Run without HDD wipe
Replace `YOUR_WIFI_PASSWORD` with your Wi-Fi password.
```bash
sudo env WIFI_SSID="Bedroom" WIFI_PASSWORD="YOUR_WIFI_PASSWORD" bash ./bootstrap-homelab-full.sh
```
This is the safest normal run.
It will install the homelab system and Docker apps, but it will **not wipe any HDD**.
### Step 6: Wait for reboot
The script may reboot automatically.
Your SSH connection may disconnect when:
```text
Static IP changes to 192.168.1.18
Server reboots
```
This is normal.
### Step 7: Reconnect after reboot
```bash
ssh yourusername@192.168.1.18
```
Example:
```bash
ssh lw@192.168.1.18
```
---
## Run with Wi-Fi Variables in Two Commands
If you do not want to put Wi-Fi password in the same command, use this method.
### Step 1: Set Wi-Fi name
```bash
export WIFI_SSID="Bedroom"
```
### Step 2: Enter Wi-Fi password safely
```bash
read -s -p "Enter WiFi password: " WIFI_PASSWORD; echo; export WIFI_PASSWORD
```
### Step 3: Run script while preserving Wi-Fi variables
```bash
sudo --preserve-env=WIFI_SSID,WIFI_PASSWORD bash ./bootstrap-homelab-full.sh
```
---
## Run with Samba Password Automated
If you want the Samba Windows share user password to be created automatically, use:
```bash
sudo env WIFI_SSID="Bedroom" WIFI_PASSWORD="YOUR_WIFI_PASSWORD" SAMBA_PASSWORD="YOUR_SAMBA_PASSWORD" bash ./bootstrap-homelab-full.sh
```
If `SAMBA_PASSWORD` is not provided, the script will not create a Samba password automatically. You can set it manually later:
```bash
sudo smbpasswd -a lw
sudo smbpasswd -e lw
```
---
## Run with HDD Wipe and Mount Included
Only use this when you are 100% sure your HDD is `/dev/sdb`.
First check:
```bash
lsblk -o NAME,SIZE,TYPE,FSTYPE,MOUNTPOINTS,MODEL
```
Example expected output:
```text
sda 238.5G FORESEE 256GB SS Ubuntu SSD
sdb 1.8T One Touch w/PW External HDD
```
Then run:
```bash
sudo env WIFI_SSID="Bedroom" WIFI_PASSWORD="YOUR_WIFI_PASSWORD" CONFIGURE_STORAGE=true WIPE_STORAGE=true STORAGE_DISK="/dev/sdb" bash ./bootstrap-homelab-full.sh
```
This will erase `/dev/sdb`, create one ext4 partition, mount it at:
```text
/srv/storage
```
and create folders:
```text
/srv/storage/Movies
/srv/storage/Books/Ebooks
/srv/storage/Books/Comics
/srv/storage/Books/PDFs
/srv/storage/Backups
/srv/storage/Projects
/srv/storage/Shared
/srv/storage/ISO
/srv/storage/Downloads
```
---
## Run Without Storage Setup
This is the normal safe option:
```bash
sudo env WIFI_SSID="Bedroom" WIFI_PASSWORD="YOUR_WIFI_PASSWORD" CONFIGURE_STORAGE=false WIPE_STORAGE=false bash ./bootstrap-homelab-full.sh
```
If `/srv/storage` already exists, apps will use it.
If it does not exist, the script will create folders on the OS disk.
---
## Run Without Auto Reboot
If you want to inspect everything before reboot:
```bash
sudo env WIFI_SSID="Bedroom" WIFI_PASSWORD="YOUR_WIFI_PASSWORD" AUTO_REBOOT=false bash ./bootstrap-homelab-full.sh
```
Then reboot manually:
```bash
sudo reboot
```
---
## Run Base Script Only
If you only want Docker + K3s + Cockpit + DevOps tools:
```bash
cd ~
curl -fsSL https://raw.githubusercontent.com/lakshaywalia666/homelab-bootstrap/main/bootstrap-homelab-k3s.sh -o bootstrap-homelab-k3s.sh
chmod +x bootstrap-homelab-k3s.sh
sudo env WIFI_SSID="Bedroom" WIFI_PASSWORD="YOUR_WIFI_PASSWORD" bash ./bootstrap-homelab-k3s.sh
```
---
## Installed URLs After Full Script
After the full script completes, open these from your Windows browser:
| App | URL | Purpose |
|---|---|---|
| Homepage | `http://192.168.1.18:3001` | Custom homelab dashboard |
| Jellyfin | `http://192.168.1.18:8096` | Personal Netflix |
| Kavita | `http://192.168.1.18:5001` | Books/PDF/comic reader |
| Portainer | `https://192.168.1.18:9443` | Docker control panel |
| Cockpit | `https://192.168.1.18:9090` | Ubuntu server web console |
| Uptime Kuma | `http://192.168.1.18:3002` | Optional monitoring |
| Samba | `\\192.168.1.18\HomelabStorage` | Windows network drive |
---
## App Setup After Installation
### Portainer
Open:
```text
https://192.168.1.18:9443
```
Create admin account.
Use local Docker environment.
Browser certificate warning is normal for local HTTPS.
### Homepage
Open:
```text
http://192.168.1.18:3001
```
This is the custom UI for your homelab.
### Jellyfin
Open:
```text
http://192.168.1.18:8096
```
Recommended setup:
```text
Server name: WaliaFlix
Language: English
Country/Region: India
Library type: Movies
Folder: /media/movies
Remote connections: ON for home network
Automatic port mapping: OFF
```
Put movies from Windows here:
```text
Z:\Movies
```
Jellyfin sees that as:
```text
/media/movies
```
### Kavita
Open:
```text
http://192.168.1.18:5001
```
Create admin account.
Add libraries:
```text
Name: PDFs
Type: Book
Folder: /pdfs
Name: Ebooks
Type: Book
Folder: /books
Name: Comics
Type: Comic
Folder: /comics
```
Put files from Windows here:
```text
Z:\Books\PDFs
Z:\Books\Ebooks
Z:\Books\Comics
```
Container mappings:
```text
Z:\Books\PDFs -> /pdfs
Z:\Books\Ebooks -> /books
Z:\Books\Comics -> /comics
```
### Samba Storage
Windows path:
```text
\\192.168.1.18\HomelabStorage
```
Suggested mapping:
```text
Drive letter: Z:
Folder: \\192.168.1.18\HomelabStorage
Reconnect at sign-in: yes
```
---
## Storage Layout
```text
/srv/storage/
├── appdata/
│ ├── homepage/
│ ├── jellyfin/
│ ├── kavita/
│ ├── portainer/
│ └── uptime-kuma/
├── Movies/
├── Books/
│ ├── Ebooks/
│ ├── Comics/
│ └── PDFs/
├── Backups/
├── Projects/
├── Shared/
├── ISO/
└── Downloads/
```
---
## Docker Compose Stack
The full script creates a compose stack here:
```text
/opt/homelab/compose/media-stack/docker-compose.yml
```
Services:
```text
homepage
jellyfin
kavita
portainer
uptime-kuma
```
Common commands:
```bash
cd /opt/homelab/compose/media-stack
sudo docker compose ps
sudo docker compose logs -f
sudo docker compose up -d
sudo docker compose restart
sudo docker compose pull
```
Restart one app:
```bash
sudo docker compose restart jellyfin
sudo docker compose restart kavita
sudo docker compose restart homepage
```
---
## Logs
The script saves full terminal output here:
```text
/var/log/lw-homelab-bootstrap/
```
Latest log:
```text
/var/log/lw-homelab-bootstrap/latest.log
```
View logs:
```bash
sudo less /var/log/lw-homelab-bootstrap/latest.log
```
Or use:
```bash
homelab-logs
```
Shortcut:
```bash
hllogs
```
---
## Helper Commands
After install, these commands are available:
| Command | Purpose |
|---|---|
| `homelab-info` | Show full server summary |
| `hlinfo` | Shortcut for homelab info |
| `homelab-logs` | Open latest bootstrap log |
| `hllogs` | Shortcut for logs |
| `update-homelab` | Update server and save update log |
| `ports` | Show listening ports |
| `dps` | Show Docker containers |
| `kgn` | Show Kubernetes nodes |
| `kgp` | Show Kubernetes pods |
| `kgs` | Show Kubernetes services |
| `media-stack-status` | Show Docker media stack status |
| `media-stack-logs` | Follow media stack logs |
| `storage-info` | Show storage mount and usage |
---
## Useful Checks After Reboot
### Check IP
```bash
ip -br addr
```
Expected:
```text
wlo1 UP 192.168.1.18/24
```
### Check services
```bash
systemctl is-active docker k3s cockpit.socket ssh smbd
```
Expected:
```text
active
active
active
active
active
```
### Check Kubernetes
```bash
kubectl get nodes -o wide
kubectl get pods -A
```
Expected:
```text
Node should be Ready
K3s pods should be Running or Completed
```
### Check Docker apps
```bash
cd /opt/homelab/compose/media-stack
sudo docker compose ps
```
Expected apps:
```text
homepage
jellyfin
kavita
portainer
uptime-kuma
```
### Check storage
```bash
df -h /srv/storage
ls -lah /srv/storage
```
---
## Troubleshooting
### SSH not working after script
From Windows:
```powershell
ping 192.168.1.18
ssh lw@192.168.1.18
```
On the server screen:
```bash
ip -br addr
sudo systemctl status ssh
sudo ufw status
```
### Server has two IPs
If you see both old DHCP IP and static IP, check Netplan files:
```bash
ls -lah /etc/netplan
```
Disable old cloud-init DHCP file:
```bash
sudo mkdir -p /root/netplan-disabled
sudo cp /etc/netplan/50-cloud-init.yaml /root/netplan-disabled/50-cloud-init.yaml.backup
sudo mv /etc/netplan/50-cloud-init.yaml /etc/netplan/50-cloud-init.yaml.disabled
sudo tee /etc/cloud/cloud.cfg.d/99-disable-network-config.cfg > /dev/null <<'EOF'
network: {config: disabled}
EOF
sudo netplan generate
sudo netplan apply
```
### Docker permission denied
Reboot first.
Then check:
```bash
groups
docker ps
```
If still not working:
```bash
sudo usermod -aG docker $USER
sudo reboot
```
### K3s not ready
```bash
sudo systemctl status k3s
sudo journalctl -u k3s -f
kubectl get nodes -o wide
kubectl get pods -A
```
### Cockpit not opening
```bash
sudo systemctl status cockpit.socket
sudo ufw status
sudo ufw allow 9090/tcp
sudo systemctl restart cockpit.socket
```
Open:
```text
https://192.168.1.18:9090
```
### Portainer not opening
```bash
sudo docker ps | grep portainer
sudo docker logs portainer --tail=80
sudo ufw allow 9443/tcp
```
Open:
```text
https://192.168.1.18:9443
```
### Jellyfin not opening
```bash
sudo docker ps | grep jellyfin
sudo docker logs jellyfin --tail=80
sudo ufw allow 8096/tcp
```
Open:
```text
http://192.168.1.18:8096
```
### Kavita not opening
```bash
sudo docker ps | grep kavita
sudo docker logs kavita --tail=80
sudo ufw allow 5001/tcp
```
Open:
```text
http://192.168.1.18:5001
```
### Kavita cannot see books
Check host folders:
```bash
ls -lah /srv/storage/Books/Ebooks
ls -lah /srv/storage/Books/PDFs
ls -lah /srv/storage/Books/Comics
```
Check container folders:
```bash
sudo docker exec -it kavita ls -lah /books
sudo docker exec -it kavita ls -lah /pdfs
sudo docker exec -it kavita ls -lah /comics
```
Correct mapping:
```text
/srv/storage/Books/Ebooks -> /books
/srv/storage/Books/PDFs -> /pdfs
/srv/storage/Books/Comics -> /comics
```
### Samba not working from Windows
Check service:
```bash
systemctl is-active smbd
sudo testparm
sudo ufw status
```
Allow Samba:
```bash
sudo ufw allow Samba
sudo systemctl restart smbd
```
Windows path:
```text
\\192.168.1.18\HomelabStorage
```
Username:
```text
lw
```
or:
```text
192.168.1.18\lw
```
### HDD showing 100 GB used after formatting
This is usually ext4 reserved space.
Check:
```bash
sudo tune2fs -l /dev/sdb1 | grep -E "Block count|Reserved block count|Block size"
```
Reduce reserved space to 1%:
```bash
sudo tune2fs -m 1 /dev/sdb1
df -h /srv/storage
```
For maximum usable media storage, you can set it to 0%:
```bash
sudo tune2fs -m 0 /dev/sdb1
```
---
## Updating the GitHub Repo
From Windows PowerShell:
```powershell
cd D:\Projects\homelab-bootstrap
git status
git add README.md bootstrap-homelab-full.sh bootstrap-homelab-k3s.sh
git commit -m "Update full homelab bootstrap documentation"
git push
```
If only README changed:
```powershell
git add README.md
git commit -m "Update README with full homelab launch steps"
git push
```
---
## Recommended Next Apps
After this full setup, useful next apps are:
```mermaid
mindmap
root((Mr Walia Homelab))
Monitoring
Uptime Kuma
Prometheus
Grafana
Media
Jellyfin
Immich
Books
Kavita
Paperless-ngx
DevOps
Gitea
Jenkins
GitHub Runner
Argo CD
Network
AdGuard Home
Nginx Proxy Manager
Tailscale
Security
Vaultwarden
SSH Keys
Backups
```
Recommended next order:
```text
1. Uptime Kuma
2. Immich
3. Paperless-ngx
4. Gitea
5. Prometheus + Grafana
6. Nginx Proxy Manager or Caddy
7. Tailscale
8. Vaultwarden
```
---
## Security Notes
This setup is designed for a private home network.
Do not expose apps directly to the public internet without learning:
```text
HTTPS
Reverse proxy
Firewall rules
VPN
Authentication
Backups
Updates
```
For remote access, prefer:
```text
Tailscale
WireGuard
Cloudflare Tunnel
```
Do not open SSH, Portainer, Jellyfin, Kavita, or Cockpit directly to the internet.
---
## Author
```text
Lakshay Walia
GitHub: lakshaywalia666
Project: Mr Walia DevOps Homelab
```
---
## License
Personal homelab learning project.
Use, modify, break, rebuild, and improve.