301 lines
7.6 KiB
Markdown
301 lines
7.6 KiB
Markdown
# NPM SSH Proxy for Jenkins Agents
|
|
|
|
**Date**: 2026-02-09
|
|
**Purpose**: Use Nginx Proxy Manager to proxy SSH connections to Jenkins agents
|
|
**Benefit**: Centralized access control, logging, and SSL termination
|
|
|
|
## Architecture
|
|
|
|
### Before (Direct SSH)
|
|
```
|
|
External → Router:22 → Jenkins:22
|
|
```
|
|
**Issues**:
|
|
- Direct SSH exposure
|
|
- No centralized logging
|
|
- Single point of failure
|
|
|
|
### After (NPM Proxy)
|
|
```
|
|
External → NPM:2222 → Jenkins:22
|
|
Jenkins Agent Config: Connect to NPM:2222
|
|
```
|
|
**Benefits**:
|
|
- ✅ Centralized access through NPM
|
|
- ✅ NPM logging and monitoring
|
|
- ✅ Easier to manage multiple agents
|
|
- ✅ Can add rate limiting
|
|
- ✅ SSL/TLS for agent.jar downloads via web UI
|
|
|
|
## NPM Configuration
|
|
|
|
### Step 1: Create TCP Stream in NPM
|
|
|
|
**Via NPM Web UI** (http://192.168.200.71:81):
|
|
|
|
1. **Login to NPM**
|
|
- URL: http://192.168.200.71:81
|
|
- Default: admin@example.com / changeme
|
|
|
|
2. **Navigate to Streams**
|
|
- Click **Streams** in the sidebar
|
|
- Click **Add Stream**
|
|
|
|
3. **Configure Incoming Stream**
|
|
- **Incoming Port**: `2222`
|
|
- **Forwarding Host**: `192.168.200.91` (jenkins server)
|
|
- **Forwarding Port**: `22`
|
|
- **TCP Forwarding**: Enabled
|
|
- **UDP Forwarding**: Disabled
|
|
|
|
4. **Enable SSL/TLS Forwarding** (Optional)
|
|
- For encrypted SSH tunneling
|
|
- **SSL Certificate**: Upload or use Let's Encrypt
|
|
- **Force SSL**: Enabled
|
|
|
|
5. **Save**
|
|
|
|
### Step 2: Update Firewall on NPM Server
|
|
|
|
The NPM server needs to allow incoming connections on port 2222:
|
|
|
|
```bash
|
|
# Run from ansible control machine
|
|
ansible npm -m community.general.ufw -a "rule=allow port=2222 proto=tcp" -b
|
|
|
|
# Verify
|
|
ansible npm -m shell -a "ufw status | grep 2222" -b
|
|
```
|
|
|
|
### Step 3: Update Jenkins Agent Configuration
|
|
|
|
**In Jenkins Web UI** (http://192.168.200.91:8080):
|
|
|
|
1. **Navigate to Agent**
|
|
- Go to: **Manage Jenkins** → **Manage Nodes and Clouds**
|
|
- Click on the agent that uses SSH
|
|
|
|
2. **Update SSH Host**
|
|
- **Host**: Change from `45.16.76.42` to `192.168.200.71` (NPM server)
|
|
- **Port**: Change from `22` to `2222`
|
|
- **Credentials**: Keep as `dlx-key`
|
|
|
|
3. **Advanced Settings**
|
|
- **JVM Options**: Add if needed: `-Djava.awt.headless=true`
|
|
- **Prefix Start Agent Command**: Leave empty
|
|
- **Suffix Start Agent Command**: Leave empty
|
|
|
|
4. **Save and Launch Agent**
|
|
|
|
### Step 4: Update Router Port Forwarding (Optional)
|
|
|
|
If you want external access through the router:
|
|
|
|
**Old Rule**:
|
|
- External Port: `22`
|
|
- Internal IP: `192.168.200.91` (jenkins)
|
|
- Internal Port: `22`
|
|
|
|
**New Rule**:
|
|
- External Port: `2222` (or keep 22 if you prefer)
|
|
- Internal IP: `192.168.200.71` (NPM)
|
|
- Internal Port: `2222`
|
|
|
|
## Testing
|
|
|
|
### Test 1: SSH Through NPM from Local Network
|
|
```bash
|
|
# Test SSH connection through NPM proxy
|
|
ssh -p 2222 dlxadmin@192.168.200.71
|
|
|
|
# Should connect to jenkins server
|
|
hostname # Should output: dlx-sonar
|
|
```
|
|
|
|
### Test 2: Jenkins Agent Connection
|
|
```bash
|
|
# From jenkins server, test as jenkins user
|
|
sudo -u jenkins ssh -p 2222 -i /var/lib/jenkins/.ssh/id_rsa dlxadmin@192.168.200.71 'hostname'
|
|
|
|
# Expected output: dlx-sonar
|
|
```
|
|
|
|
### Test 3: Launch Agent from Jenkins UI
|
|
1. Go to: http://192.168.200.91:8080/computer/
|
|
2. Find the agent
|
|
3. Click **Launch agent**
|
|
4. Check logs for successful connection
|
|
|
|
## NPM Stream Configuration File
|
|
|
|
NPM stores stream configurations in its database. For backup/reference:
|
|
|
|
```json
|
|
{
|
|
"incoming_port": 2222,
|
|
"forwarding_host": "192.168.200.91",
|
|
"forwarding_port": 22,
|
|
"tcp_forwarding": true,
|
|
"udp_forwarding": false,
|
|
"enabled": true
|
|
}
|
|
```
|
|
|
|
## Troubleshooting
|
|
|
|
### Issue: Cannot connect to NPM:2222
|
|
|
|
**Check NPM firewall**:
|
|
```bash
|
|
ansible npm -m shell -a "ufw status | grep 2222" -b
|
|
ansible npm -m shell -a "ss -tlnp | grep 2222" -b
|
|
```
|
|
|
|
**Check NPM stream is active**:
|
|
- Login to NPM UI
|
|
- Go to Streams
|
|
- Verify stream is enabled (green toggle)
|
|
|
|
### Issue: Connection timeout
|
|
|
|
**Check NPM can reach Jenkins**:
|
|
```bash
|
|
ansible npm -m shell -a "ping -c 2 192.168.200.91" -b
|
|
ansible npm -m shell -a "nc -zv 192.168.200.91 22" -b
|
|
```
|
|
|
|
**Check Jenkins SSH is running**:
|
|
```bash
|
|
ansible jenkins -m shell -a "systemctl status sshd" -b
|
|
```
|
|
|
|
### Issue: Authentication fails
|
|
|
|
**Verify SSH key**:
|
|
```bash
|
|
# Get Jenkins public key
|
|
ansible jenkins -m shell -a "cat /var/lib/jenkins/.ssh/id_rsa.pub" -b
|
|
|
|
# Check it's in authorized_keys
|
|
ansible jenkins -m shell -a "grep jenkins /home/dlxadmin/.ssh/authorized_keys" -b
|
|
```
|
|
|
|
### Issue: NPM stream not forwarding
|
|
|
|
**Check NPM logs**:
|
|
```bash
|
|
ansible npm -m shell -a "docker logs nginx-proxy-manager --tail 100" -b
|
|
|
|
# Look for stream-related errors
|
|
```
|
|
|
|
**Restart NPM**:
|
|
```bash
|
|
ansible npm -m shell -a "docker restart nginx-proxy-manager" -b
|
|
```
|
|
|
|
## Advanced: Multiple Jenkins Agents
|
|
|
|
For multiple remote agents, create separate streams:
|
|
|
|
| Agent | NPM Port | Forward To | Purpose |
|
|
|-------|----------|------------|---------|
|
|
| jenkins-local | 2222 | 192.168.200.91:22 | Local Jenkins agent |
|
|
| build-agent-1 | 2223 | 192.168.200.120:22 | Remote build agent |
|
|
| build-agent-2 | 2224 | 192.168.200.121:22 | Remote build agent |
|
|
|
|
## Security Considerations
|
|
|
|
### Recommended Firewall Rules
|
|
|
|
**NPM Server** (192.168.200.71):
|
|
```yaml
|
|
common_firewall_allowed_ports:
|
|
- "22/tcp" # SSH admin access
|
|
- "80/tcp" # HTTP
|
|
- "443/tcp" # HTTPS
|
|
- "81/tcp" # NPM Admin panel
|
|
- "2222/tcp" # Jenkins SSH proxy
|
|
- "2223/tcp" # Additional agents (if needed)
|
|
```
|
|
|
|
**Jenkins Server** (192.168.200.91):
|
|
```yaml
|
|
common_firewall_allowed_ports:
|
|
- "22/tcp" # SSH (restrict to NPM IP only)
|
|
- "8080/tcp" # Jenkins Web UI
|
|
- "9000/tcp" # SonarQube
|
|
```
|
|
|
|
### Restrict SSH Access to NPM Only
|
|
|
|
On Jenkins server, restrict SSH to only accept from NPM:
|
|
|
|
```bash
|
|
# Allow SSH only from NPM server
|
|
ansible jenkins -m community.general.ufw -a "rule=allow from=192.168.200.71 to=any port=22 proto=tcp" -b
|
|
|
|
# Deny SSH from all others (if not already default)
|
|
ansible jenkins -m community.general.ufw -a "rule=deny port=22 proto=tcp" -b
|
|
```
|
|
|
|
## Monitoring
|
|
|
|
### NPM Access Logs
|
|
```bash
|
|
# View NPM access logs
|
|
ansible npm -m shell -a "docker logs nginx-proxy-manager --tail 50 | grep stream" -b
|
|
```
|
|
|
|
### Connection Statistics
|
|
```bash
|
|
# Check active SSH connections through NPM
|
|
ansible npm -m shell -a "ss -tn | grep :2222" -b
|
|
|
|
# Check connections on Jenkins
|
|
ansible jenkins -m shell -a "ss -tn | grep :22 | grep ESTAB" -b
|
|
```
|
|
|
|
## Backup and Recovery
|
|
|
|
### Backup NPM Configuration
|
|
```bash
|
|
# Backup NPM database
|
|
ansible npm -m shell -a "docker exec nginx-proxy-manager sqlite3 /data/database.sqlite .dump > /tmp/npm-backup.sql" -b
|
|
|
|
# Download backup
|
|
ansible npm -m fetch -a "src=/tmp/npm-backup.sql dest=./backups/npm-backup-$(date +%Y%m%d).sql" -b
|
|
```
|
|
|
|
### Restore NPM Configuration
|
|
```bash
|
|
# Upload backup
|
|
ansible npm -m copy -a "src=./backups/npm-backup.sql dest=/tmp/npm-restore.sql" -b
|
|
|
|
# Restore database
|
|
ansible npm -m shell -a "docker exec nginx-proxy-manager sqlite3 /data/database.sqlite < /tmp/npm-restore.sql" -b
|
|
|
|
# Restart NPM
|
|
ansible npm -m shell -a "docker restart nginx-proxy-manager" -b
|
|
```
|
|
|
|
## Migration Checklist
|
|
|
|
- [ ] Create TCP stream in NPM (port 2222 → jenkins:22)
|
|
- [ ] Update NPM firewall to allow port 2222
|
|
- [ ] Test SSH connection through NPM proxy
|
|
- [ ] Update Jenkins agent SSH host to NPM IP
|
|
- [ ] Update Jenkins agent SSH port to 2222
|
|
- [ ] Test agent connection in Jenkins UI
|
|
- [ ] Update router port forwarding (if external access needed)
|
|
- [ ] Restrict Jenkins SSH to NPM IP only (optional but recommended)
|
|
- [ ] Document new configuration
|
|
- [ ] Update monitoring/alerting rules
|
|
|
|
## Related Files
|
|
|
|
- NPM host vars: `host_vars/npm.yml`
|
|
- Jenkins host vars: `host_vars/jenkins.yml`
|
|
- NPM firewall playbook: `playbooks/configure-npm-firewall.yml` (to be created)
|
|
- This documentation: `docs/NPM-SSH-PROXY-FOR-JENKINS.md`
|