diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..8d58032 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,95 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Project Overview + +This is a personal homelab setup repository documenting the migration from cloud services to self-hosted solutions on a ThinkPad running Arch Linux. The project uses Docker for containerized services behind an Nginx reverse proxy. + +## Architecture + +### Network Infrastructure +- **Domain**: ak-homelab.duckdns.org (DuckDNS dynamic DNS) +- **Static IP**: 192.168.0.100 (dual interface: ethernet enp4s0, WiFi wlp1s0) +- **SSH**: Custom port 2222 for system access +- **Reverse Proxy**: Nginx for path-based routing to services + +### Service Architecture +``` +Internet → Router → Nginx (80/443) → Services + → SSH (2222) → System + → Gitea SSH (2223) → Git operations +``` + +**Current Services:** +- Gitea Git server: Docker container on port 3000, accessible via `/gitea/` path +- Nginx: Reverse proxy routing to `ak-homelab.duckdns.org/servicename/` + +### Configuration Management + +All configurations are version controlled in the `config/` directory: +- `config/docker/gitea/`: Gitea container setup and deployment scripts +- `config/nginx/`: Reverse proxy configurations +- `config/scripts/`: Utility scripts for system maintenance + +Configuration files include deployment instructions in comments showing target locations (e.g., `/opt/docker/gitea/`, `/etc/nginx/sites-available/`). + +## Key Commands + +### Docker Service Management +```bash +# Gitea operations (from /opt/docker/gitea/) +docker-compose logs gitea # View logs +docker-compose down # Stop +docker-compose up -d # Start +docker-compose pull && docker-compose up -d # Update + +# Deploy from repo +sudo cp config/docker/gitea/docker-compose.yml /opt/docker/gitea/ +``` + +### Nginx Operations +```bash +# Deploy configuration +sudo cp config/nginx/homelab.conf /etc/nginx/sites-available/homelab +sudo ln -s /etc/nginx/sites-available/homelab /etc/nginx/sites-enabled/homelab + +# Management +sudo nginx -t # Test config +sudo systemctl reload nginx # Reload +sudo systemctl status nginx # Status +``` + +### SSL Certificate Management +```bash +sudo certbot --nginx -d ak-homelab.duckdns.org +sudo systemctl enable certbot.timer # Auto-renewal +``` + +## Development Workflow + +### Task Tracking +Use `TODO.md` for centralized task management organized by category (Network & Security, Git & Development, System Configuration, etc.). Mark completed items and update status in documentation. + +### Configuration Changes +1. Edit files in `config/` directory +2. Test locally when possible +3. Deploy to target locations with sudo commands included in file headers +4. Update documentation status in `docs/services.md` +5. Commit changes with logical separation + +### Documentation Structure +- `docs/`: Technical documentation for setup procedures +- `README.md`: Overview and current status +- `TODO.md`: Active task tracking +- Configuration files self-document deployment locations in headers + +### Network Configuration Notes +- System uses dual ethernet ports (enp3s0f0, enp4s0) - stick to enp4s0 consistently +- Port conflicts: SSH (2222), Gitea SSH (2223), Gitea Web (3000) +- Router forwarding: HTTP (80), HTTPS (443), SSH (2222), Git SSH (2223) + +### Service URLs +- **Local access**: http://192.168.0.100/servicename/ +- **External access**: http://ak-homelab.duckdns.org/servicename/ +- **Gitea SSH**: ssh://git@ak-homelab.duckdns.org:2223 \ No newline at end of file diff --git a/README.md b/README.md index 5c63bf0..c27c046 100644 --- a/README.md +++ b/README.md @@ -7,9 +7,9 @@ Setting up a personal homelab using a ThinkPad laptop running Arch Linux to move - [x] Linux installation (Arch Linux on ThinkPad) - [x] SSH remote access (hostname: homelab) - [x] Dotfiles and development environment setup -- [ ] Network domain setup +- [x] Network domain setup - [ ] Self-hosted cloud storage (ownCloud/Nextcloud) -- [ ] Self-hosted git repository (Gitea/Forgejo/GitLab) +- [x] Self-hosted git repository (Gitea/Forgejo/GitLab) - [ ] Gradual migration from commercial cloud services ## Hardware @@ -27,25 +27,45 @@ Setting up a personal homelab using a ThinkPad laptop running Arch Linux to move - ✅ SSH access configured (accessible as `homelab`) - ✅ Dotfiles management with yadm configured and merged - ✅ Development environment setup completed -- Next: Network domain setup and self-hosted services +- ✅ Network domain setup (DuckDNS + Nginx reverse proxy) +- ✅ Gitea Git server running (Docker container) +- Next: SSL certificates, additional self-hosted services ## Documentation Structure ### Quick Start Guide -1. **System Setup**: Follow [system-setup.md](system-setup.md) for Arch installation and configuration -2. **Network Security**: Configure SSH, DNS, and VPN using [network-security.md](network-security.md) -3. **Services**: Plan and deploy applications from [services.md](services.md) +1. **System Setup**: Follow [docs/system-setup.md](docs/system-setup.md) for Arch installation and configuration +2. **Network Security**: Configure SSH, DNS, and VPN using [docs/network-security.md](docs/network-security.md) +3. **Services**: Plan and deploy applications from [docs/services.md](docs/services.md) 4. **Tasks**: Track progress in [TODO.md](TODO.md) -5. **Issues**: Find solutions in [troubleshooting.md](troubleshooting.md) +5. **Issues**: Find solutions in [docs/troubleshooting.md](docs/troubleshooting.md) + +### Repository Structure +``` +homelab/ +├── README.md # This overview +├── TODO.md # Task tracking +├── docs/ # Detailed documentation +│ ├── system-setup.md # Arch Linux installation & config +│ ├── network-security.md # SSH, DNS, VPN, firewall +│ ├── services.md # Self-hosted services +│ └── troubleshooting.md # Solutions & fixes +└── config/ # Configurations & scripts + ├── docker/gitea/ # Gitea container setup + ├── nginx/ # Reverse proxy configs + └── scripts/ # Utility scripts +``` ### Documentation Files -- **[system-setup.md](system-setup.md)** - Complete Arch Linux installation, TTY config, desktop setup -- **[network-security.md](network-security.md)** - SSH hardening, DuckDNS, WireGuard VPN, firewall setup -- **[services.md](services.md)** - Self-hosted services: Git hosting, cloud storage, media server +- **[docs/system-setup.md](docs/system-setup.md)** - Complete Arch Linux installation, TTY config, desktop setup +- **[docs/network-security.md](docs/network-security.md)** - SSH hardening, DuckDNS, WireGuard VPN, firewall setup +- **[docs/services.md](docs/services.md)** - Self-hosted services: Git hosting, cloud storage, media server - **[TODO.md](TODO.md)** - Centralized task list with progress tracking by category -- **[troubleshooting.md](troubleshooting.md)** - Hardware issues, software problems, and solutions +- **[docs/troubleshooting.md](docs/troubleshooting.md)** - Hardware issues, software problems, and solutions ### Current Configuration - **System**: Arch Linux with XFCE desktop, ter-124b TTY font, Colemak layout -- **Security**: SSH hardened, DuckDNS configured (ak-homelab.duckdns.org) +- **Network**: Static IP (192.168.0.100), SSH port 2222, DuckDNS (ak-homelab.duckdns.org) +- **Services**: Nginx reverse proxy, Gitea Git server (Docker) +- **Security**: SSH hardened, firewall planned, SSL certificates pending - **Development**: yadm dotfiles, tmux with temperature monitoring, zsh with proper history diff --git a/config/docker/gitea/docker-compose.yml b/config/docker/gitea/docker-compose.yml new file mode 100644 index 0000000..c622e07 --- /dev/null +++ b/config/docker/gitea/docker-compose.yml @@ -0,0 +1,26 @@ +# DEPLOYMENT LOCATION: /opt/docker/gitea/docker-compose.yml +# Move this file with: sudo cp gitea-docker-compose.yml /opt/docker/gitea/docker-compose.yml +# Create data directory: sudo mkdir -p /opt/docker/gitea/data +# Set permissions: sudo chown -R hoborg:hoborg /opt/docker/gitea + +networks: + gitea: + external: false + +services: + server: + image: gitea/gitea:latest + container_name: gitea + environment: + - USER_UID=1000 + - USER_GID=1000 + restart: always + networks: + - gitea + volumes: + - ./data:/data + - /etc/timezone:/etc/timezone:ro + - /etc/localtime:/etc/localtime:ro + ports: + - "3000:3000" + - "2223:22" \ No newline at end of file diff --git a/config/docker/gitea/setup.sh b/config/docker/gitea/setup.sh new file mode 100644 index 0000000..f458ff1 --- /dev/null +++ b/config/docker/gitea/setup.sh @@ -0,0 +1,40 @@ +#!/bin/bash +# Gitea Docker Setup Script +# Run with: sudo bash gitea-setup.sh + +set -e + +echo "Setting up Gitea Docker environment..." + +# Create directory structure +echo "Creating /opt/docker/gitea directory..." +mkdir -p /opt/docker/gitea/data + +# Copy docker-compose file +echo "Copying docker-compose.yml..." +cp gitea-docker-compose.yml /opt/docker/gitea/docker-compose.yml + +# Set correct permissions +echo "Setting permissions..." +chown -R hoborg:hoborg /opt/docker/gitea + +# Start Gitea +echo "Starting Gitea container..." +cd /opt/docker/gitea +docker-compose up -d + +echo "" +echo "✅ Gitea setup complete!" +echo "" +echo "🌐 Web interface: http://192.168.0.100:3000" +echo "🌍 External access: http://ak-homelab.duckdns.org:3000 (after router port forwarding)" +echo "" +echo "📋 Next steps:" +echo "1. Configure router port forwarding: 3000 → 192.168.0.100:3000" +echo "2. Access web interface to complete initial setup" +echo "3. Configure admin user and repository settings" +echo "" +echo "🔧 Container management:" +echo " View logs: docker logs gitea" +echo " Stop: docker-compose down" +echo " Update: docker-compose pull && docker-compose up -d" \ No newline at end of file diff --git a/config/nginx/homelab.conf b/config/nginx/homelab.conf new file mode 100644 index 0000000..e5b26a1 --- /dev/null +++ b/config/nginx/homelab.conf @@ -0,0 +1,55 @@ +# DEPLOYMENT LOCATION: /etc/nginx/sites-available/homelab +# Deploy with: sudo cp nginx-homelab.conf /etc/nginx/sites-available/homelab +# Enable with: sudo ln -s /etc/nginx/sites-available/homelab /etc/nginx/sites-enabled/homelab + +server { + listen 80; + server_name ak-homelab.duckdns.org; + + # Security headers + add_header X-Frame-Options "SAMEORIGIN" always; + add_header X-Content-Type-Options "nosniff" always; + add_header X-XSS-Protection "1; mode=block" always; + + # Main landing page + location / { + root /var/www/homelab; + index index.html index.htm; + try_files $uri $uri/ =404; + } + + # Gitea reverse proxy + location /gitea/ { + proxy_pass http://127.0.0.1:3000/; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + + # Handle websockets for live updates + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + + # Increase timeout for large repos + proxy_connect_timeout 60s; + proxy_send_timeout 60s; + proxy_read_timeout 60s; + } + + # Future services (commented out for now) + # location /cloud/ { + # proxy_pass http://127.0.0.1:8080/; + # proxy_set_header Host $host; + # proxy_set_header X-Real-IP $remote_addr; + # proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + # proxy_set_header X-Forwarded-Proto $scheme; + # } + + # location /media/ { + # proxy_pass http://127.0.0.1:8096/; + # proxy_set_header Host $host; + # proxy_set_header X-Real-IP $remote_addr; + # proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + # proxy_set_header X-Forwarded-Proto $scheme; + # } +} \ No newline at end of file diff --git a/config/nginx/setup.sh b/config/nginx/setup.sh new file mode 100644 index 0000000..51031c3 --- /dev/null +++ b/config/nginx/setup.sh @@ -0,0 +1,60 @@ +#!/bin/bash +# Nginx Setup Script for Homelab +# Run with: sudo bash nginx-setup.sh + +set -e + +echo "Setting up Nginx reverse proxy..." + +# Install nginx and SSL tools +echo "Installing nginx and certbot..." +pacman -S --noconfirm nginx certbot certbot-nginx + +# Create sites directories (some distributions don't have these) +mkdir -p /etc/nginx/sites-available +mkdir -p /etc/nginx/sites-enabled + +# Enable sites-enabled in main nginx.conf if not already +if ! grep -q "sites-enabled" /etc/nginx/nginx.conf; then + echo "Adding sites-enabled include to nginx.conf..." + sed -i '/http {/a \ \ \ \ include /etc/nginx/sites-enabled/*;' /etc/nginx/nginx.conf +fi + +# Copy site configuration +echo "Copying site configuration..." +cp nginx-homelab.conf /etc/nginx/sites-available/homelab + +# Enable the site +echo "Enabling homelab site..." +ln -sf /etc/nginx/sites-available/homelab /etc/nginx/sites-enabled/homelab + +# Create web root directory +echo "Creating web root directory..." +mkdir -p /var/www/homelab +chown -R hoborg:hoborg /var/www/homelab + +# Test nginx configuration +echo "Testing nginx configuration..." +nginx -t + +# Enable and start nginx +echo "Starting nginx service..." +systemctl enable nginx +systemctl start nginx + +echo "" +echo "✅ Nginx setup complete!" +echo "" +echo "📋 Next steps:" +echo "1. Create landing page: sudo nvim /var/www/homelab/index.html" +echo "2. Configure router port forwarding:" +echo " - Port 80 → 192.168.0.100:80" +echo " - Port 443 → 192.168.0.100:443" +echo " - Remove port 3000 forwarding" +echo "3. Test access: http://ak-homelab.duckdns.org/" +echo "4. Set up SSL: sudo certbot --nginx -d ak-homelab.duckdns.org" +echo "" +echo "🔧 Management commands:" +echo " Test config: sudo nginx -t" +echo " Reload: sudo systemctl reload nginx" +echo " Status: sudo systemctl status nginx" diff --git a/docs/network-security.md b/docs/network-security.md new file mode 100644 index 0000000..958952d --- /dev/null +++ b/docs/network-security.md @@ -0,0 +1,488 @@ +# Network & Security Configuration + +Complete guide for securing and networking your homelab. + +## SSH Security Setup + +### Initial Configuration +```bash +# Generate SSH key pair +ssh-keygen -t ed25519 -C "homelab-key" -f ~/.ssh/homelab_ed25519 + +# Copy public key to target +ssh-copy-id -i ~/.ssh/homelab_ed25519.pub user@target +``` + +### SSH Hardening + +**Status:** ✅ **Complete** - Port changed to 2222 + +Edit `/etc/ssh/sshd_config`: +``` +# Disable root login +PermitRootLogin no + +# Use key-based authentication only +PasswordAuthentication no +PubkeyAuthentication yes + +# Change default port (CRITICAL - currently still on 22) +Port 2222 + +# Restrict users +AllowUsers hoborg + +# Security settings +Protocol 2 +X11Forwarding no +AllowTcpForwarding no +ClientAliveInterval 300 +ClientAliveCountMax 2 +MaxAuthTries 3 +MaxStartups 2 +``` + +**Completed:** +1. ✅ Changed SSH port from 22 to 2222 +2. ✅ Updated router port forwarding rules +3. ✅ External access via ak-homelab.duckdns.org:2222 working + +Restart SSH: `sudo systemctl restart sshd` + +### Mosh Alternative (Investigation Needed) + +**Issue:** SSH can be unreliable on WiFi connections with packet loss. + +**Mosh Benefits:** +- Maintains connection during network switches (ethernet ↔ WiFi) +- Handles poor WiFi connections better +- Local echo for responsive typing +- Roaming support (IP changes don't break connection) + +**Installation:** +```bash +# Server side +sudo pacman -S mosh + +# Client side +mosh user@server +``` + +**Requirements:** +- UDP ports 60000-61000 open on router +- SSH still needed for initial authentication + +**Status:** ✅ **Local use working** ❌ **External blocked by ISP** + +**Key Findings:** +- **Local mosh**: Works perfectly (`mosh localhost`, `mosh 192.168.0.100`) +- **External mosh**: Blocked by ISP UDP port filtering on ports 60000-61000 +- **SSH still needed**: Mosh uses SSH for initial authentication, then switches to UDP + +**ISP UDP Blocking Issue:** +- Most ISPs block UDP ports 60000-61000 for "security" +- SSH works fine (TCP port 2222) but mosh fails (UDP 60000-61000) +- Router port forwarding is correct, but ISP drops UDP packets + +**Current Recommendation:** +- Use mosh for local/internal network connections +- Stick with SSH for external connections until VPN is set up +- VPN tunnel can bypass ISP UDP blocking + +### SSH Client Configuration +Create `~/.ssh/config`: +``` +Host homelab + HostName ak-homelab.duckdns.org + User hoborg + Port 2222 + IdentityFile ~/.ssh/homelab_ed25519 + ServerAliveInterval 60 +``` + +**Usage:** +```bash +# Connect via SSH +ssh homelab + +# Connect via Mosh (uses SSH config automatically) +mosh homelab +``` + +## Dynamic DNS with DuckDNS + +### Account Setup +1. Create account at duckdns.org +2. Create subdomain: `ak-homelab.duckdns.org` +3. Get token from dashboard + +### Automatic IP Updates +Update script at `~/.local/scripts/duckdns.py` (Python implementation) + +Cron job for automatic updates: +```bash +# Update every 5 minutes +*/5 * * * * /home/hoborg/.local/scripts/duckdns.py >/dev/null 2>&1 +``` + +### Current Setup (Router-based) + +**Status:** ✅ **Migrated from script to router DynDNS** + +**Changes made:** +- ✅ Disabled cron job script (`*/5 * * * *` entry removed) +- ✅ Enabled router Dynamic DNS for ak-homelab.duckdns.org +- ⏳ **Testing pending** - Cannot force public IP change to verify + +**Router DynDNS Benefits:** +- Immediate updates on IP change (vs 5-minute delay) +- Works when server is down +- Lower resource usage + +**Limitations:** +- Likely IPv4-only (Sagemcom router limitation) +- Less control over update process + +### Testing +```bash +# Check current IP +curl -s https://ipinfo.io/ip + +# Verify DNS resolution +nslookup ak-homelab.duckdns.org + +# Check IPv6 (likely not updated by router) +nslookup -type=AAAA ak-homelab.duckdns.org +``` + +**Testing will occur naturally when ISP changes public IP address.** + +## VPN Setup with WireGuard + +### What is WireGuard? +WireGuard is a modern, lightweight VPN protocol that creates secure tunnels between devices. It encrypts all network traffic and routes it through a VPN server, making your internet connection private and secure. + +**Key benefits:** +- **Privacy**: Hides your IP address and encrypts traffic +- **Security**: Protects against man-in-the-middle attacks on public WiFi +- **Access**: Bypass geo-restrictions and enables remote homelab access +- **Performance**: Much faster than OpenVPN with lower battery drain +- **Simplicity**: Easy to configure compared to other VPN protocols + +**When you need VPN:** +- Accessing homelab remotely over internet +- Working from public WiFi frequently +- Need to bypass ISP restrictions +- Running public-facing services + +**Costs:** WireGuard itself is free. Self-hosted VPN costs $5-20/month for VPS hosting. + +**Use cases:** +- Access homelab services remotely (SSH, web interfaces, file shares) +- Secure connection on public WiFi +- Bypass ISP restrictions or geo-blocks + +**Performance:** Much faster and lighter than OpenVPN, better battery life on mobile devices. + +### Server Configuration +Install WireGuard: `pacman -S wireguard-tools` + +Generate keys: +```bash +wg genkey | tee server_private.key | wg pubkey > server_public.key +``` + +Server config `/etc/wireguard/wg0.conf`: +```ini +[Interface] +PrivateKey = +Address = 10.0.0.1/24 +ListenPort = 51820 +PostUp = iptables -A FORWARD -i %i -j ACCEPT; iptables -A FORWARD -o %i -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE +PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -D FORWARD -o %i -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE + +[Peer] +PublicKey = +AllowedIPs = 10.0.0.2/32 +``` + +### Client Configuration +Generate client keys: +```bash +wg genkey | tee client_private.key | wg pubkey > client_public.key +``` + +Client config: +```ini +[Interface] +PrivateKey = +Address = 10.0.0.2/24 +DNS = 1.1.1.1 + +[Peer] +PublicKey = +Endpoint = ak-homelab.duckdns.org:51820 +AllowedIPs = 0.0.0.0/0 +PersistentKeepalive = 25 +``` + +### Enable VPN +```bash +sudo systemctl enable wg-quick@wg0 +sudo systemctl start wg-quick@wg0 +``` + +## Firewall Configuration + +### UFW (Uncomplicated Firewall) + +**What it does:** Controls what network traffic is allowed in/out of your server. + +**Key functions:** +- **Default deny**: Blocks all incoming connections by default +- **Port control**: Open only specific ports you need (SSH, HTTP, etc.) +- **Rate limiting**: Prevent brute force attacks +- **Application profiles**: Pre-configured rules for common services + +**Why needed:** Without firewall, all services are exposed to network attacks. + +### UFW Setup +```bash +# Install and enable UFW +pacman -S ufw +sudo ufw enable + +# Default policies +sudo ufw default deny incoming +sudo ufw default allow outgoing + +# SSH access +sudo ufw allow 2222/tcp + +# WireGuard +sudo ufw allow 51820/udp + +# HTTP/HTTPS for services +sudo ufw allow 80/tcp +sudo ufw allow 443/tcp +``` + +### Advanced Rules +```bash +# Rate limiting for SSH +sudo ufw limit 2222/tcp + +# Allow from specific networks +sudo ufw allow from 192.168.1.0/24 to any port 22 + +# Log denied connections +sudo ufw logging on +``` + +## Network Security Best Practices + +### Port Management +- **Change default ports**: SSH (2222), WireGuard (51820) +- **Close unused ports**: Regular port scans with nmap +- **Port forwarding**: Only forward necessary ports + +### Access Control +- **VPN-first approach**: Access services through VPN tunnel +- **IP whitelisting**: Restrict access to known IPs when possible +- **Rate limiting**: Prevent brute force attacks + +### Monitoring +- **Log analysis**: Monitor `/var/log/auth.log` for SSH attempts +- **Network monitoring**: Use netstat/ss to check listening ports +- **Intrusion detection**: Use fail2ban for automated blocking + +## fail2ban - Intrusion Prevention + +### What is fail2ban? + +**What it does:** Automatically blocks IP addresses that show malicious behavior. + +**Key functions:** +- **Log monitoring**: Watches system logs for suspicious activity +- **Pattern detection**: Identifies failed login attempts, scanning, etc. +- **Automatic blocking**: Temporarily bans offending IP addresses +- **Customizable rules**: Configure what triggers a ban and for how long + +**Common protections:** +- SSH brute force attempts +- Web server attacks (404 scanning, etc.) +- Email server abuse +- Custom application attacks + +**Example:** After 5 failed SSH login attempts in 10 minutes, ban IP for 1 hour. + +**Why important:** Reduces server load and prevents automated attacks from succeeding through persistence. + +### fail2ban Installation & Setup + +```bash +# Install fail2ban +sudo pacman -S fail2ban + +# Enable and start service +sudo systemctl enable fail2ban +sudo systemctl start fail2ban + +# Create local configuration +sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local +``` + +### Basic SSH Protection Configuration + +Edit `/etc/fail2ban/jail.local`: +```ini +[sshd] +enabled = true +port = 2222 +filter = sshd +logpath = /var/log/auth.log +maxretry = 5 +bantime = 3600 +findtime = 600 +``` + +**Configuration explained:** +- `maxretry = 5`: Ban after 5 failed attempts +- `bantime = 3600`: Ban for 1 hour (3600 seconds) +- `findtime = 600`: 5 attempts within 10 minutes triggers ban +- `port = 2222`: Monitor custom SSH port + +### Restart and Monitor + +```bash +# Restart fail2ban to apply changes +sudo systemctl restart fail2ban + +# Check status +sudo fail2ban-client status +sudo fail2ban-client status sshd + +# View banned IPs +sudo fail2ban-client get sshd banned +``` + +## Router Configuration + +### Port Forwarding +Forward these ports to your homelab server: +- SSH: External port → Internal 2222 +- WireGuard: 51820 → 51820 +- Web services: 80/443 → 80/443 (if needed) + +### Security Settings +- **Disable WPS**: Turn off WiFi Protected Setup +- **Strong WiFi password**: WPA3 with complex passphrase +- **Guest network**: Separate network for guests +- **Firmware updates**: Keep router firmware current + +## Network Planning + +### Dual Network Interface Issue (Critical) + +**Problem:** Server has both ethernet and WiFi interfaces. When switching between connections, IP address changes from ethernet (192.168.0.22) to different WiFi IP, breaking SSH connections and port forwards. + +**Limitation:** Most routers don't allow DHCP reservation of same IP for multiple MAC addresses. + +**Solutions:** + +**Option 1: Static IP Configuration (Recommended)** +Configure both interfaces with same static IP: +```bash +# Check interface names +ip link show + +# Configure ethernet interface +sudo systemctl edit --full systemd-networkd +# Create /etc/systemd/network/20-ethernet.network +[Match] +Name=enp* + +[Network] +DHCP=no +Address=192.168.0.100/24 +Gateway=192.168.0.1 +DNS=192.168.0.1 + +# Create /etc/systemd/network/25-wifi.network +[Match] +Name=wlp* + +[Network] +DHCP=no +Address=192.168.0.100/24 +Gateway=192.168.0.1 +DNS=192.168.0.1 +``` + +**Option 2: Hostname-based Access** +Use local hostname resolution instead of IP: +```bash +# Access via hostname (works for both interfaces) +ssh hoborg@ak-homelab.local +# or configure local DNS/mDNS +``` + +**Option 3: Bridge Networking** +Create bridge combining both interfaces for automatic failover: +```bash +# Advanced: Bridge both interfaces +ip link add name br0 type bridge +ip link set enp3s0 master br0 +ip link set wlp2s0 master br0 +``` + +**Current Setup:** +- Router: 192.168.0.1 +- Ethernet: 192.168.0.100 (static IP achieved) +- WiFi: Static IP needed (same .100) +- External: ak-homelab.duckdns.org ✅ +- SSH: Port 2222 ✅ + +**Network Interface Identification:** +- **enp3s0f0**: First ethernet port (98:fa:9b:f1:06:d5) +- **enp4s0**: Second ethernet port (98:fa:9b:f1:06:d4) ← **Use this one** +- **wlp1s0**: WiFi interface (0c:dd:24:e6:0f:87) + +**Issue Solved:** Dual ethernet ports caused MAC address confusion when cable was moved between ports. Stick to enp4s0 consistently. + +### IP Address Scheme +- **Router**: 192.168.0.1 +- **Homelab server**: 192.168.0.100 (target static IP) +- **Current ethernet**: 192.168.0.22 (can migrate to .100) +- **DHCP range**: 192.168.0.10-99 (excluding static IPs) +- **VPN subnet**: 10.0.0.0/24 + +### DNS Configuration +- **Primary DNS**: Router (192.168.1.1) +- **Secondary DNS**: 1.1.1.1, 8.8.8.8 +- **Local domain**: homelab.local +- **Dynamic DNS**: ak-homelab.duckdns.org + +### Service Architecture +``` +Internet → Router → Homelab Server + ↓ + ┌─────────────────────────────┐ + │ SSH (2222) │ + │ WireGuard VPN (51820) │ + │ Web Services (80/443) │ + │ Monitoring & Logging │ + └─────────────────────────────┘ +``` + +## Backup and Recovery + +### Configuration Backups +- **SSH keys**: Store securely, separate from server +- **WireGuard configs**: Document peer configurations +- **Firewall rules**: Export UFW rules with `ufw status numbered` + +### Network Documentation +- **IP mappings**: Document static assignments +- **Port forwards**: List all forwarded ports and purposes +- **Access credentials**: Secure storage of passwords/keys \ No newline at end of file diff --git a/docs/services.md b/docs/services.md new file mode 100644 index 0000000..16f1598 --- /dev/null +++ b/docs/services.md @@ -0,0 +1,440 @@ +# Services & Applications + +Planning and configuration for self-hosted services and applications. + +## Git Repository Hosting + +### Service Options +- **Gitea**: Lightweight, Go-based, minimal resource usage ✅ *Recommended* +- **Forgejo**: Gitea fork, community-driven development +- **GitLab CE**: Feature-rich but more resource intensive +- **Gogs**: Simple, lightweight alternative + +### Gitea Installation (Docker - Recommended) + +**Status:** ✅ **Container Running** ⚠️ **Configuration Issues** - UI accessible, config needs debugging + +**Prerequisites:** +```bash +# Install Docker and Docker Compose +sudo pacman -S docker docker-compose +sudo systemctl enable docker +sudo systemctl start docker + +# Add user to docker group (logout/login required) +sudo usermod -aG docker hoborg +``` + +**Gitea Docker Setup:** +```bash +# Create directories for persistent data +mkdir -p ~/docker/gitea/{data,config} + +# Run Gitea container +docker run -d \ + --name gitea \ + -p 3000:3000 \ + -p 2222:22 \ + -v ~/docker/gitea/data:/data \ + -v ~/docker/gitea/config:/etc/gitea \ + -e USER_UID=1000 \ + -e USER_GID=1000 \ + gitea/gitea:latest + +# Alternative: Docker Compose (preferred) +# See docker-compose.yml below +``` + +**Docker Compose Configuration:** +Create `~/docker/gitea/docker-compose.yml`: +```yaml +version: "3" + +networks: + gitea: + external: false + +services: + server: + image: gitea/gitea:latest + container_name: gitea + environment: + - USER_UID=1000 + - USER_GID=1000 + restart: always + networks: + - gitea + volumes: + - ./data:/data + - /etc/timezone:/etc/timezone:ro + - /etc/localtime:/etc/localtime:ro + ports: + - "3000:3000" + - "2223:22" # Gitea SSH (avoid conflict with system SSH on 2222) +``` + +**Start with Docker Compose:** +```bash +cd ~/docker/gitea +docker-compose up -d +``` + +### Current Configuration + +**Container Status:** ✅ Running at /opt/docker/gitea +**Access URLs:** +- **Local Web**: http://192.168.0.100:3000 +- **External Web**: http://ak-homelab.duckdns.org:3000 (requires port forwarding) +- **Git SSH**: ssh://git@ak-homelab.duckdns.org:2223 (requires port forwarding) + +**Port Assignments:** +- **System SSH**: 2222 (for server administration) +- **Gitea SSH**: 2223 (for Git operations) +- **Gitea Web**: 3000 (web interface) + +**Database**: SQLite (default, stored in container volume) +**Data Location**: /opt/docker/gitea/data (persistent volume) + +**Router Port Forwarding Required:** +- 3000 → 192.168.0.100:3000 (web interface) +- 2223 → 192.168.0.100:2223 (Git SSH operations) + +**Container Management:** +```bash +cd /opt/docker/gitea +docker-compose logs gitea # View logs +docker-compose down # Stop container +docker-compose up -d # Start container +docker-compose pull && docker-compose up -d # Update +``` + +### Gitea Configuration Recommendations + +**Database Selection:** +- ✅ **SQLite** (Recommended for homelab) + - Zero configuration, single file + - Perfect for personal/small team use + - Easy backups and migration +- **PostgreSQL** (Production alternative) + - Better performance for heavy usage + - Requires additional container setup + +**Domain & URL Configuration:** +- **Server Domain**: `ak-homelab.duckdns.org` +- **Gitea Base URL**: `http://ak-homelab.duckdns.org/gitea/` +- **SSH Domain**: `ak-homelab.duckdns.org` +- **SSH Port**: `2223` + +**Password Hash Algorithm:** +- ✅ **Argon2** (Recommended) + - Most secure modern algorithm + - Resistant to GPU/ASIC attacks + - Higher CPU usage but excellent security +- **bcrypt** (Alternative) + - Well-tested, lower resource usage + - Good balance of security and performance + +**Setup Progress:** +1. ✅ Gitea container running +2. ✅ Nginx reverse proxy setup complete +3. 📋 Router port forwarding (80, 443) - **Next** +4. ⚠️ Gitea web configuration - **Partially complete, needs debugging** + - Initial setup wizard completed + - Base URL configuration issue (extra space in config) + - UI accessible but routing may be broken +5. 📋 SSL certificate setup - **After router config** + +**Current Access:** +- ✅ Local UI working: http://192.168.0.100/gitea/ +- ❓ External access: Pending router port forwarding +- ⚠️ Configuration debugging needed + +**Debug Tasks:** +- Fix base URL in `/opt/docker/gitea/data/gitea/conf/app.ini` +- Check ROOT_URL setting for extra spaces +- Verify redirect behavior after fix + +## Cloud Storage Solutions + +### Service Options +- **Copyparty**: Quite new self-hosted file storage solution, must investigate! +- **Nextcloud**: Full-featured, extensive app ecosystem ✅ *Recommended* +- **ownCloud**: Original project, stable and mature +- **Seafile**: Performance-focused file sync +- **Syncthing**: Decentralized sync (no server needed) + +### Nextcloud Installation +```bash +# Via snap (recommended) +sudo snap install nextcloud + +# Or via Docker +docker run -d \ + --name nextcloud \ + -p 8080:80 \ + -v nextcloud_data:/var/www/html \ + nextcloud +``` +Personal notes: Not a fan of snap, isn't there an AUR package? +Go with docker otherwise + +### Features +- File synchronization across devices +- Video files, game installers -> high prio +- Self-hosted git mirrors of favorite FOSS projects -> medium prio +- Calendar and contacts (CalDAV/CardDAV) -> low prio +- Document editing (OnlyOffice/Collabora) -> low prio +- Photo management and sharing -> low prio +- Mobile apps available? + +## Media Management + +### Jellyfin Media Server +```bash +# Install via AUR +yay -S jellyfin-server jellyfin-web + +# Enable service +sudo systemctl enable jellyfin +sudo systemctl start jellyfin +``` + +Configuration: +- **Port**: 8096 (web interface) +- **Media paths**: `/data/movies`, `/data/tv`, `/data/music` +- **Transcoding**: Hardware acceleration if available + +### Photo Management +- **PhotoPrism**: AI-powered photo management +- **Immich**: Modern photo backup solution +- **LibrePhotos**: Privacy-focused alternative + +## Monitoring & Logging + +### System Monitoring +```bash +# Prometheus + Grafana stack +docker-compose up -d prometheus grafana node-exporter +``` + +### Log Management +- **Centralized logging**: rsyslog or journald +- **Log rotation**: logrotate configuration +- **Analysis**: grep, awk, or ELK stack for advanced needs + +### Health Checks +- **Uptime monitoring**: Simple HTTP checks +- **Service status**: systemd service monitoring +- **Disk space**: Automated alerts for low space + +## Containerization Strategy + +### Docker Setup +```bash +# Install Docker +pacman -S docker docker-compose +sudo systemctl enable docker + +# Add user to docker group +sudo usermod -aG docker hoborg +``` + +### Container Management +- **Orchestration**: Docker Compose for multi-service apps +- **Storage**: Named volumes for persistent data +- **Networking**: Custom networks for service isolation +- **Updates**: Watchtower for automated updates + +## Reverse Proxy Configuration + +### Decision Matrix: Nginx vs Traefik + +**Problem:** Multiple services need to be accessible under single domain with path-based routing. +**Solution:** Reverse proxy to route requests based on URL paths. + +#### Nginx +✅ **Pros:** +- Mature & battle-tested (decades of production use) +- High performance for static files and caching +- Flexible configuration - handles any routing scenario +- Extensive ecosystem and documentation +- Can handle non-Docker services easily + +❌ **Cons:** +- Manual configuration required +- No auto-discovery of services +- Requires config reload for changes + +#### Traefik +✅ **Pros:** +- Docker-native auto-discovery via labels +- Automatic HTTPS with Let's Encrypt +- Dynamic configuration (no restarts) +- Modern design for containerized environments + +❌ **Cons:** +- Less mature, smaller ecosystem +- Docker-dependent (less flexible) +- Steeper learning curve for complex scenarios + +**Decision:** ✅ **Nginx** - Better for homelab due to reliability, documentation, and flexibility for mixed Docker/non-Docker services. + +### URL Architecture Decision + +**Options Considered:** +1. **Separate subdomains**: `gitea.ak-homelab.duckdns.org` ❌ *DuckDNS doesn't support nested subdomains* +2. **Multiple DuckDNS domains**: `ak-homelab-git.duckdns.org` ❌ *Management overhead* +3. **Path-based routing**: `ak-homelab.duckdns.org/gitea/` ✅ **Selected** + +**Chosen Architecture:** +``` +ak-homelab.duckdns.org/ → Landing page/dashboard +ak-homelab.duckdns.org/gitea/ → Gitea Git server +ak-homelab.duckdns.org/cloud/ → Nextcloud file sync +ak-homelab.duckdns.org/media/ → Jellyfin media server +ak-homelab.duckdns.org/monitor/ → System monitoring +``` + +### Advanced Nginx Options + +**Nginx Plus (Commercial):** $2500+/year +- Advanced load balancing, health checks +- API management, JWT validation +- Real-time monitoring dashboard +- **Verdict:** Overkill for homelab + +**Nginx + Lua (OpenResty):** +- Embed Lua scripts for dynamic processing +- Complex routing logic, authentication +- API gateway functionality +- **Verdict:** Powerful but complex, not needed initially + +### Nginx Setup + +**Status:** ✅ **Complete** - Reverse proxy configured and running + +```bash +# Install nginx and SSL tools +sudo pacman -S nginx certbot certbot-nginx + +# Create configuration +sudo nano /etc/nginx/sites-available/homelab + +# Enable site +sudo ln -s /etc/nginx/sites-available/homelab /etc/nginx/sites-enabled/ + +# Test and reload +sudo nginx -t +sudo systemctl reload nginx +``` + +**Configuration Template:** +```nginx +server { + listen 80; + server_name ak-homelab.duckdns.org; + + # Main landing page + location / { + root /var/www/homelab; + index index.html; + } + + # Gitea reverse proxy + location /gitea/ { + proxy_pass http://127.0.0.1:3000/; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } + + # Future services + # location /cloud/ { + # proxy_pass http://127.0.0.1:8080/; + # proxy_set_header Host $host; + # } +} +``` + +### Router Port Forwarding Requirements +- **HTTP**: Port 80 → 192.168.0.100:80 +- **HTTPS**: Port 443 → 192.168.0.100:443 +- **Remove**: Direct port 3000 forwarding (will go through nginx) + +### SSL Certificates +```bash +# Let's Encrypt via certbot (after nginx setup) +sudo certbot --nginx -d ak-homelab.duckdns.org + +# Auto-renewal +sudo systemctl enable certbot.timer +``` + +## Backup Strategy + +### Configuration Backups +- **Service configs**: Docker volumes, /etc configs +- **Database dumps**: Regular automated backups +- **Storage**: External drive or cloud backup + +### Automated Backups +```bash +#!/bin/bash +# backup-services.sh +DATE=$(date +%Y%m%d) + +# Backup Gitea +tar -czf /backup/gitea-$DATE.tar.gz /var/lib/gitea/ + +# Backup Nextcloud data +rsync -av /var/snap/nextcloud/common/nextcloud/data/ /backup/nextcloud-$DATE/ + +# Database backup +sudo -u postgres pg_dump gitea > /backup/gitea-db-$DATE.sql +``` + +## Resource Planning + +### Hardware Requirements +- **RAM**: 4GB minimum, 8GB recommended +- **Storage**: + - System: 50GB SSD + - Data: 1TB+ HDD for media/files +- **Network**: Gigabit Ethernet preferred + +### Service Resource Usage +| Service | RAM | CPU | Storage | Port | +|---------|-----|-----|---------|------| +| Gitea | 200MB | Low | 5GB+ | 3000 | +| Nextcloud | 512MB | Medium | 10GB+ | 8080 | +| Jellyfin | 1GB | High* | Media | 8096 | +| Monitoring | 500MB | Low | 2GB | 3000/9090 | + +*High during transcoding + +## Security Considerations + +### Service Hardening +- **Regular updates**: Automated security patches +- **Access control**: VPN-only access when possible +- **Authentication**: Strong passwords, 2FA where available +- **Network isolation**: Separate VLANs or containers + +### Data Protection +- **Encryption**: Full disk encryption (LUKS) +- **Backups**: Encrypted offsite backups +- **Access logs**: Monitor service access patterns +- **Fail2ban**: Automatic IP blocking for repeated failures + +## Future Expansion + +### Additional Services to Consider +- **Home Assistant**: ABSOLUTELY NOT +- **Bitwarden/Vaultwarden**: Password management + - How is this better than keepassxc + filesync? +- **Pi-hole**: Network-wide ad blocking +- **Wireguard UI**: Web interface for VPN management +- **Bookstack**: Documentation wiki + - What is this for? How does it compare to Logseq? +- **FreshRSS**: RSS feed aggregator diff --git a/docs/system-setup.md b/docs/system-setup.md new file mode 100644 index 0000000..e17ffe7 --- /dev/null +++ b/docs/system-setup.md @@ -0,0 +1,158 @@ +# System Setup Guide + +Complete guide for Arch Linux installation and system configuration. + +## Initial Installation + +### Pre-installation +1. Boot from Arch ISO +2. Verify boot mode: `ls /sys/firmware/efi/efivars` +3. Connect to internet: `iwctl` for WiFi +4. Update system clock: `timedatectl set-ntp true` + +### Disk Preparation +1. List disks: `fdisk -l` +2. Partition the disk: `cfdisk /dev/sdX` + - EFI partition: 512M, type EFI System + - Root partition: remaining space, type Linux filesystem +3. Format partitions: + ```bash + mkfs.fat -F32 /dev/sdX1 # EFI + mkfs.ext4 /dev/sdX2 # Root + ``` +4. Mount filesystems: + ```bash + mount /dev/sdX2 /mnt + mkdir /mnt/boot + mount /dev/sdX1 /mnt/boot + ``` +Current partition setup is a quite fragmented leftover from my dual-booting days. Later we should wipe the leftover +Windows drive for extra storage, but first we should confirm there's no essential files there +(unlikely since it wasn't booted for months, mostly using other windows PC) + +### System Installation +1. Install base packages: `pacstrap /mnt base linux linux-firmware` +2. Generate fstab: `genfstab -U /mnt >> /mnt/etc/fstab` +3. Chroot: `arch-chroot /mnt` +4. Set timezone: `ln -sf /usr/share/zoneinfo/Europe/Budapest /etc/localtime` +5. Generate hardware clock: `hwclock --systohc` +6. Configure locale: + - Edit `/etc/locale.gen`, uncomment `en_US.UTF-8 UTF-8` + - Run: `locale-gen` + - Create `/etc/locale.conf`: `LANG=en_US.UTF-8` +7. Set hostname: `echo "homelab" > /etc/hostname` +8. Configure hosts file +9. Set root password: `passwd` +10. Install bootloader: `pacman -S grub efibootmgr` +11. Install GRUB: `grub-install --target=x86_64-efi --efi-directory=/boot --bootloader-id=GRUB` +12. Generate config: `grub-mkconfig -o /boot/grub/grub.cfg` + +## Post-Installation Setup + +### User Management +```bash +# Create user +useradd -m -G wheel -s /bin/bash hoborg +passwd hoborg + +# Configure sudo +pacman -S sudo +visudo # Uncomment %wheel ALL=(ALL) ALL +``` + +### Essential Packages +```bash +pacman -S git base-devel openssh networkmanager +systemctl enable NetworkManager +systemctl enable sshd +``` + +### AUR Access +```bash +# Install yay AUR helper +git clone https://aur.archlinux.org/yay.git +cd yay +makepkg -si +``` + +## Desktop Environment + +### XFCE Installation +```bash +pacman -S xfce4 xfce4-goodies lightdm lightdm-gtk-greeter +systemctl enable lightdm +``` + +### Themes and Appearance +- **Window Manager Theme**: Matcha-dark-aliz +- **Icons**: Papirus-Maia +- **Fonts**: + - System: Install Nerd Fonts (`ttf-iosevkaterm-nerd ttf-jetbrains-mono-nerd`) + - TTY: ter-124b (12x24 bold) + +## Development Environment + +### Dotfiles Management +```bash +# Install yadm +pacman -S yadm + +# Clone dotfiles +yadm clone git@gitlab.com:akrejczinger/dotfiles.git +``` + +### Shell Configuration +- **Shell**: zsh with antidote plugin manager +- **Terminal**: wezterm with Catppuccin theme +- **Multiplexer**: tmux with catppuccin theme and temperature monitoring +- **Editor**: neovim with lazy.nvim plugin manager + +### Key Configurations +- **Keyboard Layout**: Colemak (US variant in X11) +- **TTY Layout**: Colemak with caps lock → backspace via systemd service +- **Font Fallbacks**: Noto fonts for Unicode support + +## TTY Configuration + +### Font and Layout +```bash +# Configure /etc/vconsole.conf +KEYMAP=colemak +FONT=ter-124b +FONT_MAP=8859-1 +``` + +### Caps Lock Fix +Caps lock mapped to backspace via systemd service: +```bash +# /etc/systemd/system/caps-backspace.service +sudo setkeycodes 3a 14 # Map caps scancode to backspace keycode +``` + +### Color Scheme +TTY colors configured in `.zshrc` for better readability. + +## System Maintenance + +### Package Management +- Regular updates: `yay -Syu` +- Orphaned packages: `yay -Yc` +- Cache cleanup: `yay -Sc` + +### Backup Strategy +- Dotfiles: yadm + git repository +- System configs: Document in this guide +- User data: External backup solution + +## Hardware-Specific Notes + +### ThinkPad Optimizations +- **Temperature Monitoring**: Available via `sensors` command +- **Battery Management**: TLP for power optimization +- **Trackpad**: libinput with natural scrolling +- **Function Keys**: Media keys work out of box + +### Network Configuration +- **WiFi**: NetworkManager with GUI applet +- **Ethernet**: Automatic DHCP +- **Bluetooth**: bluez with pulseaudio integration diff --git a/docs/troubleshooting.md b/docs/troubleshooting.md new file mode 100644 index 0000000..6a3f4ac --- /dev/null +++ b/docs/troubleshooting.md @@ -0,0 +1,312 @@ +# Bluetooth keeps disconnecting - reconnecting + +Solution: Change config in /etc/bluetooth/main.conf +`ControllerMode = bredr` +Then `sudo systemctl restart bluetooth` + +UPDATE: It's still not fixed :( +Trying `yay -S pipewire wireplumber` +TODO test it again + +# Touchpad scroll direction (libinput) + +To change touchpad scroll direction on Arch Linux using libinput driver: + +## Investigation steps: +1. Check which driver is used: `pacman -Q | grep -E "(synaptics|libinput)"` +2. Verify libinput config exists: `ls /usr/share/X11/xorg.conf.d/ | grep libinput` + +## Solution for libinput: +Create `/etc/X11/xorg.conf.d/30-touchpad.conf`: + +``` +Section "InputClass" + Identifier "touchpad" + Driver "libinput" + MatchIsTouchpad "on" + Option "NaturalScrolling" "true" + Option "Tapping" "on" + Option "TappingDrag" "on" + Option "DisableWhileTyping" "on" +EndSection +``` + +Set `NaturalScrolling` to: +- `"true"` for macOS-style (natural) scrolling +- `"false"` for traditional scrolling + +Restart X11 (log out/in) or reboot to apply changes. + +## Alternative: Synaptics driver (legacy) + +If using the older synaptics driver instead of libinput: + +### Investigation steps: +1. Check for synaptics: `pacman -Q xf86-input-synaptics` +2. Look for config: `ls /usr/share/X11/xorg.conf.d/ | grep synaptics` + +### Solution: +Create `/etc/X11/xorg.conf.d/70-synaptics.conf`: + +``` +Section "InputClass" + Identifier "touchpad" + Driver "synaptics" + MatchIsTouchpad "on" + MatchDevicePath "/dev/input/event*" + Option "VertScrollDelta" "-111" + Option "HorizScrollDelta" "-111" + Option "TapButton1" "1" + Option "TapButton2" "3" + Option "TapButton3" "2" + Option "PalmDetect" "1" + Option "SHMConfig" "on" +EndSection +``` + +Synaptics scroll direction options: +- `VertScrollDelta` and `HorizScrollDelta`: + - Positive values (e.g., `"111"`) for traditional scrolling + - Negative values (e.g., `"-111"`) for natural/reversed scrolling + +**Note:** libinput is the modern standard. Consider switching from synaptics to libinput for better support and features. + +# Theme switching issues + +## Cross-application theme synchronization + +**Issue:** Need to synchronize theme (light/dark) across tmux, nvim, and other terminal applications. + +**Solution:** File-based theme management system using `~/.vim_theme`: + +### Setup: + +1. **Create theme switcher script** (`~/.config/tmux/themeswitch.sh`): +```bash +#!/bin/bash +if [ -f ~/.vim_theme ] && [ "$(cat ~/.vim_theme)" = "light" ]; then + tmux set -g @catppuccin_flavor "latte" +else + tmux set -g @catppuccin_flavor "mocha" +fi +``` + +2. **Add to tmux config** (`~/.config/tmux/tmux.conf`): +```bash +# Dynamic theme switching based on ~/.vim_theme file +run 'bash ~/.config/tmux/themeswitch.sh' +``` + +3. **Add to shell config** (`~/.zshrc`): +```bash +# Export THEME environment variable for nvim and other apps +if [ -f ~/.vim_theme ]; then + export THEME=$(cat ~/.vim_theme) +else + export THEME="dark" # default +fi +``` + +### Usage: +```bash +# Switch to light theme +echo "light" > ~/.vim_theme + +# Switch to dark theme +echo "dark" > ~/.vim_theme +``` + +### Benefits: +- ✅ **Single source of truth:** `~/.vim_theme` file controls all applications +- ✅ **Automatic propagation:** New terminals inherit theme via shell config +- ✅ **No environment variable issues:** File-based approach avoids tmux env var propagation problems +- ✅ **Cross-application support:** nvim reads `$THEME`, tmux uses catppuccin flavors + +### Limitations: +- **Tmux live reload:** Changes require tmux config reload or session restart +- **Workaround:** Use tmux-resurrect to quickly restore sessions after restart + +## Legacy: Tmux and terminal not updating after theme switch + +**Issue:** After running the theme switcher script, tmux sessions and existing terminals don't reflect the new theme until restarted. + +**Temporary workaround:** +- Restart tmux sessions: `tmux kill-server && tmux` +- Open new terminal windows + +**Status:** ✅ **Solved** - Use file-based theme management system above + +## Tmux window names showing hostname instead of command + +**Issue:** Tmux windows show "homelab" (hostname) for inactive tabs but correct command names for active tabs. + +**Root cause:** Catppuccin tmux theme with `@catppuccin_window_tabs_enabled on` uses different text formatting for active vs inactive windows. + +**Solution:** Disable catppuccin window tabs: +``` +set -g @catppuccin_window_tabs_enabled off +``` + +**Alternative:** Configure explicit window text for both states: +``` +set -g @catppuccin_window_default_text "#W" +set -g @catppuccin_window_current_text "#W" +``` + +Also ensure automatic renaming is enabled: +``` +setw -g automatic-rename on +setw -g allow-rename on +``` + +# Font and Unicode Display Issues + +## Missing emoji and unicode symbols + +**Issue:** Emojis show as boxes or missing characters, unicode symbols don't display properly. + +**Solution:** Install comprehensive unicode font packages: +```bash +sudo pacman -S noto-fonts-emoji noto-fonts-extra +fc-cache -f +``` + +## Nerd Font icons not displaying + +**Issue:** Developer icons (programming languages, git symbols, file types) show as blank spaces or boxes. + +**Root cause:** Terminal emulator not configured to use Nerd Font as primary font. + +**Solution:** +1. Install Nerd Fonts: +```bash +sudo pacman -S ttf-iosevkaterm-nerd ttf-jetbrains-mono-nerd +fc-cache -f +``` + +2. Configure terminal to use Nerd Font as primary font +3. For wezterm, ensure config includes: +```lua +config.font = wezterm.font_with_fallback { + 'IosevkaTerm Nerd Font', + 'JetBrainsMono Nerd Font Mono', + 'Noto Color Emoji' +} +``` + +**Testing:** Use printf with direct codepoints: +```bash +printf "Icons: \\ue702 \\uf121 \\uf015 \\uf07b\\n" +``` + +## Ancient/exotic script support + +**Comprehensive coverage achieved with:** +- `noto-fonts` (base unicode) +- `noto-fonts-cjk` (Chinese/Japanese/Korean) +- `noto-fonts-emoji` (color emoji) +- `noto-fonts-extra` (additional scripts) + +Successfully displays: Egyptian hieroglyphs, Cuneiform, Nordic runes, Hungarian rovás, Arabic, Chinese, Japanese, Korean, Thai, Hindi, Hebrew, Greek, Tamil. + +# Cannot tile windows by drag and dropping + +Keyboard workaround: Go to Settings > Window Manager > Keyboard, set up tiling shortcuts (set to Super+arrow keys) + +# Additional Known Issues (TODO Items) + +## Tmux battery indicator missing until config reload + +**Issue:** Battery indicator doesn't appear in tmux status line immediately after starting tmux. + +**Temporary workaround:** Reload tmux config with `Prefix + r` or restart tmux session. + +**Status:** Investigation needed + +## TTY fallbacks needed + +**Issue:** When not in X11/graphical mode, nvim and tmux need proper fallback configurations. + +**Status:** Completed + +**Solutions implemented:** +- ✅ **nvim:** TTY detection and color scheme fallback configured +- ✅ **Font:** Selected ter-124b (12x24 bold) for good readability +- ✅ **Keyboard:** Colemak layout with caps lock remapped to backspace +- ✅ **Caps lock fix:** Uses systemd service with `setkeycodes 3a 14` + +**Configuration files:** +- `/etc/systemd/system/caps-backspace.service` - Permanent caps lock remapping +- TTY font testing script: `~/.local/scripts/test-fonts.sh` + +## TTY Caps Lock Not Working as Backspace + +**Issue:** With colemak keymap loaded, caps lock acts like Control instead of backspace in TTY. + +**Root cause:** Colemak keymap maps caps lock to Control, which conflicts with tmux navigation keys. + +**Solution:** Use `setkeycodes` to remap at scancode level: +```bash +sudo setkeycodes 3a 14 # Map caps lock scancode to backspace keycode +``` + +**Permanent fix:** Systemd service created at `/etc/systemd/system/caps-backspace.service` + +## Laptop sleeps when lid is closed + +Solution: + +sudo nvim /etc/systemd/logind.conf + +Uncomment and change these lines: + +``` +HandleLidSwitch=ignore +HandleLidSwitchExternalPower=ignore +HandleLidSwitchDocked=ignore +``` + +Then restart service: +`sudo systemctl restart systemd-logind` + +## IP addresses keep changing + +Due to 3 interfaces: +* Wifi +* Ethernet left port (ThinkPad adapter) - Wired Connection 1 +* Ethernet right port (regular ethernet cable) - Wired Connection 2 + +### Proposed solution + +* Stick with wired2 + +● Configure static IP for "Wired connection 2" (enp4s0): + + * Set static IP to 192.168.0.100 + sudo nmcli connection modify "Wired connection 2" \ + ipv4.method manual \ + ipv4.addresses 192.168.0.100/24 \ + ipv4.gateway 192.168.0.1 \ + ipv4.dns 192.168.0.1 + + * Apply the changes + sudo nmcli connection up "Wired connection 2" + + Then configure WiFi with the same static IP: + + * First connect to your WiFi if not already + sudo nmcli connection up "Telekom-4b28df-2.4GHz" + + * Set same static IP for WiFi + sudo nmcli connection modify "Telekom-4b28df-2.4GHz" \ + ipv4.method manual \ + ipv4.addresses 192.168.0.100/24 \ + ipv4.gateway 192.168.0.1 \ + ipv4.dns 192.168.0.1 + + Verify the configuration: + nmcli connection show "Wired connection 2" | grep ipv4 + ip addr show enp4s0 + + This way both your ethernet (enp4s0) and WiFi will use 192.168.0.100, solving your dual interface IP issue. + Ready to run these commands?