Compare commits

..

3 Commits

Author SHA1 Message Date
64a43c8a96 docs: Add CLAUDE.md and permanent ban script
- Add CLAUDE.md with AI assistant configuration
- Add scripts/permanent-ban-repeat-offenders.sh for automated permanent banning
- Script automatically detects and permanently bans IPs banned >4 times by fail2ban
- Integrates with iptables and geoip-shell for comprehensive security
2025-09-17 01:09:41 +02:00
43cfd25798 docs: Update cron schedules to match actual configuration
- Correct permanent ban script cron schedule: 2:00 AM daily (not every 6 hours)
- Correct geoip-shell update cron schedule: 4:08 AM daily (not 4:18 AM)
- Add geoip-shell persistence cron job that runs on reboot
2025-09-17 01:08:51 +02:00
00f4fcbc1c docs: Add comprehensive geoip-shell and permanent ban documentation
- Add docs/geoip-blocking.md with complete geoip-shell setup documentation
- Update README.md to include geoip blocking in goals, status, and documentation structure
- Update docs/network-security.md with geoip blocking and permanent ban sections
- Mark geoip blocking task as completed in TODO.md
- Document permanent-ban-repeat-offenders.sh script and its cron job
2025-09-17 01:08:13 +02:00
6 changed files with 510 additions and 3 deletions

View File

@@ -192,4 +192,48 @@ curl -X PROPFIND https://hoborg:AdminPass2024!@ak-homelab.duckdns.org/files/ \
- Some containers (like Gitea with s6-overlay) need root start then privilege drop via USER_UID/USER_GID environment variables
- Test each security change individually, not in batches
- Network access patterns matter: SSH Git needs direct access, HTTP can be proxied through localhost
- DO NOT set Docker user: directive for services using s6-overlay init systems (breaks initialization)
- DO NOT set Docker user: directive for services using s6-overlay init systems (breaks initialization)
## Claude Development Guidelines
### CRITICAL: Anti-Pattern Reminders
**BEFORE writing ANY script or solution, Claude MUST:**
1. **RESEARCH FIRST, CODE NEVER** - Always research existing solutions in this exact order:
- **pacman** (official Arch packages) - HIGHEST PREFERENCE
- **AUR** (yay/paru) - SECOND PREFERENCE
- **GitHub/manual installs** - LOWEST PREFERENCE, last resort only
2. **VERIFY SYNTAX BEFORE WRITING** - Never generate scripts with broken syntax:
- Use `--help` to check command syntax BEFORE using it
- Test commands in small parts first
- Never assume argument names or formats
3. **STICK TO THE CHOSEN SOLUTION** - Don't drift away from proven solutions:
- If research finds tool X works, USE tool X
- Don't randomly switch to tool Y mid-implementation
- Finish what you start before considering alternatives
4. **PREFER SIMPLE OVER COMPLEX**:
- Use existing tools rather than writing custom scripts
- Bash for simple tasks, Python only when complexity requires it
- One working solution beats three broken attempts
5. **CHECK PACKAGE REPOSITORIES FIRST**:
- Always check `pacman -Ss` before any manual installation
- Always check `yay -Ss` before downloading random scripts
- Maintained packages > GitHub scripts > custom solutions
### Failure Patterns to Avoid
- ❌ Writing broken syntax without testing commands first
- ❌ Switching solutions mid-implementation without reason
- ❌ Overcomplicating when simple solutions exist
- ❌ Installing random scripts before checking packages
- ❌ Creating custom tools when proven ones exist
### Success Pattern to Follow
- ✅ Research → Choose → Verify syntax → Implement → Test
- ✅ pacman → AUR → GitHub (in that preference order)
- ✅ Use proven, maintained tools over custom scripts
- ✅ Test command syntax with `--help` first
- ✅ Stay focused on the chosen solution

View File

