mirror of
https://github.com/LamGC/quickly-conf-sshd.git
synced 2025-04-29 14:17:32 +00:00
parent
55e79bef46
commit
4d253a8f7e
72
README.md
72
README.md
@ -1,2 +1,70 @@
|
||||
# install-ssh
|
||||
Quickly install SSH into the server.
|
||||
# Quickly Configuring SSH Server
|
||||
快速地将 SSH 密钥部署到服务器中,并定期更新。
|
||||
|
||||
这个脚本可以帮你做到这些事情:
|
||||
- 快速配置服务器的 SSH Server;
|
||||
- 定期自动更新 SSH 公钥到服务器中;
|
||||
- 集中管理注册到服务器的 SSH 公钥(例如使用 Github 管理 SSH 公钥);
|
||||
|
||||
## Usage
|
||||
部署密钥并设置定期更新:
|
||||
```bash
|
||||
curl -s https://ssh.lamgc.me | bash -s -- -c
|
||||
```
|
||||
如果不希望自动更新密钥,可以移除 `-c` 参数:
|
||||
```bash
|
||||
curl -s https://ssh.lamgc.me | bash -s
|
||||
```
|
||||
添加 `-p yes` 参数可以设置允许 Root 用户使用密码登录 SSH:
|
||||
```bash
|
||||
curl -s https://ssh.lamgc.me | bash -s -- -p yes
|
||||
```
|
||||
要查看脚本的帮助信息,请使用 `-h` 参数:
|
||||
```bash
|
||||
curl -s https://ssh.lamgc.me | bash -s -- -h
|
||||
```
|
||||
|
||||
## Install
|
||||
### Configuration
|
||||
先 Fork 本仓库,Fork 后在仓库设置中启用 Github Pages,分支指向 main 分支,目录为仓库根目录。
|
||||
配置好后将仓库克隆到本地,然后修改 `cf-worker/src/index.js` 中的前五个变量:
|
||||
```javascript
|
||||
// 改成你自己的 Github 用户名,注意是登录 Github 的那个用户名.
|
||||
const githubUserName = "LamGC";
|
||||
// 改成你 Fork 后的仓库名,记得要开启 Github Pages 功能.
|
||||
const githubInstSshProjectName = "quickly-conf-sshd";
|
||||
// 如果可以,建议在此设置备用的 SSH 公钥, 以防 Github 无法使用.
|
||||
const backupSshKeys = ``;
|
||||
// Worker 的访问地址, 如果不填的话默认为请求的地址, 填了就会用这里的地址(要去 Worker 的触发器那绑定, 否则无效).
|
||||
const defaultBaseUrl = "";
|
||||
// Cron 表达式, 默认 1 天执行一次更新.
|
||||
const cronExpression = "0 0 * * *";
|
||||
```
|
||||
|
||||
### Use Wrangler
|
||||
如果你安装了 Cloudflare 的 Wrangler,可以直接在 `cf-worker` 目录中执行:
|
||||
```bash
|
||||
wrangler publish
|
||||
```
|
||||
执行后将会自动创建 Worker 并上传 worker js 代码,Worker 的名字是 `quickly-conf-ssh-worker`。
|
||||
|
||||
### Manual Install
|
||||
如果你没有安装 Wrangler,那就手动在 Cloudflare Workers 中新建一个 Worker,名字你喜欢就好(也可以使用 `quickly-conf-ssh-worker`),选择 HTTP 处理程序,然后下一步;
|
||||
|
||||

|
||||
|
||||
创建完成后点击 Worker 名称右边的**快速编辑**,将 `cf-worker/src/index.js` 中的内容复制到编辑框中,把原本的代码覆盖掉,然后保存;
|
||||

