Compare commits

..

20 Commits

Author SHA1 Message Date
12ff0e15bd Add Gitea troubleshooting documentation
- Document common Docker issues and filesystem permission problems
- Include service management and configuration validation steps
- Provide systematic debugging approach for Gitea deployment issues
2025-09-13 20:50:43 +02:00
cff0ee6acb Update project documentation
- Add security hardening guidelines to CLAUDE.md with container-specific notes
- Update TODO.md with new security and dockerization tasks
- Add geoblocking and syncthing sync items to task list
2025-09-13 20:50:31 +02:00
de6fa58726 Update homepage: Replace Transmission with qBittorrent 2025-09-13 20:50:14 +02:00
e608ce6d5b Update Docker configurations for balanced security and functionality
- Simplify daemon.json to minimal working version, removing problematic
  security settings that caused read-only filesystem issues
- Update Gitea docker-compose.yml to working configuration:
  - Remove read-only filesystem (breaks s6-overlay init)
  - Keep user privilege dropping via USER_UID/USER_GID
  - Bind SSH port directly for Git operations
  - Maintain localhost binding for web interface
2025-09-13 20:49:34 +02:00
66e3249ced Update qBittorrent setup documentation
- Enhanced configuration and security guidance
- Updated setup procedures and best practices
2025-09-12 20:41:06 +02:00
398862c72b Update CLAUDE.md with latest project documentation
- Updated project instructions and configuration guidance
- Enhanced development workflow documentation
2025-09-12 20:40:50 +02:00
9f4f79a85e Add development tooling documentation
- AGENTS.md: Documentation for AI agents and development workflows
- opencode.json: OpenCode configuration file for testing alternative AI tools
2025-09-12 20:40:36 +02:00
06f837f4a1 Add project gitignore 2025-09-12 20:40:21 +02:00
0065113a19 docs: Add development tools section with OpenCode evaluation
- Document OpenCode as tested alternative to Claude Code
- Note: OpenCode is excellent but causes laptop overheating during intensive use
2025-09-12 20:39:17 +02:00
5a4eb2fd72 Add automated security hardening setup script
- scripts/setup-security-hardening.sh: One-command deployment of all security configurations
- Includes SSH hardening, kernel parameters, Docker security, fail2ban, and nginx rate limiting
- Provides status output and next steps for verification
2025-09-12 20:39:02 +02:00
ad9a3ab23e Add comprehensive security documentation
- docs/ssh-honeypot-setup.md: Complete SSH honeypot installation and monitoring guide
- docs/ssh-intrusion-monitoring.md: SSH attack detection and analysis procedures
- docs/security-configurations.md: Updated catalog of all security configuration files
- Includes installation procedures, monitoring commands, and troubleshooting guides
2025-09-12 20:38:49 +02:00
8bbe8e0e28 Add Docker daemon and service hardening configurations
- config/docker/daemon.json: Docker security hardening with logging limits and security options
- config/systemd/nginx.service.d/rate-limit.conf: Nginx resource limits and connection throttling
- Includes deployment instructions for container and service security
2025-09-12 20:38:33 +02:00
5e714f4e45 Add SSH hardening and kernel security configurations
- config/ssh/sshd_config_hardening: Enhanced SSH security settings
- config/ssh/banner: Legal warning banner for SSH connections
- config/sysctl/99-security.conf: Kernel network and memory protection parameters
- Includes deployment instructions for system-level hardening
2025-09-12 20:38:21 +02:00
9fbc311c2d Add comprehensive fail2ban security configuration
- config/fail2ban/jail.local: Main jail configuration with SSH, web, and service protection
- config/fail2ban/filter.d/sshd-ddos.conf: SSH connection flooding protection
- config/fail2ban/filter.d/nginx-badbots.conf: Web scanner and bot detection
- config/fail2ban/filter.d/gitea-auth.conf: Gitea authentication failure detection
- Includes deployment instructions for automated IP banning
2025-09-12 20:38:07 +02:00
471659a95a Add SSH honeypot configuration files
- config/systemd/ssh-honeypot.service: Systemd service for port 22 honeypot
- config/honeypot/response.sh: Response script that logs connections and sends fake SSH banner
- Both files include deployment instructions and setup commands
2025-09-12 20:37:30 +02:00
3d2201bc40 docs: Add comprehensive security hardening guide
- Document critical security vulnerabilities found
- Provide step-by-step hardening procedures
- Include SSL certificate recovery from git history
- Add SSH hardening with Mosh compatibility
- Document VPN setup with WireGuard
- Create implementation checklists and status tracking
2025-09-12 19:21:47 +02:00
6980c36ae9 Harden Docker container configurations
- Gitea: Bind ports to localhost, add security options, resource limits, health checks
- Jellyfin: Add security options, enhanced resource limits, health checks (kept host networking for GPU)
- qBittorrent: Bind torrent ports to localhost, add security options, health checks
- All configs: Non-root users, capability drops, no-new-privileges, tmpfs hardening

Security improvements:
- Ports no longer exposed to all interfaces (0.0.0.0)
- Added security options (no-new-privileges, cap_drop)
- Resource limits and health checks implemented
- Read-only filesystems where possible
- Temporary filesystems with restrictions
2025-09-12 19:14:59 +02:00
ff2aedacf6 Add qBittorrent Docker configuration
- Add docker-compose.yml for qBittorrent container setup
- Add config directory with qBittorrent configuration files
- Include GeoDB, RSS feeds, categories, and watched folders config
2025-09-12 19:00:56 +02:00
ee5f2a4c18 Add service configurations and documentation
- Update Jellyfin Docker Compose configuration
- Add qBittorrent manual setup documentation
2025-09-12 18:53:58 +02:00
3dfe146297 Update core configuration files
- Update CLAUDE.md with comprehensive homelab documentation
- Update TODO.md with current task status
- Configure copyparty file server settings
- Update nginx reverse proxy configuration
- Refresh homelab homepage
- Update services documentation
2025-09-12 18:53:49 +02:00
42 changed files with 2261 additions and 73 deletions

