背景
每次新装服务器,配置基础环境,总是各种翻看笔记,各种复制粘贴,实在太烦琐了,于是写了个通用的一键初始化脚本,并发布到网站,方便调用,正所谓懒惰是技术进步的最大源动力。
脚本使用方法
安装curl
如果已有curl,可忽略此步骤。
1
| apt-get -y install curl
|
示例1
创建用户yanyong
,设置FQDN为blog.yanyong.cc
,设置ssh端口23422
,设置阿里源,设置中国上海时区Asia/Shanghai
。
1
2
3
4
5
6
| curl -fsSL https://raw.yanyong.cc/sh/debian10-init.sh | bash -s -- \
--fqdn=blog.yanyong.cc \
--user=yanyong \
--port=23422 \
--source=ali \
--tz=Asia/Shanghai
|
执行结果,脚本已更新,此图可能与实际返回结果有所不同。
示例2
创建用户testuser
,成功创建用户会触发禁用root远程登录和禁用密码验证登录,如有需要启用root远程登录或密码验证登录,查看可选操作。
1
| curl -fsSL https://raw.yanyong.cc/sh/debian10-init.sh | bash -s user=testuser
|
示例3
apt-get dist-upgrade更新系统。
1
| curl -fsSL https://raw.yanyong.cc/sh/debian10-init.sh | bash -s distupgrade
|
如果跨版本更新系统,例如当前是debian 9,需要传入--source=...
参数修改成debian 10的源,此示例为香港源。
1
| curl -fsSL https://raw.yanyong.cc/sh/debian10-init.sh | bash -s distupgrade source=hk
|
特别说明
查看帮助:curl -fsSL https://raw.yanyong.cc/sh/debian10-init.sh | bash -s help
。参数的小横线--
可以省略,如user=yanyong
等同于--user=yanyong
,参数顺序无要求。
创建用户时,默认设置用户密码为随机生成的16位字符串,生成密钥对,保存在创建的用户家目录的.ssh目录下,并设置密钥密码为随机生成的8位字符串。也可以指定密码--password=PASSWORD
(用户密码),--keyPasswd=PASSWORD
(密钥密码)。
hostname无需指定,取FQDN的最左边记录值为主机名(如FQDN为www.example.com
,则hostname为www
)。
APT源设置,--source=cn
为中科大源,--source=hk
为香港源,--source=us
为美国源,--source=ali
为阿里源,--source=aws
为亚马逊源。修改源,会相应的修改NTP地址,已自动选择,无须指定。
查看所有可用时区:timedatectl list-timezones
。
初始化脚本每次执行,无论有没有参数,默认都有以下处理:
- apt-get upgrade更新系统。
- 安装man, sudo, vim, net-tools等。
- 自定义profile文件,优化历史命令记录,设置命令别名,如
ll
, lt
等。 - 如果成功创建用户,就会禁用root远程登录和禁用密码验证登录。
- 启用iptables防火墙,开启ping,开启ssh的端口,开启80和443端口。
可选操作
如有需要,启用root远程登录。
1
| sudo sed -ri 's/^(PermitRootLogin )no$/\1yes/' /etc/ssh/sshd_config && sudo systemctl reload ssh
|
如有需要,启用密码验证登录。
1
| sudo sed -ri 's/^(PasswordAuthentication )no$/\1yes/' /etc/ssh/sshd_config && sudo systemctl reload ssh
|
如有需要,关闭iptables防火墙。
1
2
3
| sudo iptables -P INPUT ACCEPT
sudo iptables -F INPUT # 可选
: | sudo tee /etc/iptables/rules.v4 # 可选,重启后也不会打开防火墙
|
脚本内容
以下内容可能不是最新版本,最新版本见raw链接:[raw]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
| #!/usr/bin/env bash
# Author: [email protected]
set -e
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
SCRIPTNAME="${0##*/}"
ARGS="$*"
usage(){
echo "Usage: /PATH/SCRIPTNAME [[--]fqdn=FQDN] [[--]port=PORT] [ [--]user=USERNAME [[--]passwd=PASSWORD] [[--]keyPasswd=PASSWORD] ] [[--]source={cn|CN|hk|HK|us|US|ali|ALI|aws|AWS}] [[--]tz=Asia/Shanghai] [[--]help]"
}
setCN(){
mirror=http://mirrors.ustc.edu.cn/debian/
security=http://mirrors.ustc.edu.cn/debian-security
ntp='0.cn.pool.ntp.org 1.cn.pool.ntp.org 2.cn.pool.ntp.org 3.cn.pool.ntp.org'
}
setHK(){
mirror=http://ftp.hk.debian.org/debian/
#security=http://ftp.hk.debian.org/debian-security
security=http://security.debian.org/debian-security
ntp='0.hk.pool.ntp.org 1.hk.pool.ntp.org 2.hk.pool.ntp.org 3.hk.pool.ntp.org'
}
setUS(){
mirror=http://ftp.us.debian.org/debian/
security=http://security.debian.org/debian-security
ntp='0.us.pool.ntp.org 1.us.pool.ntp.org 2.us.pool.ntp.org 3.us.pool.ntp.org'
}
setALI(){
mirror=http://mirrors.aliyun.com/debian/
security=http://mirrors.aliyun.com/debian-security/ # must .../debian-security/
ntp='0.cn.pool.ntp.org 1.cn.pool.ntp.org 2.cn.pool.ntp.org 3.cn.pool.ntp.org'
}
setAWS(){
mirror=http://cdn-aws.deb.debian.org/debian/
security=http://security.debian.org/debian-security
ntp='0.amazon.pool.ntp.org 1.amazon.pool.ntp.org 2.amazon.pool.ntp.org 3.amazon.pool.ntp.org'
}
getArguments(){
for i in $ARGS; do
case $i in
--fqdn=?*|fqdn=?*)
eval ${i#--}
;;
--port=?*|port=?*)
eval ${i#--}
;;
--user=?*|user=?*)
eval ${i#--}
;;
--passwd=?*|passwd=?*)
eval ${i#--}
;;
--keyPasswd=?*|keyPasswd=?*)
eval ${i#--}
;;
--source=?*|source=?*)
eval ${i#--}
{ [[ $source = cn || $source = CN ]] && setCN; } || \
{ [[ $source = hk || $source = HK ]] && setHK; } || \
{ [[ $source = us || $source = US ]] && setUS; } || \
{ [[ $source = ali || $source = ALI ]] && setALI; } || \
{ [[ $source = aws || $source = AWS ]] && setAWS; }
;;
--tz=?*|tz=?*)
eval ${i#--}
;;
--help|help)
usage
exit 0
;;
*)
usage
exit 3
;;
esac
done
if [[ -z $user ]] && ( [[ -z $passwd ]] && [[ -z $keyPasswd ]] ); then # 不传入用户名参数,不创建用户
createuser=false
elif [[ -z $user ]] && ( [[ -n $passwd ]] || [[ -n $keyPasswd ]] ); then # 只传入密码参数无用户名参数,返回脚本用法并退出
usage; exit 4
fi
}
setDefaultVariables(){
#full_domain="${fqdn:-www.example.com}"
full_domain="${fqdn}"
my_hostname=${full_domain%%.*}
my_ip=`hostname -I | awk '{print $1}'`
checkPort=`awk '/^Port/{print $2}' /etc/ssh/sshd_config`
current_port="${checkPort:-22}"
#ssh_port="${port:-$current_port}"
ssh_port="${port}"
#new_user="${user:-example}"
new_user="${user}"
password16="${passwd:-`tr -dc '[:alnum:]' < /dev/urandom | head -c 16`}"
password8="${keyPasswd:-`tr -dc '[:digit:][:lower:]' < /dev/urandom | head -c 8`}"
#debian_mirror="${mirror:-http://mirrors.ustc.edu.cn/debian/}"
#debian_security="${security:-http://mirrors.ustc.edu.cn/debian-security}"
#ntp_servers="${ntp:-0.cn.pool.ntp.org 1.cn.pool.ntp.org 2.cn.pool.ntp.org 3.cn.pool.ntp.org}"
debian_mirror="${mirror}"
debian_security="${security}"
ntp_servers="${ntp}"
#time_zone="${tz:-Asia/Shanghai}"
time_zone="${tz}"
}
setGlobalVariables(){
_fqdn="${full_domain}"
_hostname=${my_hostname}
_ip=${my_ip}
_currentport="${current_port}"
_sshport="${ssh_port}"
_user="${new_user}"
_password="${password16}"
_passwd_key="${password8}"
_source="${debian_mirror}"
_source_security="${debian_security}"
_ntp="${ntp_servers}"
_tz="${time_zone}"
}
updateOS(){
if [[ -n $_source ]]; then
if [[ ! -f /etc/apt/sources.list.origin ]]; then cp /etc/apt/sources.list{,.origin}; fi
cat > /etc/apt/sources.list <<- EOF
deb $_source buster main
deb-src $_source buster main
deb $_source_security buster/updates main
deb-src $_source_security buster/updates main
deb $_source buster-updates main
deb-src $_source buster-updates main
EOF
sed -ri 's/^#?(NTP=).*$/\1'"$_ntp"'/' /etc/systemd/timesyncd.conf # 直接替换,懒得各种判断
systemctl restart systemd-timesyncd
fi
apt-get update && apt-get -y upgrade
apt-get -y install man sudo vim net-tools
}
setHostname(){
if [[ -n $_hostname ]]; then
hostname $_hostname
echo $_hostname > /etc/hostname
if ! grep -q "$_ip $_fqdn $_hostname" /etc/hosts; then
echo "$_ip $_fqdn $_hostname" >> /etc/hosts
fi
fi
}
setProfile(){
if [[ ! -f /etc/profile.d/myProfile.sh ]]; then
tee /etc/profile.d/myProfile.sh <<- EOF
export HISTFILESIZE=20000
export HISTTIMEFORMAT="%F %T"
export HISTCONTROL="ignoreboth"
alias ls='ls --color=auto'
alias ll='ls -l --color=auto'
alias lt='ls -alt --color=auto'
alias grep='grep --color=auto'
alias cp='cp -i'
alias mv='mv -i'
alias rm='rm -i'
umask 022
export TMOUT=3600
EOF
fi
}
setTimezone(){
if [[ -n $_tz ]]; then
timedatectl set-timezone $_tz
#sed -ri 's/^#+(NTP=).*$/\1'"$_ntp"'/' /etc/systemd/timesyncd.conf
#systemctl restart systemd-timesyncd
fi
}
createUser(){
if [[ ! $createuser = false ]]; then
if ! id -u $_user &> /dev/null; then
iscreate=true
useradd -m $_user -s /bin/bash
eval chpasswd <<< "$_user:$_password"
usermod -aG sudo $_user
if [[ ! -f /etc/sudoers.d/nopasswd ]]; then
echo -e '%sudo\tALL=(ALL:ALL) NOPASSWD: ALL' > /etc/sudoers.d/nopasswd
fi
mkdir /home/$_user/.ssh
chown $_user:$_user /home/$_user/.ssh
chmod 700 /home/$_user/.ssh
su - $_user -c "ssh-keygen -qf /home/$_user/.ssh/id_rsa.$_user -t rsa -N $_passwd_key"
cat /home/$_user/.ssh/id_rsa.$_user.pub > /home/$_user/.ssh/authorized_keys
chown $_user:$_user /home/$_user/.ssh/authorized_keys
chmod 600 /home/$_user/.ssh/authorized_keys
else
iscreate=false
echo -en "\033[33m[Warning] \033[0m"
echo "User: $_user exist!"
fi
else
iscreate=false
fi
}
setSSH(){
if [[ ! -f /etc/ssh/sshd_config.origin ]]; then cp /etc/ssh/sshd_config{,.origin}; fi
if grep -Eq '^PermitRootLogin (yes|no)$' /etc/ssh/sshd_config; then
sed -ri -e 's/^(PermitRootLogin )yes$/\1no/' /etc/ssh/sshd_config
else
echo 'PermitRootLogin no' >> /etc/ssh/sshd_config
fi
if grep -Eq '^PasswordAuthentication (yes|no)$' /etc/ssh/sshd_config; then
sed -ri -e 's/^(PasswordAuthentication )yes$/\1no/' /etc/ssh/sshd_config
else
echo 'PasswordAuthentication no' >> /etc/ssh/sshd_config
fi
if [[ -n $_sshport ]]; then # 如果指定ssh端口
if [[ ! $_sshport = $_currentport ]]; then # 如果端口不一致
if grep -q '^Port [0-9]\+' /etc/ssh/sshd_config; then # 如果配置文件有指定Port
sed -ri 's/^Port [0-9]+/Port '"$_sshport"'/' /etc/ssh/sshd_config
else # 如果配置文件没有指定Port,比如默认22端口的情况
echo "Port $_sshport" >> /etc/ssh/sshd_config
fi
fi
fi
systemctl reload ssh
}
setIptables(){
echo 'iptables-persistent iptables-persistent/autosave_v4 boolean true' | debconf-set-selections
echo 'iptables-persistent iptables-persistent/autosave_v6 boolean false' | debconf-set-selections
apt-get -y install iptables-persistent
if ! iptables -C INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT &> /dev/null; then iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT; fi
if ! iptables -C INPUT -i lo -j ACCEPT &> /dev/null; then iptables -A INPUT -i lo -j ACCEPT; fi
if ! iptables -C INPUT -p icmp -m state --state NEW --icmp-type echo-request -j ACCEPT &> /dev/null; then iptables -A INPUT -p icmp -m state --state NEW --icmp-type echo-request -j ACCEPT; fi
if [[ -n $_sshport ]]; then # 如果指定ssh端口
if [[ ! $_sshport = $_currentport ]]; then # 如果端口不一致,删除当前规则,添加新规则
if iptables -C INPUT -p tcp -m state --state NEW -m tcp --dport "$_currentport" -j ACCEPT &> /dev/null; then iptables -D INPUT -p tcp -m state --state NEW -m tcp --dport "$_currentport" -j ACCEPT; fi
if ! iptables -C INPUT -p tcp -m state --state NEW -m tcp --dport "$_sshport" -j ACCEPT &> /dev/null; then iptables -A INPUT -p tcp -m state --state NEW -m tcp --dport "$_sshport" -j ACCEPT; fi
else # 如果端口一致,检测是否有防火墙规则,无则添加
if ! iptables -C INPUT -p tcp -m state --state NEW -m tcp --dport "$_currentport" -j ACCEPT &> /dev/null; then iptables -A INPUT -p tcp -m state --state NEW -m tcp --dport "$_currentport" -j ACCEPT; fi
fi
else # 如果不指定ssh端口,检测是否有防火墙规则,无则添加
if ! iptables -C INPUT -p tcp -m state --state NEW -m tcp --dport "$_currentport" -j ACCEPT &> /dev/null; then iptables -A INPUT -p tcp -m state --state NEW -m tcp --dport "$_currentport" -j ACCEPT; fi
fi
if ! iptables -C INPUT -p tcp -m state --state NEW -m multiport --dports http,https -j ACCEPT &> /dev/null; then iptables -A INPUT -p tcp -m state --state NEW -m multiport --dports http,https -j ACCEPT; fi
iptables -P INPUT DROP
netfilter-persistent save
if [[ ! -f /etc/iptables/rules.v4.origin ]]; then cp /etc/iptables/rules.v4{,.origin}; fi
#iptables-restore < /etc/iptables/rules.v4.origin # run the script multiple times
}
printInfo(){
runScriptDate=`date`
echo '**************************************** End ****************************************'
echo "Output -> /root/$SCRIPTNAME.log"
if $iscreate; then
cat >> /root/$SCRIPTNAME.log <<- EOF
$runScriptDate
Arguments: $ARGS
------------------------------------------------------------------------------------------
User Name: $_user
User Password: $_password
SSH Port: $_sshport
Private Key(id_rsa.$_user):
$(cat /home/$_user/.ssh/id_rsa.$_user)
Password(id_rsa.$_user): $_passwd_key
FQDN: $_fqdn
Hostname: $_hostname
APT Source: $_source
TimeZone: $_tz
NTP: $_ntp
------------------------------------------------------------------------------------------
EOF
else
cat >> /root/$SCRIPTNAME.log <<- EOF
$runScriptDate
Arguments: $ARGS
------------------------------------------------------------------------------------------
SSH Port: $_sshport
FQDN: $_fqdn
Hostname: $_hostname
APT Source: $_source
TimeZone: $_tz
NTP: $_ntp
------------------------------------------------------------------------------------------
EOF
fi
chmod 400 /root/$SCRIPTNAME.log
str=`sed -n "/^${runScriptDate}$/,$ p" /root/$SCRIPTNAME.log`
echo -e "\033[31m${str}\033[0m"
}
main(){
getArguments
setDefaultVariables
setGlobalVariables
updateOS
setHostname
setProfile
setTimezone
createUser
setSSH
setIptables
printInfo
}
main
|
参考链接
https://www.debian.org/mirror/list
https://www.ntppool.org/zone/@
https://en.wikipedia.org/wiki/Regular_expression 注:需要爱国才可以打开的链接
https://www.wikiwand.com/en/Regular_expression 注:爱国与否都可以打开的链接
https://man7.org/linux/man-pages/man1/bash.1.html
https://www.gnu.org/software/bash/manual/html_node/Pattern-Matching.html