Compare commits
20 Commits
e1a020163f
...
12ff0e15bd
| Author | SHA1 | Date | |
|---|---|---|---|
| 12ff0e15bd | |||
| cff0ee6acb | |||
| de6fa58726 | |||
| e608ce6d5b | |||
| 66e3249ced | |||
| 398862c72b | |||
| 9f4f79a85e | |||
| 06f837f4a1 | |||
| 0065113a19 | |||
| 5a4eb2fd72 | |||
| ad9a3ab23e | |||
| 8bbe8e0e28 | |||
| 5e714f4e45 | |||
| 9fbc311c2d | |||
| 471659a95a | |||
| 3d2201bc40 | |||
| 6980c36ae9 | |||
| ff2aedacf6 | |||
| ee5f2a4c18 | |||
| 3dfe146297 |
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
scripts/tmp/*
|
||||||
76
AGENTS.md
Normal file
76
AGENTS.md
Normal 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.**
|
||||||
@@ -184,3 +184,12 @@ rclone mount homelab-webdav: ~/homelab-files --daemon
|
|||||||
curl -X PROPFIND https://hoborg:AdminPass2024!@ak-homelab.duckdns.org/files/ \
|
curl -X PROPFIND https://hoborg:AdminPass2024!@ak-homelab.duckdns.org/files/ \
|
||||||
-H "Depth: 1" -H "Content-Type: text/xml"
|
-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)
|
||||||
@@ -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
|
- **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
|
- 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
|
## Inspiration & Resources
|
||||||
- PewDiePie homelab setup video: https://www.youtube.com/watch?v=u_Lxkt50xOg
|
- PewDiePie homelab setup video: https://www.youtube.com/watch?v=u_Lxkt50xOg
|
||||||
- Need to collect tips and inspiration from this video
|
- Need to collect tips and inspiration from this video
|
||||||
|
|||||||
15
TODO.md
15
TODO.md
@@ -5,6 +5,21 @@
|
|||||||
- [x] SSH security hardening *(documented in network-security.md)*
|
- [x] SSH security hardening *(documented in network-security.md)*
|
||||||
- [x] Figure out why laptop IP changes: Different eth ports have different MAC?
|
- [x] Figure out why laptop IP changes: Different eth ports have different MAC?
|
||||||
- [x] Router port forwarding configuration
|
- [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
|
- [ ] WireGuard VPN server configuration
|
||||||
- [ ] UFW firewall setup and rules
|
- [ ] UFW firewall setup and rules
|
||||||
- [ ] fail2ban for intrusion prevention
|
- [ ] fail2ban for intrusion prevention
|
||||||
|
|||||||
@@ -31,35 +31,41 @@
|
|||||||
hoborg: AdminPass2024!
|
hoborg: AdminPass2024!
|
||||||
|
|
||||||
[/shared]
|
[/shared]
|
||||||
/home/hoborg/shared
|
/mnt/nas/shared
|
||||||
accs:
|
accs:
|
||||||
rw: guest
|
rw: guest
|
||||||
rwmd: hoborg
|
rwmd: hoborg
|
||||||
|
|
||||||
[/documents]
|
[/documents]
|
||||||
/home/hoborg/Documents
|
/mnt/nas/documents
|
||||||
accs:
|
accs:
|
||||||
rwmd: hoborg
|
rwmd: hoborg
|
||||||
|
|
||||||
[/music]
|
[/music]
|
||||||
/home/hoborg/Music
|
/mnt/nas/music
|
||||||
accs:
|
accs:
|
||||||
rw: guest
|
rw: guest
|
||||||
rwmd: hoborg
|
rwmd: hoborg
|
||||||
|
|
||||||
[/videos]
|
[/videos]
|
||||||
/home/hoborg/Videos
|
/mnt/nas/videos
|
||||||
accs:
|
accs:
|
||||||
rw: guest
|
rw: guest
|
||||||
rwmd: hoborg
|
rwmd: hoborg
|
||||||
|
|
||||||
[/private]
|
[/private]
|
||||||
/home/hoborg/private
|
/mnt/nas/private
|
||||||
accs:
|
accs:
|
||||||
rwmd: hoborg
|
rwmd: hoborg
|
||||||
|
|
||||||
[/pictures]
|
[/pictures]
|
||||||
/home/hoborg/Pictures
|
/mnt/nas/pictures
|
||||||
|
accs:
|
||||||
|
rw: guest
|
||||||
|
rwmd: hoborg
|
||||||
|
|
||||||
|
[/torrent]
|
||||||
|
/mnt/nas/torrent
|
||||||
accs:
|
accs:
|
||||||
rw: guest
|
rw: guest
|
||||||
rwmd: hoborg
|
rwmd: hoborg
|
||||||
|
|||||||
17
config/docker/daemon.json
Normal file
17
config/docker/daemon.json
Normal 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"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,6 +3,11 @@
|
|||||||
# Create data directory: sudo mkdir -p /opt/docker/gitea/data
|
# Create data directory: sudo mkdir -p /opt/docker/gitea/data
|
||||||
# Set permissions: sudo chown -R hoborg:hoborg /opt/docker/gitea
|
# 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:
|
networks:
|
||||||
gitea:
|
gitea:
|
||||||
external: false
|
external: false
|
||||||
@@ -14,13 +19,35 @@ services:
|
|||||||
environment:
|
environment:
|
||||||
- USER_UID=1000
|
- USER_UID=1000
|
||||||
- USER_GID=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:
|
networks:
|
||||||
- gitea
|
- gitea
|
||||||
volumes:
|
volumes:
|
||||||
- ./data:/data
|
- ./data:/data
|
||||||
- /etc/timezone:/etc/timezone:ro
|
- /etc/timezone:/etc/timezone:ro
|
||||||
- /etc/localtime:/etc/localtime:ro
|
- /etc/localtime:/etc/localtime:ro
|
||||||
|
|
||||||
|
# Bind ports to localhost only for reverse proxy
|
||||||
ports:
|
ports:
|
||||||
- "3000:3000"
|
- "127.0.0.1:3000:3000"
|
||||||
- "2223:22"
|
- "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
|
||||||
|
|||||||
@@ -2,6 +2,13 @@
|
|||||||
# Deploy with: sudo mkdir -p /opt/docker/jellyfin && sudo cp config/docker/jellyfin/docker-compose.yml /opt/docker/jellyfin/
|
# 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
|
# 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:
|
services:
|
||||||
jellyfin:
|
jellyfin:
|
||||||
image: jellyfin/jellyfin:latest
|
image: jellyfin/jellyfin:latest
|
||||||
@@ -16,8 +23,24 @@ services:
|
|||||||
- JELLYFIN_PublishedServerUrl=https://ak-homelab.duckdns.org/media
|
- JELLYFIN_PublishedServerUrl=https://ak-homelab.duckdns.org/media
|
||||||
|
|
||||||
# Network mode for better performance and hardware acceleration
|
# 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
|
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
|
# Volume mounts - using same folders as Copyparty
|
||||||
volumes:
|
volumes:
|
||||||
# Jellyfin configuration and data
|
# Jellyfin configuration and data
|
||||||
@@ -25,11 +48,11 @@ services:
|
|||||||
- /opt/docker/jellyfin/cache:/cache
|
- /opt/docker/jellyfin/cache:/cache
|
||||||
|
|
||||||
# Media folders (shared with Copyparty)
|
# Media folders (shared with Copyparty)
|
||||||
- /home/hoborg/Music:/media/music:ro
|
- /mnt/nas/music:/media/music:ro
|
||||||
- /home/hoborg/Videos:/media/videos:ro
|
- /mnt/nas/videos:/media/videos:ro
|
||||||
- /home/hoborg/Pictures:/media/pictures:ro
|
- /mnt/nas/pictures:/media/pictures:ro
|
||||||
- /home/hoborg/shared:/media/shared:ro
|
- /mnt/nas/shared:/media/shared:ro
|
||||||
- /home/hoborg/private:/media/private:ro
|
- /mnt/nas/private:/media/private:ro
|
||||||
|
|
||||||
# Additional media folders if they exist
|
# Additional media folders if they exist
|
||||||
# - /home/hoborg/Movies:/media/movies:ro
|
# - /home/hoborg/Movies:/media/movies:ro
|
||||||
@@ -39,15 +62,20 @@ services:
|
|||||||
devices:
|
devices:
|
||||||
- /dev/dri:/dev/dri
|
- /dev/dri:/dev/dri
|
||||||
|
|
||||||
# Memory limits for container stability
|
# Enhanced resource limits
|
||||||
deploy:
|
deploy:
|
||||||
resources:
|
resources:
|
||||||
limits:
|
limits:
|
||||||
|
cpus: '2.0'
|
||||||
memory: 2G
|
memory: 2G
|
||||||
reservations:
|
reservations:
|
||||||
|
cpus: '0.5'
|
||||||
memory: 512M
|
memory: 512M
|
||||||
|
|
||||||
# Optional: Create a custom network if not using host networking
|
# Health check
|
||||||
# networks:
|
healthcheck:
|
||||||
# jellyfin:
|
test: ["CMD", "curl", "-f", "http://localhost:8096/health"]
|
||||||
# driver: bridge
|
interval: 30s
|
||||||
|
timeout: 10s
|
||||||
|
retries: 3
|
||||||
|
start_period: 60s
|
||||||
|
|||||||
Binary file not shown.
@@ -0,0 +1,2 @@
|
|||||||
|
{
|
||||||
|
}
|
||||||
@@ -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"
|
||||||
@@ -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#()
|
||||||
@@ -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})"
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
{
|
||||||
|
}
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
{
|
||||||
|
}
|
||||||
71
config/docker/qbittorrent/docker-compose.yml
Normal file
71
config/docker/qbittorrent/docker-compose.yml
Normal 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
|
||||||
9
config/fail2ban/filter.d/gitea-auth.conf
Normal file
9
config/fail2ban/filter.d/gitea-auth.conf
Normal 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 =
|
||||||
17
config/fail2ban/filter.d/nginx-badbots.conf
Normal file
17
config/fail2ban/filter.d/nginx-badbots.conf
Normal 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 =
|
||||||
10
config/fail2ban/filter.d/sshd-ddos.conf
Normal file
10
config/fail2ban/filter.d/sshd-ddos.conf
Normal 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 =
|
||||||
98
config/fail2ban/jail.local
Normal file
98
config/fail2ban/jail.local
Normal 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
|
||||||
20
config/honeypot/response.sh
Normal file
20
config/honeypot/response.sh
Normal 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
|
||||||
@@ -21,6 +21,25 @@ server {
|
|||||||
add_header X-Content-Type-Options "nosniff" always;
|
add_header X-Content-Type-Options "nosniff" always;
|
||||||
add_header X-XSS-Protection "1; mode=block" 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
|
# Main landing page - highest priority
|
||||||
location / {
|
location / {
|
||||||
root /var/www/homelab;
|
root /var/www/homelab;
|
||||||
@@ -157,6 +176,7 @@ server {
|
|||||||
proxy_set_header Connection "upgrade";
|
proxy_set_header Connection "upgrade";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
ssl_certificate /etc/letsencrypt/live/ak-homelab.duckdns.org/fullchain.pem; # managed by Certbot
|
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
|
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
|
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
|
||||||
|
|||||||
14
config/ssh/banner
Normal file
14
config/ssh/banner
Normal 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.
|
||||||
|
|
||||||
|
================================================================================
|
||||||
22
config/ssh/sshd_config_hardening
Normal file
22
config/ssh/sshd_config_hardening
Normal 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
|
||||||
36
config/sysctl/99-security.conf
Normal file
36
config/sysctl/99-security.conf
Normal 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
|
||||||
13
config/systemd/nginx.service.d/rate-limit.conf
Normal file
13
config/systemd/nginx.service.d/rate-limit.conf
Normal 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
|
||||||
23
config/systemd/ssh-honeypot.service
Normal file
23
config/systemd/ssh-honeypot.service
Normal 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
|
||||||
@@ -150,6 +150,11 @@
|
|||||||
<h3>Jellyfin</h3>
|
<h3>Jellyfin</h3>
|
||||||
<p>Movies, Music & TV Shows</p>
|
<p>Movies, Music & TV Shows</p>
|
||||||
</a>
|
</a>
|
||||||
|
<a href="/qbt/" class="service">
|
||||||
|
<i class="fas fa-download"></i>
|
||||||
|
<h3>qBittorrent</h3>
|
||||||
|
<p>Torrent Downloads</p>
|
||||||
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -180,6 +185,11 @@
|
|||||||
<h3>NAS Storage</h3>
|
<h3>NAS Storage</h3>
|
||||||
<p>Network Attached Storage</p>
|
<p>Network Attached Storage</p>
|
||||||
</a>
|
</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">
|
<a href="http://192.168.0.1" class="service admin" target="_blank">
|
||||||
<i class="fas fa-network-wired"></i>
|
<i class="fas fa-network-wired"></i>
|
||||||
<h3>Router</h3>
|
<h3>Router</h3>
|
||||||
|
|||||||
121
docs/qbittorrent-setup.md
Normal file
121
docs/qbittorrent-setup.md
Normal 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
|
||||||
240
docs/security-configurations.md
Normal file
240
docs/security-configurations.md
Normal 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
448
docs/security-hardening.md
Normal 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
|
||||||
@@ -476,6 +476,17 @@ sudo docker-compose logs -f jellyfin
|
|||||||
- **Immich**: Modern photo backup solution
|
- **Immich**: Modern photo backup solution
|
||||||
- **LibrePhotos**: Privacy-focused alternative
|
- **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
|
## Monitoring & Logging
|
||||||
|
|
||||||
### System Monitoring
|
### System Monitoring
|
||||||
|
|||||||
196
docs/ssh-honeypot-setup.md
Normal file
196
docs/ssh-honeypot-setup.md
Normal 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
|
||||||
288
docs/ssh-intrusion-monitoring.md
Normal file
288
docs/ssh-intrusion-monitoring.md
Normal 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
|
||||||
86
docs/troubleshooting/gitea-troubleshooting-summary.md
Normal file
86
docs/troubleshooting/gitea-troubleshooting-summary.md
Normal 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
49
opencode.json
Normal 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"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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!"
|
|
||||||
112
scripts/setup-security-hardening.sh
Executable file
112
scripts/setup-security-hardening.sh
Executable 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"
|
||||||
Reference in New Issue
Block a user