1
.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
scripts/tmp/*

76
AGENTS.md Normal file
View File

@@ -0,0 +1,76 @@
# AI Agent Instructions and Restrictions
## CRITICAL SECURITY RESTRICTIONS
### ❌ SUDO COMMAND PROHIBITION
**NEVER, UNDER ANY CIRCUMSTANCES, RUN SUDO COMMANDS**
The AI agent MUST NOT execute any commands that require elevated privileges:
-`sudo` commands
-`su` commands
- ❌ Commands that modify system files directly
- ❌ Commands that require root privileges
### ✅ APPROVED ALTERNATIVES
Instead of running sudo commands, the AI should:
1. **Create scripts** that the user can run with `sudo -A`
2. **Document commands** for the user to execute manually
3. **Explain what needs to be done** and why
4. **Provide step-by-step instructions** for the user
### EXAMPLES
**❌ WRONG:**
```bash
sudo systemctl restart nginx
sudo chmod 755 /etc/nginx/conf.d/
```
**✅ CORRECT:**
```bash
# Create a script for the user to run
echo "systemctl restart nginx" > /tmp/restart-nginx.sh
chmod +x /tmp/restart-nginx.sh
# Then tell the user:
# "Run: sudo -A /tmp/restart-nginx.sh"
```
### RATIONALE
- User explicitly denied AI access to sudo
- Security best practice: AI should not have root privileges
- User prefers manual control over system changes
- Prevents accidental system modifications
### VERIFICATION
This restriction has been tested and verified:
- ✅ AI cannot run sudo commands via bash tool
- ✅ AI will create scripts instead
- ✅ User maintains full control over privileged operations
## OTHER OPERATIONAL GUIDELINES
### File Operations
- ✅ Read files in user directories
- ✅ Write files in user directories
- ✅ Create scripts in `/tmp` or user directories
- ❌ Modify system configuration files directly
### Network Operations
- ✅ Check network status with unprivileged commands
- ✅ Test connectivity
- ❌ Modify firewall rules directly
- ❌ Bind to privileged ports (< 1024)
### Service Management
- Start/stop/restart system services directly
- Check service status with unprivileged commands
- Create systemd service files for user to deploy
---
**REMEMBER: When in doubt, create a script and let the user run it with sudo.**

View File

@@ -183,4 +183,13 @@ rclone mount homelab-webdav: ~/homelab-files --daemon
# Test WebDAV
curl -X PROPFIND https://hoborg:AdminPass2024!@ak-homelab.duckdns.org/files/ \
-H "Depth: 1" -H "Content-Type: text/xml"
```
```
- Always edit the local configs before when possible, and then copy them to the proper location. Instead of editing system files directly (and then losing the config and it won't be in this repo)
- Never run sudo commands, instead create a script in scripts/tmp and ask the user to run it.
## Security Hardening Guidelines
- When working on security hardening, make sure you **understand the service needs** first, to ensure the security doesn't interfre with normal operations (e.g. some services need read/write filesystem access, not just read)
- 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)

View File

@@ -21,6 +21,10 @@ Setting up a personal homelab using a ThinkPad laptop running Arch Linux to move
- **Android tablet**: Not good for long-term work but can be useful for short SSH sessions
- Runs Manjaro in a VM, same OS like the laptop
## Development Tools
- **Claude Code**: Primary AI coding assistant (via CLI)
- **OpenCode**: Tested alternative - excellent tool, better than Claude Code in some ways, but causes laptop overheating issues during intensive use
## Inspiration & Resources
- PewDiePie homelab setup video: https://www.youtube.com/watch?v=u_Lxkt50xOg
- Need to collect tips and inspiration from this video

19
TODO.md
View File

@@ -5,6 +5,21 @@
- [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.
- [ ] !!! 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
- [ ] Ran out of AI quota mid-security review so continue where we left off. Some scripts created but it's not
complete yet
- [ ] Some logs saved to ~/audit
- [ ] ENCRYPTED FOLDER idea:
- Use tomb to create an encrypted vault e.g. /mnt/nas/nas_encrypted
- Have a local folder that's empty e.g. <something>/nas_plain
- Use tomb to unlock and mount /mnt/nas/nas_encrypted to <something>/nas_plain
- Jellyfin is set up to look at nas_plain
- When locked: Jellyfin sees empty folder
- When unlocked: Jellyfin has access
- TO TEST: What about preview pictures etc. within Jellyfin? Adult content may still be visible
- [ ] WireGuard VPN server configuration
- [ ] UFW firewall setup and rules
- [ ] fail2ban for intrusion prevention
@@ -53,7 +68,7 @@ Lower priority - mostly using SSH or TTY anyways
- [ ] Copy any media files from other devices
## Music Collection Management
- [ ] Extract playlists from YouTube Music and SoundCloud
- [ ] Extract playlists from YouTube Music and SoundCloud
- Store metadata (author, song title) in plaintext format
- Tools to consider: ytmusicapi (YouTube Music), scdl (SoundCloud), Google Takeout
- Output formats: CSV, JSON, M3U with metadata, plain text lists
@@ -88,7 +103,7 @@ Lower priority - mostly using SSH or TTY anyways
- [x] Set up reverse proxy with SSL certificates *(completed - HTTPS working with auto-renewal)*
- [ ] Make sure all services are dockerized unless we have a good reason not to
- Gitea: ✅ Docker
- Jellyfin: ✅ Docker
- Jellyfin: ✅ Docker
- Copyparty: ❌ systemd service (consider dockerizing)
- Nginx: ❌ system package (fine as-is for reverse proxy)
- Portainer: ✅ Docker

View File

@@ -31,35 +31,41 @@
hoborg: AdminPass2024!
[/shared]
/home/hoborg/shared
/mnt/nas/shared
accs:
rw: guest
rwmd: hoborg
[/documents]
/home/hoborg/Documents
/mnt/nas/documents
accs:
rwmd: hoborg
[/music]
/home/hoborg/Music
/mnt/nas/music
accs:
rw: guest
rwmd: hoborg
[/videos]
/home/hoborg/Videos
/mnt/nas/videos
accs:
rw: guest
rwmd: hoborg
[/private]
/home/hoborg/private
/mnt/nas/private
accs:
rwmd: hoborg
[/pictures]
/home/hoborg/Pictures
/mnt/nas/pictures
accs:
rw: guest
rwmd: hoborg
[/torrent]
/mnt/nas/torrent
accs:
rw: guest
rwmd: hoborg

17
config/docker/daemon.json Normal file
View File

@@ -0,0 +1,17 @@
# Docker Daemon Configuration (Minimal Working Version)
# Deploy to: /etc/docker/daemon.json
#
# Setup commands:
# sudo cp config/docker/daemon.json /etc/docker/
# sudo systemctl restart docker
#
# Note: Removed problematic security settings that caused read-only filesystem issues.
# Only keeping essential logging configuration.
{
"log-driver": "json-file",
"log-opts": {
"max-size": "100m",
"max-file": "3"
}
}

View File

@@ -3,6 +3,11 @@
# Create data directory: sudo mkdir -p /opt/docker/gitea/data
# Set permissions: sudo chown -R hoborg:hoborg /opt/docker/gitea
# WORKING CONFIGURATION - Balanced security and functionality
# - Ports bound to localhost only
# - Non-root user (1000:1000)
# - Removed read-only filesystem (causes s6-svscan issues)
networks:
gitea:
external: false
@@ -14,13 +19,35 @@ services:
environment:
- USER_UID=1000
- USER_GID=1000
restart: always
- GITEA__server__ROOT_URL=https://ak-homelab.duckdns.org/gitea/
- GITEA__server__SSH_PORT=2223
restart: unless-stopped
# Let Gitea container handle user switching internally (USER_UID/USER_GID)
# DO NOT set user: directive - breaks s6-overlay init system
networks:
- gitea
volumes:
- ./data:/data
- /etc/timezone:/etc/timezone:ro
- /etc/localtime:/etc/localtime:ro
# Bind ports to localhost only for reverse proxy
ports:
- "3000:3000"
- "2223:22"
- "127.0.0.1:3000:3000"
- "2223:22"
# Reasonable resource limits
deploy:
resources:
limits:
memory: 1G
# Health check
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/api/healthz"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s

View File

@@ -2,6 +2,13 @@
# Deploy with: sudo mkdir -p /opt/docker/jellyfin && sudo cp config/docker/jellyfin/docker-compose.yml /opt/docker/jellyfin/
# Start with: cd /opt/docker/jellyfin && sudo docker-compose up -d
# HARDENED CONFIGURATION - Updated for security
# - Non-root user maintained (1000:1000)
# - Security options added
# - Resource limits enhanced
# - Health check added
# - Network mode kept for hardware acceleration (acceptable risk)
services:
jellyfin:
image: jellyfin/jellyfin:latest
@@ -16,8 +23,24 @@ services:
- JELLYFIN_PublishedServerUrl=https://ak-homelab.duckdns.org/media
# Network mode for better performance and hardware acceleration
# NOTE: Host networking is required for GPU hardware acceleration
# This is an acceptable security trade-off for media performance
network_mode: host
# Security hardening
read_only: false # Jellyfin needs write access for transcoding
tmpfs:
- /tmp:noexec,nosuid,size=2G
cap_drop:
- ALL
cap_add:
- CHOWN
- SETUID
- SETGID
- DAC_OVERRIDE
security_opt:
- no-new-privileges:true
# Volume mounts - using same folders as Copyparty
volumes:
# Jellyfin configuration and data
@@ -25,11 +48,11 @@ services:
- /opt/docker/jellyfin/cache:/cache
# Media folders (shared with Copyparty)
- /home/hoborg/Music:/media/music:ro
- /home/hoborg/Videos:/media/videos:ro
- /home/hoborg/Pictures:/media/pictures:ro
- /home/hoborg/shared:/media/shared:ro
- /home/hoborg/private:/media/private:ro
- /mnt/nas/music:/media/music:ro
- /mnt/nas/videos:/media/videos:ro
- /mnt/nas/pictures:/media/pictures:ro
- /mnt/nas/shared:/media/shared:ro
- /mnt/nas/private:/media/private:ro
# Additional media folders if they exist
# - /home/hoborg/Movies:/media/movies:ro
@@ -39,15 +62,20 @@ services:
devices:
- /dev/dri:/dev/dri
# Memory limits for container stability
# Enhanced resource limits
deploy:
resources:
limits:
cpus: '2.0'
memory: 2G
reservations:
cpus: '0.5'
memory: 512M
# Optional: Create a custom network if not using host networking
# networks:
# jellyfin:
# driver: bridge
# Health check
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8096/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 60s

View File

@@ -0,0 +1,2 @@
{
}

View File

@@ -0,0 +1,79 @@
(N) 2025-09-10T12:25:50 - qBittorrent v5.1.2 started. Process ID: 153
(N) 2025-09-10T12:25:50 - Using config directory: /config/qBittorrent
(N) 2025-09-10T12:25:50 - Trying to listen on the following list of IP addresses: "0.0.0.0:6881,[::]:6881"
(I) 2025-09-10T12:25:50 - Peer ID: "-qB5120-"
(I) 2025-09-10T12:25:50 - HTTP User-Agent: "qBittorrent/5.1.2"
(I) 2025-09-10T12:25:50 - Distributed Hash Table (DHT) support: ON
(I) 2025-09-10T12:25:50 - Local Peer Discovery support: ON
(I) 2025-09-10T12:25:50 - Peer Exchange (PeX) support: ON
(I) 2025-09-10T12:25:50 - Anonymous mode: OFF
(I) 2025-09-10T12:25:50 - Encryption support: ON
(I) 2025-09-10T12:25:50 - Successfully listening on IP. IP: "127.0.0.1". Port: "TCP/6881"
(I) 2025-09-10T12:25:50 - Successfully listening on IP. IP: "127.0.0.1". Port: "UTP/6881"
(I) 2025-09-10T12:25:50 - Successfully listening on IP. IP: "172.19.0.2". Port: "TCP/6881"
(I) 2025-09-10T12:25:50 - Successfully listening on IP. IP: "172.19.0.2". Port: "UTP/6881"
(I) 2025-09-10T12:25:50 - Successfully listening on IP. IP: "::1". Port: "TCP/6881"
(I) 2025-09-10T12:25:50 - Successfully listening on IP. IP: "::1". Port: "UTP/6881"
(W) 2025-09-10T12:25:50 - Couldn't load IP geolocation database. Reason: No such file or directory
(N) 2025-09-10T12:25:50 - Using built-in WebUI.
(W) 2025-09-10T12:25:50 - Couldn't load WebUI translation for selected locale (C).
(N) 2025-09-10T12:25:50 - WebUI: Now listening on IP: *, port: 8080
(I) 2025-09-10T12:25:50 - Detected external IP. IP: "31.46.51.110"
(I) 2025-09-10T12:25:50 - IP geolocation database loaded. Type: DBIP-Country-Lite. Build time: Mon Sep 1 03:19:30 2025.
(I) 2025-09-10T12:25:50 - Successfully updated IP geolocation database.
(W) 2025-09-10T12:27:31 - WebAPI login failure. Reason: invalid credentials, attempt count: 1, IP: ::ffff:172.19.0.1, username: admin
(W) 2025-09-10T12:27:37 - WebAPI login failure. Reason: invalid credentials, attempt count: 2, IP: ::ffff:172.19.0.1, username: admin
(W) 2025-09-10T12:28:34 - WebAPI login failure. Reason: invalid credentials, attempt count: 3, IP: ::ffff:172.19.0.1, username: admin
(N) 2025-09-10T12:29:02 - WebAPI login success. IP: ::ffff:172.19.0.1
(N) 2025-09-10T12:30:39 - WebUI translation for selected locale (en) has been successfully loaded.
(N) 2025-09-10T12:31:08 - WebAPI login success. IP: ::ffff:172.19.0.1
(N) 2025-09-10T23:41:28 - qBittorrent termination initiated
(N) 2025-09-10T23:41:28 - Saving resume data completed.
(N) 2025-09-10T23:41:28 - BitTorrent session successfully finished.
(N) 2025-09-10T23:41:28 - qBittorrent is now ready to exit
(N) 2025-09-10T23:43:04 - qBittorrent v5.1.2 started. Process ID: 148
(N) 2025-09-10T23:43:04 - Using config directory: /config/qBittorrent
(N) 2025-09-10T23:43:04 - Trying to listen on the following list of IP addresses: "0.0.0.0:6881,[::]:6881"
(I) 2025-09-10T23:43:04 - Peer ID: "-qB5120-"
(I) 2025-09-10T23:43:04 - HTTP User-Agent: "qBittorrent/5.1.2"
(I) 2025-09-10T23:43:04 - Distributed Hash Table (DHT) support: ON
(I) 2025-09-10T23:43:04 - Local Peer Discovery support: ON
(I) 2025-09-10T23:43:04 - Peer Exchange (PeX) support: ON
(I) 2025-09-10T23:43:04 - Anonymous mode: OFF
(I) 2025-09-10T23:43:04 - Encryption support: ON
(I) 2025-09-10T23:43:04 - IP geolocation database loaded. Type: DBIP-Country-Lite. Build time: Mon Sep 1 03:19:30 2025.
(N) 2025-09-10T23:43:04 - Using built-in WebUI.
(N) 2025-09-10T23:43:04 - WebUI translation for selected locale (en) has been successfully loaded.
(N) 2025-09-10T23:43:04 - WebUI: Now listening on IP: *, port: 8080
(I) 2025-09-10T23:43:04 - Successfully listening on IP. IP: "127.0.0.1". Port: "TCP/6881"
(I) 2025-09-10T23:43:04 - Successfully listening on IP. IP: "127.0.0.1". Port: "UTP/6881"
(I) 2025-09-10T23:43:04 - Successfully listening on IP. IP: "172.19.0.2". Port: "TCP/6881"
(I) 2025-09-10T23:43:04 - Successfully listening on IP. IP: "172.19.0.2". Port: "UTP/6881"
(I) 2025-09-10T23:43:04 - Successfully listening on IP. IP: "::1". Port: "TCP/6881"
(I) 2025-09-10T23:43:04 - Successfully listening on IP. IP: "::1". Port: "UTP/6881"
(I) 2025-09-10T23:43:07 - Detected external IP. IP: "31.46.51.110"
(N) 2025-09-12T09:27:37 - qBittorrent termination initiated
(N) 2025-09-12T09:27:37 - Saving resume data completed.
(N) 2025-09-12T09:27:37 - BitTorrent session successfully finished.
(N) 2025-09-12T09:27:37 - qBittorrent is now ready to exit
(N) 2025-09-12T09:29:21 - qBittorrent v5.1.2 started. Process ID: 146
(N) 2025-09-12T09:29:21 - Using config directory: /config/qBittorrent
(N) 2025-09-12T09:29:21 - Trying to listen on the following list of IP addresses: "0.0.0.0:6881,[::]:6881"
(I) 2025-09-12T09:29:21 - Peer ID: "-qB5120-"
(I) 2025-09-12T09:29:21 - HTTP User-Agent: "qBittorrent/5.1.2"
(I) 2025-09-12T09:29:21 - Distributed Hash Table (DHT) support: ON
(I) 2025-09-12T09:29:21 - Local Peer Discovery support: ON
(I) 2025-09-12T09:29:21 - Peer Exchange (PeX) support: ON
(I) 2025-09-12T09:29:21 - Anonymous mode: OFF
(I) 2025-09-12T09:29:21 - Encryption support: ON
(I) 2025-09-12T09:29:21 - Successfully listening on IP. IP: "127.0.0.1". Port: "TCP/6881"
(I) 2025-09-12T09:29:21 - Successfully listening on IP. IP: "127.0.0.1". Port: "UTP/6881"
(I) 2025-09-12T09:29:21 - Successfully listening on IP. IP: "172.19.0.2". Port: "TCP/6881"
(I) 2025-09-12T09:29:21 - Successfully listening on IP. IP: "172.19.0.2". Port: "UTP/6881"
(I) 2025-09-12T09:29:21 - Successfully listening on IP. IP: "::1". Port: "TCP/6881"
(I) 2025-09-12T09:29:21 - Successfully listening on IP. IP: "::1". Port: "UTP/6881"
(I) 2025-09-12T09:29:21 - IP geolocation database loaded. Type: DBIP-Country-Lite. Build time: Mon Sep 1 03:19:30 2025.
(N) 2025-09-12T09:29:21 - Using built-in WebUI.
(N) 2025-09-12T09:29:21 - WebUI translation for selected locale (en) has been successfully loaded.
(N) 2025-09-12T09:29:21 - WebUI: Now listening on IP: *, port: 8080
(I) 2025-09-12T09:29:23 - Detected external IP. IP: "31.46.51.110"

View File

@@ -0,0 +1,2 @@
[Stats]
AllStats=@Variant(\0\0\0\x1c\0\0\0\x2\0\0\0\x12\0\x41\0l\0l\0t\0i\0m\0\x65\0U\0L\0\0\0\x4\0\0\0\0\0\x12+H\0\0\0\x12\0\x41\0l\0l\0t\0i\0m\0\x65\0\x44\0L\0\0\0\x4\0\0\0\0\0\xf#()

View File

@@ -0,0 +1,55 @@
[Application]
FileLogger\Age=1
FileLogger\AgeType=1
FileLogger\Backup=true
FileLogger\DeleteOld=true
FileLogger\Enabled=true
FileLogger\MaxSizeBytes=66560
FileLogger\Path=/config/qBittorrent/logs
[AutoRun]
enabled=false
program=
[BitTorrent]
Session\AddTorrentStopped=false
Session\DefaultSavePath=/downloads/
Session\ExcludedFileNames=
Session\Port=6881
Session\QueueingSystemEnabled=true
Session\SSL\Port=6913
Session\ShareLimitAction=Stop
Session\TempPath=/downloads/incomplete/
[Core]
AutoDeleteAddedTorrentFile=Never
[LegalNotice]
Accepted=true
[Meta]
MigrationVersion=8
[Network]
Cookies=@Invalid()
PortForwardingEnabled=false
Proxy\HostnameLookupEnabled=false
Proxy\Profiles\BitTorrent=true
Proxy\Profiles\Misc=true
Proxy\Profiles\RSS=true
[Preferences]
Connection\PortRangeMin=6881
Connection\UPnP=false
Downloads\SavePath=/downloads/
Downloads\TempPath=/downloads/incomplete/
General\Locale=en
MailNotification\req_auth=true
WebUI\Address=*
WebUI\Password_PBKDF2="@ByteArray(ZKvbJkSupyOioYkDDVrMYA==:d65EaPafxao/dcmEXRsFaMgRcGBoCSxTcGZiY/LCa48TUErDQC03rNemvsCClKqDbi4ec7idnMkHd6Ila+4vxg==)"
WebUI\ServerDomains=*
WebUI\Username=hoborg
[RSS]
AutoDownloader\DownloadRepacks=true
AutoDownloader\SmartEpisodeFilter=s(\\d+)e(\\d+), (\\d+)x(\\d+), "(\\d{4}[.\\-]\\d{1,2}[.\\-]\\d{1,2})", "(\\d{1,2}[.\\-]\\d{1,2}[.\\-]\\d{4})"

View File

@@ -0,0 +1,2 @@
{
}

View File

@@ -0,0 +1,2 @@
{
}

View File

@@ -0,0 +1,71 @@
# DEPLOYMENT LOCATION: /opt/docker/qbittorrent/docker-compose.yml
# Deploy with: sudo mkdir -p /opt/docker/qbittorrent && sudo cp config/docker/qbittorrent/docker-compose.yml /opt/docker/qbittorrent/
# Start with: cd /opt/docker/qbittorrent && sudo docker-compose up -d
# HARDENED CONFIGURATION - Updated for security
# - Torrent ports bound to localhost (VPN/reverse tunnel recommended for external access)
# - Non-root user (1000:1000)
# - Security options added
# - Resource limits maintained
# - Read-only config volume where possible
services:
qbittorrent:
image: linuxserver/qbittorrent:latest
container_name: qbittorrent
restart: unless-stopped
# User and group IDs to match host user (hoborg)
environment:
- PUID=1000
- PGID=1000
- TZ=Europe/Prague
- WEBUI_PORT=8080
# Security hardening
user: "1000:1000"
read_only: false # qBittorrent needs write access for downloads
tmpfs:
- /tmp:noexec,nosuid,size=100m
cap_drop:
- ALL
cap_add:
- CHOWN
- SETUID
- SETGID
- NET_BIND_SERVICE # For port binding
security_opt:
- no-new-privileges:true
# Network - bind to localhost for security
# NOTE: For external torrent access, use VPN or port forwarding
ports:
- "127.0.0.1:8080:8080" # Web UI (reverse proxy only)
- "127.0.0.1:6881:6881" # BitTorrent TCP (localhost only)
- "127.0.0.1:6881:6881/udp" # BitTorrent UDP (localhost only)
# Volume mounts
volumes:
# qBittorrent configuration
- /opt/docker/qbittorrent/config:/config
# Torrent storage on NAS
- /mnt/nas/torrent:/downloads
# Enhanced resource limits
deploy:
resources:
limits:
cpus: '1.0'
memory: 1G
reservations:
cpus: '0.25'
memory: 256M
# Health check
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080"]
interval: 30s
timeout: 10s
retries: 3
start_period: 30s

View File

@@ -0,0 +1,9 @@
# Fail2ban filter for Gitea authentication failures
# Deploy to: /etc/fail2ban/filter.d/gitea-auth.conf
[Definition]
failregex = .*Failed authentication attempt for .* from <HOST>
.*Invalid credentials from <HOST>
.*Login attempt failed .* from <HOST>
ignoreregex =

View File

@@ -0,0 +1,17 @@
# Fail2ban filter for nginx bad bots and scanners
# Deploy to: /etc/fail2ban/filter.d/nginx-badbots.conf
[Definition]
failregex = ^<HOST> -.*"(GET|POST|HEAD).*HTTP.*" (400|401|403|404|405|406|407|408|409|410|411|412|413|414|415|416|417|500|501|502|503|504|505)
^<HOST> -.*".*sqlmap.*"
^<HOST> -.*".*nikto.*"
^<HOST> -.*".*nmap.*"
^<HOST> -.*".*masscan.*"
^<HOST> -.*".*nessus.*"
^<HOST> -.*".*openvas.*"
^<HOST> -.*".*vega.*"
^<HOST> -.*".*morfeus.*"
^<HOST> -.*".*ZmEu.*"
^<HOST> -.*".*Havij.*"
ignoreregex =

View File

@@ -0,0 +1,10 @@
# Fail2ban filter for SSH DDoS attacks
# Deploy to: /etc/fail2ban/filter.d/sshd-ddos.conf
# Catches rapid connection attempts that may overwhelm SSH
[Definition]
failregex = ^%(__prefix_line)sConnection from <HOST> port \d+$
^%(__prefix_line)sConnection closed by <HOST> port \d+ \[preauth\]$
^%(__prefix_line)sDisconnected from <HOST> port \d+ \[preauth\]$
ignoreregex =

View File

@@ -0,0 +1,98 @@
# Fail2ban Jail Configuration for Homelab
# Deploy to: /etc/fail2ban/jail.local
#
# Setup commands:
# sudo cp config/fail2ban/jail.local /etc/fail2ban/
# sudo systemctl restart fail2ban
# sudo systemctl enable fail2ban
[DEFAULT]
# Ban settings
bantime = 3600
findtime = 600
maxretry = 5
banaction = ufw
backend = systemd
# Ignore local networks and your management IPs
ignoreip = 127.0.0.1/8 ::1 192.168.0.0/16 10.0.0.0/8
# Email notifications (configure if needed)
# destemail = your-email@domain.com
# sender = fail2ban@homelab
# action = %(action_mwl)s
#
# SSH Protection (Critical - Primary attack vector)
#
[sshd]
enabled = true
port = 2222
filter = sshd
logpath = /var/log/auth.log
maxretry = 3
bantime = 7200
findtime = 300
[sshd-ddos]
enabled = true
port = 2222
filter = sshd-ddos
logpath = /var/log/auth.log
maxretry = 6
bantime = 3600
findtime = 60
#
# Web Service Protection
#
[nginx-http-auth]
enabled = true
filter = nginx-http-auth
logpath = /var/log/nginx/error.log
maxretry = 3
bantime = 3600
[nginx-badbots]
enabled = true
filter = nginx-badbots
logpath = /var/log/nginx/access.log
maxretry = 2
bantime = 86400
findtime = 600
[nginx-noscript]
enabled = true
filter = nginx-noscript
logpath = /var/log/nginx/access.log
maxretry = 6
bantime = 86400
[nginx-noproxy]
enabled = true
filter = nginx-noproxy
logpath = /var/log/nginx/access.log
maxretry = 2
bantime = 86400
#
# Docker/Container Protection
#
[gitea-auth]
enabled = true
filter = gitea-auth
logpath = /opt/docker/gitea/data/log/gitea.log
maxretry = 5
bantime = 1800
findtime = 300
#
# System Protection
#
[systemd-auth]
enabled = true
filter = systemd-auth
logpath = /var/log/auth.log
maxretry = 5
bantime = 3600
findtime = 300

View File

@@ -0,0 +1,20 @@
#!/bin/bash
# SSH Honeypot Response Script
# Deploy to: /opt/honeypot/response.sh
#
# Setup commands:
# sudo mkdir -p /opt/honeypot
# sudo cp config/honeypot/response.sh /opt/honeypot/
# sudo chmod +x /opt/honeypot/response.sh
# sudo touch /var/log/honeypot.log
# sudo chmod 644 /var/log/honeypot.log
# Log connection with timestamp and client IP
CLIENT_IP=${NCAT_REMOTE_ADDR:-unknown}
echo "$(date): SSH honeypot connection from $CLIENT_IP" >> /var/log/honeypot.log
# Send fake SSH banner to make it look like OpenSSH
echo "SSH-2.0-OpenSSH_8.9"
# Brief delay before closing connection
sleep 2

View File

@@ -21,6 +21,25 @@ server {
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
# qBittorrent Web UI
location /qbt/ {
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;
proxy_set_header X-Forwarded-Host $host;
# WebSocket support for real-time updates
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
# qBittorrent specific settings
proxy_cookie_path / "/qbt/";
proxy_redirect off;
}
# Main landing page - highest priority
location / {
root /var/www/homelab;
@@ -157,6 +176,7 @@ server {
proxy_set_header Connection "upgrade";
}
ssl_certificate /etc/letsencrypt/live/ak-homelab.duckdns.org/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/ak-homelab.duckdns.org/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot

14
config/ssh/banner Normal file
View File

@@ -0,0 +1,14 @@
# SSH Login Banner
# Deploy to: /etc/ssh/banner
================================================================================
AUTHORIZED ACCESS ONLY
================================================================================
This system is for authorized users only. All activity may be monitored and
recorded. Unauthorized access is prohibited and will be prosecuted to the
full extent of the law.
If you are not an authorized user, disconnect immediately.
================================================================================

View File

@@ -0,0 +1,22 @@
# SSH Hardening Configuration
# Deploy by appending to: /etc/ssh/sshd_config
#
# Setup commands:
# sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.backup
# sudo cat config/ssh/sshd_config_hardening >> /etc/ssh/sshd_config
# sudo sshd -t
# sudo systemctl restart sshd
# Enhanced security settings
ClientAliveInterval 300
ClientAliveCountMax 2
Compression no
LogLevel VERBOSE
MaxSessions 3
TCPKeepAlive no
X11Forwarding no
AllowAgentForwarding no
AllowTcpForwarding no
GatewayPorts no
PermitTunnel no
Banner /etc/ssh/banner

View File

@@ -0,0 +1,36 @@
# Kernel Security Parameters for Homelab
# Deploy to: /etc/sysctl.d/99-security.conf
#
# Setup commands:
# sudo cp config/sysctl/99-security.conf /etc/sysctl.d/
# sudo sysctl -p /etc/sysctl.d/99-security.conf
# Network security
net.ipv4.conf.default.rp_filter = 1
net.ipv4.conf.all.rp_filter = 1
net.ipv4.ip_forward = 0
net.ipv4.conf.all.accept_source_route = 0
net.ipv4.conf.default.accept_source_route = 0
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.default.accept_redirects = 0
net.ipv4.conf.all.secure_redirects = 0
net.ipv4.conf.default.secure_redirects = 0
net.ipv4.conf.all.send_redirects = 0
net.ipv4.conf.default.send_redirects = 0
net.ipv4.icmp_echo_ignore_broadcasts = 1
net.ipv4.icmp_ignore_bogus_error_responses = 1
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_max_syn_backlog = 2048
net.ipv4.tcp_syn_retries = 3
net.ipv4.tcp_synack_retries = 3
# IPv6 security (if enabled)
net.ipv6.conf.default.accept_redirects = 0
net.ipv6.conf.all.accept_redirects = 0
net.ipv6.conf.default.accept_source_route = 0
net.ipv6.conf.all.accept_source_route = 0
# Memory protection
kernel.dmesg_restrict = 1
kernel.kptr_restrict = 1
kernel.yama.ptrace_scope = 1

View File

@@ -0,0 +1,13 @@
# Nginx Service Rate Limiting Configuration
# Deploy to: /etc/systemd/system/nginx.service.d/rate-limit.conf
#
# Setup commands:
# sudo mkdir -p /etc/systemd/system/nginx.service.d
# sudo cp config/systemd/nginx.service.d/rate-limit.conf /etc/systemd/system/nginx.service.d/
# sudo systemctl daemon-reload
# sudo systemctl restart nginx
[Service]
# Limit nginx connections
LimitNOFILE=65536
LimitNPROC=4096

View File

@@ -0,0 +1,23 @@
# SSH Honeypot Service
# Deploy to: /etc/systemd/system/ssh-honeypot.service
#
# Setup commands:
# sudo cp config/systemd/ssh-honeypot.service /etc/systemd/system/
# sudo systemctl daemon-reload
# sudo systemctl enable ssh-honeypot.service
# sudo systemctl start ssh-honeypot.service
[Unit]
Description=SSH Honeypot (Port 22)
After=network.target
[Service]
ExecStart=/usr/bin/ncat -l -k -p 22 -c /opt/honeypot/response.sh
Restart=always
RestartSec=5
Group=honeypot
StandardOutput=journal
StandardError=journal
[Install]
WantedBy=multi-user.target

View File

@@ -150,6 +150,11 @@
<h3>Jellyfin</h3>
<p>Movies, Music & TV Shows</p>
</a>
<a href="/qbt/" class="service">
<i class="fas fa-download"></i>
<h3>qBittorrent</h3>
<p>Torrent Downloads</p>
</a>
</div>
</div>
@@ -180,6 +185,11 @@
<h3>NAS Storage</h3>
<p>Network Attached Storage</p>
</a>
<a href="http://localhost:8384/" class="service admin" target="_blank">
<i class="fas fa-sync-alt"></i>
<h3>Syncthing</h3>
<p>File Synchronization</p>
</a>
<a href="http://192.168.0.1" class="service admin" target="_blank">
<i class="fas fa-network-wired"></i>
<h3>Router</h3>

121
docs/qbittorrent-setup.md Normal file
View File

@@ -0,0 +1,121 @@
# qBittorrent Setup Guide
This document provides comprehensive step-by-step instructions for setting up qBittorrent in your homelab environment, including both automated deployment and manual configuration.
## Prerequisites
- qBittorrent container running via Docker
- NAS directory structure set up at `/mnt/nas/torrent/`
- Nginx reverse proxy configured for `/qbt/` path
## Current NAS Structure
The following directory structure should already exist:
```
/mnt/nas/torrent/
├── watch/
│ ├── music/
│ ├── videos/
│ ├── documents/
│ └── private/
└── complete/
├── music/
├── videos/
├── documents/
└── private/
```
## Manual Configuration Steps
### 1. Access qBittorrent Web UI
1. Open your browser and navigate to: `https://ak-homelab.duckdns.org/qbt/`
2. Login with:
- **Username**: `admin`
- **Password**: Check Docker logs for temporary password:
```bash
docker logs qbittorrent 2>&1 | grep "temporary password"
```
3. **IMPORTANT**: Change the default password on first login
### 2. Configure Basic Settings
1. Go to **Tools → Options → Downloads**
2. Set **Default Torrent Management Mode**: `Automatic`
3. Set **Default Save Path**: `/downloads/complete`
4. Enable **Auto managed torrents**
5. Click **Apply**
### 3. Create Download Categories
Right-click in the main torrent area and select **Add category** for each:
| Category | Save Path |
|----------|-----------|
| `music` | `/downloads/complete/music` |
| `videos` | `/downloads/complete/videos` |
| `documents` | `/downloads/complete/documents` |
| `private` | `/downloads/complete/private` |
### 4. Set Up Watch Folders
1. Go to **Tools → Options → Downloads**
2. Navigate to **Monitored Folder** section
3. Click **Add** to create watch folders:
| Watch Folder Path | Category |
|------------------|----------|
| `/downloads/watch/music` | `music` |
| `/downloads/watch/videos` | `videos` |
| `/downloads/watch/documents` | `documents` |
| `/downloads/watch/private` | `private` |
### 5. Test Configuration
1. Download a test `.torrent` file
2. Drop it into `/mnt/nas/torrent/watch/music/`
3. Verify it appears in qBittorrent with the correct category
4. Confirm it downloads to `/mnt/nas/torrent/complete/music/`
### 6. Optional: Hardlink Organization
After confirming downloads work correctly, you can set up automatic hardlinking to organize files for Jellyfin access:
```bash
./scripts/organize-torrents.py
```
This creates hardlinks from completed torrents to appropriate media directories without duplicating files.
## Troubleshooting
### Common Issues
1. **Permission errors**: Ensure qBittorrent container has read/write access to mounted volumes
2. **Watch folders not working**: Check that the paths are correctly mapped in docker-compose.yml
3. **Categories not auto-assigning**: Verify watch folder paths match exactly
### Docker Volume Mapping
Ensure your `docker-compose.yml` includes these volume mappings:
```yaml
volumes:
- /mnt/nas/torrent:/downloads
- qbittorrent-config:/config
```
### Logs
Check container logs for issues:
```bash
docker logs qbittorrent
```
## Security Recommendations
1. Change default admin password immediately
2. Enable 2FA if available in your qBittorrent version
3. Consider using authentication bypass only for local network access
4. Regularly update the container image for security patches

View File

@@ -0,0 +1,240 @@
# Security Configuration Files
## Overview
This document catalogs all security-related configuration files in the homelab repository and their deployment locations.
## SSH Security Configurations
### SSH Honeypot
- **Config File**: `config/systemd/ssh-honeypot.service`
- **Deploy To**: `/etc/systemd/system/ssh-honeypot.service`
- **Purpose**: Systemd service for SSH honeypot on port 22
- **Dependencies**: `config/honeypot/response.sh`
- **Config File**: `config/honeypot/response.sh`
- **Deploy To**: `/opt/honeypot/response.sh`
- **Purpose**: Response script for honeypot connections
- **Log File**: `/var/log/honeypot.log`
### SSH Service Hardening
- **System File**: `/etc/ssh/sshd_config`
- **Key Settings**:
- `Port 2222` (moved from default port 22)
- `PermitRootLogin no`
- `PasswordAuthentication no`
- `PubkeyAuthentication yes`
## Network Security
### Nginx Security Headers
- **Config File**: `config/nginx/homelab.conf`
- **Deploy To**: `/etc/nginx/sites-available/homelab`
- **Security Features**:
- SSL/TLS configuration
- Security headers (HSTS, CSP, etc.)
- Rate limiting
- Access controls
### NetworkManager Security
- **Config File**: `config/networkmanager/01-homelab.conf`
- **Deploy To**: `/etc/NetworkManager/conf.d/01-homelab.conf`
- **Purpose**: Static IP and interface security settings
## Service-Specific Security
### Gitea Security
- **Config File**: `config/docker/gitea/docker-compose.yml`
- **Security Features**:
- Custom SSH port (2223)
- Database isolation
- Volume permissions
- Network restrictions
### Jellyfin Security
- **Config File**: `config/docker/jellyfin/docker-compose.yml`
- **Security Features**:
- User/group restrictions
- Volume mount security
- Network isolation
### qBittorrent Security
- **Config File**: `config/docker/qbittorrent/docker-compose.yml`
- **Security Features**:
- VPN integration capability
- Web UI access controls
- File permission restrictions
## System Security Services
### Copyparty File Server
- **Config File**: `config/systemd/copyparty.service`
- **Deploy To**: `/etc/systemd/system/copyparty.service`
- **Config File**: `config/copyparty/copyparty.conf`
- **Deploy To**: `~/.config/copyparty/copyparty.conf`
- **Security Features**:
- WebDAV authentication
- Access controls
- Upload restrictions
## Security Hardening Configurations
### Fail2ban Intrusion Prevention
- **Config File**: `config/fail2ban/jail.local`
- **Deploy To**: `/etc/fail2ban/jail.local`
- **Purpose**: Automated IP banning for SSH, web, and service attacks
- **Config Files**: `config/fail2ban/filter.d/`
- **Deploy To**: `/etc/fail2ban/filter.d/`
- **Filters**:
- `sshd-ddos.conf` - SSH connection flooding protection
- `nginx-badbots.conf` - Web scanner and bot detection
- `gitea-auth.conf` - Gitea authentication failure detection
### SSH Security Hardening
- **Config File**: `config/ssh/sshd_config_hardening`
- **Deploy To**: Append to `/etc/ssh/sshd_config`
- **Purpose**: Enhanced SSH security settings
- **Config File**: `config/ssh/banner`
- **Deploy To**: `/etc/ssh/banner`
- **Purpose**: Legal warning banner for SSH connections
### Kernel Security Parameters
- **Config File**: `config/sysctl/99-security.conf`
- **Deploy To**: `/etc/sysctl.d/99-security.conf`
- **Purpose**: Network and memory protection parameters
### Docker Security Configuration
- **Config File**: `config/docker/daemon.json`
- **Deploy To**: `/etc/docker/daemon.json`
- **Purpose**: Docker daemon security hardening
### Service Rate Limiting
- **Config File**: `config/systemd/nginx.service.d/rate-limit.conf`
- **Deploy To**: `/etc/systemd/system/nginx.service.d/rate-limit.conf`
- **Purpose**: Nginx resource limits and connection throttling
## Monitoring and Logging
### Service Monitoring
- **Config File**: `config/systemd/glances-web.service`
- **Deploy To**: `/etc/systemd/system/glances-web.service`
- **Purpose**: System monitoring with web interface
### System Logging
- **Config File**: `config/systemd/01-server-logind.conf`
- **Deploy To**: `/etc/systemd/logind.conf.d/01-server-logind.conf`
- **Purpose**: Login and session security settings
## Security Documentation
### Setup Guides
- `docs/ssh-honeypot-setup.md` - SSH honeypot installation and configuration
- `docs/ssh-intrusion-monitoring.md` - Comprehensive SSH monitoring guide
- `docs/qbittorrent-setup.md` - Secure torrent client setup
### Security Procedures
- `docs/security-configurations.md` - This file (configuration catalog)
- Various service-specific security notes in configuration files
## Deployment Security
### File Permissions
All configuration files include deployment commands with appropriate permissions:
```bash
# Service files
sudo chmod 644 /etc/systemd/system/*.service
# Scripts
sudo chmod +x /opt/honeypot/response.sh
# Config files
sudo chmod 644 /etc/nginx/sites-available/*
sudo chmod 600 ~/.config/copyparty/copyparty.conf
```
### Service Security
```bash
# Enable services securely
sudo systemctl daemon-reload
sudo systemctl enable --now servicename.service
# Verify service status
sudo systemctl status servicename.service
```
## Security Validation
### Configuration Testing
```bash
# Test nginx configuration
sudo nginx -t
# Verify SSH configuration
sudo sshd -t
# Check systemd service syntax
sudo systemd-analyze verify /etc/systemd/system/servicename.service
```
### Security Scanning
```bash
# Check listening ports
ss -tlnp
# Verify service users and permissions
sudo systemctl show servicename.service
# Check file permissions
find config/ -type f -ls
```
## Security Updates
### Regular Maintenance
1. **Weekly**: Review honeypot logs, update fail2ban rules
2. **Monthly**: Update service configurations, security patches
3. **Quarterly**: Full security audit, penetration testing
4. **Annually**: Certificate renewal, security policy review
### Configuration Backup
All configurations are version-controlled in git:
```bash
# Backup current configs
git add config/ docs/
git commit -m "Update security configurations"
# Restore from backup
git checkout HEAD -- config/
```
## Security Contacts and Escalation
### Log Locations
- **Security Incidents**: `/var/log/security.log`
- **Authentication**: `/var/log/auth.log`
- **Honeypot**: `/var/log/honeypot.log`
- **Service Logs**: `journalctl -u servicename.service`
### Incident Response
1. Immediate containment (block IPs, disable services)
2. Evidence preservation (copy logs, take snapshots)
3. Impact assessment (check for compromise)
4. Recovery procedures (restore from known-good configs)
5. Post-incident review (update procedures and configurations)
## Compliance and Standards
### Security Frameworks
- **Network Security**: Defense in depth with multiple layers
- **Access Control**: Principle of least privilege
- **Monitoring**: Comprehensive logging and alerting
- **Incident Response**: Documented procedures and escalation
### Audit Trail
- All configuration changes tracked in git
- Service modifications logged via systemd
- Security events captured in dedicated log files
- Regular security reviews documented in commit messages

448
docs/security-hardening.md Normal file
View File

@@ -0,0 +1,448 @@
# Homelab Security Hardening Guide
## Overview
This document tracks the security hardening process for the homelab infrastructure. Based on security audit findings, we've identified critical vulnerabilities that need immediate attention.
## Critical Security Issues (IMMEDIATE ACTION REQUIRED)
### 🚨 Port Exposure Vulnerabilities
- **qBittorrent**: Currently binding to `0.0.0.0:6881` (exposed to all interfaces)
- **Gitea**: Currently binding to `0.0.0.0:3000` and `0.0.0.0:2223`
- **Portainer**: Docker management interface exposed on port 9000
**Status**: 🔴 NOT ADDRESSED
**Priority**: CRITICAL
**Impact**: Services accessible from internet without authentication
### 🚨 Missing Intrusion Prevention
- **fail2ban**: Not installed or running
- **Firewall**: UFW/iptables not properly configured
**Status**: 🔴 NOT ADDRESSED
**Priority**: CRITICAL
**Impact**: No protection against brute force attacks
### 🚨 SSL/TLS Missing
- **HTTPS**: SSL certificates were previously configured but may have been lost
- **Let's Encrypt**: Configuration exists in git history but needs restoration
- **Git History**: Found SSL config in commit `2cd1d87` with Let's Encrypt certificates
**Status**: 🟡 PARTIALLY ADDRESSED (config exists, needs deployment)
**Priority**: CRITICAL
**Impact**: All traffic unencrypted, vulnerable to MITM attacks
**Recovery Steps:**
```bash
# Restore SSL configuration from git
git show 2cd1d87:config/nginx/homelab.conf > config/nginx/homelab-ssl.conf
# Install certbot and get certificates
sudo pacman -S certbot certbot-nginx
sudo certbot --nginx -d ak-homelab.duckdns.org
# Deploy SSL-enabled nginx config
sudo cp config/nginx/homelab-ssl.conf /etc/nginx/sites-available/homelab
sudo nginx -t && sudo systemctl reload nginx
```
## Security Scripts Available
### ✅ Container Hardening (`scripts/harden-containers.sh`)
- Docker daemon configuration hardening
- Resource limits and security profiles
- Custom seccomp profiles
- Container security monitoring scripts
**Status**: 🟡 READY TO DEPLOY
**Next Step**: Run script and deploy hardened templates
### ✅ Credential Security (`scripts/secure-credentials.sh`)
- Secure credential storage in `/opt/homelab/secrets/`
- Docker secrets implementation
- Password generation utilities
- Access audit tools
**Status**: 🟡 READY TO DEPLOY
**Next Step**: Run script and migrate existing credentials
### ✅ Security Audit (`scripts/security-audit.sh`)
- Comprehensive system security assessment
- Credential exposure detection
- Service analysis and user audit
- Log analysis capabilities
**Status**: 🟡 READY TO USE
**Next Step**: Run initial audit to establish baseline
### ✅ Fail2ban Setup (`scripts/setup-fail2ban.sh`)
- SSH protection (port 2222)
- Nginx rate limiting and bot protection
- Custom filters for homelab services
- Attack analysis and monitoring tools
**Status**: 🟡 READY TO DEPLOY
**Next Step**: Install and configure fail2ban
### ✅ SSL Security (`scripts/ssl-security-audit.sh`)
- SSL/TLS configuration hardening
- Certificate monitoring and renewal
- Security headers implementation
- SSL testing and validation tools
**Status**: 🟡 READY TO DEPLOY
**Next Step**: Set up Let's Encrypt certificates first
## Implementation Plan
### Phase 1: Critical Security Fixes (Do NOW)
#### 1. Fix Port Exposure
```bash
# Bind services to localhost only
sudo docker update --publish-add "127.0.0.1:8080:8080" qbittorrent
sudo docker update --publish-rm "0.0.0.0:8080:8080" qbittorrent
sudo docker update --publish-add "127.0.0.1:3000:3000" gitea
sudo docker update --publish-rm "0.0.0.0:3000:3000" gitea
sudo docker update --publish-add "127.0.0.1:2223:22" gitea
sudo docker update --publish-rm "0.0.0.0:2223:22" gitea
```
#### 2. Install Fail2ban
```bash
sudo -A ./scripts/setup-fail2ban.sh
```
#### 3. Configure Basic Firewall
```bash
sudo ufw enable
sudo ufw allow 2222/tcp # SSH
sudo ufw allow 80/tcp # HTTP (temporary)
sudo ufw allow 443/tcp # HTTPS
sudo ufw allow 60000:61000/udp # Mosh UDP ports
sudo ufw --force reload
```
#### 4. SSH Hardening with Mosh Support
```bash
# Install Mosh for mobile SSH
sudo pacman -S mosh
# Edit /etc/ssh/sshd_config
sudo nano /etc/ssh/sshd_config
# Add these security settings:
# Port 2222 (already done)
# PermitRootLogin no
# PasswordAuthentication no # DISABLE AFTER KEY SETUP
# PubkeyAuthentication yes
# AllowUsers hoborg
# ClientAliveInterval 300
# ClientAliveCountMax 2
# MaxAuthTries 3
# Test SSH key authentication first
ssh-copy-id -i ~/.ssh/id_ed25519.pub hoborg@ak-homelab.duckdns.org -p 2222
# Then disable password authentication
# PasswordAuthentication no
# Restart SSH
sudo systemctl restart sshd
# Test Mosh connectivity
mosh hoborg@ak-homelab.duckdns.org --ssh="ssh -p 2222"
```
#### 4. Set Up SSL Certificates
```bash
sudo pacman -S certbot certbot-nginx
sudo certbot --nginx -d ak-homelab.duckdns.org
```
### Phase 2: Container Security
#### 1. Harden Docker Configuration
```bash
sudo -A ./scripts/harden-containers.sh
```
#### 2. Deploy Hardened Container Templates
```bash
sudo -A /opt/docker/monitoring/deploy-hardened-containers.sh
```
#### 3. Secure Credentials
```bash
sudo -A ./scripts/secure-credentials.sh
/opt/homelab/secrets/generate-passwords.sh
```
### Phase 3: SSH Hardening
#### 1. Set Up SSH Security Keys
- Generate SSH keys on management devices
- Add public keys to `~/.ssh/authorized_keys`
- Test key-based authentication
#### 2. Disable Password Authentication
```bash
# Edit /etc/ssh/sshd_config
PasswordAuthentication no
ChallengeResponseAuthentication no
UsePAM no
# Ensure Mosh compatibility
# Mosh uses UDP ports 60000-61000
sudo ufw allow 60000:61000/udp
# Restart SSH
sudo systemctl restart sshd
```
#### 3. Test Mosh Connectivity
```bash
# Install mosh if not present
sudo pacman -S mosh
# Test connection
mosh user@ak-homelab.duckdns.org --ssh="ssh -p 2222"
```
### Phase 4: Monitoring & Alerting
#### 1. Set Up System Monitoring
```bash
sudo -A ./scripts/setup-netdata.sh
sudo -A ./scripts/setup-glances.sh
```
#### 2. Configure SSL Monitoring
```bash
sudo -A ./scripts/ssl-security-audit.sh
sudo systemctl enable ssl-monitor.timer
```
#### 3. Set Up Regular Security Audits
```bash
# Add to cron for weekly audits
echo "0 2 * * 1 sudo -A /home/hoborg/homelab/scripts/security-audit.sh" | sudo tee -a /etc/cron.d/homelab-security
```
### Phase 5: VPN Setup (WireGuard)
#### 1. Install WireGuard
```bash
sudo pacman -S wireguard-tools
```
#### 2. Generate Server Keys
```bash
# Generate server keys
wg genkey | tee server_private.key | wg pubkey > server_public.key
# Generate client keys (on client device)
wg genkey | tee client_private.key | wg pubkey > client_public.key
```
#### 3. Server Configuration (/etc/wireguard/wg0.conf)
```ini
[Interface]
PrivateKey = <SERVER_PRIVATE_KEY>
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 enp4s0 -j MASQUERADE
PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -D FORWARD -o %i -j ACCEPT; iptables -t nat -D POSTROUTING -o enp4s0 -j MASQUERADE
[Peer]
PublicKey = <CLIENT_PUBLIC_KEY>
AllowedIPs = 10.0.0.2/32
```
#### 4. Client Configuration
```ini
[Interface]
PrivateKey = <CLIENT_PRIVATE_KEY>
Address = 10.0.0.2/24
DNS = 1.1.1.1
[Peer]
PublicKey = <SERVER_PUBLIC_KEY>
Endpoint = ak-homelab.duckdns.org:51820
AllowedIPs = 0.0.0.0/0
PersistentKeepalive = 25
```
#### 5. Enable VPN Service
```bash
sudo systemctl enable wg-quick@wg0
sudo systemctl start wg-quick@wg0
# Update firewall
sudo ufw allow 51820/udp
sudo ufw reload
```
#### 6. Router Port Forwarding
- Forward UDP port 51820 to homelab server
- Update DuckDNS to include VPN endpoint
#### 7. Test VPN Connectivity
```bash
# On client: Check VPN status
wg show
# Test homelab access through VPN
ssh hoborg@10.0.0.1 -p 2222
curl https://ak-homelab.duckdns.org
```
## Security Checklist
### Network Security
- [ ] Ports bound to localhost only
- [ ] Firewall configured and enabled
- [ ] Fail2ban installed and running
- [ ] VPN server configured
- [ ] SSH hardened (keys only, custom port)
### SSL/TLS Security
- [ ] Let's Encrypt certificates installed
- [ ] SSL configuration hardened
- [ ] HSTS headers configured
- [ ] Certificate monitoring active
- [ ] Perfect Forward Secrecy enabled
### Container Security
- [ ] Docker daemon hardened
- [ ] Containers run as non-root users
- [ ] Resource limits applied
- [ ] Security profiles enabled
- [ ] No privileged containers
### Credential Security
- [ ] Credentials moved to secure location
- [ ] Docker secrets implemented
- [ ] Strong passwords generated
- [ ] Access logging enabled
### Monitoring & Alerting
- [ ] System monitoring active (Netdata/Glances)
- [ ] Security event monitoring
- [ ] Log analysis configured
- [ ] Automated alerts set up
## Testing Procedures
### Security Testing
1. **Port Scanning**: `nmap -sV ak-homelab.duckdns.org`
2. **SSL Testing**: `sslscan ak-homelab.duckdns.org`
3. **Container Security**: `/opt/docker/monitoring/container-security-check.sh`
4. **Fail2ban Status**: `fail2ban-client status`
### Functionality Testing
1. **SSH Access**: Test key-based and password authentication
2. **Mosh Connectivity**: Test mobile SSH sessions
3. **VPN Access**: Test remote connectivity
4. **Service Access**: Verify all services work through Nginx proxy
5. **SSL Redirect**: Ensure HTTP redirects to HTTPS
## Emergency Procedures
### Security Incident Response
1. **Isolate**: Disconnect affected systems from network
2. **Assess**: Run security audit to identify compromise
3. **Contain**: Block malicious IPs, change credentials
4. **Recover**: Restore from clean backups
5. **Learn**: Update procedures based on incident
### Backup Security
- [ ] Encrypt backups
- [ ] Store offsite securely
- [ ] Test restoration procedures
- [ ] Include configuration backups
## Previous AI Agent Recommendations
### From CLAUDE.md (Voice Assistant Setup)
- ✅ Voice server configured for Claude Code
- ✅ Piper TTS integration working
- ✅ Mosh compatibility considerations noted
### From Git History Analysis
- **SSL Configuration**: Found complete Let's Encrypt setup in commit `2cd1d87`
- **WebDAV Support**: Advanced nginx configuration with security headers
- **Service Architecture**: Well-documented reverse proxy setup
### From network-security.md
- ✅ SSH port changed to 2222
- ✅ Router port forwarding updated
- ✅ Mosh configured (ISP UDP blocking noted)
- ✅ WireGuard VPN documentation complete
- ✅ fail2ban configuration documented
- ✅ UFW firewall setup documented
## Current Status Assessment
### ✅ Completed Items
- SSH port hardening (2222)
- Router port forwarding updates
- Voice assistant integration
- Network security documentation
- VPN setup documentation
### 🔴 Critical Issues (Immediate Action Required)
- Port exposure vulnerabilities
- Missing fail2ban installation
- SSL certificate restoration needed
- SSH password authentication still enabled
### 🟡 Partially Complete
- SSL configuration exists in git (needs deployment)
- Security scripts created (need execution)
- VPN documentation complete (needs implementation)
## Next Steps Priority
1. **IMMEDIATE**: Fix port exposure and install fail2ban
2. **HIGH**: Restore SSL certificates from git history
3. **MEDIUM**: Execute security hardening scripts
4. **MEDIUM**: Set up SSH key authentication and disable passwords
5. **LOW**: Implement WireGuard VPN
6. **LOW**: Set up monitoring and alerting
## References
### Security Resources
- [Docker Security Best Practices](https://docs.docker.com/develop/dev-best-practices/security/)
- [OWASP Docker Security Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Docker_Security_Cheat_Sheet.html)
- [Mozilla SSL Configuration Generator](https://ssl-config.mozilla.org/)
- [WireGuard Documentation](https://www.wireguard.com/)
- [Let's Encrypt Certbot](https://certbot.eff.org/)
### Tools Used
- fail2ban: Intrusion prevention
- UFW: Firewall management
- certbot: SSL certificate management
- Docker: Container security features
- Netdata/Glances: System monitoring
## Status Updates
### 2025-09-12: Initial Assessment
- Identified critical port exposure vulnerabilities
- Found missing fail2ban and SSL certificates
- Created comprehensive hardening plan
- Documented all security scripts and their purposes
### Next Update: [Date]
- [Progress made]
- [Issues resolved]
- [Next steps]
---
**Last Updated**: 2025-09-12
**Security Status**: 🔴 CRITICAL - Immediate action required
**SSL Recovery**: Configuration found in git history (commit 2cd1d87)
**VPN Ready**: Complete WireGuard setup documentation available
**SSH Status**: Port hardened, password auth needs disabling

View File

@@ -476,6 +476,17 @@ sudo docker-compose logs -f jellyfin
- **Immich**: Modern photo backup solution
- **LibrePhotos**: Privacy-focused alternative
### Torrent Management
**Recommendation: Use NAS Direct Torrenting**
For homelab with NAS storage migration:
- **NAS Direct**: Internet → NAS (50% less network traffic, better performance)
- **Laptop → NAS**: Downloads go laptop → network → NAS (double network load)
- **Access**: Use Synology Download Station via Local Network admin section
- **Integration**: Mount NAS shares for Jellyfin media access
- **Efficiency**: Keeps local network clear for other services
## Monitoring & Logging
### System Monitoring

196
docs/ssh-honeypot-setup.md Normal file
View File

@@ -0,0 +1,196 @@
# SSH Honeypot Setup
## Overview
The SSH honeypot is a deception service that listens on port 22 (the default SSH port) to detect and log unauthorized access attempts. The real SSH service runs on port 2222 for legitimate access.
## Architecture
- **Honeypot**: Port 22 - Fake SSH service for logging attacks
- **Real SSH**: Port 2222 - Actual SSH access for administrators
- **Gitea SSH**: Port 2223 - Git repository access
## Configuration Files
### Service Configuration
**File**: `config/systemd/ssh-honeypot.service`
**Deploy to**: `/etc/systemd/system/ssh-honeypot.service`
The systemd service uses `ncat` to listen on port 22 and execute a response script for each connection attempt.
### Response Script
**File**: `config/honeypot/response.sh`
**Deploy to**: `/opt/honeypot/response.sh`
The script logs each connection attempt and sends a fake SSH banner to make attackers believe they've reached a real SSH service.
## Installation
```bash
# 1. Deploy service file
sudo cp config/systemd/ssh-honeypot.service /etc/systemd/system/
# 2. Create honeypot directory and deploy script
sudo mkdir -p /opt/honeypot
sudo cp config/honeypot/response.sh /opt/honeypot/
sudo chmod +x /opt/honeypot/response.sh
# 3. Create log file
sudo touch /var/log/honeypot.log
sudo chmod 644 /var/log/honeypot.log
# 4. Create honeypot group (if needed)
sudo groupadd honeypot || true
# 5. Enable and start service
sudo systemctl daemon-reload
sudo systemctl enable ssh-honeypot.service
sudo systemctl start ssh-honeypot.service
```
## Verification
```bash
# Check service status
sudo systemctl status ssh-honeypot.service
# Verify port 22 is listening
ss -tlnp | grep :22
# Test connection
telnet localhost 22
# Check logs
tail -f /var/log/honeypot.log
```
## Log Format
Each connection attempt is logged with:
- Timestamp
- Source IP address
- Connection event
Example log entry:
```
Thu Sep 12 20:18:32 CEST 2025: SSH honeypot connection from 192.168.1.100
```
## Security Considerations
### Benefits
- **Early Detection**: Identifies reconnaissance and attack attempts
- **Threat Intelligence**: Captures attacker IP addresses and timing
- **Deception**: Misleads attackers away from real services
### Limitations
- **Internal Only**: Only logs connections from within the network
- **Basic Logging**: Simple timestamp and IP logging only
- **No Interaction**: Closes connection after sending banner
## Monitoring
### Real-time Monitoring
```bash
# Monitor honeypot logs
tail -f /var/log/honeypot.log
# Monitor service logs
journalctl -u ssh-honeypot.service -f
# Check connection counts
grep "honeypot connection" /var/log/honeypot.log | wc -l
```
### Log Analysis
```bash
# Show unique attacking IPs
grep "honeypot connection" /var/log/honeypot.log | \
awk '{print $NF}' | sort | uniq -c | sort -nr
# Show attack frequency by hour
grep "honeypot connection" /var/log/honeypot.log | \
awk '{print $4}' | cut -d: -f1 | sort | uniq -c
# Recent attacks (last 24 hours)
grep "$(date +%Y-%m-%d)" /var/log/honeypot.log
```
## Integration with Real SSH
### SSH Configuration
Ensure your real SSH service (`/etc/ssh/sshd_config`) is configured to listen on port 2222:
```bash
Port 2222
PermitRootLogin no
PasswordAuthentication no
PubkeyAuthentication yes
```
### Router/Firewall Rules
- Port 22: No external forwarding (honeypot is internal only)
- Port 2222: Forward to 192.168.0.100:2222 for legitimate SSH access
- Port 2223: Forward to 192.168.0.100:2223 for Gitea SSH access
## Troubleshooting
### Service Won't Start
```bash
# Check if port 22 is already in use
ss -tlnp | grep :22
# Check service logs
journalctl -u ssh-honeypot.service -n 20
# Verify permissions
ls -la /opt/honeypot/response.sh
ls -la /var/log/honeypot.log
```
### No Logs Generated
```bash
# Test script manually
sudo /opt/honeypot/response.sh
# Check log file permissions
ls -la /var/log/honeypot.log
# Verify ncat can access script
sudo -u honeypot /opt/honeypot/response.sh
```
### Permission Errors
```bash
# Fix log permissions
sudo chmod 644 /var/log/honeypot.log
# Fix script permissions
sudo chmod +x /opt/honeypot/response.sh
# Run as root if needed (remove Group=honeypot from service file)
sudo systemctl edit ssh-honeypot.service
```
## Maintenance
### Log Rotation
Consider setting up logrotate for `/var/log/honeypot.log`:
```bash
# /etc/logrotate.d/honeypot
/var/log/honeypot.log {
weekly
rotate 4
compress
delaycompress
missingok
notifempty
}
```
### Regular Tasks
- Monitor logs weekly for attack patterns
- Archive old logs monthly
- Review and update response script as needed
- Verify service is running after system updates

View File

@@ -0,0 +1,288 @@
# SSH Intrusion Monitoring Guide
## Overview
This guide covers comprehensive SSH intrusion detection and monitoring for the homelab environment, including both honeypot analysis and real SSH service monitoring.
## Log Files and Locations
### Primary Log Files
- **Honeypot Logs**: `/var/log/honeypot.log` - Attack attempts on port 22
- **SSH Authentication**: `/var/log/auth.log` - Real SSH attempts on port 2222
- **System Security**: `/var/log/secure` or `/var/log/security.log` - General security events
- **Service Logs**: `journalctl -u sshd.service` - SSH daemon logs
### Service Status Monitoring
```bash
# Check honeypot service
systemctl status ssh-honeypot.service
# Check real SSH service
systemctl status sshd.service
# Monitor both services
systemctl status ssh-honeypot.service sshd.service
```
## Honeypot Monitoring
### Real-time Monitoring
```bash
# Live honeypot attack monitoring
tail -f /var/log/honeypot.log
# Monitor with timestamps
tail -f /var/log/honeypot.log | while read line; do echo "$(date '+%H:%M:%S') $line"; done
```
### Attack Analysis
```bash
# Count total attack attempts
grep -c "honeypot connection" /var/log/honeypot.log
# Show unique attacking IP addresses with attempt counts
grep "honeypot connection" /var/log/honeypot.log | \
awk '{print $NF}' | sort | uniq -c | sort -nr
# Attacks by hour of day
grep "honeypot connection" /var/log/honeypot.log | \
awk '{print $4}' | cut -d: -f1 | sort | uniq -c | sort -k2 -n
# Recent attacks (last 24 hours)
grep "$(date '+%a %b %d')" /var/log/honeypot.log
# Attacks from specific IP
grep "192.168.1.100" /var/log/honeypot.log
```
### Geographic Analysis
```bash
# Get country information for attacking IPs (requires geoip)
grep "honeypot connection" /var/log/honeypot.log | \
awk '{print $NF}' | sort -u | \
while read ip; do
echo -n "$ip: "
geoiplookup "$ip" 2>/dev/null | head -1 | cut -d: -f2
done
```
## Real SSH Monitoring
### Authentication Monitoring
```bash
# Monitor real SSH authentication attempts
tail -f /var/log/auth.log | grep sshd
# Failed password attempts
grep "Failed password" /var/log/auth.log | tail -10
# Successful logins
grep "Accepted password\|Accepted publickey" /var/log/auth.log | tail -10
# Invalid users attempting login
grep "Invalid user" /var/log/auth.log | tail -10
```
### Connection Analysis
```bash
# Current SSH connections
ss -tnp | grep :2222
# Active SSH sessions
who -u
# Login history
last -n 20
# Failed login attempts by IP
grep "Failed password" /var/log/auth.log | \
awk '{print $(NF-3)}' | sort | uniq -c | sort -nr
```
### Brute Force Detection
```bash
# Show IPs with multiple failed attempts
grep "Failed password" /var/log/auth.log | \
awk '{print $(NF-3)}' | sort | uniq -c | \
awk '$1 > 5 {print $2 " (" $1 " attempts)"}'
# Recent failed attempts (last hour)
grep "$(date '+%b %d %H:')" /var/log/auth.log | \
grep "Failed password"
# Successful logins after failed attempts (potential compromise)
grep -A5 -B5 "Accepted" /var/log/auth.log | \
grep -E "Failed password|Accepted"
```
## Network-Level Monitoring
### Port Scanning Detection
```bash
# Check for connection attempts to common ports
ss -tlnp | grep -E ":(22|2222|2223|80|443|8080)"
# Monitor connection attempts (requires netstat)
netstat -tln | grep LISTEN | grep -E ":(22|2222|2223)"
# Check iptables logs (if logging enabled)
grep "DROP" /var/log/kern.log | tail -10
```
### Active Connection Monitoring
```bash
# Show all network connections
ss -tuln
# Monitor new connections
watch -n 2 'ss -tn | grep :2222'
# Check for unusual processes using network
lsof -i :2222
lsof -i :22
```
## Alerting and Notifications
### Simple Alert Scripts
Create monitoring scripts for common scenarios:
```bash
# Alert on honeypot activity
#!/bin/bash
# /usr/local/bin/honeypot-alert.sh
LAST_CHECK="/tmp/honeypot-last-check"
LOG_FILE="/var/log/honeypot.log"
if [ ! -f "$LAST_CHECK" ]; then
touch "$LAST_CHECK"
fi
NEW_ATTACKS=$(find "$LOG_FILE" -newer "$LAST_CHECK" | wc -l)
if [ "$NEW_ATTACKS" -gt 0 ]; then
echo "ALERT: $NEW_ATTACKS new honeypot attacks detected"
tail -n "$NEW_ATTACKS" "$LOG_FILE"
fi
touch "$LAST_CHECK"
```
### Fail2ban Integration
Monitor fail2ban status for automatic IP blocking:
```bash
# Check fail2ban status
sudo fail2ban-client status
# Check SSH jail specifically
sudo fail2ban-client status sshd
# Show banned IPs
sudo fail2ban-client get sshd banip
# Unban IP if needed
sudo fail2ban-client set sshd unbanip 192.168.1.100
```
## Log Analysis Tools
### Basic Analysis Commands
```bash
# Most common attacking IPs across both services
(grep "honeypot connection" /var/log/honeypot.log | awk '{print $NF}'; \
grep "Failed password" /var/log/auth.log | awk '{print $(NF-3)}') | \
sort | uniq -c | sort -nr | head -10
# Timeline of attacks (both honeypot and real SSH)
(grep "honeypot connection" /var/log/honeypot.log | sed 's/honeypot/HONEYPOT/'; \
grep "Failed password" /var/log/auth.log | sed 's/Failed password/REAL_SSH/') | \
sort -k1,3
```
### Advanced Analysis
```bash
# Attack patterns by time of day
grep -E "(honeypot connection|Failed password)" \
/var/log/honeypot.log /var/log/auth.log | \
awk '{print $4}' | cut -d: -f1 | sort | uniq -c | \
sort -k2 -n
# Correlation between honeypot and real SSH attacks
comm -12 \
<(grep "honeypot connection" /var/log/honeypot.log | awk '{print $NF}' | sort -u) \
<(grep "Failed password" /var/log/auth.log | awk '{print $(NF-3)}' | sort -u)
```
## Incident Response
### Immediate Response
```bash
# Block suspicious IP immediately
sudo iptables -A INPUT -s SUSPICIOUS_IP -j DROP
# Check current connections from IP
ss -tn | grep SUSPICIOUS_IP
# Kill any active sessions from IP
sudo pkill -f "sshd.*SUSPICIOUS_IP"
```
### Investigation Steps
1. **Identify Attack Source**: Analyze logs to determine origin IP and attack pattern
2. **Check Compromise**: Look for successful logins after failed attempts
3. **Assess Impact**: Check for file modifications, new users, or privilege escalation
4. **Implement Blocks**: Add IP to fail2ban or firewall rules
5. **Monitor**: Continue monitoring for related activity
### Forensic Analysis
```bash
# Check for privilege escalation attempts
grep -i "sudo\|su\|root" /var/log/auth.log | tail -20
# Look for file access patterns
find /var/log -name "*.log" -mtime -1 -exec grep "SUSPICIOUS_IP" {} \;
# Check for new user accounts or modifications
grep -E "(useradd|usermod|passwd)" /var/log/auth.log | tail -10
```
## Automated Monitoring Setup
### Cron Jobs for Regular Monitoring
```bash
# Add to crontab (crontab -e)
# Check for new attacks every 5 minutes
*/5 * * * * /usr/local/bin/honeypot-alert.sh
# Daily security report
0 9 * * * /usr/local/bin/daily-security-report.sh
# Weekly log cleanup
0 2 * * 0 /usr/local/bin/cleanup-old-logs.sh
```
### System Integration
- Configure rsyslog to separate security logs
- Set up log rotation for security logs
- Integrate with monitoring systems (Nagios, Zabbix, etc.)
- Configure email alerts for critical events
## Best Practices
### Monitoring Frequency
- **Real-time**: Honeypot attacks, SSH authentication failures
- **Hourly**: Connection pattern analysis, unusual activity
- **Daily**: Attack summary, trend analysis, IP reputation checks
- **Weekly**: Comprehensive security review, log archiving
### Log Retention
- **Honeypot logs**: 30 days for analysis, 90 days archived
- **SSH auth logs**: 90 days active, 1 year archived
- **Security logs**: 180 days active, 2 years archived
- **Incident logs**: Permanent retention for forensic analysis
### Performance Considerations
- Monitor log file sizes and implement rotation
- Use efficient grep/awk patterns for large log files
- Consider log aggregation tools for high-volume environments
- Archive old logs to prevent disk space issues

View File

@@ -0,0 +1,86 @@
# Gitea Docker Troubleshooting - Complete Resolution
## The Problem
Gitea container failing with: `s6-svscan: fatal: unable to open .s6-svscan/lock: Read-only file system`
## Root Cause Analysis
The issue was **Docker security hardening interfering with Gitea's s6-overlay init system**.
### What Broke Gitea
1. **`read_only: true`** - Prevented s6-overlay from creating lock files
2. **`user: "1000:1000"`** - Forced non-root start, breaking s6-overlay initialization
3. **`Missing config values`**
- GITEA__server__ROOT_URL=https://ak-homelab.duckdns.org/gitea/
- GITEA__server__SSH_PORT=2223
4. **`Overy restrictive port config`**
- "127.0.0.1:3000:3000" # Web UI localhost only: ok, since requests come in via reverse proxy
- "127.0.0.1:2223:22" # Git port on localhost: NOT OK, this prevents git push/pull from outside
- "2223:22" # <- Fixed config
5. **Overly restrictive security caps** - Prevented proper container initialization
### Key Understanding: s6-overlay Init System
Gitea uses s6-overlay which requires:
1. **Start as root** to set up supervision tree and create lock files
2. **Then drop privileges** to user specified by `USER_UID`/`USER_GID` environment variables
Setting `user: "1000:1000"` at Docker level bypassed this process.
## The Solution
### Working Docker Compose Configuration
```yaml
services:
server:
image: gitea/gitea:latest
container_name: gitea
environment:
- USER_UID=1000
- USER_GID=1000
- GITEA__server__ROOT_URL=https://ak-homelab.duckdns.org/gitea/
- GITEA__server__SSH_PORT=2223
restart: unless-stopped
# DO NOT set user: directive - breaks s6-overlay init system
ports:
- "127.0.0.1:3000:3000" # Web UI - localhost only (reverse proxy)
- "2223:22" # SSH - all interfaces (direct Git access)
# Reasonable resource limits only
deploy:
resources:
limits:
memory: 1G
```
### Key Configuration Points
1. **No Docker User Directive**: Let s6-overlay handle user switching via `USER_UID`/`USER_GID`
2. **ROOT_URL**: Required for asset serving through reverse proxy
3. **SSH_PORT**: Must match external port for correct clone URLs
4. **Port Binding**: SSH needs all interfaces, web UI can be localhost-only
## Critical Port Configuration
- **Web UI**: `"127.0.0.1:3000:3000"` (through nginx reverse proxy)
- **SSH Git**: `"2223:22"` (direct access, NOT localhost-only)
**Why SSH can't be localhost-only**: Git operations come from external router/clients and need direct container access.
## Asset Loading Fix
Added `GITEA__server__ROOT_URL=https://ak-homelab.duckdns.org/gitea/` so Gitea serves assets with correct paths through reverse proxy.
## Repository Migration
For fresh Gitea instances, bare repositories must be pushed via Git protocol:
```bash
git clone /path/to/bare/repo.git working-copy
cd working-copy
git remote set-url origin https://ak-homelab.duckdns.org/gitea/user/repo.git
git push -u origin --all
git push origin --tags
```
## Lessons Learned
1. **Understand service requirements** before applying security hardening
2. **Some services need specific initialization processes** (s6-overlay)
3. **Network access patterns matter** (SSH vs HTTP proxy requirements)
4. **Test incrementally** rather than applying multiple security changes at once