|
||||
|
||||
保存后需要访问一下 Worker,检查是否有误(如果不检查仔细,把其他人的 SSH 密钥设置到服务器里了,那就寄咯):
|
||||
- 直接访问 Worker 地址,看看是否能跳转到你 Fork 的仓库中(地址栏显示了 `https://{你的 Github 用户名}.github.io/{Fork的仓库名}/`);
|
||||
- 访问 `{Worker地址}/ssh.keys`,应该显示你的在 Github 设置了的所有 SSH 公钥,如果是空的或者不是你的密钥,那就检查一下是不是 Github 用户名填错了;
|
||||
- 访问 `{Worker地址}/script.sh`,应该返回一个脚本,脚本开头的配置应与你在 Worker 开头的有关配置一致。
|
||||
|
||||
检查无误后就算安装完成了。
|
||||
|
||||
### (可选)使用自定义域名
|
||||
在 Worker 详情中,点击“触发器”,然后点击“添加自定义域”,按照提示输入已添加在 Cloudflare 中的域名即可。
|
||||

|
||||

|
||||

|
||||
|
105
cf-worker/src/index.js
Normal file
105
cf-worker/src/index.js
Normal file
@ -0,0 +1,105 @@
|
||||
// 改成你自己的 Github 用户名,注意是登录 Github 的那个用户名.
|
||||
const githubUserName = "LamGC";
|
||||
// 改成你 Fork 后的仓库名,记得要开启 Github Pages 功能.
|
||||
const githubInstSshProjectName = "quickly-conf-sshd";
|
||||
// 如果可以,建议在此设置备用的 SSH 公钥, 以防 Github 无法使用.
|
||||
const backupSshKeys = ``;
|
||||
// Worker 的访问地址, 如果不填的话默认为请求的地址, 填了就会用这里的地址(要去 Worker 的触发器那绑定, 否则无效).
|
||||
const defaultBaseUrl = "";
|
||||
// Cron 表达式, 默认 1 天执行一次更新.
|
||||
const cronExpression = "0 0 * * *";
|
||||
|
||||
// 下面的东西一般不用改.
|
||||
const baseRepoPageUrl = `https://${githubUserName.toLowerCase()}.github.io/${githubInstSshProjectName}/`;
|
||||
const installScriptUrl = `${baseRepoPageUrl}/conf-sshd.sh`;
|
||||
// 如果出现 Github 无法使用的情况, 可以修改 sshKeyUrl 来变更位置.
|
||||
// 也可以添加额外的 SSH 公钥地址(比如 KeyBase).
|
||||
const sshKeyUrls = [
|
||||
`https://github.com/${githubUserName}.keys`
|
||||
];
|
||||
|
||||
// 下面是脚本的占位符.
|
||||
const SCRIPT_PH_SSH_KEY_URL = "{{ SSH_KEY_URL }}"
|
||||
const SCRIPT_PH_SCRIPT_URL = "{{ SCRIPT_URL }}"
|
||||
const SCRIPT_PH_DEFAULT_CRON = "{{ DEFAULT_CRON }}"
|
||||
|
||||
|
||||
async function sendScriptContent(baseUrl) {
|
||||
let scriptResp = await fetch(new Request(installScriptUrl));
|
||||
if (scriptResp.ok) {
|
||||
let scriptContent = await scriptResp.text();
|
||||
|
||||
scriptContent = scriptContent.replace(SCRIPT_PH_SSH_KEY_URL, `${baseUrl}/ssh.keys`)
|
||||
.replace(SCRIPT_PH_SCRIPT_URL, `${baseUrl}/script.sh`)
|
||||
.replace(SCRIPT_PH_DEFAULT_CRON, cronExpression)
|
||||
|
||||
return new Response(scriptContent, {
|
||||
headers: {
|
||||
"content-type": "text/plain; charset=utf-8"
|
||||
}
|
||||
});
|
||||
} else {
|
||||
return new Response("Failed to get install script.", {
|
||||
status: 500,
|
||||
statusText: "Failed to get install script",
|
||||
headers: {
|
||||
"content-type": "text/plain; charset=utf-8"
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export default {
|
||||
async fetch(request, env) {
|
||||
const { pathname, host } = new URL(request.url);
|
||||
const baseUrl = defaultBaseUrl || `https://${host}`;
|
||||
if (pathname === "/ssh.keys") {
|
||||
for (let url of sshKeyUrls) {
|
||||
let response = await fetch(new Request(url));
|
||||
if (response.ok) {
|
||||
let keys = await response.text()
|
||||
return new Response(keys, {
|
||||
headers: {
|
||||
"content-type": "text/plain; charset=utf-8"
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
if (backupSshKeys.length > 0) {
|
||||
return new Response(backupSshKeys, {
|
||||
headers: {
|
||||
"content-type": "text/plain; charset=utf-8"
|
||||
}
|
||||
});
|
||||
} else {
|
||||
return new Response("Failed to get keys.", {
|
||||
status: 500,
|
||||
statusText: "Failed to get keys",
|
||||
headers: {
|
||||
"content-type": "text/plain; charset=utf-8"
|
||||
}
|
||||
});
|
||||
}
|
||||
} else if (pathname === "/") {
|
||||
const userAgent = request.headers.get("User-Agent");
|
||||
if (userAgent != null && userAgent.match(/curl|libcurl/) !== null) {
|
||||
return await sendScriptContent(baseUrl);
|
||||
} else {
|
||||
return new Response("", {
|
||||
status: 301,
|
||||
statusText: "Redirect",
|
||||
headers: {
|
||||
"Location": baseRepoPageUrl
|
||||
}
|
||||
});
|
||||
}
|
||||
} else if (pathname === "/script.sh") {
|
||||
return await sendScriptContent(baseUrl);
|
||||
} else {
|
||||
return new Response("Not found.", {
|
||||
status: 404,
|
||||
statusText: "Not Found"
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
3
cf-worker/wrangler.toml
Normal file
3
cf-worker/wrangler.toml
Normal file
@ -0,0 +1,3 @@
|
||||
name = "quickly-conf-ssh-worker"
|
||||
main = "src/index.js"
|
||||
compatibility_date = "2023-01-26"
|
217
conf-sshd.sh
Normal file
217
conf-sshd.sh
Normal file
@ -0,0 +1,217 @@
|
||||
#!/bin/bash
|
||||
|
||||
########## 一些配置 ##########
|
||||
|
||||
# 默认获取 SSH key 的地方,一般是 Github.
|
||||
sshkey_url="{{ SSH_KEY_URL }}"
|
||||
# 默认的 Cron 执行计划, 每天凌晨 0 点执行
|
||||
default_cron="{{ DEFAULT_CRON }}"
|
||||
# 脚本 Url
|
||||
script_url="{{ SCRIPT_URL }}"
|
||||
|
||||
############ 脚本区 ##########
|
||||
|
||||
script_params=$*
|
||||
has_param() {
|
||||
for param in $script_params; do
|
||||
for tParam in $@; do
|
||||
if [ "$tParam" == "$param" ]; then
|
||||
echo "true"
|
||||
return
|
||||
fi
|
||||
done
|
||||
done
|
||||
echo "false"
|
||||
}
|
||||
|
||||
get_param_value() {
|
||||
local find=false
|
||||
for param in $script_params; do
|
||||
if [ "$find" == "true" ]; then
|
||||
if [[ $param == -* ]]; then
|
||||
return
|
||||
fi
|
||||
echo $param
|
||||
return
|
||||
fi
|
||||
for tParam in $@; do
|
||||
if [ "$tParam" == "$param" ]; then
|
||||
find=true
|
||||
break
|
||||
fi
|
||||
done
|
||||
done
|
||||
}
|
||||
|
||||
use_param_keys_url() {
|
||||
local new_sshkey_url=$(get_param_value "-k" "--sshkey-url")
|
||||
if [ "$new_sshkey_url" == "" ]; then
|
||||
echo "Please specify the URL of the SSH public key."
|
||||
exit 1
|
||||
fi
|
||||
sshkey_url=$new_sshkey_url
|
||||
echo "A new SSH keys URL has been specified: $sshkey_url"
|
||||
}
|
||||
|
||||
# 检查并更新 SSH key 地址.
|
||||
if [ $(has_param "-k" "--sshkey-url") == "true" ]; then
|
||||
use_param_keys_url
|
||||
fi
|
||||
|
||||
# 帮助信息.
|
||||
if [ $(has_param "-h" "--help") == "true" ]; then
|
||||
echo "Usage: $0 [options]"
|
||||
echo "Options:"
|
||||
echo " -h, --help Print this help message."
|
||||
echo ""
|
||||
echo "Available to any user: "
|
||||
echo " -k, --sshkey-url The URL of the SSH public key."
|
||||
echo " -c, --cron [cron | false] Configure Crontab to automatically update ssh keys,"
|
||||
echo " Cron expression can be specified, If false is specified, "
|
||||
echo " Crontab settings will be deleted automatically."
|
||||
echo ""
|
||||
echo " -o, --only-update-keys Only update SSH keys, do not configure ssh server."
|
||||
echo " -u, --update-self Update this script to the latest version."
|
||||
echo ""
|
||||
echo "only available when the script is executed as root:"
|
||||
echo " -n, --no-install-sshd Do not install SSH Server."
|
||||
echo " -p, --allow-root-passwd <yes | no> Allow Root to log in with a password."
|
||||
echo ""
|
||||
exit 0
|
||||
fi
|
||||
|
||||
update_sshkeys() {
|
||||
if [ "$sshkey_url" == "" ]; then
|
||||
echo "Please specify the URL of the SSH public key."
|
||||
exit 1
|
||||
fi
|
||||
echo "Downloading SSH public key from '$sshkey_url'"
|
||||
mkdir -p ~/.ssh
|
||||
local ssh_keys=$(curl -s $sshkey_url)
|
||||
if [ $? -ne 0 ] || [ "$ssh_keys" == "" ]; then
|
||||
echo "Failed to download SSH public key at $(date '+%Y-%m-%d %H:%M:%S')"
|
||||
exit 1
|
||||
fi
|
||||
echo "-------------------- SSH Keys --------------------"
|
||||
echo "$ssh_keys"
|
||||
echo "--------------------------------------------------"
|
||||
echo $ssh_keys > ~/.ssh/authorized_keys
|
||||
chmod 600 ~/.ssh/authorized_keys
|
||||
# 输出更新成功,需要附带时间日期
|
||||
echo "SSH public key updated successfully at $(date '+%Y-%m-%d %H:%M:%S')"
|
||||
}
|
||||
|
||||
# 检查是否只更新密钥.
|
||||
if [ $(has_param "-o" "--only-update-keys") == "true" ]; then
|
||||
update_sshkeys
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# 检查是否指定了 --update-self
|
||||
if [ $(has_param "-u" "--update-self") == "true" ]; then
|
||||
echo "Updating conf-sshd script..."
|
||||
cp $0 ~/.conf-sshd/conf-sshd.sh.bak
|
||||
curl -s $script_url > $0 || cp ~/.conf-sshd/conf-sshd.sh.bak $0 && echo "Script update failed at $(date '+%Y-%m-%d %H:%M:%S')" && exit 1
|
||||
chmod +x ~/.conf-sshd/conf-sshd.sh
|
||||
echo "Script updated successfully at $(date '+%Y-%m-%d %H:%M:%S')"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# 检查 /usr/sbin/sshd 是否存在,且 /usr/sbin/sshd 执行后退出代码为 0
|
||||
/usr/sbin/sshd -T > /dev/null
|
||||
if [ $? -ne 0 ] && [ $(has_param "-n" "--no-install-sshd") == "false" ]; then
|
||||
if [ $(id -u) -eq 0 ]; then
|
||||
echo "The ssh server is not installed, and the script is executed as root, so it will be installed."
|
||||
if [ -f /etc/redhat-release ]; then
|
||||
yum install -y openssh-server
|
||||
elif [ -f /etc/debian_version ]; then
|
||||
apt-get update
|
||||
apt-get install -y openssh-server
|
||||
fi
|
||||
echo "The ssh server has been installed."
|
||||
else
|
||||
echo "The ssh server is not installed, but the script is executed as a non-root user and cannot be installed."
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
echo "The ssh server is already installed."
|
||||
fi
|
||||
|
||||
# 检查是否指定了 --allow-root-passwd
|
||||
if [ $(has_param "-p" "--allow-root-passwd") == "true" ]; then
|
||||
# 检查当前用户是否为 root
|
||||
if [ $(id -u) -eq 0 ]; then
|
||||
# 获取参数值
|
||||
allow_root_passwd=$(get_param_value "-p" "--allow-root-passwd" | tr '[:upper:]' '[:lower:]')
|
||||
if [ "$allow_root_passwd" == "yes" ]; then
|
||||
# 设置允许 root 使用密码登录
|
||||
sed -i 's/^#?PermitRootLogin.*/PermitRootLogin yes/g' /etc/ssh/sshd_config
|
||||
echo "Root user is allowed to log in with password."
|
||||
elif [ "$allow_root_passwd" == "no" ]; then
|
||||
# 设置禁止 root 使用密码登录
|
||||
sed -i 's/^#?PermitRootLogin.*/PermitRootLogin prohibit-password/g' /etc/ssh/sshd_config
|
||||
echo "Root user is prohibited from logging in with password."
|
||||
else
|
||||
echo "Please specify whether to allow root to log in with a password."
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
echo "The script is executed as a non-root user and cannot set whether to allow root to log in with a password."
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# 更新密钥.
|
||||
update_sshkeys
|
||||
|
||||
# 检查是否指定了 --cron
|
||||
if [ $(has_param "-c" "--cron") == "true" ]; then
|
||||
# 检查 Crontab 是否已安装
|
||||
if [ "$(command -v crontab)" == "" ]; then
|
||||
if [ $(id -u) -eq 0 ]; then
|
||||
echo "The crontab is not installed, and the script is executed as a root user, so it will be installed."
|
||||
if [ -f /etc/redhat-release ]; then
|
||||
yum install -y crontabs
|
||||
elif [ -f /etc/debian_version ]; then
|
||||
apt-get update
|
||||
apt-get install -y cron
|
||||
fi
|
||||
echo "The crontab has been installed."
|
||||
else
|
||||
echo "The crontab is not installed, but the script is executed as a non-root user and cannot be installed."
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
echo "The crontab is already installed."
|
||||
fi
|
||||
cron=$(get_param_value "-c" "--cron" | tr '[:upper:]' '[:lower:]')
|
||||
if [ "$cron" == "false" ]; then
|
||||
# 检查 Crontab 是否已经设置
|
||||
if [ "$(crontab -l | grep "conf-sshd.sh")" == "" ]; then
|
||||
echo "Crontab will not be configured."
|
||||
exit 0
|
||||
else
|
||||
crontab -l | grep -v "conf-sshd.sh" | crontab -
|
||||
echo "Crontab has been removed."
|
||||
exit 0
|
||||
fi
|
||||
else
|
||||
if [ "$cron" == "" ]; then
|
||||
cron=$default_cron
|
||||
fi
|
||||
# 将当前脚本移动到 ~/.conf-sshd/conf-sshd.sh 中.
|
||||
mkdir -p ~/.conf-sshd
|
||||
# 检查当前脚本是否为文件
|
||||
if [ ! -f $0 ]; then
|
||||
echo "Downloading conf-sshd script..."
|
||||
curl -o ~/.conf-sshd/conf-sshd.sh $script_url
|
||||
else
|
||||
echo "Copying conf-sshd script..."
|
||||
cp $0 ~/.conf-sshd/conf-sshd.sh
|
||||
fi
|
||||
chmod +x ~/.conf-sshd/conf-sshd.sh
|
||||
echo "Install conf-sshd script successfully."
|
||||
# 将当前脚本添加到 Crontab 中
|
||||
echo "$cron /bin/bash ~/.conf-sshd/conf-sshd.sh -o -k $sshkey_url >> ~/.conf-sshd/run.log" | crontab -
|
||||
fi
|
||||
fi
|
BIN
docs/Create-a-new-worker.png
Normal file
BIN
docs/Create-a-new-worker.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 13 KiB |
BIN
docs/add-custom-domain.png
Normal file
BIN
docs/add-custom-domain.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 32 KiB |
BIN
docs/added-custom-domain.png
Normal file
BIN
docs/added-custom-domain.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 19 KiB |
BIN
docs/copy-js-code-to-worker.png
Normal file
BIN
docs/copy-js-code-to-worker.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 65 KiB |
BIN
docs/input-custom-domain.png
Normal file
BIN
docs/input-custom-domain.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 30 KiB |
Loading…
Reference in New Issue
Block a user