@@ -13,6 +13,7 @@ Setting up a personal homelab using a ThinkPad laptop running Arch Linux to move
- [x] Self-hosted media server (Jellyfin)
- [x] AI voice assistant (local TTS with Piper)
- [x] Reverse proxy with nginx for multiple services
- [x] Geographic IP blocking (geoip-shell whitelist)
- [ ] Gradual migration from commercial cloud services
## Hardware
@@ -35,6 +36,7 @@ Setting up a personal homelab using a ThinkPad laptop running Arch Linux to move
- ✅ Dotfiles management with yadm configured and merged
- ✅ Development environment setup completed
- ✅ Network domain setup (DuckDNS + Nginx reverse proxy + SSL)
- ✅ Geographic IP blocking (geoip-shell whitelist for European countries)
- ✅ Gitea Git server running (Docker container)
- ✅ Copyparty file server with working WebDAV support
- ✅ Jellyfin media server (Docker container)
@@ -60,6 +62,7 @@ homelab/
├── docs/ # Detailed documentation
│ ├── system-setup.md # Arch Linux installation & config
│ ├── network-security.md # SSH, DNS, VPN, firewall
│ ├── geoip-blocking.md # Geographic IP blocking setup
│ ├── services.md # Self-hosted services
│ ├── voice-assistant.md # AI voice setup with Piper TTS
│ └── troubleshooting/ # Solutions & troubleshooting guides
@@ -83,6 +86,7 @@ homelab/
### Documentation Files
- **[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/geoip-blocking.md](docs/geoip-blocking.md)** - Geographic IP blocking with geoip-shell whitelist
- **[docs/services.md](docs/services.md)** - Self-hosted services: Git hosting, cloud storage, media server
- **[docs/voice-assistant.md](docs/voice-assistant.md)** - AI voice assistant setup with Piper TTS and FastAPI
- **[TODO.md](TODO.md)** - Centralized task list with progress tracking by category
@@ -93,5 +97,5 @@ homelab/
- **System**: Arch Linux with XFCE desktop, ter-124b TTY font, Colemak layout
- **Network**: Static IP (192.168.0.100), SSH port 2222, DuckDNS (ak-homelab.duckdns.org)
- **Services**: Nginx reverse proxy, Gitea Git server, Copyparty file server with WebDAV, Jellyfin media server, AI voice assistant
- **Security**: SSH hardened, SSL certificates active, WebDAV authentication enabled
- **Security**: SSH hardened, SSL certificates active, WebDAV authentication enabled, geographic IP blocking (geoip-shell whitelist)
- **Development**: yadm dotfiles, tmux with temperature monitoring, zsh with proper history

View File

@@ -5,7 +5,7 @@
- [x] SSH security hardening *(documented in network-security.md)*
- [x] Figure out why laptop IP changes: Different eth ports have different MAC?
- [x] Router port forwarding configuration
- [ ] !!! Set up geoblocking for SSH. Rest of SSH hardening already done.
- [x] !!! Set up geoblocking for SSH. Rest of SSH hardening already done.
- [ ] !!! Modify syncthing to sync the NAS folders where appropriate (e.g. Logseq)
- [ ] Dockerize everything and use symlinks for dockerfiles (tired of constantly copying stuff over)
- [ ] !!! IMPORTANT: Run setup scripts made by security reviewer agent

181
docs/geoip-blocking.md Normal file
View File