49
opencode.json Normal file
View File

@@ -0,0 +1,49 @@
{
"$schema": "https://opencode.ai/config.json",
"permission": {
"bash": {
"git branch -d": "ask",
"git branch -D": "ask",
"git status": "allow",
"git diff": "allow",
"git log": "allow",
"git show": "allow",
"git branch": "allow",
"git remote": "allow",
"git fetch": "allow",
"git pull": "allow",
"git merge": "ask",
"git rebase": "ask",
"git commit": "ask",
"git push": "ask",
"git checkout": "ask",
"git switch": "ask",
"git reset": "ask",
"git revert": "ask",
"git rm": "ask",
"git mv": "ask",
"git worktree": "ask",
"cat": "allow",
"tail": "allow",
"head": "allow",
"less": "allow",
"more": "allow",
"grep": "allow",
"find": "allow",
"ls": "allow",
"pwd": "allow",
"cd": "allow",
"mkdir": "ask",
"rm": "ask",
"rmdir": "ask",
"mv": "ask",
"cp": "ask",
"touch": "ask",
"chmod": "ask",
"chown": "ask",
"su": "deny",
"sudo": "deny",
"*": "ask"
}
}
}

View File

@@ -1,51 +0,0 @@
#!/bin/bash
# Deploy Netdata configuration and nginx config for privacy-focused local monitoring
# Run with: sudo -A ./scripts/deploy-netdata-config.sh
set -e
echo "=== Deploying Netdata privacy configuration ==="
cp /home/hoborg/homelab/config/netdata/netdata.conf /etc/netdata/netdata.conf
echo "✅ Netdata configured for local-only operation (no cloud/telemetry)"
echo "=== Backing up nginx config ==="
BACKUP_FILE="/etc/nginx/sites-available/homelab.backup.$(date +%Y%m%d-%H%M%S)"
cp /etc/nginx/sites-available/homelab "$BACKUP_FILE"
echo "Backup created: $BACKUP_FILE"
echo "=== Deploying nginx configuration with Netdata support ==="
cp /home/hoborg/homelab/config/nginx/homelab.conf /etc/nginx/sites-available/homelab
echo "=== Testing nginx configuration ==="
nginx -t
if [ $? -eq 0 ]; then
echo "=== Restarting Netdata with new config ==="
systemctl restart netdata
echo "=== Reloading nginx ==="
systemctl reload nginx
echo "✅ Configuration deployed successfully!"
else
echo "❌ ERROR: Nginx configuration test failed!"
echo "Restoring backup..."
cp "$BACKUP_FILE" /etc/nginx/sites-available/homelab
exit 1
fi
echo ""
echo "=== Testing Netdata access ==="
echo "Direct access: http://127.0.0.1:19999/"
curl -s -o /dev/null -w "Direct Netdata: HTTP %{http_code}\\n" http://127.0.0.1:19999/ || echo "Direct test failed"
echo "Reverse proxy access: https://ak-homelab.duckdns.org/netdata/"
curl -k -s -o /dev/null -w "Proxied Netdata: HTTP %{http_code}\\n" https://ak-homelab.duckdns.org/netdata/ || echo "Proxy test failed"
echo ""
echo "=== Netdata Privacy Configuration Complete! ==="
echo "✅ Cloud features disabled"
echo "✅ Telemetry disabled"
echo "✅ Local-only monitoring"
echo "✅ Accessible via: https://ak-homelab.duckdns.org/netdata/"
echo "✅ Basic auth: admin / AdminPass2024!"

