功能简介

作者注:脚本默认作用于 root 账户。

在日常运维工作中,启用基于 SSH 公钥的认证方式是一种更加安全且推荐的做法。不仅可以提高登录效率,还能有效防止暴力破解密码攻击。

本文通过一个 Bash 脚本,手把手教你如何在 Ubuntu 服务器上启用 SSH 密钥认证,并彻底关闭密码登录。

脚本自动完成以下任务:

✅ 生成 SSH 密钥对(非交互式)
✅ 设置 ~/.ssh/authorized_keys 权限并添加公钥
✅ 配置 /etc/ssh/sshd_config 文件,实现只允许密钥登录
✅ 重启 ssh 服务以使修改生效

脚本内容

创建一个 setup_ssh_key.sh 脚本文件

vim setup_ssh_key.sh

将以下内容保存并执行它即可完成所有配置。

#!/bin/bash

set -e

# ==========================================
# Usage:
#
# 默认 22 端口:
#   bash setup_ssh_key.sh
#
# 指定 2222 端口:
#   bash setup_ssh_key.sh 2222
#
# 指定 10022 端口:
#   bash setup_ssh_key.sh 10022
# ==========================================

SSH_PORT="${1:-22}"

SSH_DIR="/root/.ssh"
KEY_FILE="$SSH_DIR/id_ed25519"
AUTHORIZED_KEYS="$SSH_DIR/authorized_keys"
SSHD_CONFIG="/etc/ssh/sshd_config"

# SSH 密钥密码
KEY_PASSPHRASE="这里输入密钥密码"


# ==========================================
# Step 0: Validate SSH port
# ==========================================

echo "SSH port: $SSH_PORT"

# 必须是数字
if ! [[ "$SSH_PORT" =~ ^[0-9]+$ ]]; then
    echo "ERROR: SSH port must be a number."
    exit 1
fi

# 端口范围检查
if [ "$SSH_PORT" -lt 1 ] || [ "$SSH_PORT" -gt 65535 ]; then
    echo "ERROR: SSH port must be between 1 and 65535."
    exit 1
fi


# ==========================================
# Step 1: Create SSH directory
# ==========================================

echo "Creating SSH directory..."

mkdir -p "$SSH_DIR"

chmod 700 "$SSH_DIR"

chown root:root "$SSH_DIR"


# ==========================================
# Step 2: Generate SSH key pair
# ==========================================

echo "Generating SSH key pair..."

if [ ! -f "$KEY_FILE" ]; then

    ssh-keygen \
        -t ed25519 \
        -a 64 \
        -N "$KEY_PASSPHRASE" \
        -f "$KEY_FILE"

else

    echo "SSH key already exists:"
    echo "$KEY_FILE"

fi


# ==========================================
# Step 3: Configure authorized_keys
# ==========================================

echo "Configuring authorized_keys..."

touch "$AUTHORIZED_KEYS"

chmod 600 "$AUTHORIZED_KEYS"

PUBLIC_KEY=$(cat "${KEY_FILE}.pub")

# 防止重复添加
if ! grep -qxF "$PUBLIC_KEY" "$AUTHORIZED_KEYS"; then

    echo "$PUBLIC_KEY" >> "$AUTHORIZED_KEYS"

fi

chmod 700 "$SSH_DIR"

chmod 600 "$AUTHORIZED_KEYS"

chown -R root:root "$SSH_DIR"


# ==========================================
# Step 4: Backup SSH config
# ==========================================

echo "Backing up SSH config..."

BACKUP_FILE="${SSHD_CONFIG}.bak.$(date +%Y%m%d_%H%M%S)"

cp "$SSHD_CONFIG" "$BACKUP_FILE"

echo "Backup:"
echo "$BACKUP_FILE"


# ==========================================
# Step 5: Configure SSH
# ==========================================

echo "Configuring SSH..."

cat > "$SSHD_CONFIG" << EOF

# ==============================
# SSH Server Configuration
# ==============================

# SSH Listen Port
Port $SSH_PORT

# ------------------------------
# Basic
# ------------------------------

KbdInteractiveAuthentication no

UsePAM yes

X11Forwarding yes

PrintMotd no

AcceptEnv LANG LC_*