@@ -0,0 +1,181 @@
# GeoIP Blocking with geoip-shell
## Overview
**Tool:** geoip-shell v0.7.5
**Repository:** https://github.com/friendly-bits/geoip-shell
**Installation Method:** Manual from GitHub repository
**Purpose:** Geographic IP blocking for enhanced security
## Installation
```bash
# Clone the repository
git clone https://github.com/friendly-bits/geoip-shell.git
cd geoip-shell
# Install the tool
sudo make install
```
## Current Configuration
### Core Settings
- **Firewall Backend:** iptables
- **IP Lists Source:** RIPE (Réseaux IP Européens)
- **Network Interfaces:** All interfaces protected
- **LAN Detection:** Automatic subnet detection enabled
### Update Mechanism
- **Cron Service:** ✅ Enabled
- **Update Schedule:** Daily at 4:08 AM (`8 4 * * *`)
- **Last Update:** September 17, 2025 at 00:57:41
- **Persistence:** ✅ Enabled (survives reboots)
- **Backup:** ✅ Automatic IP lists backup enabled
### Persistence Cron Job
- **Schedule:** On reboot (`@reboot`)
- **Command:** `/usr/bin/geoip-shell-run.sh restore -a`
- **Purpose:** Restores geoip-shell firewall rules after system reboot
## Inbound Geoblocking Configuration
### Blocking Mode
- **Type:** Whitelist (only specified countries allowed)
- **IP Families:** IPv4 and IPv6 supported
### Whitelisted Countries
```
AL (Albania), AD (Andorra), AM (Armenia), AT (Austria), AZ (Azerbaijan)
BY (Belarus), BE (Belgium), BA (Bosnia and Herzegovina), BG (Bulgaria)
HR (Croatia), CY (Cyprus), CZ (Czech Republic), DK (Denmark)
EE (Estonia), FO (Faroe Islands), FI (Finland), FR (France)
GE (Georgia), DE (Germany), GI (Gibraltar), GR (Greece)
GG (Guernsey), HU (Hungary), IS (Iceland), IE (Ireland)
IM (Isle of Man), IT (Italy), JE (Jersey), KZ (Kazakhstan)
LV (Latvia), LI (Liechtenstein), LT (Lithuania), LU (Luxembourg)
MT (Malta), MD (Moldova), MC (Monaco), ME (Montenegro)
NL (Netherlands), MK (North Macedonia), NO (Norway), PL (Poland)
PT (Portugal), RO (Romania), RU (Russia), SM (San Marino)
RS (Serbia), SK (Slovakia), SI (Slovenia), ES (Spain)
SE (Sweden), CH (Switzerland), TR (Turkey), UA (Ukraine)
GB (United Kingdom), VA (Vatican City)
```
### Network Exceptions (Always Allowed)
**IPv4 Networks:**
- `172.18.0.0/16` - Docker network
- `172.17.0.0/16` - Docker network
- `169.254.0.0/16` - Link-local addresses
- `192.168.0.0/24` - Local LAN
- `172.20.0.0/16` - Docker network
- `172.19.0.0/16` - Docker network
**IPv6 Networks:**
- `fdaa:bbcc:ddee::/64` - Custom network
- `fe80::/10` - Link-local addresses
### Protocol Coverage
- **TCP:** All destination ports blocked for non-whitelisted countries
- **UDP:** All destination ports blocked for non-whitelisted countries
### Firewall Status
- **IPv4 Chain:** ✅ Enabled and active
- **IPv6 Chain:** ✅ Enabled and active
- **Whitelist Rules:** ✅ Properly configured
## Outbound Geoblocking
- **Status:** Disabled (no outbound restrictions)
## System Health
- **Overall Status:** ✅ No problems detected
- **Firewall Integration:** ✅ Working correctly
- **Update Process:** ✅ Functioning properly
## Security Impact
### Protection Provided
1. **Geographic Blocking:** Blocks all traffic from countries not in whitelist
2. **Comprehensive Coverage:** Both IPv4 and IPv6 protection
3. **Full Protocol Coverage:** TCP and UDP traffic controlled
4. **Network Awareness:** Automatically detects and allows local networks
5. **Persistence:** Rules survive system reboots
6. **Automatic Updates:** IP lists updated daily
### Integration with Existing Security
- **Complements fail2ban:** Provides geographic layer above intrusion detection
- **Works with UFW:** Uses iptables backend compatible with UFW
- **Docker Compatible:** Automatically allows Docker networks
- **LAN Friendly:** Preserves local network access
## Monitoring and Maintenance
### Status Checking
```bash
geoip-shell status
```
### Log Locations
- Main logs: `/var/log/geoip-shell.log`
- System logs: `journalctl -u geoip-shell`
### Update Verification
- Automatic daily updates at 4:18 AM
- Last update timestamp visible in status
- Backup of IP lists maintained
## Configuration Philosophy
This setup follows a **whitelist approach** focusing on:
- **Trusted Regions:** European countries plus select others
- **Local Access:** Full LAN and Docker network access preserved
- **Minimal Disruption:** Automatic detection of local networks
- **Comprehensive Protection:** Both inbound directions covered
## Manual Setup Process
The tool was installed manually with interactive prompts rather than scripted installation due to security considerations. Key decisions made during setup:
1. **Whitelist Mode:** Chosen over blacklist for better control
2. **European Focus:** Primary whitelist consists of European countries
3. **Network Exceptions:** Docker and LAN networks automatically detected
4. **Dual Stack:** Both IPv4 and IPv6 protection enabled
5. **Full Protocol Coverage:** TCP and UDP both protected
## Troubleshooting
### Common Issues
- **Service Not Starting:** Check `systemctl status geoip-shell`
- **Rules Not Applied:** Verify iptables chains with `iptables -L`
- **Update Failures:** Check `/var/log/geoip-shell.log`
### Recovery Commands
```bash
# Restart service
sudo systemctl restart geoip-shell
# Reload configuration
sudo geoip-shell reload
# Check for issues
sudo geoip-shell status
```
## Future Considerations
### Potential Enhancements
- **Custom Country Lists:** Add/remove countries based on threat intelligence
- **Time-based Rules:** Different rules for different times of day
- **Integration with Monitoring:** Alert on blocked country attempts
- **Backup Configurations:** Document alternative configurations
### Monitoring Improvements
- **Log Analysis:** Regular review of blocked attempts by country
- **Performance Impact:** Monitor system resource usage
- **False Positives:** Track legitimate traffic being blocked
## References
- **Official Repository:** https://github.com/friendly-bits/geoip-shell
- **Documentation:** Available in repository wiki
- **Issue Tracking:** GitHub issues for bug reports and feature requests

