When implementing SSH tunneling as a lightweight VPN solution, we often need to restrict interactive shell access while maintaining port forwarding capabilities. The scenario typically involves:
start putty -D 9999 mysshserver.com -N
The -N
flag prevents shell session startup client-side, but server-side configuration provides more robust control.
Ubuntu Server with OpenSSH offers several methods to disable shell access:
- ForceCommand in
sshd_config
:Match User tunneluser ForceCommand /bin/false PermitTTY no
- Custom shell alternative:
sudo usermod -s /usr/sbin/nologin tunneluser
- Command restriction:
command="echo 'Interactive shell disabled'" ssh-rsa AAAAB3NzaC1yc2E...
(in authorized_keys)
Beyond basic hardening (non-root access, key auth, port change), consider:
# /etc/ssh/sshd_config
AllowUsers tunneluser
AllowTcpForwarding yes
PermitTunnel yes
X11Forwarding no
GatewayPorts no
ClientAliveInterval 300
MaxAuthTries 2
PasswordAuthentication no
Complete setup for a web-only tunneling user:
# Create restricted user
sudo adduser --shell /usr/sbin/nologin --disabled-password tunneluser
# Configure SSH
echo 'Match User tunneluser
AllowTcpForwarding yes
PermitTTY no
ForceCommand /bin/false' | sudo tee -a /etc/ssh/sshd_config
# Restart SSH
sudo service ssh restart
Client connection then works normally for tunneling but blocks shell access attempts:
ssh -N -D 9999 tunneluser@yourserver.com
If connections fail after configuration:
- Verify
PermitTunnel
andAllowTcpForwarding
settings - Check SELinux/AppArmor restrictions on SSH
- Test with
-v
flag for connection debugging
When implementing SSH tunneling as a lightweight VPN alternative for web traffic, security-conscious administrators often want to restrict interactive shell access while maintaining the tunneling functionality. The key challenge is maintaining SOCKS proxy capabilities (via -D
flag) while preventing unauthorized command execution.
While the client-side -N
flag prevents shell initialization, these server-side approaches provide more robust control:
# Method 1: ForceCommand in sshd_config
Match User tunneluser
ForceCommand echo "This account permits web tunneling only"
PermitTTY no
# Method 2: Custom shell wrapper
#!/bin/sh
if [ -z "$SSH_ORIGINAL_COMMAND" ]; then
echo "Tunnel active - interactive shell disabled"
else
echo "Command execution blocked"
fi
For production deployments, combine these OpenSSH server configurations (/etc/ssh/sshd_config
):
Port 2222 # Change from default
PermitRootLogin no
PasswordAuthentication no
AllowUsers tunneluser
PermitTunnel yes
X11Forwarding no
AllowTcpForwarding yes
GatewayPorts no
The optimal Putty configuration for Windows clients:
putty.exe -ssh -N -D 127.0.0.1:9999 tunneluser@yourserver.com -P 2222 -i private_key.ppk
For Linux/macOS clients:
ssh -fN -D 9999 -p 2222 tunneluser@yourserver.com -i ~/.ssh/tunnel_key
Confirm restricted access works by attempting shell access:
$ ssh -p 2222 tunneluser@yourserver.com
Tunnel active - interactive shell disabled
Connection closed.
Check active tunnels with:
ss -tnp | grep sshd
lsof -i -n | egrep '\<sshd\>'
For maximum isolation, create a restricted environment:
# In /etc/ssh/sshd_config
Match User tunneluser
ChrootDirectory /var/lib/ssh_tunnel
ForceCommand internal-sftp
PermitTunnel yes
AllowTCPForwarding yes