View File

@@ -0,0 +1,112 @@
#!/bin/bash
# Security Hardening Setup Script
# Run with: sudo -A ./scripts/setup-security-hardening.sh
set -euo pipefail
echo "=== Security Hardening Setup ==="
echo "Deploying security configurations from config/ directory"
echo
# Colors for output
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'
log_info() {
echo -e "${GREEN}[INFO]${NC} $1"
}
log_warn() {
echo -e "${YELLOW}[WARN]${NC} $1"
}
# Check if running as root
if [ "$EUID" -ne 0 ]; then
echo "This script must be run as root (use sudo -A)"
exit 1
fi
REPO_DIR="/home/hoborg/homelab"
# 1. Deploy SSH hardening
log_info "Deploying SSH security configuration..."
if [ -f "$REPO_DIR/config/ssh/sshd_config_hardening" ]; then
cp /etc/ssh/sshd_config /etc/ssh/sshd_config.backup || true
cat "$REPO_DIR/config/ssh/sshd_config_hardening" >> /etc/ssh/sshd_config
cp "$REPO_DIR/config/ssh/banner" /etc/ssh/banner
chmod 644 /etc/ssh/banner
log_info "SSH hardening applied"
else
log_warn "SSH hardening config not found"
fi
# 2. Deploy kernel security parameters
log_info "Deploying kernel security parameters..."
if [ -f "$REPO_DIR/config/sysctl/99-security.conf" ]; then
cp "$REPO_DIR/config/sysctl/99-security.conf" /etc/sysctl.d/
sysctl -p /etc/sysctl.d/99-security.conf
log_info "Kernel security parameters applied"
else
log_warn "Sysctl security config not found"
fi
# 3. Deploy Docker security configuration
log_info "Deploying Docker security configuration..."
if [ -f "$REPO_DIR/config/docker/daemon.json" ]; then
mkdir -p /etc/docker
cp "$REPO_DIR/config/docker/daemon.json" /etc/docker/
systemctl restart docker
log_info "Docker security configuration applied"
else
log_warn "Docker daemon config not found"
fi
# 4. Deploy fail2ban configuration
log_info "Deploying fail2ban configuration..."
if [ -f "$REPO_DIR/config/fail2ban/jail.local" ]; then
# Install fail2ban if needed
if ! command -v fail2ban-server >/dev/null; then
log_info "Installing fail2ban..."
pacman -S --noconfirm fail2ban
fi
# Deploy config files
cp "$REPO_DIR/config/fail2ban/jail.local" /etc/fail2ban/
cp "$REPO_DIR/config/fail2ban/filter.d/"*.conf /etc/fail2ban/filter.d/
# Enable and restart
systemctl enable fail2ban
systemctl restart fail2ban
log_info "fail2ban configuration applied"
else
log_warn "fail2ban config not found"
fi
# 5. Deploy nginx rate limiting
log_info "Deploying nginx rate limiting..."
if [ -f "$REPO_DIR/config/systemd/nginx.service.d/rate-limit.conf" ]; then
mkdir -p /etc/systemd/system/nginx.service.d
cp "$REPO_DIR/config/systemd/nginx.service.d/rate-limit.conf" /etc/systemd/system/nginx.service.d/
systemctl daemon-reload
log_info "Nginx rate limiting applied"
else
log_warn "Nginx rate limiting config not found"
fi
echo
echo "=== Security Hardening Complete ==="
echo
echo "Applied configurations:"
echo " ✓ SSH hardening and banner"
echo " ✓ Kernel security parameters"
echo " ✓ Docker security configuration"
echo " ✓ fail2ban intrusion prevention"
echo " ✓ Nginx rate limiting"
echo
echo "Next steps:"
echo " 1. Test SSH connections: ssh -p 2222 user@localhost"
echo " 2. Check fail2ban status: fail2ban-client status"
echo " 3. Verify services: systemctl status sshd nginx docker"
echo " 4. Monitor logs: tail -f /var/log/honeypot.log"