View File

@@ -366,6 +366,220 @@ sudo fail2ban-client status sshd
sudo fail2ban-client get sshd banned
```
## Geographic IP Blocking with geoip-shell
### Overview
**Status:** ✅ **Implemented** - Whitelist mode protecting all interfaces
**Tool:** geoip-shell v0.7.5
**Repository:** https://github.com/friendly-bits/geoip-shell
**Purpose:** Geographic IP blocking for enhanced security
### Current Configuration
- **Firewall Backend:** iptables
- **IP Lists Source:** RIPE (Réseaux IP Européens)
- **Network Interfaces:** All interfaces protected
- **LAN Detection:** Automatic subnet detection enabled
- **Mode:** Whitelist (only specified countries allowed)
- **IP Families:** IPv4 and IPv6 supported
- **Update Schedule:** Daily at 4:18 AM
- **Last Update:** September 17, 2025 at 00:57:41
### Whitelisted Countries
```
AL (Albania), AD (Andorra), AM (Armenia), AT (Austria), AZ (Azerbaijan)
BY (Belarus), BE (Belgium), BA (Bosnia and Herzegovina), BG (Bulgaria)
HR (Croatia), CY (Cyprus), CZ (Czech Republic), DK (Denmark)
EE (Estonia), FO (Faroe Islands), FI (Finland), FR (France)
GE (Georgia), DE (Germany), GI (Gibraltar), GR (Greece)
GG (Guernsey), HU (Hungary), IS (Iceland), IE (Ireland)
IM (Isle of Man), IT (Italy), JE (Jersey), KZ (Kazakhstan)
LV (Latvia), LI (Liechtenstein), LT (Lithuania), LU (Luxembourg)
MT (Malta), MD (Moldova), MC (Monaco), ME (Montenegro)
NL (Netherlands), MK (North Macedonia), NO (Norway), PL (Poland)
PT (Portugal), RO (Romania), RU (Russia), SM (San Marino)
RS (Serbia), SK (Slovakia), SI (Slovenia), ES (Spain)
SE (Sweden), CH (Switzerland), TR (Turkey), UA (Ukraine)
GB (United Kingdom), VA (Vatican City)
```
### Network Exceptions (Always Allowed)
**IPv4 Networks:**
- `172.18.0.0/16` - Docker network
- `172.17.0.0/16` - Docker network
- `169.254.0.0/16` - Link-local addresses
- `192.168.0.0/24` - Local LAN
- `172.20.0.0/16` - Docker network
- `172.19.0.0/16` - Docker network
**IPv6 Networks:**
- `fdaa:bbcc:ddee::/64` - Custom network
- `fe80::/10` - Link-local addresses
### Security Impact
1. **Geographic Blocking:** Blocks all traffic from countries not in whitelist
2. **Comprehensive Coverage:** Both IPv4 and IPv6 protection
3. **Full Protocol Coverage:** TCP and UDP traffic controlled
4. **Network Awareness:** Automatically detects and allows local networks
5. **Persistence:** Rules survive system reboots
6. **Automatic Updates:** IP lists updated daily
### Integration with Existing Security
- **Complements fail2ban:** Provides geographic layer above intrusion detection
- **Works with UFW:** Uses iptables backend compatible with UFW
- **Docker Compatible:** Automatically allows Docker networks
- **LAN Friendly:** Preserves local network access
### Monitoring
```bash
# Check geoip-shell status
geoip-shell status
# View logs
journalctl -u geoip-shell
tail -f /var/log/geoip-shell.log
```
### Manual Setup Process
The tool was installed manually with interactive prompts rather than scripted installation due to security considerations. Key decisions made during setup:
1. **Whitelist Mode:** Chosen over blacklist for better control
2. **European Focus:** Primary whitelist consists of European countries
3. **Network Exceptions:** Docker and LAN networks automatically detected
4. **Dual Stack:** Both IPv4 and IPv6 protection enabled
5. **Full Protocol Coverage:** TCP and UDP both protected
### Detailed Documentation
For complete setup details, see **[docs/geoip-blocking.md](docs/geoip-blocking.md)**
## Permanent Ban System for Repeat Offenders
### Overview
**Status:** ✅ **Implemented** - Automated permanent banning of persistent attackers
**Script:** `scripts/permanent-ban-repeat-offenders.sh`
**Purpose:** Automatically identify and permanently ban IPs that have been banned by fail2ban more than a threshold number of times
### How It Works
#### Detection Logic
1. **Log Analysis:** Scans `/var/log/fail2ban.log*` for ban entries
2. **IP Extraction:** Extracts IP addresses from ban log entries
3. **Frequency Counting:** Counts how many times each IP has been banned
4. **Threshold Check:** Identifies IPs banned more than the threshold (4 times)
#### Permanent Banning Process
For each repeat offender:
1. **Country Lookup:** Uses `whois` to determine the country of origin
2. **Banlist Update:** Adds IP to `/etc/fail2ban/permanent-banlist.conf`
3. **Firewall Rule:** Creates permanent iptables DROP rule
4. **Persistence:** Saves iptables rules to `/etc/iptables/iptables.rules`
5. **Service Reload:** Reloads fail2ban to recognize the updated banlist
### Configuration
#### Threshold Settings
```bash
THRESHOLD=4 # Ban after 4 fail2ban bans
```
#### File Locations
- **Log File:** `/var/log/permanent-ban.log`
- **Banlist:** `/etc/fail2ban/permanent-banlist.conf`
- **Iptables Rules:** `/etc/iptables/iptables.rules`
#### Cron Schedule
- **Frequency:** Daily at 2:00 AM (`0 2 * * *`)
- **User:** root
- **Command:** `/home/hoborg/homelab/scripts/permanent-ban-repeat-offenders.sh`
### Security Benefits
#### Multi-Layer Protection
1. **fail2ban:** Temporary bans for suspicious activity
2. **Permanent Bans:** Long-term blocking of persistent attackers
3. **Geographic Blocking:** Country-level filtering via geoip-shell
4. **Network-Level:** iptables rules at the firewall level
#### Attack Prevention
- **Brute Force:** Blocks IPs that repeatedly attempt attacks
- **Botnets:** Prevents automated attacks from compromised hosts
- **Persistence:** Maintains bans across system reboots
- **Resource Protection:** Reduces server load from repeat offenders
### Monitoring and Maintenance
#### Log Analysis
```bash
# View permanent ban activity
tail -f /var/log/permanent-ban.log
# Check current permanent bans
cat /etc/fail2ban/permanent-banlist.conf
# View iptables permanent rules
iptables -L | grep DROP
```
#### Manual Execution
```bash
# Run the script manually (requires root)
sudo /home/hoborg/homelab/scripts/permanent-ban-repeat-offenders.sh
```
#### Unban Procedure
To manually unban a permanently banned IP:
```bash
# Remove from banlist
sudo sed -i "/^192\.168\.1\.100/d" /etc/fail2ban/permanent-banlist.conf
# Remove iptables rule (find the rule number first)
sudo iptables -L --line-numbers | grep "192.168.1.100"
sudo iptables -D INPUT <rule_number>
# Save iptables rules
sudo iptables-save > /etc/iptables/iptables.rules
# Reload fail2ban
sudo systemctl reload fail2ban
```
### Integration with Security Stack
#### Complementary Tools
- **fail2ban:** Provides temporary bans that feed into permanent ban detection
- **geoip-shell:** Geographic blocking at the network level
- **UFW:** Additional firewall layer
- **SSH Hardening:** Reduces initial attack surface
#### Workflow
```
Attack Attempt → fail2ban Detection → Temporary Ban → Repeat Offense → Permanent Ban → Geographic Block
```
### Troubleshooting
#### Common Issues
- **Script Not Running:** Check cron job configuration
- **Permission Errors:** Ensure script is executable and paths are correct
- **whois Failures:** Some IPs may not return country information
- **iptables-save Issues:** Check if iptables-persistent is installed
#### Diagnostic Commands
```bash
# Check cron service
sudo systemctl status cron
# Test script manually
sudo bash -x /home/hoborg/homelab/scripts/permanent-ban-repeat-offenders.sh
# Verify iptables rules
sudo iptables -L -n | grep DROP
# Check fail2ban integration
sudo fail2ban-client status
```
## Router Configuration
### Port Forwarding

View File

@@ -0,0 +1,64 @@
#!/bin/bash
# Permanent ban script for IPs that have been banned more than 4 times by fail2ban
# Run via cron: 0 */6 * * * /home/hoborg/homelab/scripts/permanent-ban-repeat-offenders.sh
LOGFILE="/var/log/permanent-ban.log"
BANLIST_FILE="/etc/fail2ban/permanent-banlist.conf"
THRESHOLD=4
# Function to log with timestamp
log_message() {
echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" | tee -a "$LOGFILE"
}
# Ensure permanent banlist file exists
if [ ! -f "$BANLIST_FILE" ]; then
touch "$BANLIST_FILE"
chmod 644 "$BANLIST_FILE"
fi
log_message "Starting repeat offender analysis (threshold: $THRESHOLD bans)"
# Get list of IPs with ban counts from fail2ban logs
REPEAT_OFFENDERS=$(grep "Ban " /var/log/fail2ban.log* | \
grep -oE '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' | \
sort | uniq -c | sort -nr | \
awk -v threshold="$THRESHOLD" '$1 > threshold {print $2 " " $1}')
if [ -z "$REPEAT_OFFENDERS" ]; then
log_message "No repeat offenders found above threshold"
exit 0
fi
# Process each repeat offender
echo "$REPEAT_OFFENDERS" | while read ip ban_count; do
# Skip if already permanently banned
if grep -q "^$ip" "$BANLIST_FILE"; then
log_message "IP $ip already permanently banned (skip)"
continue
fi
# Get country information
COUNTRY=$(whois "$ip" 2>/dev/null | grep -i "country:" | head -1 | awk '{print $2}')
# Add to permanent banlist
echo "$ip # Banned $(date '+%Y-%m-%d') - $ban_count offenses - Country: $COUNTRY" >> "$BANLIST_FILE"
# Add permanent iptables rule
iptables -I INPUT -s "$ip" -j DROP
# Make iptables rule persistent (systemd approach)
if command -v iptables-save >/dev/null 2>&1; then
iptables-save > /etc/iptables/iptables.rules 2>/dev/null || true
fi
log_message "PERMANENTLY BANNED: $ip ($ban_count offenses, Country: $COUNTRY)"
done
# Reload fail2ban to ensure it sees the updated banlist
if systemctl is-active --quiet fail2ban; then
log_message "Reloading fail2ban service"
systemctl reload fail2ban
fi
log_message "Repeat offender analysis completed"