5.7 KiB
name, description
| name | description |
|---|---|
| ssh-server-setup | Set up SSH key authentication, configure firewalls, harden SSH, and audit server security. Use when: (1) user needs SSH access to a server, (2) SSH connection fails with permission errors, (3) setting up key-based auth for new users, (4) enabling/configuring UFW firewall, (5) analyzing SSH attacks, (6) hardening SSH config. |
SSH Server Setup & Troubleshooting
Quick Setup (New Key Pair)
1. Generate Key Pair
# On client machine (or use Xshell's key generator)
ssh-keygen -t rsa -b 2048 -f ~/.ssh/id_rsa -C "user@host"
2. Install Public Key on Server
# On server
mkdir -p /home/<user>/.ssh
echo '<public-key-content>' >> /home/<user>/.ssh/authorized_keys
chmod 700 /home/<user>/.ssh
chmod 600 /home/<user>/.ssh/authorized_keys
chmod 755 /home/<user> # CRITICAL: must NOT be 777 or group-writable
chown -R <user>:<user> /home/<user>/.ssh
3. Verify SSH Config Allows Key Auth
grep -E "^(PubkeyAuthentication|AuthorizedKeysFile)" /etc/ssh/sshd_config
# Should show:
# PubkeyAuthentication yes
# AuthorizedKeysFile .ssh/authorized_keys
⚠️ Critical Pitfall: Home Directory Permissions
Symptom: SSH logs show Authentication refused: bad ownership or modes for directory /home/<user>
Root cause: SSH (OpenSSH) refuses public key authentication if the user's home directory has group or other write permissions (e.g., 777, 775).
Fix:
chmod 755 /home/<user>
Why: OpenSSH considers a writable home directory a security risk — other users could manipulate ~/.ssh/authorized_keys. The directory must be owned by the user and not writable by group/others.
Debugging:
# Check current permissions
ls -la /home/ | grep <user>
# Should show drwxr-xr-x (755), NOT drwxrwxrwx (777) or drwxrwxr-x (775)
# Check SSH logs for the exact error
tail -20 /var/log/auth.log | grep -i "ssh\|publickey"
# Or on systemd systems:
journalctl -u ssh --no-pager -n 20
Permission Checklist
| Path | Owner | Permissions | Why |
|---|---|---|---|
/home/<user> |
<user> |
755 |
SSH refuses auth if group/other writable |
~/.ssh/ |
<user> |
700 |
Only owner should access SSH config |
~/.ssh/authorized_keys |
<user> |
600 |
Only owner should read/write keys |
~/.ssh/id_rsa (private) |
<user> |
600 |
Private key must be restricted |
Xshell-Specific Notes
- Generate key: 工具 → 用户密钥管理器 → 新建 → RSA 2048
- Import key: 工具 → 用户密钥管理器 → 导入
- Connection settings:
- 协议: SSH
- 用户身份验证: 方法选 Public Key(不是 Password)
- 用户名:
ubuntu(or whatever the server user is) - 用户密钥: select the imported key
Common Errors
| Error | Cause | Fix |
|---|---|---|
bad ownership or modes for directory |
Home dir writable by group/others | chmod 755 /home/<user> |
bad ownership or modes for file |
authorized_keys wrong perms | chmod 600 ~/.ssh/authorized_keys |
Permission denied (publickey) |
Key not in authorized_keys | Add public key to file |
Connection closed by foreign host |
Auth failed, server disconnects | Check logs for specific reason |
所选的用户密钥未在远程主机上注册 |
Public key not installed on server | Add public key to authorized_keys |
UFW Firewall Setup
When enabling SSH access, always set up UFW in this order to avoid lockout:
# 1. Allow SSH FIRST (before enabling firewall)
sudo ufw allow 22/tcp comment "SSH"
# 2. Set default policies
sudo ufw default deny incoming
sudo ufw default allow outgoing
# 3. Enable (use --force for non-interactive)
sudo ufw --force enable
# 4. Verify
sudo ufw status verbose
Opening additional ports later:
sudo ufw allow 80/tcp comment "HTTP"
sudo ufw allow 443/tcp comment "HTTPS"
sudo ufw allow from <specific-ip> to any port 22 # Restrict SSH to specific IP
SSH Attack Analysis
Check attack patterns:
# Failed/disconnected attempts with IP counts
journalctl -u ssh --no-pager --since "2026-05-01" | \
grep -i "failed\|invalid\|refused\|disconnected.*preauth" | \
grep -oE '[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+' | sort | uniq -c | sort -rn | head -15
# Successful logins only
journalctl -u ssh --no-pager --since "2026-05-01" | grep "Accepted" | \
grep -oE '[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+' | sort | uniq -c | sort -rn
IP geolocation lookup:
# ip-api.com (free, no key needed, rate limited 45/min)
curl -s "http://ip-api.com/json/<IP>?fields=country,regionName,isp,org"
Typical attack sources: Cloud provider IPs (Tencent Cloud, Alibaba Cloud, OVH, Hetzner) — these are botnet/scanner nodes, not targeted attacks.
SSH Hardening (sshd_config)
Add to /etc/ssh/sshd_config:
MaxAuthTries 3 # Limit auth attempts per connection
LoginGraceTime 30 # Timeout for auth (seconds)
ClientAliveInterval 300 # Send keepalive every 5 min
ClientAliveCountMax 2 # Disconnect after 2 missed keepalives
MaxSessions 3 # Limit concurrent sessions per connection
AllowAgentForwarding no # Disable unless needed
AllowTcpForwarding no # Disable unless needed
Apply: sudo systemctl restart sshd
Server Security Audit Checklist
# 1. SSH config
cat /etc/ssh/sshd_config | grep -v "^#" | grep -v "^$"
# 2. Firewall status
sudo ufw status verbose
# 3. fail2ban status (if installed)
sudo fail2ban-client status sshd
# 4. Auto-updates
cat /etc/apt/apt.conf.d/20auto-upgrades
# 5. Listening ports
ss -tlnp | grep -v "127.0.0.1" | grep -v "::1"
# 6. System resources
free -h && df -h / && uptime
# 7. Swap config
swapon --show
cat /proc/sys/vm/swappiness