home-lab/research/ssh-forwarding-solutions.md
Geir Okkenhaug Jerstad fa2b84cf65 fix: resolve sma user definition conflict between modules
- Remove duplicate sma user definition from incus.nix module
- The sma user is properly defined in modules/users/sma.nix with incus-admin group
- This resolves the isNormalUser/isSystemUser assertion failure blocking congenital-optimist rebuild
- Clean up grey-area configuration and modularize services
- Update SSH keys with correct IP addresses for grey-area and reverse-proxy
2025-06-07 16:58:22 +02:00

298 lines
7.4 KiB
Markdown

# 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 1337
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)