Subsystem sftp /usr/lib/openssh/sftp-server


# ------------------------------
# Authentication
# ------------------------------

MaxAuthTries 6

# Root can login using SSH key
PermitRootLogin prohibit-password

# Disable password login
PasswordAuthentication no

# Enable public key authentication
PubkeyAuthentication yes

# Only allow public key authentication
AuthenticationMethods publickey

EOF


# ==========================================
# Step 6: Check SSH configuration
# ==========================================

echo "Checking SSH configuration..."

if ! sshd -t; then

    echo ""
    echo "ERROR: SSH configuration is invalid!"
    echo ""

    echo "Restoring backup..."

    cp "$BACKUP_FILE" "$SSHD_CONFIG"

    echo "SSH service will NOT be restarted."

    exit 1

fi

echo "SSH configuration is valid."


# ==========================================
# Step 7: Configure firewall
# ==========================================

if command -v ufw >/dev/null 2>&1; then

    echo "Checking UFW..."

    if ufw status | grep -q "Status: active"; then

        echo "Opening SSH port $SSH_PORT in UFW..."

        ufw allow "${SSH_PORT}/tcp"

    else

        echo "UFW is not active. Skip firewall configuration."

    fi

else

    echo "UFW not installed. Skip firewall configuration."

fi


# ==========================================
# Step 8: Restart SSH
# ==========================================

echo "Reloading systemd..."

systemctl daemon-reload


# Ubuntu 24.04 / 22.10+ may use ssh.socket
if systemctl list-unit-files | grep -q '^ssh.socket'; then

    if systemctl is-active --quiet ssh.socket; then

        echo "Detected active ssh.socket"

        echo "Restarting ssh.socket..."

        systemctl restart ssh.socket

    fi

fi


# Restart normal SSH service as well
if systemctl list-unit-files | grep -q '^ssh.service'; then

    echo "Restarting ssh.service..."

    systemctl restart ssh

elif systemctl list-unit-files | grep -q '^sshd.service'; then

    echo "Restarting sshd.service..."

    systemctl restart sshd

else

    echo "ERROR: SSH service not found!"

    exit 1

fi


# ==========================================
# Step 9: Verify listening port
# ==========================================

echo ""
echo "=========================================="
echo "Checking SSH listening port"
echo "=========================================="

ss -lntp | grep -E "(:${SSH_PORT}[[:space:]])" || true


# ==========================================
# Step 10: Show SSH status
# ==========================================

echo ""

systemctl --no-pager --full status ssh 2>/dev/null || \
systemctl --no-pager --full status sshd 2>/dev/null || true


# ==========================================
# Complete
# ==========================================

echo ""
echo "=========================================="
echo "SSH configuration completed"
echo "=========================================="
echo ""

echo "SSH Port:"
echo "$SSH_PORT"

echo ""

echo "Private key:"
echo "$KEY_FILE"

echo ""

echo "Public key:"
echo "${KEY_FILE}.pub"

echo ""

echo "Connect example:"
echo "ssh -p $SSH_PORT -i $KEY_FILE root@SERVER_IP"

echo ""
echo "IMPORTANT:"
echo "Do NOT close the current SSH connection"
echo "until you verify the new SSH port works."
echo ""

执行脚本文件 后面加端口号 可指定端口

bash ./setup_ssh_key.sh

注意事项

✅ 将id_ed25519文件内容 下载到本地-登录使用的密钥文件

vim ~/.ssh/id_ed25519

✅ 生成的密钥类型为 RSA,长度 4090 位,适用于大多数客户端。
✅ 若已有密钥文件,请注意备份 ~/.ssh/id_ed25519 和 id_ed25519.pub。
✅ 修改 sshd_config 存在风险,请谨慎操作,建议保留当前终端连接直到验证成功。
✅ 公钥也可复制到其他用户账户,实现多账户免密登录。

重启失败

Failed to restart sshd.service: Unit sshd.service not found.

那可能没有安装 SSH Server。Ubuntu/Debian 可以安装:

sudo apt update
sudo apt install -y openssh-server

sudo systemctl enable --now ssh

作者:Joseph Lee  创建时间:2026-08-13 17:36
最后编辑:Joseph Lee  更新时间:2026-09-14 16:51