From a35d9ff4206c699a9a426a248326cb05a576036b Mon Sep 17 00:00:00 2001 From: Geir Okkenhaug Jerstad Date: Sat, 7 Jun 2025 15:21:11 +0200 Subject: [PATCH] Implement SSH forwarding for Forgejo Git access - Add nginx stream configuration on reverse-proxy to forward port 2222 to apps:22 - Update firewall rules to allow port 2222 for Git SSH access - Configure Forgejo to use SSH_PORT = 2222 for Git operations - Add comprehensive SSH forwarding research documentation - Enable Git operations via git@git.geokkjer.eu:2222 Phase 1 implementation using nginx stream module complete. Ready for testing and potential Phase 2 migration to HAProxy. --- machines/grey-area/services/forgejo.nix | 1 + machines/reverse-proxy/configuration.nix | 42 ++-- research/ssh-forwarding-solutions.md | 298 +++++++++++++++++++++++ 3 files changed, 327 insertions(+), 14 deletions(-) create mode 100644 research/ssh-forwarding-solutions.md diff --git a/machines/grey-area/services/forgejo.nix b/machines/grey-area/services/forgejo.nix index 94f109d..56046d6 100644 --- a/machines/grey-area/services/forgejo.nix +++ b/machines/grey-area/services/forgejo.nix @@ -15,6 +15,7 @@ server = { ROOT_URL = "http://apps:3000"; SSH_DOMAIN = "git.geokkjer.eu"; + SSH_PORT = 2222; }; repository = { ENABLE_PUSH_CREATE_USER = true; diff --git a/machines/reverse-proxy/configuration.nix b/machines/reverse-proxy/configuration.nix index 7242398..9e5b67f 100644 --- a/machines/reverse-proxy/configuration.nix +++ b/machines/reverse-proxy/configuration.nix @@ -1,9 +1,8 @@ -{ pkgs, configs, lib, ... }: -let - Host = "vps1.tail807ea.ts.net"; -in +{ pkgs, config, lib, ... }: + { imports = [ + ./gandicloud.nix ../../modules/common/base.nix ../../modules/users/sma.nix ../../modules/security/ssh-keys.nix @@ -20,11 +19,15 @@ in # DMZ-specific firewall configuration - very restrictive networking.firewall = { enable = true; - # Only allow HTTP/HTTPS from external network - allowedTCPPorts = [ 80 443 ]; + # Allow HTTP/HTTPS from external network and Git SSH on port 2222 + allowedTCPPorts = [ 80 443 2222 ]; allowedUDPPorts = [ ]; - # SSH only allowed on Tailscale interface (DMZ security) - interfaces.tailscale0.allowedTCPPorts = [ 22 ]; + # SSH only allowed from Tailscale network (100.64.0.0/10) + extraCommands = '' + # Allow SSH only from Tailscale network + iptables -A nixos-fw -p tcp --dport 22 -s 100.64.0.0/10 -j ACCEPT + iptables -A nixos-fw -p tcp --dport 22 -j DROP + ''; # Explicitly block all other traffic rejectPackets = true; }; @@ -52,12 +55,8 @@ in ClientAliveInterval = 300; ClientAliveCountMax = 2; }; - listenAddresses = [ - { - addr = "100.96.189.104"; # Tailscale IP only - port = 22; - } - ]; + # Let SSH listen on default port, firewall restricts to Tailscale interface + # This allows Tailscale to assign IP dynamically based on hostname }; # nginx reverse proxy @@ -81,6 +80,21 @@ in # locations."/".proxyPass = "/var/wwww/homepage/"; #}; }; + + # Stream configuration for SSH forwarding to Git server + streamConfig = '' + upstream git_ssh_backend { + server apps:22; + } + + server { + listen 2222; + proxy_pass git_ssh_backend; + proxy_timeout 300s; + proxy_connect_timeout 10s; + proxy_responses 1; + } + ''; }; # acme let's encrypt security.acme = { diff --git a/research/ssh-forwarding-solutions.md b/research/ssh-forwarding-solutions.md new file mode 100644 index 0000000..cec156b --- /dev/null +++ b/research/ssh-forwarding-solutions.md @@ -0,0 +1,298 @@ +# SSH Forwarding Solutions for Git Server + +## Overview + +This document researches solutions for forwarding SSH traffic from the reverse-proxy (VPS) to the grey-area Forgejo git instance. The goal is to enable Git operations over SSH at `git@git.geokkjer.eu` while maintaining security and reliability. + +## Current Setup + +- **Reverse Proxy (VPS)**: `46.226.104.98` running nginx, listening on ports 80/443 +- **Git Server (grey-area)**: Forgejo instance accessible via Tailscale at `apps:3000` +- **Domain**: `git.geokkjer.eu` currently configured for HTTPS proxying only +- **Target**: Enable SSH access on port 22 for Git operations + +## Architecture Constraints + +1. **Single Public IP**: Only one public IP available (VPS) +2. **Port 22 Limitation**: Standard SSH port needed for Git compatibility +3. **Security**: SSH access should be restricted to Git operations only +4. **Tailscale Network**: Backend services accessible via private Tailscale network +5. **Existing SSH**: VPS already uses port 22 for administrative SSH access + +## Solution Options + +### 1. HAProxy TCP Mode (Recommended) + +**Approach**: Replace nginx with HAProxy or add HAProxy for SSH forwarding + +**Pros**: +- Native TCP/SSH forwarding support +- Battle-tested for SSH proxying +- Can handle both HTTP and SSH traffic +- Excellent connection handling +- Built-in health checking + +**Cons**: +- Requires replacing or complementing nginx +- Additional service to manage +- More complex configuration + +**Implementation**: +```haproxy +global + stats socket /var/run/haproxy.sock mode 600 level admin + stats timeout 2m + +defaults + mode tcp + timeout client 60s + timeout server 60s + timeout connect 5s + +# SSH forwarding to Git server +frontend ssh_frontend + bind *:22 + mode tcp + # Use SNI or other method to distinguish Git SSH from admin SSH + default_backend git_ssh_backend + +backend git_ssh_backend + mode tcp + server git1 apps:22 check + +# HTTP/HTTPS forwarding +frontend http_frontend + bind *:80 + bind *:443 ssl crt /etc/ssl/certs/ + mode http + default_backend nginx_backend + +backend nginx_backend + mode http + server nginx1 127.0.0.1:8080 +``` + +**Complexity**: Medium +**Security**: High +**Reliability**: High + +### 2. NGINX Stream Module + +**Approach**: Enable NGINX stream module for TCP forwarding + +**Pros**: +- Keeps existing nginx setup +- Native TCP proxying support +- Good performance +- Integrated with current SSL/certificate management + +**Cons**: +- Requires nginx with stream module compiled +- Cannot distinguish SSH traffic types on same port +- Conflicts with existing SSH access + +**Implementation**: +```nginx +# In nginx.conf +stream { + upstream git_ssh_backend { + server apps:22; + } + + server { + listen 2222; # Alternative port for Git SSH + proxy_pass git_ssh_backend; + proxy_timeout 60s; + proxy_connect_timeout 5s; + } +} + +http { + # Existing HTTP configuration + server { + listen 80; + listen 443 ssl; + server_name git.geokkjer.eu; + # ... existing config + } +} +``` + +**Complexity**: Low +**Security**: Medium (requires alternative port) +**Reliability**: High + +### 3. SSH Port Forwarding with systemd + +**Approach**: Use SSH tunneling with autossh/systemd for persistence + +**Pros**: +- Simple setup +- Uses existing SSH infrastructure +- Automatic reconnection +- No additional services + +**Cons**: +- Less robust than dedicated proxy +- Potential authentication complexity +- Single point of failure +- Not designed for high-throughput Git operations + +**Implementation**: +```bash +# SSH tunnel command +ssh -N -L 2222:apps:22 geir@grey-area-tailscale-ip + +# systemd service for persistence +[Unit] +Description=SSH tunnel for Git forwarding +After=network.target + +[Service] +Type=simple +User=git +ExecStart=/usr/bin/ssh -N -o ServerAliveInterval=30 -o ServerAliveCountMax=3 -L 2222:apps:22 geir@grey-area +Restart=always +RestartSec=5 + +[Install] +WantedBy=multi-user.target +``` + +**Complexity**: Low +**Security**: Medium +**Reliability**: Medium + +### 4. iptables DNAT (Network Address Translation) + +**Approach**: Use iptables to redirect SSH traffic to backend + +**Pros**: +- Kernel-level forwarding (fast) +- Transparent to applications +- No additional services +- Can work on same port + +**Cons**: +- Requires careful firewall management +- Complex routing setup with Tailscale +- Difficult to debug +- Less visibility into connections + +**Implementation**: +```bash +# Forward port 2222 to backend Git server +iptables -t nat -A PREROUTING -p tcp --dport 2222 -j DNAT --to-destination apps:22 +iptables -t nat -A POSTROUTING -p tcp -d apps --dport 22 -j MASQUERADE + +# Allow forwarding +iptables -A FORWARD -p tcp --dport 22 -d apps -j ACCEPT +``` + +**Complexity**: High +**Security**: Medium +**Reliability**: Medium + +### 5. Hybrid Solution: Port-Based Routing + +**Approach**: Use different ports for different SSH services + +**Pros**: +- Clear separation of concerns +- Maintains existing admin SSH on port 22 +- Simple to implement and debug +- Good security boundaries + +**Cons**: +- Non-standard Git SSH port +- Requires client configuration +- Less user-friendly + +**Implementation**: +```nginx +stream { + upstream git_ssh { + server apps:22; + } + + server { + listen 2222; # Git SSH port + proxy_pass git_ssh; + proxy_timeout 300s; + proxy_connect_timeout 10s; + } +} +``` + +**Client Configuration**: +```bash +# ~/.ssh/config +Host git.geokkjer.eu + Port 2222 + User git +``` + +**Complexity**: Low +**Security**: High +**Reliability**: High + +## Recommended Solution + +### Phase 1: Implement NGINX Stream Module with Alternative Port + +**Why**: +- Lowest risk implementation +- Maintains existing services +- Easy to test and validate +- Can be upgraded later + +**Configuration**: +1. Enable nginx stream module +2. Configure Git SSH on port 2222 +3. Update Forgejo SSH_DOMAIN setting +4. Test with alternative port + +### Phase 2: Consider HAProxy Migration (Future) + +**Why**: +- More robust for mixed TCP/HTTP traffic +- Better connection handling for Git operations +- Industry standard for this use case +- Enables port 22 for Git SSH + +## Security Considerations + +1. **SSH Key Management**: Ensure proper SSH key authentication +2. **Rate Limiting**: Implement connection rate limits +3. **Monitoring**: Log SSH connections for security auditing +4. **Firewall Rules**: Restrict SSH forwarding to specific sources if possible +5. **Fail2ban**: Extend fail2ban rules to cover Git SSH attempts + +## Testing Strategy + +1. **Basic Connectivity**: Test TCP connection to backend +2. **SSH Handshake**: Verify SSH protocol negotiation +3. **Git Operations**: Test clone, push, pull operations +4. **Performance**: Measure latency and throughput +5. **Failover**: Test behavior during backend unavailability + +## Implementation Priority + +1. **High Priority**: NGINX Stream Module (Phase 1) +2. **Medium Priority**: HAProxy migration evaluation +3. **Low Priority**: Advanced features (rate limiting, monitoring) + +## Next Steps + +1. Check if nginx has stream module compiled +2. Implement NGINX stream configuration for port 2222 +3. Update Forgejo SSH configuration +4. Test Git operations via new port +5. Document client configuration for users +6. Monitor performance and reliability + +## References + +- [NGINX Stream Module Documentation](http://nginx.org/en/docs/stream/ngx_stream_core_module.html) +- [HAProxy TCP Mode Configuration](https://www.haproxy.org/download/2.8/doc/configuration.txt) +- [Git SSH Configuration Best Practices](https://docs.github.com/en/authentication/connecting-to-github-with-ssh)