安装 OpenSSH 客户端:
Add-WindowsCapability -Online -Name OpenSSH.Client~~~~0.0.1.0
安装完成后,关闭当前 PowerShell,重新打开一个新的 PowerShell,然后验证
ssh -V
如果能看到类似:OpenSSH_for_Windows_...就说明装好了。
生成密钥
打开 PowerShell,执行:
ssh-keygen -t ed25519 -C "my-ssh-key"
它会提示:
Enter file in which to save the key (C:\Users\你的用户名\.ssh\id_ed25519):
直接按回车即可。
接着提示:
Enter passphrase (empty for no passphrase):
这里有两种选择:想方便就直接回车留空;想更安全,就设置一个密钥密码。
生成后通常会有两个文件:
- C:\Users\你的用户名.ssh\id_ed25519
- C:\Users\你的用户名.ssh\id_ed25519.pub
其中:
- id_ed25519 = 私钥,绝对不要发给别人
- id_ed25519.pub = 公钥,可以放到 Linux 服务器
一键脚本
写入公钥 + 改端口 28308 + 禁止密码登录 + 启用密钥登录
bash <<'EOF'
set -e
PORT="28308"
PUBLIC_KEY="ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKEXnTbbNLvba2POVcH06gorqMYjRT+JCs+KQlSXKSWt my-ssh-key"
# ==============================
# 确定当前登录用户
# ==============================
if [ -n "$SUDO_USER" ] && [ "$SUDO_USER" != "root" ]; then
SSH_USER="$SUDO_USER"
else
SSH_USER="$(who am i 2>/dev/null | awk '{print $1}')"
[ -z "$SSH_USER" ] && SSH_USER="root"
fi
HOME_DIR="$(getent passwd "$SSH_USER" | cut -d: -f6)"
SSH_DIR="$HOME_DIR/.ssh"
AUTH_KEYS="$SSH_DIR/authorized_keys"
echo "SSH 用户: $SSH_USER"
echo "用户目录: $HOME_DIR"
# ==============================
# 创建 SSH 密钥目录
# ==============================
mkdir -p "$SSH_DIR"
chmod 700 "$SSH_DIR"
touch "$AUTH_KEYS"
chmod 600 "$AUTH_KEYS"
# 避免重复添加同一把公钥
if ! grep -Fqx "$PUBLIC_KEY" "$AUTH_KEYS"; then
echo "$PUBLIC_KEY" >> "$AUTH_KEYS"
echo "公钥已写入: $AUTH_KEYS"
else
echo "公钥已经存在,无需重复添加"
fi
# 修正权限
chown -R "$SSH_USER":"$(id -gn "$SSH_USER")" "$SSH_DIR"
chmod 700 "$SSH_DIR"
chmod 600 "$AUTH_KEYS"
# ==============================
# 备份 SSH 配置
# ==============================
BACKUP="/etc/ssh/sshd_config.bak.$(date +%Y%m%d-%H%M%S)"
cp -a /etc/ssh/sshd_config "$BACKUP"
echo "SSH 配置已备份到:"
echo "$BACKUP"
# ==============================
# 删除旧的全局 SSH 配置项
# ==============================
sed -i \
-e '/^[[:space:]#]*Port[[:space:]]/d' \
-e '/^[[:space:]#]*PasswordAuthentication[[:space:]]/d' \
-e '/^[[:space:]#]*PubkeyAuthentication[[:space:]]/d' \
-e '/^[[:space:]#]*KbdInteractiveAuthentication[[:space:]]/d' \
-e '/^[[:space:]#]*ChallengeResponseAuthentication[[:space:]]/d' \
-e '/^[[:space:]#]*PermitEmptyPasswords[[:space:]]/d' \
/etc/ssh/sshd_config
# ==============================
# 在配置文件开头加入安全设置
# 防止文件末尾存在 Match 导致配置失效
# ==============================
TMP_FILE="$(mktemp)"
cat > "$TMP_FILE" <<CONFIG
# ===== Custom SSH Security Settings =====
Port $PORT
PubkeyAuthentication yes
PasswordAuthentication no
KbdInteractiveAuthentication no
ChallengeResponseAuthentication no
PermitEmptyPasswords no
CONFIG
cat /etc/ssh/sshd_config >> "$TMP_FILE"
cat "$TMP_FILE" > /etc/ssh/sshd_config
rm -f "$TMP_FILE"
# ==============================
# root 用户只允许密钥登录
# ==============================
if [ "$SSH_USER" = "root" ]; then
sed -i '/^[[:space:]#]*PermitRootLogin[[:space:]]/d' /etc/ssh/sshd_config
TMP_FILE="$(mktemp)"
echo "PermitRootLogin prohibit-password" > "$TMP_FILE"
cat /etc/ssh/sshd_config >> "$TMP_FILE"
cat "$TMP_FILE" > /etc/ssh/sshd_config
rm -f "$TMP_FILE"
fi
# ==============================
# 检查 SSH 配置
# ==============================
if ! sshd -t; then
echo
echo "SSH 配置检查失败!"
echo "正在自动恢复原配置..."
cp -a "$BACKUP" /etc/ssh/sshd_config
exit 1
fi
echo "SSH 配置检查通过"
# ==============================
# UFW
# ==============================
if command -v ufw >/dev/null 2>&1; then
if ufw status | grep -q "Status: active"; then
ufw allow ${PORT}/tcp >/dev/null
echo "UFW 已放行 TCP $PORT"
fi
fi
# ==============================
# firewalld
# ==============================
if command -v firewall-cmd >/dev/null 2>&1; then
if systemctl is-active --quiet firewalld; then
firewall-cmd --permanent --add-port=${PORT}/tcp >/dev/null
firewall-cmd --reload >/dev/null
echo "firewalld 已放行 TCP $PORT"
fi
fi
# ==============================
# SELinux
# ==============================
if command -v getenforce >/dev/null 2>&1; then
if [ "$(getenforce)" != "Disabled" ]; then
if command -v semanage >/dev/null 2>&1; then
semanage port -a -t ssh_port_t -p tcp "$PORT" 2>/dev/null || \
semanage port -m -t ssh_port_t -p tcp "$PORT"
echo "SELinux 已允许 SSH 使用端口 $PORT"
fi
fi
fi
# ==============================
# 重启 SSH
# ==============================
if systemctl list-unit-files | grep -q '^ssh\.service'; then
systemctl restart ssh
elif systemctl list-unit-files | grep -q '^sshd\.service'; then
systemctl restart sshd
else
service ssh restart 2>/dev/null || service sshd restart
fi
echo
echo "=========================================="
echo " SSH 配置完成"
echo "=========================================="
echo "用户: $SSH_USER"
echo "SSH端口: $PORT"
echo "公钥登录: 已启用"
echo "密码登录: 已禁止"
echo "空密码: 已禁止"
echo
echo "公钥位置:"
echo "$AUTH_KEYS"
echo
echo "重要:先不要关闭当前 SSH 窗口!"
echo
echo "请从另外一个终端测试:"
echo
echo "ssh -p $PORT $SSH_USER@服务器IP"
echo
echo "确认能够登录后,再关闭当前连接。"
echo "=========================================="
EOF
你的公钥已经填在这里,脚本顶部这一行:
PUBLIC_KEY="ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKEXnTbbNLvba2POVcH06gorqMYjRT+JCs+KQlSXKSWt my-ssh-key"
常见问题
OpenSSH 安装了,但是错误 解决方法
在 PowerShell 执行:
Test-Path C:\Windows\System32\OpenSSH\ssh.exe
如果返回:
True
再执行:
C:\Windows\System32\OpenSSH\ssh.exe -V
如果能正常显示版本,就直接把 OpenSSH 目录永久加入 PATH :
[Environment]::SetEnvironmentVariable(
"Path",
[Environment]::GetEnvironmentVariable("Path","Machine") + ";C:\Windows\System32\OpenSSH",
"Machine"
)