VPS基本部署环境的搭建与配置

6/6/2021 服务器部署泛域名证书运维脚本反向代理Cloudflare CDNGit HooksCrontabNFSSwapOneinStackfrp内网穿透

# 1. VPS及域名的购买和基本配置

# 1.1 VPS的购买及基本配置

# 1.1.1 购买Banwagon VPS

如果是自己玩的话,推荐购买国外VPS,搭网站不用备案,带宽足,价格低廉。国内阿里云、腾讯云、百度云等大厂真是一言难尽,上述国外VPS的优点取反就是国内VPS的缺点,国内VPS看似便宜,磁盘空间也足,但同价位VPS的带宽是MB级的,用起来慢的一批,要想快就要买高配的,算下来价格比国外的还贵,而且没备案的域名不能给国内服务器用。当然如果是商业用途还是老老实实使用国内VPS厂商的吧,延迟会低一些,该备案备案。

推荐老牌大厂Banwagon (opens new window),支持支付宝付款,且新用户购买后1个月内可以退款。购买时建议使用循环优惠码(后续每次续订都会享受折扣),一般每年黑色星期五(相当于国外的双11)会放出来最大力度的优惠码。这里放一个平时的循环优惠码,如果失效了请自行搜索。

循环优惠码:BWH3HYATVBJW(6.58%)
循环优惠码:BWH3OGRI2BMW(5.83%)
循环优惠码:ireallyreadtheterms8(5.5%)
1
2
3

Banwagon

购买后会往你的邮箱里发送:“发票”,“IP、端口号、root密码”,KiWiVM管理面板地址等必要信息。

# 1.1.2 使用KiWiVM面板管理VPS

我们打开管理面板 KiWiVM (opens new window),重置一个KiWiVM密码(邮箱验证),然后输入IP和刚刚重置的KiWiVM密码即可登录。

KiWiVM管理面板

在此点击Install new OS,选择一个合适的系统镜像进行安装,我选择的是Debian 11 x86_64,下文所有的操作命令也都是基于该系统的,如有不同请自行查阅。

VPS搭建并使用科学上网可能会导致被墙,检测方法及解决方式如下:

[1] 搬瓦工官方查询IP是否被墙:登录KiWiVM面板后,将最后的main.php替换成main-exec.php?mode=blacklistcheck,即可打开官方的是否被墙检测页。

搬瓦工检测IP是否被封锁

注:其他IP检测工具 https://www.idcoffer.com/ipcheck (opens new window)http://port.ping.pe (opens new window)

[2] 付费更换IP解决被墙问题:https://www.bwgyhw.cn/go/?url=https://bwh88.net/ipchange.php (8.79美刀每次)

付费更换IP解决被墙问题

注:如果是自用,就没必要付费换IP了,可以添加代理访问服务器,被墙之后一般过几个月就会自行放出来(如果不想被墙,就不要使用自己服务器搭建的科学上网服务,尤其是在两会、国庆等敏感时期)

# 1.1.3 通过KiWiVM管理面板进行数据迁移

俩服务器之间可以直接通过镜像同步,无需把镜像下载到本地再上传,以下方法仅适用于两台VPS都是Banwagon的。

  • 旧服务器:Snapshots——Export——复制VEID和TOKEN
  • 新服务器:Snapshots——Import Snapshots——粘贴VEID和TOKEN

# 1.2 SSH远程连接VPS

# 1.2.1 使用FinallShell远程连接

然后就可以使用FinallShell、Xshell等工具ssh远程连接到该服务器了,我这里建议使用FinallShell(它包含了Xshell和Xftp的功能,还不用破解),界面如下所示:

FinallShell

名称随便填(有多个服务器的话建议标注上IP以区分),主机填写服务器IP,端口填写服务器端口,用户名填root,密码填root密码。

解决FinallShell退格乱码问题:选项——终端——Backspace退格键选择ASCIl-Backspace,Delete删除键选择ASCll-Delete

# 1.2.2 设置代理访问被墙服务器

如果服务器被墙了(连接时报错:Session.connect xxx Need Username/Password authentication),还可通过添加代理服务器访问(前提是电脑上装有可用的代理工具,如Clash、SSR等)

名称随便填,类型选HTTP,主机填127.0.0.1,端口号一般是1080(端口根据你代理软件的配置来填)

# 1.3 域名的购买与解析

# 1.3.1 购买NameSilo域名

NameSilo (opens new window)是一家国外的知名域名服务注册商,价格便宜而且非常可靠,管理也很方便,支持支付宝付款。这家有很多首年1美刀廉价域名,当然一般都是些不知名的域名(我们所熟知的.com.cn域名一般价格很贵),如果是自己玩的话买个廉价域名就好了。下面放一个优惠1美刀的优惠码(优惠后的实际购买价格不低于1美刀,例如你买了个1.5美刀的域名,使用该优惠码只能优惠至1美刀),如果失效了自行搜索。

idcspy2020(优惠1美刀) 
1

# 1.3.2 NameSilo域名解析

购买完域名之后,首先要做的事儿就是域名解析(说白了就是把域名与你的服务器IP进行绑定)

[1] 打开NameSilo官网 (opens new window),依次完成下图所示的三步操作

NameSilo域名解析1

[2] Type选A,Address/Value处填服务器IP,TTL填3600即可(是指全国各地的DNS服务器中缓存解析结果的时间周期)

NameSilo域名解析2

注:一个二级域名可以绑若干个三级域名;一般十分钟左右 DNS 解析记录会生效(可以直接在cmd里ping域名验证是否解析成功)

# 1.4 目录挂载与硬盘合并

# 1.4.1 使用NFS挂载另一台服务器上的目录

NFS(network file system)网络文件系统工具,通过网络使不同机器或者操作系统之间分享部分文件,用于宿主机和目标机之间的文件共享。使用该方式需要管理员权限,服务端配置好后,客户端不需要认证登录就可以挂载。

测试服务器示例:

文件服务器(被挂载机):192.168.1.100    // 实际存储文件的地方
操作服务器(挂载机):192.168.1.200      // 使用文件的地方(实际不存储在这里)
1
2

Step1:安装 NFS(两台机器都需要安装)并设置开机自启

$ sudo apt-get install nfs-kernel-server -y     // 安装 NFS 服务
$ systemctl status nfs-kernel-server.service    // 查看NFS服务是否启动
$ systemctl enable nfs-kernel-server.service    // 设置NFS主程序开机启动
1
2
3

Step2:在文件服务器(被挂载机)上新建目录,配置权限,配置挂载

$ mkdir -p /nfs_mount/.nfs_do_not_delete && chmod 777 -R /nfs_mount/.nfs_do_not_delete
$ vim /etc/exports       
1
2

编辑需要共享的目录和允许访问的服务器(*为不限制IP,不建议这么做,但如果不想限制IP就把如下配置的192.168.1.200换成*即可)及权限,内容如下:

/nfs_mount/.nfs_do_not_delete 192.168.1.200(rw,sync,no_root_squash)    
1

注:如果服务器的端口大于1024,则还需要加上insecure,如果未加 insecure,下一步挂载时会报错mount.nfs: access denied by server while mounting

/nfs_mount/.nfs_do_not_delete 192.168.1.200(insecure,rw,sync,no_root_squash)  
1

重启文件服务器(被挂载机)NFS服务。

$ sudo /etc/init.d/nfs-kernel-server restart
1

另注:如果挂载后创建文件出现mount.nfs: Read-only file system的错误,是/etc/exports的配置有问题(例如IP与权限的那个括号之间应该没有空格,请查看是不是加了空格导致的)。

Step3:操作服务器(挂载机)新建目录,配置挂载

$ mkdir /storage
$ sudo mount 192.168.1.100:/nfs_mount/.nfs_do_not_delete /storage/
$ mount      // 显示当前系统已经挂载的设备及挂载点
$ cd /storage && touch test.txt  // 创建测试文件,去文件服务器(被挂载机)查看文件是否存在
$ cd /storage && rm -f test.txt  // 删除测试文件
1
2
3
4
5

使用 umount 卸载挂载

 $ sudo umount 192.168.1.100:/nfs_mount/.nfs_do_not_delete /storage
1

注意:如果出现 umount.nfs: XXX: device is busy 错误,可使用以下方式强制卸载挂载

$ sudo fuser –m –v /storage
$ kill -9 [pid]
$ sudo umount –lf 192.168.1.100:/nfs_mount/.nfs_do_not_delete /storage
1
2
3

Step4:设置开机自动挂载

$ vim /etc/rc.local  // 写入如下配置
sudo mount 192.168.1.100:/nfs_mount/.nfs_do_not_delete /storage/
1
2

# 1.4.2 使用LVM合并多个硬盘作为一个目录

需求情景:大模型研究需要大量磁盘资源,而提供的服务器是多个几TB的硬盘,总量还行,但单个的空间都太小了,想要将多块硬盘共同作为根目录。

应用实例:以下例子是朋友发给我的,未亲自尝试。

$ fdisk -l                             //查看分区
$ fdisk /dev/vdb                       //对vdb磁盘进行分区
$ partprobe                            //刷新分区表
$ pvcreate /dev/vdb1                   //建立LVM物理卷
$ vgcreate vg1 /dev/vdb1               //建立卷组vg1
$ lvcreate -L 25599 -n lv0 vg1         //建立逻辑卷lv0
$ lvextend -l +100%FREE /dev/vg1/lv0   //增加逻辑卷lv0容量
$ mkfs -t ext4 /dev/vg1/lv0            //初始化磁盘lv0
$ mount /dev/vg1/lv0 /app/minio/data/  //挂载磁盘lv0到/app/minio/data/
1
2
3
4
5
6
7
8
9

注意事项:需要注意的地方也是朋友发给我的,未亲自尝试。

  • 建议做冗余,防止因为一块硬盘损坏导致整个崩掉。做冗余的话建议raid6,因为5有重建失败风险。
  • 支持SSD与普通硬盘共同使用(但速度可能会慢),但大概率不支持跨机合并使用。
  • LVM对磁盘合并之后,空间大小基本没有多少损耗,即两块1TB磁盘合并后,总空间几乎接近2TB

# 1.5 调整Swap交换分区

# 1.5.1 什么是Swap

Swap:交换分区,就是当内存不足的时候,把一部分硬盘空间虚拟成内存使用,从而解决内存容量不足的情况。

  • 当RAM耗尽时,Linux系统使用部分硬盘内存并将其分配给正在运行的应用程序。
  • 应用程序使用 Swap 交换空间会导致其性能将下降,因为它无法以与RAM中相同的速度访问数据。Swap交换空间只是用来应急的,所以它的分配要适量。

# 1.5.2 Swap的分配原则

Debian/Ubuntu系:

  • 如果RAM小于1GB,Swap空间至少要和RAM一样大,甚至是要为RAM的两倍大小。
  • 如果RAM大于1GB,Swap交换空间应该至少等于RAM大小的平方根,并且最多为RAM大小的两倍。
  • 如果要休眠,Swap交换大小应该等于RAM的大小加上RAM大小的平方根。
RAM大小 Swap大小 激活Swap后合计大小
256MB 256MB 512MB
512MB 512MB 1GB
1GB 1GB 2GB
3GB 2GB 5GB
4GB 2GB 6GB
6GB 2GB 8GB
8GB 3GB 11GB
12GB 3GB 15GB
16GB 4GB 20GB
32GB 6GB 38GB
64GB 8GB 72GB
128GB 11GB 139GB

注:事实上没有一个真正确定的Swap交换空间分配大小,根据实际情况来吧,如果不在乎多点交换空间,可以使用两倍于RAM的这种方案。

# 1.5.3 如何调整Swap空间

通过以下操作可以扩充Swap空间(扩充之后的总Swap空间为原始值+扩充值)

  • Step1:查看Swap分区大小: free -h

  • Step2:创建Swap分区的文件:dd if=/dev/zero of=/root/swapfile bs=1M count=4096

    注:其中 bs是每块的大小,count是块的数量,bs*count就是swap文件的大小了,这里就是1M*4096=4G。根据实际需要自行调整count的数量。此外,/root/swapfile是Swap文件的路径,可以根据需求修改,后续操作的路径要与此对应。

  • Step3:格式化交换分区文件:mkswap /root/swapfile

  • Step4:启用Swap分区文件:swapon /root/swapfile

  • Step5:添加开机启动:修改 /etc/fstab 文件,末尾加/root/swapfile swap swap defaults 0 0

  • Step6:再次查看Swap分区大小: free -h,扩充完毕。

如果需要删除Swap空间:

  • Step1:卸载swap文件:swapoff /root/swapfile
  • Step2:从配置中删除:修改/etc/fstab文件,去掉之前加的那行
  • Step3:删除Swap分区文件:rm -rf /root/swapfile

如果需要调整Swap空间大小:

  • Step1:卸载swap文件:swapoff /root/swapfile
  • Step2:删除Swap分区文件:rm -rf /root/swapfile
  • Step3:重新创建Swap分区文件:dd if=/dev/zero of=/root/swapfile bs=1M count=2048
  • Step4:格式化交换分区文件:mkswap /root/swapfile
  • Step5:启用Swap分区文件:swapon /root/swapfile

# 1.5.4 什么情况才会使用Swap

实际上,并不是等所有的物理内存都消耗完毕之后,才去使用Swap的空间,什么时候使用是由 swappiness 参数值控制的。

$ cat /proc/sys/vm/swappiness
1

CentOS系统的默认值为30,Debian11系统的默认值为60。

  • swappiness=0的时候表示最大限度使用物理内存,然后才是Swap空间,
  • swappiness=100的时候表示积极的使用Swap分区,并且把内存上的数据及时的搬运到Swap空间里面。

建议:生产环境建议把swappiness值调低,优先保证性能。测试环境且内存不足时,可以把swappiness值调高,优先保证应用程序可以运行。

# 1.5.5 修改swappiness参数

临时修改:临时修改swappiness参数值,但重启系统后又会变成系统默认值。

$ sysctl vm.swappiness=10
1

永久修改:永久修改swappiness参数值,重启系统也不会变了。

$ vim /etc/sysctl.conf   // 在该文件里添加如下参数
vm.swappiness=10
$ sysctl -p              // 激活设置
1
2
3

# 2. Linux常用命令

# 2.1 Linux基本命令使用

# 2.1.1 文件目录

ls命令:显示指定文件或指定目录中的所有文件信息
    -l:按长格式显示文件详细信息(可用于查看文件权限)
cd命令:改变当前目录为指定的目录(不指定目录参数时,进入用户的主目录)
mkdir命令:建立目录
    -m 权限:按指定的权限建立目录
    -p:递归建立目录
rmdir命令:删除目录(若目录不空,则删除操作不能成功)
touch命令:修改文件的修改时间和访问时间的时间标签为现在时间(若指定的文件不存在,就建立一个新的空文件)
rm命令:删除文件(可直接删除掉目录内的所有文件)
pwd命令:显示当前目录的绝对路径   $(pwd)代表当前目录,常用于shell脚本编写
tree命令:以树状图列出目录的内容
    -a 显示所有文件和目录
    -C 在文件和目录清单加上色彩,便于区分各种类型
    -p 列出权限标示
find命令:从指定的目录开始向下查找满足条件的文件,对找到的文件执行指定操作
ln命令:为某一个文件或目录在另外一个位置建立一个同步的链接(类似于Win的快捷方式) 
     建立软链接:ln -s a目录 b目录   取消软链接 rm -rf b目录
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

注:/bin存放二进制可执行文件,常用命令一般都在这里。/usr 用于存放系统应用程序。

# 2.1.2 拷贝移动

cp命令:复制文件
    cp [选项] 源文件 目标文件
    cp [选项] 源文件 目标目录
mv命令:移动文件、重命名文件
    mv[选项] 源文件 目标文件  (重命名文件)
    mv[选项] 源文件 目标目录  (移动文件)
1
2
3
4
5
6

# 2.1.3 文件内容

cat命令:显示文件内容 (注:cat /etc/issue 查看Linux系统版本)
nano命令:编辑文件内容  [sudo] nano filename
    - 想要退出,按下Ctrl+X。
    - 如果你退出前没有保存所做的修改,它会提示你是否要保存。不要,请按N,反之,则按Y。
    - 然后它会让你确认要保存的文件名,确认或修改后按Enter即可。
more命令:分屏显示文件内容
grep命令:在文本文件中查找与指定模式相匹配的字符串,显示含有匹配字符串的行
wc命令:显示文件的字节数、字数和行数
sort命令:对文本文件中的各行按字符顺序排序并显示
1
2
3
4
5
6
7
8
9

# 2.1.4 远程管理

ifconfig命令:显示或配置网络设备
ping命令:用于确定网络的连通性                
    ping  主机名      ping  域名      ping  IP地址
ssh命令:用于安全访问远程服务器的网络协议    
    ssh user@host(例:ssh [email protected]
1
2
3
4
5

# 2.1.5 权限管理

chmod命令:修改文件或目录的存取权限
    -R:递归的改变指定目录及其下的文件和子目录的权限属性
umask命令:设置、显示文件创建时的权限掩码
chgrp命令:变更文件或目录的所属群组
useradd命令:建立用户帐号和创建用户的起始目录,使用权限是root
passwd命令:更改使用者的密码
userdel命令:可删除用户帐号与相关的文件
    若不加参数,则仅删除用户帐号,而不删除相关文件
1
2
3
4
5
6
7
8

# 2.1.6 下载安装

wget命令:从网络上下载文件,wget+网址即可。
curl命令:从网络上下载文件
    -o 提供名称,下载文件会以该名称保存
    -O 下载文件以原始名称保存
apt-get命令:自动从互联网的软件仓库中安装、卸载、更新软件或操作系统(Debian&&ubuntu)
    apt-get [选项] install|remove|update pkg1 [pkg2 ...]
yum命令:自动从互联网的软件仓库中安装、卸载、更新软件或操作系统(CentOS)
    yum [选项] install|remove|update pkg1 [pkg2 ...]
1
2
3
4
5
6
7
8

# 2.1.7 压缩解压

对于.tar.xz
- xz格式(最常用,压缩率和压缩速度都较快)
    压缩:tar Jcvf filename.tar.xz some filedirs
    解压:tar Jxvf filename.tar.xz some filedirs
- bz2格式(最不常用,压缩率最高,压缩速度最慢)
    压缩:tar jcvf filename.tar.bz2 some filedirs
    解压:tar jxvf filename.tar.bz2 some filedirs
- gz格式(压缩速度最快,压缩率较低)
    压缩:tar zcvf filename.tar.gz some filedirs
    解压:tar zxvf filename.tar.gz some filedirs  
对于.zip
     压缩:zip -r myfile.zip ./*(需要先切换目录)
     解压:unzip -o -d /mydir myfile.zip  (-o:不提示的情况下覆盖文件,-d指定解压目录)    
对于.7z
    解压:7za x myfile.7z
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

注:使用tar解压文件到指定目录时出现Not found in archive问题,在 filename.tar.gz 后面加个 -C参数即可。

# 2.1.8 磁盘管理

du 命令主要用来查看磁盘空间使用情况。

$ du                                  // 无需加任何参数,默认是KB为单位
$ du Python-3.7.6.tgz                 // du后面直接跟上文件或者文件夹名,显示指定文件所占空间
$ du -h Python-3.7.6.tgz              // 使用-h参数,让结果更便于识别和阅读
$ du -h Python-3.7.6.tgz test.txt     // 查看多个文件所占到空间(想要显示几个文件的,就在后面加几个文件名即可)
$ du -sh /etc/                        // 显示目录总和的大小(使用-s参数只显示总和)
$ du -ah test/                        // 文件和目录的大小都显示,使用-a参数
$ du -a -d 1 /etc/                    // 如果文件和目录深度太深,只想看第一层,可以使用-d或者--max-depth=1参数
$ du -m Python-3.7.6/                 // -m参数是以MB为单位进行输出,不足1MB的按照1MB进行处理。
1
2
3
4
5
6
7
8

du命令语法格式如下:

du命令语法格式

du和df命令的区别:

1)两者都统计范围有所区别

  • df 命令是从总体上统计系统各磁盘的占用情况,不能统计具体的文件夹或文件的大小。
  • du 命令既可以从总体上统计,也可以统计具体的文件夹或文件的大小。

2)计算方式和计算速度有差异

  • df 命令通过文件系统来快速获取文件系统空间大小的信息,相较而言速度快,效率高;
  • du 命令需要逐级进入指定目录去遍历每一个子目录,逐个计算每个文件大小并相加,最终实现效果展示。 计算速度相对来说略慢,如果要统计子文件特别多的目录,计算时间比较长。

3)计算结果的差异

  • df 命令可以获取已经删除文件的占空间的大小。 因为文件删除并不会导致文件立马从文件系统当中消失,有时候会有程序占用,这时候我们用df还是可以统计到的。
  • du 命令不能统计刚刚被删除的文件,只能计算没有被删除,且当前存在的文件。

由此,可以得出一个结论: du命令的统计更精准,但受到权限和速度的限制。df命令不算准确,但好处就是效率高,没有权限限制。

# 2.1.9 系统管理

xrandr命令:调整屏幕分辨率
    xrandr  查看当前屏幕支持的分辨率       
    xrandr -s 1920x1080 修改分辨率
top命令:默认按照CPU的占用情况,显示占用量较大的进程
free命令:显示系统当前内存的使用情况
df命令:显示文件系统的磁盘使用情况(-h选项可以以更符合阅读习惯的方式显示磁盘使用量)
ps命令:查看进程的状态
kill命令:中止进程
reboot命令:重启Linux系统
shutdown命令:关闭Linux系统 
sudo命令:变更用户身份,若不指定此参数,则预设变更为root
备注:可使用“Ctrl+Z快捷键”中止命令的执行
1
2
3
4
5
6
7
8
9
10
11
12

# 2.1.10 其他常用

who命令:显示已登录的用户
echo命令:显示命令行中的参数字符串(如果有空格,用引号将字符串括起来)
date命令:显示、设置系统日期和时间
cal命令:显示月份和日历
man命令:显示联机手册页
exit命令:结束当前的终端会话
history命令:查看命令执行历史
    history [n] 列出最近的n条命令
sleep命令:设置下一条命令执行之前暂停指定的时间 eg:sleep 5m (暂停5分钟后继续执行)
    s - 秒 ,m - 分钟,h - 小时,d - 天
1
2
3
4
5
6
7
8
9
10

# 2.2 Linux常用操作

# 2.2.1 常用命令安装

常用命令的安装

$ apt-get install -y sudo                                     # 安装sudo
$ sudo apt-get update                                         # 更新apt-get
$ apt-get install iputils-ping -y                             # 安装ping
$ apt-get install -y wget                                     # 安装wget
$ apt-get install curl -y                                     # 安装curl
$ apt-get install xz-utils                                    # 安装xz
$ apt-get install p7zip-full                                  # 安装7z
$ apt-get install zip                                         # 安装zip
$ apt-get install tree                                        # 安装tree
$ apt-get install vim -y                                      # 安装vim
$ apt-get install lsof                                        # 安装lsof
$ apt-get install -y psmisc                                   # 安装ps
$ apt-get install screen                                      # 安装screen
1
2
3
4
5
6
7
8
9
10
11
12
13

说明:如果使用 apt-get 出现 404 Not Found 错误,说明用的系统太老了,那个源已经弃用了,可以升级系统或者换源解决。

# 2.2.2 使用Shell脚本

Shell脚本是一个可执行文件,其中包含了多行用于命令行输入的文本,也包含了一些用于控制脚本中各行命令执行顺序的专用命令。

运行shell脚本时,必须启动其他程序来解释该脚本,这个程序在Shell脚本的首行指定。在shell提示符下输入脚本名运行脚本时,shell首先检查脚本文件的首行内容,然后启动该行中指定的解释器。

  • Shell脚本的首行格式:以#作为前缀,后面紧跟一个!,之后是解释器的完整路径。(如:#! /bin/bash
  • 文本文件必须设定执行权限,不然无法运行。(如:chmod ugo+x test.sh
  • 运行该脚本:在命令行输入./(告诉文件在当前目录下),后面紧跟脚本名。(如./test.sh)

基本示例:

[1] Shell脚本接受命令数组传参的示例(./test.sh 1 2 3)

方式一:

#!/bin/bash 
for i in $@  
do  
    echo $i  
done 
1
2
3
4
5

方式二:

#!/bin/bash

echo "执行的文件名:$0";
echo "第一个参数为:$1";
echo "第二个参数为:$2";
echo "第三个参数为:$3";
1
2
3
4
5
6

[2] Shell脚本遍历数组

#!/bin/bash 
array=("1" "2")
for i in ${array[@]}  
do  
    echo $i
done
1
2
3
4
5
6

[3] 打印当前目录

echo "$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
1

[4] 校验文件夹或文件是否存在

# 校验文件夹,不存在则创建
if [ ! -d "/data/" ];then
    mkdir /data
else
    echo "文件夹已经存在"
fi

# 检验文件,不存在则创建
if [ ! -f "/data/filename" ];then
    touch /data/filename
else
    echo "文件已经存在"
fi
1
2
3
4
5
6
7
8
9
10
11
12
13

[5] 遍历目录里的所有文件

#! /bin/bash
function read_dir(){
   for file in `ls $1`       # 注意此处这是两个反引号,表示运行系统命令
   do
       if [ -d $1"/"$file ]  # 注意此处之间一定要加上空格,否则会报错
       then
           read_dir $1"/"$file
       else
           echo $1"/"$file   # 在此处处理文件即可
       fi
   done
}   
# 读取第一个参数
read_dir $1
1
2
3
4
5
6
7
8
9
10
11
12
13
14

执行脚本的时候后面跟上需要遍历的目录路径作为参数即可。

[6] 替换文件内容

# 设置增量更新过滤条件
WHERE="update_time > str_to_date('$MAX_TIME', '%Y-%m-%d %H:%i:%s')"
# 创建改写后的json临时配置文件(把1=1替换成上面的where条件)
sed "s/1=1/$WHERE/g" ${basePath}/job/${i} > ${tempPath}/${i/.json/_temp.json}
1
2
3
4

[7] 数组追加元素

# shell数组没有追加函数可以用,可利用数组的长度${#arr[*]}来追加元素
arr[${#arr[*]}]=追加的元素1
arr[${#arr[*]}]=追加的元素2
1
2
3

[8] 在shell脚本里使用sudo命令

$ echo "your_git_user_password" | sudo -S 命令
1

# 2.2.3 查看及修改系统配置

[1] 查看系统发行版

$ cat /etc/issue             // 适用于ubuntu、debian等系统
$ cat /etc/redhat-release    // 适用于redhat、centos等系统
1
2

[2] 修改系统时间

通过修改时区文件来修改系统时间

$ date -R   // 查看系统时间
$ rm -rf /etc/localtime
$ ln -s /usr/share/zoneinfo/Asia/Shanghai /etc/localtime 
$ date -R
1
2
3
4

[3] 查看系统安装时间

$ stat / | awk '/Birth: /{print $2 " " substr($3,1,5)}'
1

[4] 查看系统用户

$ cat /etc/passwd | head -5 | cut -f1 -d:
1

[5] 查看出厂编号

$ dmidecode -s system-serial-number
1

# 2.2.4 放行指定端口及ufw防火墙

Step1:安装iptables(通常系统都会自带,如果没有就需要安装)

$ apt-get update
$ apt-get install iptables
1
2

Step2:放行指定端口(以8888为例)并保存放行规则。

$ iptables -I INPUT -p tcp --dport 8888 -j ACCEPT
$ iptables-save
1
2

完成上述设置便将端口的放行规则添加到了防火墙中,防火墙的一些其他命令如下:

$ iptables -L              # 查看防火墙规则
$ iptables -D INPUT 3      # 比如删除INPUT链的第3条规则
1
2

Step3:保持规则持续生效

设置完就已经放行了指定的端口,但重启后会失效,下面设置持续生效规则。

$ apt-get install iptables-persistent
$ netfilter-persistent save
$ netfilter-persistent reload
1
2
3

设置完成后指定端口就会持续放行了。

ufw防火墙常用命令

$ sudo ufw enable      // 启动ufw防火墙
$ sudo ufw disable     // 关闭ufw防火墙
$ sudo ufw status      // 查看ufw防火墙状态
$ sudo ufw allow 443   // 允许外部访问443端口
$ sudo ufw deny 443    // 禁止外部访问443端口
1
2
3
4
5

# 2.2.5 Crontab定时任务与设置开机自启

crontab 是 Linux 下的计划任务,当时间达到我们设定的时间时,可以自动触发某些脚本的运行。

Debian系统自带crontab,Ubuntu的话需要自己安装,命令如下:

安装:apt-get install cron
启动:service cron start
重启:service cron restart
停止:service cron stop
1
2
3
4

crontab 相关命令

crontab [-u username]    // 省略用户表表示操作当前用户的crontab
    -e      (修改 crontab 文件,如果文件不存在会自动创建)
    -l      (显示 crontab 文件)
    -r      (删除 crontab 文件)
1
2
3
4

另注CentOS的crontab安装及管理命令:

$ yum install crontabs      // 安装
$ systemctl enable crond    // 设为开机启动
$ systemctl start crond     // 启动crond服务
$ systemctl status crond    // 查看状态
$ crontab -e                // 编辑定时任务
1
2
3
4
5

crontab 定时任务语法:

# For details see man 4 crontabs
# Example of job definition:
# .---------------- minute (0 - 59)
# | .------------- hour (0 - 23)
# | | .---------- day of month (1 - 31)
# | | | .------- month (1 - 12) OR jan,feb,mar,apr ...
# | | | | .---- day of week (0 - 6) (Sunday=0 or 7) OR sun,mon,tue,wed,thu,fri,sat
# | | | | |
# * * * * * user-name command to be executed
定时任务的每段为:分,时,日,月,周,用户,命令
第1列表示分钟1~59 每分钟用*或者 */1表示
第2列表示小时1~23(0表示0点)
第3列表示日期1~31
第4列表示月份1~12
第5列标识号星期0~6(0表示星期天)
第6列要运行的命令

*:表示任意时间都,实际上就是“每”的意思。可以代表00-23小时或者00-12每月或者00-59分
-:表示区间,是一个范围,00 17-19 * * * cmd,就是每天17,18,19点的整点执行命令
,:是分割时段,30 3,19,21 * * * cmd,就是每天凌晨3和晚上19,21点的半点时刻执行命令
/n:表示分割,可以看成除法,*/5 * * * * cmd,每隔五分钟执行一次
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

crontab定时任务实例:

实例1:每分钟执行一次myCommand
* * * * * myCommand
实例2:每小时的第3和第15分钟执行
3,15 * * * * myCommand
实例3:在上午8点到11点的第3和第15分钟执行
3,15 8-11 * * * myCommand
实例4:每隔两天的上午8点到11点的第3和第15分钟执行
3,15 8-11 */2  *  * myCommand
实例5:每周一上午8点到11点的第3和第15分钟执行
3,15 8-11 * * 1 myCommand
实例6:每晚的21:30重启smb
30 21 * * * /etc/init.d/smb restart
实例7:每月1、10、22日的4 : 45重启smb
45 4 1,10,22 * * /etc/init.d/smb restart
实例8:每周六、周日的1 : 10重启smb
10 1 * * 6,0 /etc/init.d/smb restart
实例9:每天18 : 00至23 : 00之间每隔30分钟重启smb
0,30 18-23 * * * /etc/init.d/smb restart
实例10:每星期六的晚上11 : 00 pm重启smb
0 23 * * 6 /etc/init.d/smb restart
实例11:每一小时重启smb
* */1 * * * /etc/init.d/smb restart
实例12:晚上11点到早上7点之间,每隔一小时重启smb
* 23-7/1 * * * /etc/init.d/smb restart
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

Crontab 中有个特殊的任务,叫作 @reboot ,这个任务就是在系统重启之后自动运行某个脚本。

要设置开机自启,首先在任意目录创建一个shell脚本然后赋予执行权限,然后输入crontab -e在里面配置上对应的@reboot任务即可。

$ crontab -e
@reboot /myshell/auto_run_script.sh
1
2

Crontab定时任务不执行问题

问题描述:在CentOS Linux release 7.9.2009 (Core)系统的服务器上,配置好了定时任务,但定时任务没有执行,排查了任务配置、运行状态、运行日志均未发现异常,重启Crontab也仍旧不执行。(另注:在Docker里的Debian GNU/Linux 11系统也出现了该问题,该系统来自于“FROM python:3.9”基础镜像,但宿主服务器系统也是CentOS。在Debian GNU/Linux 11的服务器无该问题)

Crontab定时任务未执行问题

解决方案:是任务配置处出了问题,把它改写成 cd /home/mysql_data_backup && ./test.sh即可正常执行。太玄学了,可能是有的服务器系统环境不支持直接绝对路径脚本的写法吧,以后Crontab定时任务还是统一写成cd /dir_path && ./script.sh的形式吧。

# 2.2.6 jar包部署执行

Springboot项目的部署流程(用IDEA的Maven插件将其打成jar包——将jar上传到服务器——写个运行脚本并开机自启——域名解析、反向代理、HTTPS)

$ java -jar xxx.jar        // 运行jar包
$ nohup java -jar xxx.jar  // 后台运行jar包
$ ps aux|grep xxx.jar      // 查看指定jar的进程
$ kill -9 进程号            // 杀死指定jar进程
1
2
3
4

注:正式部署建议加上时区参数,如东8区-Duser.timezone=GMT+8,不设置的话会导致日志记录时间异常(即便修改了系统之间也没用--date命令显示的时间是对的),可能会影响问题排查及项目使用。服务器部署jar包的完整示例命令如下:

$ nohup java -jar -Duser.timezone=GMT+8 xxx.jar > xxx.log 2>&1 &
1

注意事项:

  • nohup加在一个命令的最前面,表示不挂断的运行命令。
  • 2>&1的意思是将标准错误(2)也定向到标准输出(1)的输出文件。
  • &加在一个命令的最后面,表示这个命令放在后台执行。

# 2.2.7 文件及目录操作

[1] 查看目录结构

$ apt-get install tree  // 安装tree命令(Debian、Ubuntu系统)
$ yum -y install tree  // 安装tree命令(CentOS系统)
$ tree -L 2    // 显示当前目录的目录结构,限制目录层级为2     
1
2
3

[2] 统计文件及文件夹个数

$ ls -l | grep "^-" | wc -l   // 统计当前目录下文件的个数(不包括子目录)
$ ls -lR| grep "^-" | wc -l   // 统计当前目录下文件的个数(包括子目录)
$ ls -lR | grep "^d" | wc -l  // 查看某目录下文件夹的个数(包括子目录)
1
2
3

[3] 查找文件及目录

$ find . -type d -name "tra*"  // 根据名称查找目录
$ find /shell -type f -name '*.sh'|xargs grep 'ufw'  // 根据字符串的信息查找文件
1
2

[4] 拷贝同步大量文件

rsync 是一个常用的 Linux 应用程序,用于文件同步。它可以在本地计算机与远程计算机之间,或者两个本地目录之间同步文件(但不支持两台远程计算机之间的同步)。它也可以当作文件复制工具,替代cp和mv命令。

$ sudo apt-get install rsync
$ rsync -a /olddir /newdir
1
2

[5] 远程文件拷贝

$ scp -P port /root/file.txt root@ip:/root/file.txt   // 远程拷贝文件
$ scp -r -P port /root/dir root@ip:/root/             // 远程拷贝目录
1
2

注:port是目标服务器的端口号(如果两台服务器的端口号相同,可省略该参数),root@ip是目标服务器的用户和ip。以上命令在发送方输入,之后会提示输入接收方的服务器连接密码。

[6] 递归删除某目录下指定扩展名的文件

在删除文件之前,建议先预览文件列表(如果文件列表很长,至少部分预览):

$ find path/to/files -type f -regextype posix-extended -iregex '.*\.(avi|mkv|wmv|mp4)$'
1

上面的命令将显示要删除的文件列表。若要实际删除文件,只需在末尾添加-delete

$ find path/to/files -type f -regextype posix-extended -iregex '.*\.(avi|mkv|wmv|mp4)$' -delete
1

如果您想要查看剩余的内容,可以加个!逆匹配输出

$ find path/to/files -type f -regextype posix-extended ! -iregex '.*\.(avi|mkv|wmv|mp4)$'
1

解释说明:

  • -type f将匹配限制为仅文件(目录不会被匹配),把它放在开头而不是结尾,因为谓词的顺序对速度很重要。
  • -iregex表示不区分大小写,如果要区分的话选择-regex
  • 尽量使用 find xxx -delete来删除文件,它比 rm 命令执行速度更快且更安全。

[7] 生成图片的base64字符串写入文件

$ base64 base64_gegerate_test.png > base64.txt
1

[8] 生成指定位数的随机密钥

$ openssl rand -hex 32
1

# 2.2.8 查询CPU详细参数

总核数 = 物理CPU个数 X 每颗物理CPU的核数

总逻辑CPU数 = 物理CPU个数 X 每颗物理CPU的核数 X 超线程数

$ cat /proc/cpuinfo                                            // 查询CPU型号(完整)
$ cat /proc/cpuinfo | grep name | cut -f2 -d: | uniq -c        // 查看CPU型号(简略)
$ cat /proc/cpuinfo| grep "physical id"| sort| uniq| wc -l     // 查看物理CPU个数
$ cat /proc/cpuinfo| grep "cpu cores"| uniq                    // 查看每个物理CPU中core的个数(即核数)
$ cat /proc/cpuinfo| grep "processor"| wc -l                   // 查看逻辑CPU的个数
$ cat /proc/cpuinfo | grep -e "cpu cores" -e "siblings" | sort | uniq  //超线程,分别输出cpu cores和siblings数量,使用超线程则后者翻倍
1
2
3
4
5
6

# 2.2.9 磁盘空间及系统资源占用分析

[1] 磁盘空间占用分析

$ df -hl                      // 查看磁盘剩余空间
$ du -s /* | sort -nr         // 查看哪个目录占用空间大
$ du -h --max-depth=1         // 查看当前目录下文件夹大小情况
$ du -h                       // 输出各个子目录及文件的大小
$ du -sh                      // 只输出一个总和大小
$ sudo find / -size +100M     // 列出所有大于100M的文件
$ rm -rf /var/log/*           // 删除所有log文件
$ cat /dev/null > file.log    // 清空指定日志文件
$ sudo apt-get clean          // 清理apt-get缓存
$ sudo rm -rf /tmp/*          // 删除/tmp目录下的临时文件
$ pip3 cache purge            // 删除pip3的缓存文件
$ rm -rf ~/.cache/huggingface // 删除huggingface缓存 
1
2
3
4
5
6
7
8
9
10
11
12

注:分析及清理服务器磁盘空间个人最常用的命令

$ find / -size +100M          // 列出所有大于100M的文件
$ du -h --max-depth=1         // 查看当前目录下文件夹大小情况(从根目录一级一级往下找)
$ docker system df            // 类似于Linux上的df命令,用于查看Docker的磁盘使用情况
$ docker ps --size            // 查看docker容器占用的磁盘空间
$ docker system prune         // 可用于清理磁盘,删除关闭的容器、无用的数据卷和网络,以及无tag的镜像
$ docker system prune -a      // 清理得更加彻底,除了上述内容之外,还可以将没有容器使用Docker镜像都删掉。
1
2
3
4
5
6

批量清空Docker容器日志 clear_docker_log.sh:

#!/bin/sh 

echo "======== start clean docker containers logs ========"  

logs=$(find /var/lib/docker/containers/ -name *-json.log)  

for log in $logs  
        do  
                echo "clean logs : $log"  
                cat /dev/null > $log  
        done  

echo "======== end clean docker containers logs ========"  
1
2
3
4
5
6
7
8
9
10
11
12
13

[2] 系统资源占用分析

// 查看内存占用
$ free -h  // 查看内存占用情况
$ free -m  // 查看剩余内存

// 1.CPU占用最多的前10个进程
$ ps auxw|head -1;ps auxw|sort -rn -k3|head -10 

// 2.内存消耗最多的前10个进程 
$ ps auxw|head -1;ps auxw|sort -rn -k4|head -10 

// 3.虚拟内存使用最多的前10个进程 
$ ps auxw|head -1;ps auxw|sort -rn -k5|head -10
1
2
3
4
5
6
7
8
9
10
11
12

[3] 监控进程状态

$ ps -aux | grep 进程号
1

[4] 查看进程的调用位置

$ pwdx 进程号 // 查看进程的调用位置(命令1)
$ sudo ls -l /proc/进程号/cwd  // 查看进程的调用位置(命令2)
1
2

[5] kill指定端口号的进程

$ lsof -i:端口号
$ kill -9 进程号  
1
2

[6] 批量kill进程

$ kill -s 9 $(lsof -i:端口号 -t)    // 把某端口号下的所有进程全部kill
$ killall -9 进程名                 // 把某进程名的所有进程全部kill
1
2

注意:如果会模糊匹配到不想kill的进程,尽量不要用killall命令去关闭。

[7] 根据程序路径kill进程

$ ps aux | grep /root/test.sh | grep -v grep | awk '{print $2}' | xargs kill -9
1

注:grep -v grep 排除掉grep自身的进程,awk '{print $2}'打印出第二行的内容,xargs kill -9杀死进程

[8] 查看指定行数的nohup.out日志

$ tail -fn 100 nohup.out
1

[9] 清理指定时间前的指定类型文件

// 清理7天前的pdf文件
$ find /root/tmp -name "*.pdf" -type f -mtime +7 -exec rm -rf {} \; > /dev/null 2>&1
// 清理1分钟前的pdf文件
$ find /root/tmp -name "*.pdf" -type f -mmin +1 -exec rm -rf {} \; > /dev/null 2>&1
1
2
3
4

# 2.2.10 进程被kill的问题排查

OOM killer:Linux内核Out-Of-Memory killer机制是一种防止内存耗尽影响系统运行而采用的一种自我保护机制。根据内核源码oom_kill.c中的定义,系统会依据“进程占用的内存”,“进程运行的时间”,“进程的优先级”,“是否为 root 用户进程“,”子进程个数和占用内存“,”用户控制参数oom_adj ”等计算一个oom_score值,分数越高就越会被内核优先杀掉。

查看被kill的所有进程:

$ dmesg | grep -i -B100 'killed process'      
1

查看kill日志

$ egrep -i 'killed process' /var/log/syslog 
1

含义说明:

  • total-vm:进程总共使用的虚拟内存;
  • anon-rss:虚拟内存实际占用的物理内存;
  • file-rss:虚拟内存实际占用的磁盘空间;

# 2.2.11 解决IP无法ping通的问题

检查内核参数 icmp_echo_ignore_all

$ cat /proc/sys/net/ipv4/icmp_echo_ignore_all
1

若返回结果为0,表示系统允许所有的 ICMP Echo 请求,请检查防火墙设置。

若返回结果为1,表示系统禁止所有的 ICMP Echo 请求,执行如下命令即可解决:

$ echo "0" >/proc/sys/net/ipv4/icmp_echo_ignore_all
1

另注:可分别通过如下命令查询本机IP地址

$ ip a  |grep inet |grep -v inet6 |grep -v '127.0.0.1' |awk '{print $2}' |awk -F / '{print$1}'
$ curl ip.sb
1
2

# 2.2.12 Shell脚本实现进度条

#/bin/bash
 
progress_bar=''          
for i in {0..100..2}
do
    printf "process:[%-50s]%d%%\r" $progress_bar $i
    sleep 0.2
    progress_bar=#${progress_bar}
done
echo ""
1
2
3
4
5
6
7
8
9
10

含义说明:

  • 先定义process_bar为空,后依次加#,递增
  • 0到100之间,每次递增2,所以进度条使用%-50s来显示,其中-代表左对齐。50是字符串宽度
  • %d来显示进度条的i,%%则代表百分号
  • \r回车
  • sleep 0.2每次间隔0.2秒
  • echo "" 起到换行作用

执行效果:

process:[##################################################]100%
1

# 2.2.13 重命名中文乱码文件

情景描述:往服务器上传了一批文件,目录里存在中文,出现乱码,且常规的重命名命令无效。

解决办法:

Step1:切换到当前目录下
Step2:在当前目录执行 ls -il 获取文件或文件夹的inum编号(即第一列)
Step3:使用find ./ -inum <第2步查到的inum号> -exec mv {} ./<重新命名的文件或文件夹> \;
1
2
3

# 2.2.14 文本文件局部查看及删除内容

适用情景:GB、TB级的超大文本格式数据文件,编辑器无法打开完整文件,需要对其局部内容查看及局部内容删除。

局部查看文件内容

$ cat filename | tail -n 10                  // 显示文件最后10行
$ cat filename | head -n 10                  // 显示文件前面10行
$ cat filename | tail -n +10                 // 从10行开始显示,显示10行以后的所有行
$ cat filename | head -n 50 | tail -n +10    // 显示10行到50行
$ cat filename1 filename2 | grep xxx         // 在filename1 和 filename2中查找xxx关键字
$ cat aaaa*.log | grep xxx                   // 模糊匹配aaaa开头的文件并在这些文件中查找xxx关键字
$ cat aaaa*.log | grep xxx -c                // 模糊匹配aaaa开头的文件并在这些文件中查找xxx关键字统计出现次数
$ grep 'xxxx' app.log                        // app.log中查找xxx(文本)
$ grep 'xxxx' -r dir                         // dir文件目录中递归(-r)查找xxx(文本)
1
2
3
4
5
6
7
8
9

局部删除文件内容

$ sed -i 'Nd' filename                 // 删除第N行
$ sed -i 'M,Nd' filename               // 删除第M到N行
$ sed -e '/abc/d'  a.txt               // 删除a.txt中含"abc"的行,但不改变a.txt文件本身,操作之后的结果在终端显示
$ sed -e '/abc/d'  a.txt  > a.log      // 删除a.txt中含"abc"的行,将操作之后的结果保存到a.log
$ sed '/abc/d;/efg/d' a.txt > a.log    // 删除含字符串"abc"或“efg"的行,将结果保存到a.log
1
2
3
4
5

# 2.2.15 查找Nginx配置文件的路径

需求情景:旧项目的维护部署,但不知道项目的Nginx配置文件路径。

查找命令:ps -aux|grep nginx

常见位置:/usr/local/nginx/conf/vhost/etc/nginx/conf.d

# 2.2.16 Shell脚本实现耗时统计

#!/bin/bash

startTime=`date +"%Y-%m-%d %H:%M:%S"`
startTime_s=`date +%s`

echo "===开始执行:$startTime"

echo "当前任务的执行进程如下:"
ps aux | grep $$
echo "若要提前终止本任务,执行以下命令即可:"
echo "kill -9 $$"

sleep 30m

endTime=`date +"%Y-%m-%d %H:%M:%S"`
endTime_s=`date +%s`

sumTime=$[ $endTime_s - $startTime_s ]

echo "===结束执行:$endTime,总耗时:$sumTime秒"
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

注:$$符号用于获取Shell脚本自身的PID

# 2.2.17 查看是否开启CPU虚拟化

Step1:首先输入以下命令查看是否支持CPU虚拟化

$ cat /proc/cpuinfo |grep vmx    // vmx - Intel的虚拟化技术Intel-VT
$ cat /proc/cpuinfo |grep svm    // svm - Secure virtual machine, AMD的虚拟化技术AMD-V
1
2

如果有输出,则说明CPU支持虚拟化技术。

Step2:然后执行如下命令查看是否开启CPU虚拟化

$ lsmod |grep kvm

kvm_intel             376832  0
kvm                  1011712  1 kvm_intel
1
2
3
4

如果输出结果里有kvm_intel,则说明已开启CPU虚拟化;如果没有kvm_intel,则说明未开启CPU虚拟化。

如果没有开启的话,需要进入BIOS然后在CPU相关的配置项中进行开启,然后启动后再查看。

Step3:查看是否开启KVM嵌套虚拟化

$ modinfo kvm_intel | grep nested

parm:           nested_early_check:bool
parm:           nested:bool

$ cat /sys/module/kvm_intel/parameters/nested

Y
1
2
3
4
5
6
7
8

如果上面的结果显示是Y,则说明已开启KVM嵌套虚拟化;如果不是Y,则需要手动开启嵌套虚拟化。

# 2.2.18 在Linux使用Wine运行exe

Wine是一款免费开源的软件,可以在Linux系统上模拟Windows环境,能够运行大部分Windows程序,这里以 ffmpeg.exe 为例。

$ apt-get install wine
$ dpkg --add-architecture i386 && apt-get update && apt-get install wine32
$ winecfg
$ wine --version
$ wine ffmpeg.exe -i input.mp4
1
2
3
4
5

在Linux使用Wine运行exe

将该命令放置到 Python 脚本中,也是同样可以使用的。

import os

f = os.popen("wine ffmpeg.exe -i input.mp4")  
print(f.read())       
1
2
3
4

# 2.2.19 通过SSH创建SOCKS5代理

需求情景:单位用的国内服务器无法直接访问 Hugging Face 等境外网站,自己手里有境外服务器可以作为代理。

探索过程:尝试过搭建Tinyproxy、Squid等工具,但 HTTPS 一直没代理访问成功,之后发现客户端可以直接通过 SSH 创建 SOCKS5 代理来应对此问题。

$ ssh -D 1080 -C -N -q -f -p 服务器端口号 服务器用户名@服务器IP       // 需要输入服务器密码  
$ curl -x socks5h://localhost:1080 https://www.google.com        // 测试代理服务
$ export http_proxy=socks5h://localhost:1080 https_proxy=socks5h://localhost:1080   // 配置代理服务
1
2
3

# 2.2.20 监测CPU资源占用

可以使用如下命令查询CPU占用:

$ top -bn1 | grep "Cpu(s)" | awk '{print $2}' | awk -F. '{print $1"%"}'
1

如下是一个CPU监控脚本,定时查询CPU占用,可以对其稍加改造,当CPU占用达到指定阈值时,进行某种操作,防止资源被占满。

#!/bin/bash

# 默认CPU使用率的阈值
THRESHOLD=80

# 默认检查间隔时间(秒)
INTERVAL=60

# 默认日志文件路径
LOG_FILE="./cpu_usage.log"

# 从命令行读取检查间隔、日志文件路径和CPU阈值(如果提供)
while getopts "i:l:t:" opt; do
    case $opt in
        i) INTERVAL=$OPTARG ;;
        l) LOG_FILE=$OPTARG ;;
        t) THRESHOLD=$OPTARG ;;
        *) echo "用法: $0 [-i 检查间隔(秒)] [-l 日志文件路径] [-t CPU使用率阈值]" >&2
           exit 1 ;;
    esac
done

# 检查CPU使用率的函数
check_cpu_usage() {
    # 获取CPU使用率,仅保留整数部分
    cpu_usage=$(top -bn1 | grep "Cpu(s)" | awk '{print $2}' | awk -F. '{print $1}')
    
    # 比较当前CPU使用率与阈值
    if [ "$cpu_usage" -ge "$THRESHOLD" ]; then
        echo "$(date): 警告:CPU使用率超过阈值,当前使用率为:$cpu_usage%" | tee -a "$LOG_FILE"
    else
        echo "$(date): CPU使用率正常,当前使用率为:$cpu_usage%" | tee -a "$LOG_FILE"
    fi
}

# 主循环,每隔一段时间检查一次CPU使用率
while true; do
    check_cpu_usage
    sleep $INTERVAL
done
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

使用方式:

// 添加权限
$ chmod +x cpu_usage.sh
// 前台运行
$ ./cpu_usage.sh -i 60 -t 90 -l ./cpu_usage.log
// 后台运行
$ nohup ./cpu_usage.sh -i 60 -t 90 -l ./cpu_usage.log > /dev/null 2>&1 &
// 关闭脚本
$ ps aux | grep cpu_usage.sh
$ kill -9 [PID]
1
2
3
4
5
6
7
8
9

# 2.2.21 列出后台任务并终止进程

需求情景:部署了大模型服务,使用 Ctrl+Z 组合键将进程放入后台并停止执行。为了彻底终止这个进程,并释放其占用的GPU资源。

Step1:列出后台任务

使用jobs命令列出当前shell会话中所有的后台任务,这将会显示所有后台任务的列表,每个任务前都有一个编号。

$ jobs
1

Step2:终止后台进程

可以使用kill命令加上%任务编号来强制终止一个特定的后台任务。如果任务编号是3,应该执行:

$ kill -9 %3
1

# 2.2.22 强制停止指定端口的所有进程

需求情景:某端口下有大量进程,一个个输入进程PID来进行kill太麻烦,可通过以下命令一键kill该端口下的所有进程。

$ lsof -ti :8000 | xargs kill -9
1

# 2.2.23 使用screen在后台启动服务

安装screen命令

$ apt-get install screen   // Debian/Ubuntu
$ yum install screen  // CentOS/RedHat
1
2

查看screen帮助

$ screen -help
1

screen基本使用

$ screen -ls                                  // 查看screen后台任务列表
$ screen -S 后台任务名 -dm bash -c '启动命令'    // 使用screen创建后台任务
$ screen -r 后台任务名                          // 查看screen后台任务的日志(Ctrl+A+D分离,退出查看服务不中断)
$ screen -r 后台任务名 -X quit                  // 关闭screen后台任务
1
2
3
4

# 2.2.24 创建指定大小的占位文件

通过如下命令能够创建指定大小的占位文件,可用于一些情形的测试。

$ dd if=/dev/zero of=/root/20G_file bs=1G count=20
1

说明:bs=1G表示每一次读写1G数据,count=20表示读写20次,这样就指定了生成文件的大小为20G。

# 2.2.25 通过cat命令写入文件

适用情景:需要创建或覆盖某文件,但没有安装基础的vi、vim、nano等终端文本编辑器(如Docker容器内的阉割版Linux系统、涉密不可联网的环境等),可以通过cat命令来写入,开头和结尾加上EOF即可。

$ cat > /etc/nginx/conf.d/nginx_balance.conf << EOF
upstream nginx_balance {
 server 127.0.0.1:1701 weight=1 max_fails=1 fail_timeout=10s;
 server 127.0.0.1:1702 weight=1 max_fails=1 fail_timeout=10s;
 server 127.0.0.1:1703 weight=1 max_fails=1 fail_timeout=10s;
}

server {
 listen 8000;
 server_name 127.0.0.1;
 location ~* ^(/) {
 gzip on;
 gzip_vary on;
 gzip_min_length 1k;
 gzip_buffers 16 16k;
 gzip_http_version 1.1;
 gzip_comp_level 9;
 gzip_types text/plain application/javascript application/x-javascript text/css 
text/xml text/javascript application/json;
 proxy_pass http://nginx_balance;
 client_max_body_size 48m;
 include proxy.conf;
 }
}
EOF
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

# 2.2.26 占用某端口测试网络联通性

需求情景:有些服务器的端口放行要通过管理面板和服务器防火墙两步放行,在还没部署应用之前,可以通过以下方式占用端口,之后再用 telnet 命令验证运维人员是否把应用端口真正放行了。

$ apt-get install socat
$ socat TCP-LISTEN:8000,fork EXEC:/bin/cat
1
2

# 2.2.27 根据进程PID查询程序路径

$ systemctl status [PID]                   // 方式一
$ ps -aux | grep [PID] | grep root         // 方式二
1
2

注:可结合lsof命令,通过指定端口找到相应的程序路径和用户。

# 2.2.28 篡改文件的修改时间元数据

需求情景:文件进行了特殊处理,但不想让别人知道改过,跟其他文件的时间保持一致,可通过以下命令修改文件的修改时间元数据。

$ touch -a -m -t 202407112317 model-00004-of-00004.safetensors
1

# 2.2.29 批量删除指定的终端历史记录

// 禁用历史记录
$ set +o history
// 删除指定id的历史记录,示例为删掉4-8
$ for i in {4..8}; do history -d 4; done   
// 恢复历史记录
$ set -o history
1
2
3
4
5
6

# 2.3 原生部署开发环境

常用开发环境的版本号查询:

$ java -v
$ javac -v
$ mvn --version
$ python3 -v
$ pip3 -V
$ nginx -v
$ mysql -V
$ redis-server -v
$ nodejs --version
$ npm --version
$ go version
$ docker version
$ docker-compose --version
$ git version
$ curl -XGET localhost:9200
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# 2.3.1 安装jdk与maven环境

以下分别介绍Open JDK 11、Open JDK 8、Oracle JDK8的安装及配置过程,Maven的配置与JDK的配置有关

jdk11(Open JDK 11)

$ sudo apt-get update
$ sudo apt-get install default-jdk
1
2

jdk8(Open JDK 8)

目前 Java OpenJDK 8 在官方 Debian Buster 存储库中不可用,我们需要使用第三方源 AdoptOpenJDK (opens new window) 进行安装。

$ sudo apt-get update
$ sudo apt install apt-transport-https ca-certificates wget dirmngr gnupg software-properties-common
$ wget -qO - https://adoptopenjdk.jfrog.io/adoptopenjdk/api/gpg/key/public | sudo apt-key add -
$ sudo add-apt-repository --yes https://adoptopenjdk.jfrog.io/adoptopenjdk/deb/
$ sudo apt update
$ sudo apt install adoptopenjdk-8-hotspot
1
2
3
4
5
6

安装完成后使用如下命令验证:

$ java -version
$ javac -version
1
2

如果需要卸载,可使用如下命令:

$ sudo apt remove default-jdk                // 卸载jdk11
$ sudo apt remove adoptopenjdk-8-hotspot     // 卸载jdk8
1
2

注:jdk8的安装路径为/usr/lib/jvm/adoptopenjdk-8-hotspot-amd64

jdk8(Oracle JDK8)

Oracle官网 (opens new window) 或者 第三方网站 (opens new window) 下载JDK安装包,将其与安装脚本放置到同一个目录下,授予脚本可执行权限然后执行脚本即可。

例如:jdk-8u202-linux-x64.tar.gz

$ wget https://mirrors.huaweicloud.com/java/jdk/8u202-b08/jdk-8u202-linux-x64.tar.gz
1

install_jdk.sh

#!/bin/bash

# 请将下载的jdk-xxx-linux-xxx.tar.gz包与此脚本放置到同一目录
# 授予此脚本可执行权限(chmod +x install_jdk.sh)
# 安装完毕后,如果测试命令不好使,再次执行 source /etc/profile 命令即可。

# 检查jvmpath路径
jvmpath=/usr/lib/jvm/

if [ ! -d "$jvmpath" ]; then
	echo "正在创建$jvmpath目录"
	mkdir $jvmpath
	echo "目录$jvmpath创建成功"
fi

jdkfile=$(ls | grep jdk-*-linux-*.tar.gz)


if [ -f "$jdkfile" ]; then

	# 解压jdk安装包
	tar -zxvf $jdkfile -C $jvmpath
	echo "解压JDK成功"

	# 配置环境变量
	echo "配置环境变量"
	jdkdirname=$(ls $jvmpath) 
  cp /etc/profile /etc/profile.bak
	echo "JAVA_HOME=$jvmpath/$jdkdirname" >> /etc/profile
	echo "JRE_HOME=\${JAVA_HOME}/jre" >> /etc/profile
	echo "CLASSPATH=.:\${JAVA_HOME}/lib:\${JRE_HOME}/lib" >> /etc/profile
	echo "PATH=\$PATH:\${JAVA_HOME}/bin:\${JRE_HOME}/bin" >> /etc/profile
	source /etc/profile
	echo "配置环境成功"

	# 检查是否配置成功
	echo "测试是否安装成功"
	java -version
	javac -version

fi
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

另附:CentOS7系统安装openjdk8

$ yum search java | grep jdk                               // 查看java版本库
$ yum install java-1.8.0-openjdk java-1.8.0-openjdk-devel  // 安装java8
$ ll /usr/lib/jvm                                          // 查看安装位置
$ vi /etc/profile                                          // 设置环境变量(在末尾加上如下内容,JAVA_HOME换成自己的)

#set java environment
JAVA_HOME=/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.322.b06-1.el7_9.x86_64
JRE_HOME=$JAVA_HOME/jre
CLASS_PATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar:$JRE_HOME/lib
PATH=$PATH:$JAVA_HOME/bin:$JRE_HOME/bin
export JAVA_HOME JRE_HOME CLASS_PATH PATH

$ source /etc/profile                                     // 刷新配置,使其生效
$ java -version
$ javac -version

如果出现 Error downloading packages: fribidi-1.0.2-1.el7_7.1.x86_64: [Errno 256] No more mirrors to try. 错误,输入如下命令再重试。
$ yum --enablerepo=base clean metadata
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

Maven(3.8.4)

Step1:下载Maven

$ cd /opt
$ wget https://dlcdn.apache.org/maven/maven-3/3.8.4/binaries/apache-maven-3.8.4-bin.tar.gz
$ tar -zxvf apache-maven-3.8.4-bin.tar.gz
$ rm -f apache-maven-3.8.4-bin.tar.gz
1
2
3
4

附:可以去 https://maven.apache.org/download.cgi (opens new window) 找所需要的版本。

Step2:配置环境变量

$ vim /etc/profile.d/maven.sh
1

配置信息如下:

export JAVA_HOME=/usr/lib/jvm/adoptopenjdk-8-hotspot-amd64
export M2_HOME=/opt/apache-maven-3.8.4
export PATH=${M2_HOME}/bin:${PATH}
1
2
3

使用source命令重新加载环境变量

$ source /etc/profile.d/maven.sh
1

检查maven的版本:

$ mvn --version
1

Step3:配置maven的settings文件

$ mkdir /opt/apache-maven-3.8.4/repository
$ vim /opt/apache-maven-3.8.4/conf/settings.xml
1
2

配置好localRepository的路径

<localRepository>/opt/apache-maven-3.8.4/repository</localRepository>
1

配置好镜像源地址

<mirror>
      <id>alimaven</id>
      <name>aliyun maven</name>
       <url>http://maven.aliyun.com/nexus/content/groups/public/</url>
      <mirrorOf>central</mirrorOf>
</mirror>
1
2
3
4
5
6

# 2.3.2 安装python与conda环境

[1] 将Python升级为3.x

Debian10 预装的 python 是 2.7.16 版本,而现在很多新软件都是用 python3 编写的,有一些甚至已经不支持 Python2 了,这时候就会报一大堆错,因此建议升级到 Python3.x 版本。

Step1:下载Python3.x

$ wget https://www.python.org/ftp/python/3.7.6/Python-3.7.6.tgz
$ tar -zxvf Python-3.7.6.tgz
1
2

Step2:安装配置

$ cd Python-3.7.6/
$ ./configure
1
2

注:如果执行./configure时报错no acceptable C compiler found in $PATH,安装一下gcc库即可。

Step3:编译安装

$ make
$ make install
1
2

注:如果执行make install时报错can't decompress data; zlib not available,则需要先安装以下依赖。

// Ubuntu/Debian系统
$ sudo apt-get install -y make build-essential libssl-dev zlib1g-dev libbz2-dev libreadline-dev libsqlite3-dev wget curl llvm libncurses5-dev libncursesw5-dev xz-utils tk-dev libffi-dev liblzma-dev python-openssl

// Fedora/CentOS系统
$ sudo yum install zlib-devel bzip2 bzip2-devel readline-devel sqlite sqlite-devel openssl-devel xz xz-devel libffi-devel
1
2
3
4
5

Step4:验证是否安装成功

$ python -V
Python 2.7.16
$ python3 -V
Python 3.7.6
1
2
3
4

一个是旧版本 2.x,另外一个是新版本 3.x

另注:如果运行代码时遇到 missing python bz2 module 错误,则需要安装 libbz2-dev 库,再重新编译 Python 环境。

$ sudo apt-get install libbz2-dev
$ cd Python-3.7.6/
$ ./configure
$ make
$ make install
1
2
3
4
5

Step5:设置 3.x 为默认版本

查看 Python 的路径,在 /usr/bin 下面。可以看到 python 链接的是 python 2.7,所以,执行 python 就相当于执行 python 2.7。

将原来 python 的软链接重命名:

$ mv /usr/bin/python /usr/bin/python.bak
1

将 python 链接至 python3:

$ ln -s /usr/local/bin/python3 /usr/bin/python
1

查看 python 版本:

$ python -V
Python 3.7.6
1
2

[2] 安装conda与pip环境

Conda 是一个开源的软件包管理系统和环境管理系统,用于安装多个版本的软件包及其依赖关系,并在它们之间轻松切换。 Conda 是为 Python 程序创建的,适用于 Linux,OS X 和Windows,也可以打包和分发其他软件。

$ curl -O https://repo.anaconda.com/archive/Anaconda3-2019.03-Linux-x86_64.sh   // 从官网下载安装脚本
$ bash Anaconda3-2019.03-Linux-x86_64.sh   // 阅读协议确认安装,安装完成后再输入yes以便不需要手动将Anaconda添加到PATH
$ conda create -n conda_env python=3.8     // 安装虚拟环境,conda_env是给虚拟环境起的别名(任意即可)
$ conda activate conda_env                 // 激活虚拟环境
$ conda deactivate                         // 关闭虚拟环境
$ conda config --set auto_activate_base false  // 取消每次启动自动激活conda的基础环境(base)
$ conda info --envs                        // 查询所有虚拟环境
$ conda remove -n conda_env --all          // 删除虚拟环境
1
2
3
4
5
6
7
8

pip是一个软件包管理系统,可让您安装Python软件包。使用pip,您可以从[Python软件包索引(PyPI)和其他存储库中安装软件包。

Step1:更新软件包列表

$ sudo apt update
1

Step2:安装pip

$ sudo apt install python3-pip
1

注:如果你的python版本是2.x的话,这里的命令换成sudo apt install python-pip

Step3:查看pip3版本

$ pip3 --version
1

Step4:将 pip 链接至 pip3:

$ ln -s /usr/local/bin/pip3 /usr/bin/pip
1

Step5:查看pip版本

$ pip --version
1

# 2.3.3 安装nvm、node.js、npm、yarn环境

使用nvm可以管理多个版本的Node.js,方便随时切换。

$ curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.1/install.sh | bash
$ source ~/.bashrc
$ nvm --version
1
2
3

Node.js是跨平台JavaScript的运行环境,旨在在服务器端执行JavaScript代码。npm是Node.js的默认软件包管理器,可帮助开发人员共享和重用其代码。Yarn是新的 JS 包管理工具 ,为了弥补 npm 的一些缺陷而出现的。

Yarn 包在 Yarn 存储库中可用。运行以下命令以导入存储库的 GPG 密钥并启用 APT 存储库:

$ curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add -
$ echo "deb https://dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/sources.list.d/yarn.list
1
2

之后使用如下命令安装上述环境:

$ sudo apt update
$ sudo apt install nodejs npm yarn
1
2

安装后,可用以下命令进行验证:

$ nodejs --version
$ npm --version
$ yarn --version
1
2
3

# 2.3.4 安装mysql环境

授予脚本可执行权限然后执行脚本即可。

install_mysql.sh

#!/bin/bash

# 下载deb安装包
wget https://dev.mysql.com/get/Downloads/MySQL-5.7/mysql-server_5.7.31-1ubuntu18.04_amd64.deb-bundle.tar
# 新建目录
mkdir mysql5.7.31
mv mysql-server_5.7.31-1ubuntu18.04_amd64.deb-bundle.tar ./mysql5.7.31
# 解压
cd mysql5.7.31
sudo tar -vxf mysql-server_5.7.31-1ubuntu18.04_amd64.deb-bundle.tar
# 删除2个测试相关的包
sudo rm -f mysql-testsuite_5.7.31-1ubuntu18.04_amd64.deb
sudo rm -f mysql-community-test_5.7.31-1ubuntu18.04_amd64.deb
# 安装依赖
sudo apt-get install libtinfo5
sudo apt-get install libmecab2
# 使用deb安装
sudo dpkg -i mysql-*.deb
# 启动mysql
sudo service mysql start
# 查看mysql状态
sudo service mysql status
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

常用命令如下:

$ sudo service mysql start       // 启动mysql服务
$ sudo service mysql stop        // 停止mysql服务
$ sudo service mysql restart     // 重启mysql服务
$ sudo service mysql status      // 查看mysql状态
1
2
3
4

# 2.3.5 安装redis环境

授予脚本可执行权限然后执行脚本即可。

install_redis.sh

#!/bin/bash

sudo apt-get update
sudo apt-get install redis-server
redis-server /etc/redis.conf   # 使用配置文件启动,守护进程
1
2
3
4
5

验证是否启动成功

$ redis-cli
127.0.0.1:6379> ping
PONG   // 返回PONG即为启动成功
127.0.0.1:6379> shutdown  // 关闭Redis服务
not connected> ping
Could not connect to Redis at 127.0.0.1:6379: Connection refused   // 服务已经关闭
not connected>
1
2
3
4
5
6
7

Redis默认是没有密码的(仅能本机访问),如果要设置密码,并放行外网访问,请修改/etc/redis/redis.conf的配置,修改后重启Redis服务。

$ vim /etc/redis/redis.conf

# 1.设置访问密码(放开requirepass的注释并将foobared修改成你要的密码,如:123456)
# requirepass foobared
requirepass 123456
# 2.放通外网访问(注释掉redis.conf中的bind)
# bind 127.0.0.1 ::1
 
$ /etc/init.d/redis-server restart    
1
2
3
4
5
6
7
8
9

常用命令如下:

/etc/init.d/redis-server restart    # 重启服务
/etc/init.d/redis-server start      # 启动服务
/etc/init.d/redis-server stop       # 停止服务
1
2
3

另注:如果redis已经在线上系统上应用了,如果想不停机永久设置或修改密码,可通过以下方式实现,两个步骤缺一不可。

  • Step1:修改配置文件里的密码(这里的配置信息重启后才能生效)

    $ vim /etc/redis/redis.conf
    
    # 1.设置访问密码(放开requirepass的注释并将foobared修改成你要的密码,如:123456)
    # requirepass foobared
    requirepass 123456
    # 2.放通外网访问(注释掉redis.conf中的bind)
    # bind 127.0.0.1 ::1
    
    1
    2
    3
    4
    5
    6
    7
  • Step2:用redis-cli修改密码(这里是即时生效,但重启后会失效)

    $ redis-cli
    $ config set requirepass 123456
    
    1
    2

# 2.3.6 安装zookeeper与kafka环境

本机部署单机版Kafka可以参照官方教程:https://kafka.apache.org/quickstart (opens new window)

Step1:从 Kafka官网 (opens new window)下载最新版安装包,并解压

$ wget https://dlcdn.apache.org/kafka/3.3.1/kafka_2.13-3.3.1.tgz
$ tar -xzf kafka_2.13-3.3.1.tgz
$ cd kafka_2.13-3.3.1
1
2
3

Step2:后台启动ZooKeeper服务

$ nohup /root/kafka/kafka_2.13-3.3.1/bin/zookeeper-server-start.sh /root/kafka/kafka_2.13-3.3.1/config/zookeeper.properties 1>/dev/null 2>&1 &
1

注:如果2181端口没被占用,可以使用默认配置启动,当然也可以根据实际情况对 zookeeper.properties 的配置进行修改。

Step3:后台启动Kafka服务

$ nohup /root/kafka/kafka_2.13-3.3.1/bin/kafka-server-start.sh /root/kafka/kafka_2.13-3.3.1/config/server.properties 1>/dev/null 2>&1 &
1

注:如果9092端口没被占用,可以使用默认配置启动,当然也可以根据实际情况对 server.properties 的配置进行修改,性能调优会用到这个。

# 2.3.7 安装nginx环境

授予脚本可执行权限然后执行脚本即可。

install_nginx.sh

#!/bin/bash

## 依赖安装
# 安装gcc g++依赖库
sudo apt-get install build-essential
sudo apt-get install libtool
# 安装pcre依赖库
sudo apt-get update
sudo apt-get install libpcre3 libpcre3-dev
# 安装zlib依赖库
sudo apt-get install zlib1g-dev
# 安装SSL依赖库
sudo apt-get install openssl

## Nginx安装
# 下载安装包
wget http://nginx.org/download/nginx-1.20.1.tar.gz
# 解压
tar -zxvf nginx-1.20.1.tar.gz
# 进入解压目录
cd nginx-1.20.1
# 配置
./configure --prefix=/usr/local/nginx 
# 编译并且安装:
make && make install
# 进入sbin目录启动
cd /usr/local/nginx/sbin
./nginx
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

常用nginx命令:

$ service nginx start
$ nginx -t
$ nginx -s reload
1
2
3

注:如果想要将某个目录的文件暴露出来变成url供前端访问,可通过如下方式

在nginx.conf 里添加一行 include vhost/*.conf;,然后新建 vhost/web_static.conf 配置文件,内容如下:

server {
    listen 18080;
    server_name _;

    location / {
        root /root/web_static;
        autoindex on;
    }
}
1
2
3
4
5
6
7
8
9

# 2.3.8 安装go及bee环境

说明:bee 工具是一个为了协助快速开发 beego 项目而创建的项目,通过 bee 您可以很容易的进行 beego 项目的创建、热编译、开发、测试、和部署。

Step1:安装并配置go开发环境

$ sudo apt update
$ sudo apt install curl
$ curl -O https://dl.google.com/go/go1.19.6.linux-amd64.tar.gz
$ tar xvf go1.19.6.linux-amd64.tar.gz && rm -f go1.19.6.linux-amd64.tar.gz
$ sudo chown -R root:root ./go
$ sudo mv go /usr/local
$ vim ~/.profile
1
2
3
4
5
6
7

在配置文件末尾追加go的环境配置

export GOROOT=/usr/local/go
export GOPATH=$HOME/work
export PATH=$GOPATH/bin:$GOROOT/bin:$PATH
1
2
3

刷新.profile配置文件并验证安装是否成功

$ source ~/.profile
$ go version
1
2

Step2:bee 工具的安装

$ apt-get install git
$ go env -w GO111MODULE=on
$ go get -u github.com/beego/beego/v2
$ go get -u github.com/beego/bee/v2
$ bee version
1
2
3
4
5

说明:这里有个坑,网上给的方案大多是如下命令:

go get github.com/astaxie/beego
go get github.com/beego/bee
1
2

会耗费很长时间且遇到一些错误,无法成功安装,这是由于hcl包同样更新到了v2,所以此路径不再可用。

cannot find package "github.com/hashicorp/hcl/hcl/printer" in any of:
        xxx\src\github.com\hashicorp\hcl\hcl\printer (from $GOROOT)
        xxx\src\github.com\hashicorp\hcl\hcl\printer (from $GOPATH)
1
2
3

# 2.3.9 安装ffmpeg工具

$ vi /etc/apt/sources.list   // 编辑文件,添加如下配置
deb http://www.deb-multimedia.org jessie main

$ sudo apt-get update
$ sudo apt-get install deb-multimedia-keyring
$ sudo apt-get install ffmpeg
1
2
3
4
5
6

# 2.3.10 安装c++环境

$ sudo apt-get install g++
$ sudo apt-get install -y make
1
2

# 2.3.11 安装Munge服务

Munge是认证服务,用于生成和验证证书。应用于大规模的HPC集群中。它允许进程在“具有公用用户和组的”主机组中,对另外一个“本地或者远程的”进程的UID和GID进行身份验证。这些主机构成由共享密钥定义的安全领域。在此领域中的客户端能够在不使用root权限,不保留端口,或其他特定平台下进行创建凭据和验证。简而言之,在集群中,Munge能够实现本地或者远程主机进程的GID和UID验证。

安装munge

$ sudo apt-get update
$ sudo apt-get install munge
1
2

设置正确的权限

$ sudo chown -R munge: /etc/munge /var/log/munge /var/lib/munge
$ sudo chmod 700 /etc/munge /var/log/munge /var/lib/munge
$ sudo chown munge:munge /etc/munge/munge.key
$ sudo chmod 400 /etc/munge/munge.key
1
2
3
4

启动munge服务

$ sudo systemctl enable munge
$ sudo systemctl start munge
1
2

检查munge服务状态

$ sudo systemctl status munge

● munge.service - MUNGE authentication service
     Loaded: loaded (/lib/systemd/system/munge.service; enabled; vendor preset: enabled)
     Active: active (running) since Mon 2023-06-27 21:08:42 CST; 1min 48s ago
       Docs: man:munged(8)
   Main PID: 1003194 (munged)
      Tasks: 4 (limit: 9528)
     Memory: 684.0K
        CPU: 11ms
     CGroup: /system.slice/munge.service
             └─1003194 /usr/sbin/munged

Feb 12 21:08:42 eula systemd[1]: Starting MUNGE authentication service...
Feb 12 21:08:42 eula systemd[1]: Started MUNGE authentication service.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

注:可以通过如下命令进行卸载

// 停止munge服务
$ sudo systemctl stop munge
// 卸载munge
$ sudo apt-get remove --purge munge
// 清理残留文件
$ sudo rm -rf /etc/munge /var/log/munge /var/lib/munge
1
2
3
4
5
6

# 2.4 vim常用操作

# 2.4.1 vim工作模式

vim主要包含普通模式、插入模式、末行模式等三种工作模式。

  • 普通模式:启动vim编辑器后默认进入普通模式,该模式中主要完成如光标移动、字符串查找,以及删除、复制、粘贴文件内容等相关操作。
  • 插入模式:该模式中主要的操作就是录入文件内容,可以对文本文件正文进行修改、或者添加新的内容。处于输入模式时,vim编辑器的最后一行会出现“-- INSERT --”的状态提示信息。按i可进入插入模式。
  • 末行模式:该模式中可以设置vim编辑环境、保存文件、退出编辑器,以及对文件内容进行查找、替换等操作。处于末行模式时,vim编辑器的最后一行会出现冒号“:”提示符。按ESC可进入末行模式。

# 2.4.2 vim常用命令

[1] 移动光标操作

j:向下
20j:向下移动 20 行
k:向上
h:向左
l:向右
0:到行首
^:到行首第一个字符,如果前面有空格的话
$:到行尾
gg:快速到文件头
G:快速到文件尾
50G:跳转到第 50 行
1
2
3
4
5
6
7
8
9
10
11

[2] 复制操作

yy:复制一行
8yy:向下复制8行
yw:复制光标开始的一个单词
y$:复制光标到行尾
yfA:复制光标到第一个大写A中间的内容
y2fA:复制光标到第二个大写A中间的内容
1
2
3
4
5
6

[3] 剪切操作

x:向后剪切一个一个字符,如果是在行尾,则为向前剪切
4x:剪切4个
xp:非行尾交换两个字符,如从bs变成sb
1
2
3

[4] 删除操作

删除的内容会放到剪贴板,按p即可粘贴到其他地方。

dd:删除一行
10dd:删除10行
dw:删除一个单词
df":删除到出现的第一个双引号
d^:删除至行首
1
2
3
4
5

[5] 粘贴操作

p:粘贴复制或剪切的内容
5p:将复制或剪切的内容粘贴5次
1
2

[6] 查找和替换操作

在normal模式下按下 / 即可进入查找模式,输入要查找的字符串并按下回车。 Vim会跳转到第一个匹配。 按下 n 查找下一个,按下 N 查找上一个。

r+<待替换字母>:将游标所在字母替换为指定字母
R+<待替换字母*n>:连续替换,直到按下Esc
cc:替换整行,即删除游标所在行,并进入插入模式
cw:替换一个单词,即删除一个单词,并进入插入模式
1
2
3
4

[7] 全选操作

ggvG:全选(高亮显示)
ggyG:全部复制
ggdG:全部删除
1
2
3

[8] 撤销操作

u:撤销一次操作
U:撤销当前行的所有修改
1
2

[9] 保存操作

wq:保存当前文件并退出
q!:不保存,强制退出
1
2

# 2.5 Linux运维脚本

# 2.5.1 自动重启挂掉的jar包

部署到服务器上的jar包有时会自己挂掉,比如当系统内存占用过高,触发了oom-killer机制,导致进程被kill。我们可以在服务器部署一个监控脚本monitor.sh,定时监测系统情况,当服务挂掉时自动重启,一定程度的保证系统的高可用性。

#!/bin/bash

# 变量
jarName=xxx.jar
timeZone=GMT+8
jarUrl=/myproject/xxx
webUrl=https://xxx.xxx.xxx/
logName=xxx.log

# grep -v grep: 在文档中过滤掉包含有grep字符的行
# awk '{print $2}': 按空格截取第二个
pid=`ps -ef|grep $jarName |grep -v grep| awk '{print $2}'`
# wc -l: jar包进程的数量
num=`ps -ef|grep $jarName |grep -v grep| awk '{print $2}'| wc -l`

MonitorFunction(){
    # 输出文本
    echo "[info]进入监控脚本"`date +'%Y-%m-%d %H:%M:%S'`
    # -eq: 等于
    if [[ $num -eq 0 ]]; then
        echo "[error]进程不存在,重启"`date +'%Y-%m-%d %H:%M:%S'`
        # >> /dev/null : jar包生成日志不打印到此脚本日志中
        java -jar $jarUrl/$jarName >> /dev/null &
    else
        # 获取页面访问状态
        # -m 10: 最多查询10s  --connect-timeout 10:10秒连接超时  -o /dev/null: 屏蔽原有输出信息  -s: silent  -w %{http_code}: 控制额外输出
        code=`curl -s -o /dev/null -m 10 --connect-timeout 10 $webUrl -w %{http_code}`
        # -ne: 不等于
        if [[ $code -ne 200 ]]; then
            echo "[error]页面访问失败,code=$code,重启"`date +'%Y-%m-%d %H:%M:%S'`
            kill -9 $pid
            nohup java -jar -Duser.timezone=GMT+8 $jarUrl/$jarName >> $jarUrl/$logName 2>&1 &
        else
            echo "[info]页面访问成功,code=$code,time="`date +'%Y-%m-%d %H:%M:%S'`
        fi
    fi
}
MonitorFunction
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

注:webUrl应该给出公开访问的地址(比如有登录页面的,应该出登录页的地址而不是首页的地址),不然curl测出来的状态码是302,导致项目没有挂掉也不断地重启。

可以使用如下命令获取目标网址的重定向目标:

$ curl -Ls -w %{url_effective} -o /dev/null https://google.com    // 把url换成你的目标网址,输出的即可作为webUrl
1

然后给脚本设置可执行权限,再执行crontab -e命令,设置定时任务。

*/1 * * * * bash /myshell/monitor.sh >> /myproject/monitor.log
1

说明:每一分钟执行一次并将日志打印在固定文件中,若文件不存在会自动创建。

# 2.5.2 自动重启挂掉的python服务

#! /bin/bash

while true 
do
	monitor=`ps -ef | grep server.py | grep -v grep | wc -l` 
	if [ $monitor -eq 0 ] 
	then
		echo "server.py is not running, restart server.py"
		nohup python server.py > server.log 2>&1 &
	else
		echo "server.py is running"
	fi
	sleep 5
done
1
2
3
4
5
6
7
8
9
10
11
12
13
14

# 2.5.3 jar包运维脚本

可以把springboot项目打包出的jar包通过运维脚本来管理。

脚本1:restart.sh

#!/bin/bash
#这里可替换为你自己的执行程序,其他代码无需更改
APP_NAME=xxl-job-admin-2.1.6.RELEASE.jar

#使用说明,用来提示输入参数
usage() {
    echo "Usage: sh 执行脚本.sh [start|stop|restart|status]"
    exit 1
}

#检查程序是否在运行
is_exist(){
  pid=`ps -ef|grep $APP_NAME|grep -v grep|awk '{print $2}' `
  #如果不存在返回1,存在返回0     
  if [ -z "${pid}" ]; then
   return 1
  else
    return 0
  fi
}

#启动方法
start(){
  is_exist
  if [ $? -eq "0" ]; then
    echo "${APP_NAME} is already running. pid=${pid} ."
  else
    nohup java -jar $APP_NAME > /dev/null 2>&1 &
  fi
}

#停止方法
stop(){
  is_exist
  if [ $? -eq "0" ]; then
    kill -9 $pid
  else
    echo "${APP_NAME} is not running"
  fi  
}

#输出运行状态
status(){
  is_exist
  if [ $? -eq "0" ]; then
    echo "${APP_NAME} is running. Pid is ${pid}"
  else
    echo "${APP_NAME} is NOT running."
  fi
}

#重启
restart(){
  stop
  start
}

#根据输入参数,选择执行对应方法,不输入则执行使用说明
case "$1" in
  "start")
    start
    ;;
  "stop")
    stop
    ;;
  "status")
    status
    ;;
  "restart")
    restart
    ;;
  *)
    usage
    ;;
esac
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

使用方法:给脚本赋予可执行权限,放到jar同一目录下,执行下列命令管理即可。

$ ./restart.sh status
$ ./restart.sh start
$ ./restart.sh stop
$ ./restart.sh restart
1
2
3
4

脚本2:restart.sh

#!/bin/bash

#define default variable
app_path=$(cd `dirname $0`; pwd)
app_log="${app_path}/app.log"
port=8080

if [ -e $app_log ]; then
	touch ${app_log}
fi

#goto directory
cd ${app_path}

#kill app process
lsof -i :${port}|grep -v "PID"|awk '{print "kill -9",$2}'|sh

#clear log
cat /dev/null>${app_log}

#start app
chmod 777 * -R
nohup java -jar *.jar  1>${app_log} &
tail -fn 100 ${app_log}
exit 0
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

# 2.5.4 解压zip文件脚本

#!/bin/bash

#define default variable
base_path=$(cd `dirname $0`; pwd)
app_path="${base_path}/dist"
zip_name="${base_path}/dist.zip"
chmod 777 ${zip_name}
rm -fr ${app_path}
unzip -d ${app_path} ${zip_name}
echo "unzip success!"
1
2
3
4
5
6
7
8
9
10

# 2.5.5 将文件传输到其他服务器

sshpass是为了解决scp命令需要输入密码的问题,只需要在发送方安装,可在线安装也可离线安装。

$ apt-get install sshpass
1

sshpass.sh

#!/bin/sh

# 定义scp参数
source_dir=/root/source/
target_dir=/root/target/
host=目标服务器IP
port=目标服务器端口
username=目标服务器用户名
password=目标服务器密码

# 将本机某目录下的所有文件拷贝到另一台服务器的指定目录
time=$(date "+%Y-%m-%d %H:%M:%S")
echo "===$time task start===" >> scp.log
for filename in $(ls $source_dir)
do
    # 传输文件
    echo "sshpass -p $password scp -P $port $source_dir$filename $username@$host:$target_dir" >> scp.log
    sshpass -p $password scp -r -P $port $source_dir$filename $username@$host:$target_dir
    # 删除文件
    # echo "rm -f $source_dir$filename" >> scp.log
    # rm -f $source_dir$filename
done
echo "===$time task end===" >> scp.log
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

# 2.5.6 根据进程名或PID过滤进程信息

根据进程名过滤进程信息

#! /bin/bash
# Function: 根据输入的程序的名字过滤出所对应的PID,并显示出详细信息,如果有几个PID,则全部显示
read -p "请输入要查询的进程名:" NAME
N=`ps -aux | grep $NAME | grep -v grep | wc -l` ##统计进程总数
if [ $N -le 0 ];then
  echo "该进程名没有运行!"
fi
i=1
while [ $N -gt 0 ]
do
  echo "进程PID: `ps -aux | grep $NAME | grep -v grep | awk 'NR=='$i'{print $0}'| awk '{print $2}'`"
  echo "进程命令:`ps -aux | grep $NAME | grep -v grep | awk 'NR=='$i'{print $0}'| awk '{print $11}'`"
  echo "进程所属用户: `ps -aux | grep $NAME | grep -v grep | awk 'NR=='$i'{print $0}'| awk '{print $1}'`"
  echo "CPU占用率:`ps -aux | grep $NAME | grep -v grep | awk 'NR=='$i'{print $0}'| awk '{print $3}'`%"
  echo "内存占用率:`ps -aux | grep $NAME | grep -v grep | awk 'NR=='$i'{print $0}'| awk '{print $4}'`%"
  echo "进程开始运行的时刻:`ps -aux | grep $NAME | grep -v grep | awk 'NR=='$i'{print $0}'| awk '{print $9}'`"
  echo "进程状态:`ps -aux | grep $NAME | grep -v grep | awk 'NR=='$i'{print $0}'| awk '{print $8}'`"
  echo "进程虚拟内存:`ps -aux | grep $NAME | grep -v grep | awk 'NR=='$i'{print $0}'| awk '{print $5}'`"
  echo "进程共享内存:`ps -aux | grep $NAME | grep -v grep | awk 'NR=='$i'{print $0}'| awk '{print $6}'`"
  echo "***************************************************************"
  let N-- i++
done
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

根据PID过滤进程信息

#! /bin/bash
# Function: 根据用户输入的PID,过滤出该PID所有的信息
read -p "请输入要查询的PID: " P
n=`ps -aux| awk '$2~/^'$P'$/{print $11}'|wc -l`
if [ $n -eq 0 ];then
 echo "该PID不存在!!"
 exit
fi
echo "--------------------------------"
echo "进程PID: $P"
echo "进程命令:`ps -aux| awk '$2~/^'$P'$/{print $11}'`"
echo "进程所属用户: `ps -aux| awk '$2~/^'$P'$/{print $1}'`"
echo "CPU占用率:`ps -aux| awk '$2~/^'$P'$/{print $3}'`%"
echo "内存占用率:`ps -aux| awk '$2~/^'$P'$/{print $4}'`%"
echo "进程开始运行的时刻:`ps -aux| awk '$2~/^'$P'$/{print $9}'`"
echo "进程状态:`ps -aux| awk '$2~/^'$P'$/{print $8}'`"
echo "进程虚拟内存:`ps -aux| awk '$2~/^'$P'$/{print $5}'`"
echo "进程共享内存:`ps -aux| awk '$2~/^'$P'$/{print $6}'`"
echo "--------------------------------"
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

# 2.5.7 将rm命令改为移至垃圾箱

trash.sh 是一个作为 rm 的安全替代脚本,它通过将文件和目录移动到垃圾箱而不是永久删除它们来安全地处理它们,本质上讲 rm 修改成了 mv。

$ wget https://raw.githubusercontent.com/qqAys/trash.sh/main/trash.sh -O ~/trash.sh
$ chmod +x ~/trash.sh
$ echo 'alias rm="~/trash.sh"' >> ~/.bashrc
$ source ~/.bashrc
1
2
3
4

注意事项:

[1] 如果想要清空垃圾箱,执行 rm -c 命令即可,系统将提示您确认清空垃圾箱,并在删除之前显示其内容。

[2] 如果要关闭该功能,执行如下命令即可。

$ sed -i '/alias rm="~\/trash.sh"/d' ~/.bashrc
$ unalias rm
$ source ~/.bashrc
1
2
3

trash.sh

#!/bin/bash

# 垃圾桶
TRASH_DIR=~/.trash

# 如果不存在垃圾桶
if [ ! -d "$TRASH_DIR" ]; then
    mkdir -p "$TRASH_DIR"
fi

# 构建时间
TIMESTAMP=$(date +"%Y-%m-%d_%H-%M-%S")

# 清空垃圾桶
if [ "$1" == "-c" ]; then
    FILE_COUNT=$(find "$TRASH_DIR" -type f | wc -l)
    DIR_COUNT=$(find "$TRASH_DIR" -type d | wc -l)
    TOTAL_SIZE=$(du -sh "$TRASH_DIR" | cut -f1)
    ((DIR_COUNT--))

    echo "Trash:"
    echo "$FILE_COUNT files"
    echo "$DIR_COUNT directories"
    echo "Total size: $TOTAL_SIZE"

    echo -n "Are you sure you want to clear the trash? [Y/N]: "
    read -r CONFIRM
    if [ "$CONFIRM" == "Y" ] || [ "$CONFIRM" == "y" ]; then
        /bin/rm -rf "$TRASH_DIR"/*
        echo "Trash cleared."
    else
        echo "Operation cancelled."
    fi
    exit 0
fi

# 判断非空
if [ "${#@}" -eq 0 ]; then
    echo "No files or directories provided."
    exit 1
fi

# 显示预移动的文件或文件夹
for FILE in "$@"; do
    if [ -e "$FILE" ]; then
        echo "Files and directories to be moved to trash:"
        if [ -d "$FILE" ]; then
            echo "Directory: $FILE"
        else
            echo "File: $FILE"
        fi
    else
        echo "Warning: $FILE does not exist."
        exit 0
    fi
done

# 确认操作
echo -n "Are you sure you want to move the above items to the trash? [Y/N]: "
read -r CONFIRM_MOVE
if [ "$CONFIRM_MOVE" != "Y" ] && [ "$CONFIRM_MOVE" != "y" ]; then
    echo "Operation cancelled."
    exit 0
fi

# 移动每个文件或文件夹到垃圾桶,并加上时间
for FILE in "$@"; do
    if [ -e "$FILE" ]; then
        BASENAME=$(basename "$FILE")
        # 判断文件夹
        if [ -d "$FILE" ]; then
            mv "$FILE" "$TRASH_DIR/$BASENAME-$TIMESTAMP"
            echo "Moved directory $FILE to $TRASH_DIR/$BASENAME-$TIMESTAMP"
        else
            mv "$FILE" "$TRASH_DIR/$BASENAME-$TIMESTAMP"
            echo "Moved file $FILE to $TRASH_DIR/$BASENAME-$TIMESTAMP"
        fi
    else
        echo "Warning: $FILE does not exist."
    fi
done
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

# 3. 科学上网环境的搭建

以下采用一键脚本搭建科学上网环境,虽然足够方便,一般也没有什么问题,但存在一定的隐患,建议运行前先看一下脚本的内容,了解清楚它都对你的服务器做了什么,再去执行。

# 3.1 SSR服务器端搭建

# 3.1.1 ShadowsocksR简介

ShadowsocksR是一个高性能安全的socks5代理,基于和兼容Shadowsocks,帮助用户更加安全访问全球网络。ShadowsocksR简称为SSR,支持复杂协议和混淆,有更强的抗干扰能力。

# 3.1.2 一键脚本搭建SSR服务

$ wget -N --no-check-certificate https://makeai.cn/bash/ssrmu.sh && chmod +x ssrmu.sh && bash ssrmu.sh
1

ssr-server

# 3.2 Trojan-Go服务器端搭建

# 3.2.1 Trojan-Go简介

Trojan是一款新型的代理工具,其特点是代理流量和伪装网站共用服务器的443端口,使代理流量被识别为正常的网站浏览,从而降低被封锁的机率。Trojan-Go则是在Trojan的基础上,经过二次开发,优化了原版的一些功能,额外添加了新的功能,比如Trojan-Go支持多路复用,支持CDN流量中转。

# 3.2.2 一键脚本搭建Trojan-Go服务

$ bash <(curl -sL https://raw.githubusercontent.com/phlinhng/v2ray-tcp-tls-web/master/install.sh) && v2script
1

trojan-go-server

# 4. 版本控制环境搭建

# 4.1 Git环境搭建

# 4.1.1 安装配置Git

Step1:下载安装Git服务器

$ apt-get install git
1

Step2:验证是否安装成功

$ git --version
1

若显示版本信息则说明安装成功。

# 4.1.2 创建用户并赋予权限

Step1:创建git用户

$ adduser git
1

用户名以git为例,根据提示设置密码。

Step2:赋予git用户权限

$ chmod 740 /etc/sudoers
$ nano /etc/sudoers
1
2

root ALL=(ALL:ALL) ALL这一行下面添加git ALL=(ALL:ALL) ALL

# User privilege specification
root    ALL=(ALL:ALL) ALL
git     ALL=(ALL:ALL) ALL
1
2
3

保存退出后,修改回文件权限

$ chmod 440 /etc/sudoers
1

Step3:关闭git用户的shell权限

考虑到安全因素,需要禁止git用户ssh登录服务器,设置后git用户可以通过ssh正常使用git服务,但无法登录shell。

$ nano /etc/passwd
1

将最后一行的bash处改为git-shell

git:x:1001:1001:,,,:/home/git:/bin/bash 改成 git:x:1001:1001:,,,:/home/git:/bin/git-shell
1

# 4.1.3 初始化git仓库并配置SSH

Step1:初始化git仓库

$ cd /home/git                    //切换到git用户目录
$ mkdir repo.git                  //创建仓库目录,以repo.git为例
$ cd repo.git                     //进入仓库目录
$ git init --bare                 //使用--bare参数初始化为裸仓库,这样创建的仓库不包含工作区
1
2
3
4

Step2:查看公钥

打开本地的 git bash,输入以下命令查看公钥(前提是本地已经配好了git环境并完成初始化),复制公钥

$ cat ~/.ssh/id_rsa.pub
1

Step3:配置SSH

$ cd /home/git                   //切换到git用户目录
$ mkdir .ssh                     //创建.ssh目录
$ cd .ssh                        //进入.ssh目录
$ nano authorized_keys           //将本地的公钥复制到authorized_keys文件里
1
2
3
4

Step4:用户组管理

修改/home/git/repo.git目录的用户组权限为git:git

$ sudo chown git:git -R /home/git/repo.git
1

修改后执行下列命令后再查看

$ ls -l /home/git
1

# 4.1.4 本地连接远程仓库

打开本地的git bash,检出仓库并设置记住用户名和密码,然后我们就可以使用git进行版本控制了,git无需手动设置开机自启。

Step1:本地检出仓库

$ git clone ssh://git@ip:port/home/git/repo.git
1

Step2:设置记住用户名和密码

$ git config --global credential.helper store
1

# 4.2 SVN环境搭建

# 4.2.1 安装配置SVN

Step1:下载安装SVN服务器

$ apt-get install subversion
1

Step2:创建仓库,首先创建SVN的根目录 svn,然后再创建一个项目目录(以test为例)

$ mkdir /svn
$ mkdir /svn/test
1
2

Step3:创建新的 svn 仓库

$ svnadmin create /svn/test
1

Step4:启动 svn 服务,并指定 svn 数据存储的根目录

$ svnserve -d -r /svn
1

Step5:放行 svn 所使用的3690端口

放行3690端口(不放行会报错“由于连接方在一段时间后没有正确答复或连接的主机没有反应,连接尝试失败”),然后就可以用 TortoiseSVN 客户端 Checkout 这个项目了,SVN地址为svn://IP/test

# 4.2.2 SVN权限控制

默认的SVN配置是允许匿名访问的,我们可以配置权限使其只能通过用户名密码登录后才能访问。

Step1:编辑配置文件

$ nano /svn/test/conf/svnserve.conf
1

添加以下四行代码(或者把原有配置里对应这四项的#及空格去掉,改成如下配置)

anon-access = none      
auth-access = write     
password-db = passwd    
authz-db = authz    
1
2
3
4

这四行的含义分别是:匿名用户无权限、授权用户可写、使用哪个文件作为账号文件、使用哪个文件作为权限文件。

Step2:添加用户名密码

$ nano /svn/test/conf/passwd
1

在后面添加用户名(以testuser为例)和密码(以testpasswd为例)

[users]
testuser = testpasswd 
1
2

Step3:给用户分配权限

$ nano /svn/test/conf/authz
1

在后面添加如下权限

[/]
testuser = rw     
*=
1
2
3

注:r代表读权限,w代表写权限(如果多个用户就一行一个)

Step4:重启 svn 服务

$ killall svnserve    
$ svnserve -d -r /svn
1
2

重启 svn 服务之后就可以用设置的用户名密码登录了。

# 4.2.3 SVN开机自启

我们可以使用crontab的@reboot任务实现SVN的开机自启。

Step1:创建 启动svn 服务的shell脚本并赋予执行权限

$ mkdir /myshell
$ cd /myshell
$ touch startsvn.sh
$ echo "svnserve -d -r /svn" >> startsvn.sh
$ chmod u+x startsvn.sh
1
2
3
4
5

Step2:将shell脚本添加到 crontab 计划任务里

$ crontab -e
1

然后把如下内容写入,重启即可

@reboot /myshell/startsvn.sh
1

# 5. 网站环境搭建

# 5.1 使用 acme.sh 申请泛域名SSL证书

SSL证书是一种数字证书,用于加密从用户的浏览器发送到Web服务器的数据。 通过这种方式,发送的数据对于使用Wireshark等数据包嗅探器来拦截和窃听您的通信的黑客来说是安全的。

Chrome一直在推动https,所有的http协议网站被标记为不安全,如果再不对网站进行https改造的话,那么可能会对信任度造成一定的影响,所以说对一个面向用户的网站来说,开启https是非常有必要的。

HTTPS证书验证与数据传输

下面将使用acme.sh开源项目申请免费的 Let's Encrypt (opens new window) 泛域名SSL证书。

# 5.1.1 安装 acme.sh 服务

$ curl  https://get.acme.sh | sh
1

acme.sh

普通用户和 root 用户都可以安装使用,安装过程进行了以下几步:

  • [1] 把 acme.sh 安装到你的 root 目录下,并创建 一个 bash 的 alias, 方便你的使用。

  • [2] 自动为你创建 cronjob, 每天 0:00 点自动检测所有的证书, 如果快过期了, 需要更新, 则会自动更新证书。

注:安装过程不会污染已有的系统任何功能和文件,所有的修改都限制在安装目录中。那个socat未安装的问题不用管,那是http验证无Web Server时才需要的。

# 5.1.2 生成SSL泛域名证书

acme.sh 实现了 acme 协议支持的所有验证协议,一般有两种方式验证:http 和 dns 验证。

  • http 验证:http 方式需要在你的网站根目录下放置一个文件,来验证你的域名所有权。
  • dns 验证:dns 方式,在域名上添加一条 txt 解析记录,验证域名所有权。

dns 方式的可以使用域名解析商提供的 API 自动添加 txt 记录完成验证,下面我们将采用这种方法申请Namesilo的泛域名证书。

Step1:打开 https://www.namesilo.com/account/api-manager (opens new window) 去申请 NameSilo API,勾选第2个复选框,点击Generate,即可生成。

申请NameSilo-API

注:务必不要勾选上Generate key for read-only access的哪个复选框,否则会导致Unable to add the DNS record. Error add txt for domain的问题。另外,生成的API只出现一次,如果没记下来只能重置。

Step2:在服务器输入以下命令,实现自动dns验证生成泛域名证书。

$ cd /root/.acme.sh
$ export Namesilo_Key="xxxxxxxxxxxxxxxxxxxxxxxx"
$ ./acme.sh --issue --dns dns_namesilo --dnssleep 1800 -d example.com -d *.example.com
1
2
3

等待1800s即可看到申请下来的SSL证书(NameSilo的验证比较慢,官方文档上写的900s有时不足以验证完)

申请下来的SSL证书

生成文件都放在/root/.acme.sh/example.com/目录下,其中:example.com.key是密钥文件,fullchain.cer是证书文件。

注:如果你的域名不是NameSilo的,上述操作有所不同,具体请参考: https://github.com/acmesh-official/acme.sh/wiki/dnsapi (opens new window)

# 5.1.3 acme.sh的一些其他管理命令

[1] 更新 acme.sh

目前由于 acme 协议和 letsencrypt CA 都在频繁的更新, 因此 acme.sh 也经常更新以保持同步。

$ ./acme.sh --upgrade                          # 升级 acme.sh 到最新版
$ ./acme.sh  --upgrade  --auto-upgrade         # 开启自动升级
$ ./acme.sh --upgrade  --auto-upgrade  0       # 关闭自动更新
$ ./acme.sh --uninstall                        # 卸载acme.sh
1
2
3
4

[2] 管理证书

$ ./acme.sh --list                              # 查看证书列表
$ ./acme.sh remove example.com                  # 删除指定证书
1
2

注:证书/密钥文件未从磁盘中删除,需要自己去删除相应的目录/root/.acme.sh/example.com/

[3] 证书自动续订

安装了 acme.sh 后,它会添加一个自动任务到你服务器的Cron里,每天都会检查你的证书是否快要过期,acme.sh 会自动帮你续签。

$ ./acme.sh --renew -d example.com --force      # 强制续签证书
$ ./acme.sh --remove -d example.com [--ecc]     # 停止续签证书
1
2

[4] 错误排查

如果使用命令出现了错误,可在原有命令的基础上加上--debug排查问题。

# 5.2 使用OneinStack搭建Nginx并进行配置

# 5.2.1 OneinStack简介

项目简介:OneinStack是一套部署开发环境的脚本工具,它的部署方式是纯原生部署,我主要使用里面的Nginx,用来辅助生成配置。

项目地址:https://github.com/oneinstack/oneinstack (opens new window)

# 5.2.2 使用OneinStack搭建Nginx服务

$ wget -c http://mirrors.linuxeye.com/oneinstack-full.tar.gz && tar xzf oneinstack-full.tar.gz && ./oneinstack/install.sh --nginx_option 1
1

注:OneinStack采用编译安装的方式搭建Nginx服务,速度比较慢,请耐心等待,常用的默认目录有:

Nginx安装目录: /usr/local/nginx
Nginx配置目录:/usr/local/nginx/conf
网站数据目录:/data/wwwroot/域名
1
2
3

# 5.2.3 创建网站开启HTTPS

OneinStack 内置了 acme.sh,它会自动帮你申请 SSL 证书。

$ cd ./oneinstack
$ ./vhost.sh
1
2

配置过程的参考示例如下(示例域名为www.demo.com):

#######################################################################
#       OneinStack for CentOS/RedHat 7+ Debian 8+ and Ubuntu 16+      #
#       For more information please visit https://oneinstack.com      #
#######################################################################

What Are You Doing?
        1. Use HTTP Only
        2. Use your own SSL Certificate and Key
        3. Use Let's Encrypt to Create SSL Certificate and Key
        q. Exit
Please input the correct option: 2 【选择2】(使用了Cloudfare CDN的话,可以选择自签名证书)

Please input domain(example: www.example.com): www.demo.com 【输入域名】
domain=www.demo.com

Please input the directory for the domain:www.demo.com :
(Default directory: /data/wwwroot/www.demo.com): 【回车,使用默认配置】
Virtual Host Directory=/data/wwwroot/www.demo.com

Create Virtul Host directory......
set permissions of Virtual Host directory......

Do you want to add more domain name? [y/n]: n  【输入n,不添加其他域名了】

Do you want to redirect all HTTP requests to HTTPS? [y/n]: y  【输入y,强制HTTPS】

You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.

Country Name (2 letter code) [CN]: 【回车】

State or Province Name (full name) [Shanghai]: 【回车】

Locality Name (eg, city) [Shanghai]: 【回车】

Organization Name (eg, company) [Example Inc.]: 【回车】

Organizational Unit Name (eg, section) [IT Dept.]: 【回车】

Do you want to add hotlink protection? [y/n]: n 【输入n,不需要防盗链保护】

Allow Rewrite rule? [y/n]: y 【输入y,允许重写规则】

Please input the rewrite of programme :
wordpress,opencart,magento2,drupal,joomla,codeigniter,laravel
thinkphp,pathinfo,discuz,typecho,ecshop,nextcloud,zblog,whmcs rewrite was exist.
(Default rewrite: other): 【回车】
You choose rewrite=other

Allow Nginx/Tengine/OpenResty access_log? [y/n]: y  【输入y,允许日志记录】
You access log file=/data/wwwlogs/www.demo.com_nginx.log

#######################################################################
#       OneinStack for CentOS/RedHat 7+ Debian 8+ and Ubuntu 16+      #
#       For more information please visit https://oneinstack.com      #
#######################################################################
Your domain:                  www.demo.com
Virtualhost conf:             /usr/local/nginx/conf/vhost/www.demo.com.conf
Directory of:                 /data/wwwroot/www.demo.com
Rewrite rule:                 /usr/local/nginx/conf/rewrite/other.conf
Self-signed SSL Certificate:  /usr/local/nginx/conf/ssl/www.demo.com.crt
SSL Private Key:              /usr/local/nginx/conf/ssl/www.demo.com.key
SSL CSR File:                 /usr/local/nginx/conf/ssl/www.demo.com.csr
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

配置完成后,修改一下配置文件

$ vim /usr/local/nginx/conf/vhost/www.demo.com.conf
1

server模块删除内容:

  location ~ [^/]\.php(/|$) {
    #fastcgi_pass remote_php_ip:9000;
    fastcgi_pass unix:/dev/shm/php-cgi.sock;
    fastcgi_index index.php;
    include fastcgi.conf;
  }

  location /.well-known {
    allow all;
  }
1
2
3
4
5
6
7
8
9
10

server模块新增内容:

location ^~ /.well-known/acme-challenge/ {
  default_type "text/plain";
  allow all;
  root /data/wwwroot/www.demo.com/;  # 把路径换一下
}
1
2
3
4
5

检查并重载Nginx配置

$ nginx -t
$ nginx -s reload
1
2

注:使用nginx -t命令可以检查Nginx配置,若出现如下内容则说明配置正确。

nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /usr/local/nginx/conf/nginx.conf test is successful
1
2

之后把资源文件放置到 /data/wwwroot/www.demo.com 目录即可,打开Chrome浏览器即可访问(如果出现403则需要给这个目录添加一下权限)。

# 5.2.4 配置反向代理

如果需要配置反向代理的话(比如Docker部署的服务),流程同上,只是修改Nginx配置文件处有所不同。

server模块删除内容:

  location ~ [^/]\.php(/|$) {
    #fastcgi_pass remote_php_ip:9000;
    fastcgi_pass unix:/dev/shm/php-cgi.sock;
    fastcgi_index index.php;
    include fastcgi.conf;
  }
  location ~ .*\.(gif|jpg|jpeg|png|bmp|swf|flv|mp4|ico)$ {
    expires 30d;
    access_log off;
  }
  location ~ .*\.(js|css)?$ {
    expires 7d;
    access_log off;
  }
    location /.well-known {
    allow all;
  }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

server模块新增内容:

location / {
  proxy_set_header HOST $host;
  proxy_set_header X-Forwarded-Proto $scheme;
  proxy_set_header X-Real-IP $remote_addr;
  proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  proxy_pass http://demo;  # 与下面 upstream 的名称一致即可
}
location ~ .*\.(gif|jpg|jpeg|png|bmp|swf|flv|mp4|ico)$ {
  proxy_pass http://demo;  # 与下面 upstream 的名称一致即可
  expires 30d;
  access_log off;
}
location ~ .*\.(js|css)?$ {
  proxy_pass http://demo;   # 与下面 upstream 的名称一致即可
  expires 7d;
  access_log off;
}
location ^~ /.well-known/acme-challenge/ {
  default_type "text/plain";
  allow all;
  root /data/wwwroot/www.demo.com/;  # 把路径换一下
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

与server模块同级新增内容:

upstream demo {
  server 127.0.0.1:8888;  # 8888换成自己的反向代理端口号
}
1
2
3

# 5.2.5 给任意Web服务添加账号密码

htpasswd是Apache附带的程序,htpasswd生成包含用户名和密码的文本文件,每行内容格式为“用户名:密码”,用于基本身份认证。

$ apt-get install apache2-utils
$ htpasswd -c /root/.htpasswd your_account_user
1
2

修改Nginx配置,在 location / {} 内添加如下代码片段,可以顺便把域名和https一并配置了。

    auth_basic           "input you user name and password";
    auth_basic_user_file /root/.htpasswd;
1
2

之后重载nginx配置,再次访问就需要密码验证了。

$ nginx -t
$ nginx -s reload
1
2

# 5.3 网站开启CDN服务

# 5.3.1 CDN与Cloudflare是什么

CDN的全称是Content Delivery Network,即内容分发网络。 CDN是构建在现有网络基础之上的智能虚拟网络,依靠部署在各地的边缘服务器,通过中心平台的负载均衡、内容分发、调度等功能模块,使用户就近获取所需内容,降低网络拥塞,提高用户访问响应速度和命中率。CDN的关键技术主要有内容存储和分发技术。

Cloudflare 是一家全球最著名的 CDN 加速服务商,提供了免费和付费的网站加速和保护服务。即使是免费版,也提供了比较全面和强大的功能,非常不错。对于国外访问(或者使用代理)的加速效果十分明显,但对国内访问加速效果十分有限,如果是国内商用的话还是要买国内的CDN服务。

Cloudflare-CDN

通过使用 Cloudflare CDN 服务提供的全球节点,一方面可以提高网站响应速度和性能,节省源站资源;另一方面也可以保护站点抵御攻击,保证网站长期稳定在线。

# 5.3.2 开启Cloudflare CDN服务

Step1:打开 Cloudflare CDN官网 (opens new window)注册账号,登录后点击添加站点(填根域名即可),选择选择 Free 套餐,确认计划。

Step2:这时 Cloudflare 会自动扫描域名已有的 DNS 解析记录,如果扫描到的话,会显示在下面,没有或者显示不正确,则需要我们自己设置。

开启Cloudflare-CDN

Step3:添加成功后会显示在下面,点击 Continue 继续,按说明修改自己的域名服务器为 Cloudflare 给出的地址。

修改域名服务器地址
dawn.ns.cloudflare.com
plato.ns.cloudflare.com
1
2

NameSilo的修改方式是:勾选域名——点击Change Nameservers——删掉原有的名称服务器,添加新的域名服务器。

NameSilo修改域名服务器

注:修改域名服务器后需要一定时间生效,不会立即检测到,需要稍微等待一会儿(可打开cmd输入nslookup 域名进行验证,如有多个IP出现,则证明已生效)。配置了CDN之后再ping域名指向的就不是我们服务器本身的IP地址了,这样对保护我们的服务器也有好处。

Step4:CDN生效后主页的域名处会标注绿色的“有效“二字,这时我们就可以开启CDN的各种服务了,根据自己需求进行配置就好。

Cloudflare-CDN功能

# 5.3.3 重定向次数过多问题

问题描述:域名配置了 Cloudflare CDN 服务,给部署的服务用Nginx配置了反向代理,访问页面却出现重定向次数过多问题。

重定向次数过多问题

问题原因:开启SSL证书后选择灵活SSL,由于灵活的SSL强制通过未加密的HTTP连接到源Web服务器,然而web服务器只能以https的方式进行访问,结果http就被拒之门外了。

解决方法:对于采用cloudflare提供的CDN加速来说,将灵活SSL切换到完全的SSL即可解决问题。

完全的SSL

# 5.3.4 CDN缓存问题

开启了CDN之后,网站的一些静态资源在更新后不会即时刷新,需要等待一段时间。如果你是在调试过程,想要即时看到结果,可以开启开发模式(登录Cloudflare CDN——缓存——配置——打开“开发模式”的按钮)

Cloudflare-CDN的开发模式

注:开启Cloudflare CDN的“开发模式”可以很方便的禁用掉缓存,但该方式仅生效3h,若要永久生效需要设置绕过缓存的规则。

设置规则绕过缓存(Caching——Cache Rules)

Cloudfare-CDN绕过缓存

# 5.3.5 关闭IPv6支持

进入 CloudFlare 后台,在网站配置的“Network”下面,可以看到“IPv6 兼容性”的选项,但是比较坑的一点就是图形界面不让你操作,只能使用API去操作。

IPv6兼容性

我们可以借助 CloudFlare 的 API 来实现关闭 IPv6,首先打开我们的 账户 (opens new window) 获取 API Key。

API密钥

点击Global API Key后面的查看即可。

接下来使用curl命令发送请求即可,我们只需要修改邮箱和密钥处即可。

$ curl -X PATCH "https://api.cloudflare.com/client/v4/zones/023e105f4ecef8ad9ca31a8372d0c353/settings/ipv6" -H "X-Auth-Email: 邮箱" -H "X-Auth-Key: 密钥" -H "Content-Type: application/json" --data '{"value":"off"}'
1

请求成功后,再回到IPv6的界面,发现它已经被成功关闭啦。

# 5.3.6 配置IP黑名单

问题情境:我博客被恶意刷评论了,从发送频率来看是脚本去刷的,会不断产生新的恶意评论,手动批量删除是没用的。

解决方案:由于此次就一个IP在刷恶意评论,因此直接将该IP放入Cloudfare CDN的黑名单了事。

  • Cloudfare CDN——Security——WAF——Custom rules——Create rule——参考如下方式填写规则(若有多个IP可采用列表)

Cloudfare-CDN配置IP拦截规则

设置了IP黑名单之后,成功的解决了此次的问题,可以看到该IP还是在源源不断的进行请求,只不过现在都被拦截掉了。

Cloudfare-CDN将IP放入黑名单

# 5.4 Git Hooks自动部署

# 5.4.1 Git Hooks简介

Git 除了用作版本控制,还有许多高级功能,Git Hooks 就是其中之一。简单来说,Hook 就是在执行某个事件之前或之后进行一些其他额外的操作。Git 支持的非常多的钩子供我们使用,下面以post-receive钩子为例讲解自动部署项目。

在本地修改项目并生成编译后用于部署的文件,使用Git推送到VPS的Git仓库。Git Hooks实际上就是当Git仓库收到最新的push时,将Git仓库接受到的内容复制到VPS上的网站目录内。相当于完成了手动将用于部署的文件复制到VPS网站根目录里的操作。

# 5.4.2 创建网站并更改权限

使用Nginx创建网站,修改网站根目录的用户组权限为git:git

$ sudo chown git:git -R 网站根目录
1

修改后执行下列命令后再查看

$ ls -l 网站根目录
1

# 5.4.3 修改Nginx配置

在Nginx配置文件里注释掉以下代码

    location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$
    {
        expires      30d;
        error_log /dev/null;
        access_log /dev/null;
    }

    location ~ .*\.(js|css)?$
    {
        expires      12h;
        error_log /dev/null;
        access_log /dev/null; 
    }
1
2
3
4
5
6
7
8
9
10
11
12
13

再添加如下代码(按照自己的网站根目录来)

    location ~* ^.+\.(ico|gif|jpg|jpeg|png)$ {
        root 网站根目录;
        access_log   off;
        expires      1d;
    }

    location ~* ^.+\.(css|js|txt|xml|swf|wav)$ {
        root 网站根目录;
        access_log   off;
        expires      10m;
    }

    location / {
        root 网站根目录;
        if (-f $request_filename) {
        rewrite ^/(.*)$  /$1 break;
        }
    }

    location /nginx_status {
        stub_status on;
        access_log off;
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

# 5.4.4 配置Git Hooks

创建post-receive文件

$ cd /home/git/blog.git/hooks     //切换到hooks目录下
$ nano post-receive               //创建post-receive文件并编辑
1
2

编写post-receive文件(以下仅作为参考,根据实际情况来写)

#!/bin/bash
GIT_REPO=/home/git/blog.git
TMP_GIT_CLONE=/tmp/blog
PUBLIC_WWW=网站根目录
rm -rf ${TMP_GIT_CLONE}
git clone $GIT_REPO $TMP_GIT_CLONE
rm -rf ${PUBLIC_WWW}/*
cp -rf ${TMP_GIT_CLONE}/* ${PUBLIC_WWW}
1
2
3
4
5
6
7
8

保存退出后,赋予其执行权限

$ chmod +x post-receive
1

# 5.5 frp内网穿透

# 5.5.1 frp工具简介

frp 是一个专注于内网穿透的高性能的反向代理应用,支持 TCP、UDP、HTTP、HTTPS 等多种协议。可以将内网服务以安全、便捷的方式通过具有公网 IP 节点的中转暴露到公网。

frp 原理:frp 由客户端(frpc)和服务端(frps)组成,服务端部署在有公网 IP 的机器上,客户端部署在需要穿透的内网服务的机器上。用户可以通过访问frps服务端,然后由frp根据请求将数据包路由到对应的内网服务器,从而实现内外网之间的通信需求。

代理类型:在 frp 中一个代理对应一个需要暴露的内网服务。一个客户端支持同时配置多个代理。

类型 描述
tcp 单纯的 TCP 端口映射,服务端会根据不同的端口路由到不同的内网服务。
udp 单纯的 UDP 端口映射,服务端会根据不同的端口路由到不同的内网服务。
http 针对 HTTP 应用定制了一些额外的功能,例如修改 Host Header,增加鉴权。
https 针对 HTTPS 应用定制了一些额外的功能。
stcp 安全的TCP 内网代理,需要在被访问者和访问者的机器上都部署 frpc,不需要在服务端暴露端口。
sudp 安全的 UDP 内网代理,需要在被访问者和访问者的机器上都部署 frpc,不需要在服务端暴露端口。
Xtcp 点对点内网穿透代理,功能同 stcp,但是流量不需要经过服务器中转。
tcpmux 支持服务端 TCP 端口的多路复用,通过同一个端口访问不同的内网服务。

frp 特点:通过在有公网 IP 的节点上部署 frp 服务端,可以轻松地将内网服务穿透到公网,同时提供很多的功能特性,这包括:

  • 代理组间的负载均衡
  • 服务端和客户端 UI 页面
  • 端口复用,多个服务通过同一个服务端端口暴露
  • 高度扩展性的服务端插件系统,方便结合自身需求进行功能扩展
  • 多个原生支持的客户端插件,便于独立使用 frp 客户端完成某些工作
  • 客户端服务端通信支持 TCP、KCP 以及 Websocket 等多种协议
  • 采用 TCP 连接流式复用,在单个连接间承载更多请求,节省连接建立时间

# 5.5.2 服务端与客户端配置

要使用frp内网穿透,要在服务端和客户端都进行配置,通常,服务端是有公网IP的服务器,客户端是内网服务器。

服务端配置:服务端可以使用这个一键脚本进行安装配置,https://github.com/MvsCode/frps-onekey (opens new window)

$ wget https://raw.githubusercontent.com/mvscode/frps-onekey/master/install-frps.sh -O ./install-frps.sh
$ chmod 700 ./install-frps.sh
$ ./install-frps.sh install
1
2
3

所有配置都使用默认的就可以跑起来(公网IP这里我脱敏成了111.111.111.111),实际使用可以按照需求进行配置,安装过程如下:

vhost http port、vhost https port 这里特意不使用默认的 80与443,因为之后可能会再配置 Nginx,这里尽量不去占用它的端口。

  • 另注:Nginx 配置里加上 proxy_set_header Host $proxy_host; 可解决配置域名后出现 Invalid Host header 的问题。
+------------------------------------------------------------+
|   frps for Linux Server, Author Clang ,Mender MvsCode     |
|      A tool to auto-compile & install frps on Linux        |
+------------------------------------------------------------+


Please select frps download url:
[1].gitee
[2].github (default)
Enter your choice (1, 2 or exit. default [github]): 2
-----------------------------------
       Your select: 2    
-----------------------------------
Loading network version for frps, please wait...
frps Latest release file frp_0.51.3_linux_amd64.tar.gz
Loading You Server IP, please wait...
You Server IP:111.111.111.111
————————————————————————————————————————————
     Please input your server setting:
————————————————————————————————————————————

Please input frps bind_port [1-65535](Default Server Port: 5443):
frps bind_port: 5443


Please input frps vhost_http_port [1-65535](Default : 80):
frps vhost_http_port: 81


Please input frps vhost_https_port [1-65535](Default : 443):
frps vhost_https_port: 444


Please input frps dashboard_port [1-65535](Default : 6443):
frps dashboard_port: 6443


Please input frps dashboard_user(Default : admin):
frps dashboard_user: admin


Please input frps dashboard_pwd(Default : dmmSEiiE):
frps dashboard_pwd: dmmSEiiE


Please input frps token(Default : wbWhbDKpjZmlC01s):
frps token: wbWhbDKpjZmlC01s


Please input frps subdomain_host(Default : 111.111.111.111):
frps subdomain_host: 111.111.111.111


Please input frps max_pool_count [1-200]
(Default : 50):
frps max_pool_count: 50

Please select log_level
1: info (default)
2: warn
3: error
4: debug
-------------------------
Enter your choice (1, 2, 3, 4 or exit. default [1]): 
log_level: info


Please input frps log_max_days [1-30]
(Default : 3 day):
frps log_max_days: 3

Please select log_file
1: enable (default)
2: disable
-------------------------
Enter your choice (1, 2 or exit. default [1]): 
log_file: enable

Please select tcp_mux
1: enable (default)
2: disable
-------------------------
Enter your choice (1, 2 or exit. default [1]): 
tcp_mux: true

Please select kcp support
1: enable (default)
2: disable
-------------------------
Enter your choice (1, 2 or exit. default [1]): 
kcp support: true

============== Check your input ==============
You Server IP      : 111.111.111.111
Bind port          : 5443
kcp support        : true
vhost http port    : 81
vhost https port   : 444
Dashboard port     : 6443
Dashboard user     : admin
Dashboard password : dmmSEiiE
token              : wbWhbDKpjZmlC01s
subdomain_host     : 111.111.111.111
tcp_mux            : true
Max Pool count     : 50
Log level          : info
Log max days       : 3
Log file           : enable
================================================

frps status manage : frps {start|stop|restart|status|config|version}
Example:
  start: frps start
   stop: frps stop
restart: frps restart
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

注意事项:开启KCP之后,无论在下载还是延迟上都会有很大的优化,由于支持端口复用,就算环境不支持KCP也不会出错,所以这个选项建议默认开启。

  • KCP是一个快速可靠协议,能以比 TCP浪费10%-20%的带宽的代价,换取平均延迟降低 30%-40%,且最大延迟降低三倍的传输效果。纯算法实现,并不负责底层协议(如UDP)的收发,需要使用者自己定义下层数据的发送方式,以 callback的方式提供给 KCP。连时钟都需要外部传递进来,内部不会有任何一次系统调用。
  • TCP是为流量设计的(每秒内可以传输多少KB的数据),讲究的是充分利用带宽。而 KCP是为流速设计的(单个数据从一端发送到一端需要多少时间),以10%-20%带宽浪费的代价换取了比 TCP快30%-40%的传输速度。
  • 可以简单理解为基于UDP的KCP协议就是在保留UDP高传输速度的同时尽可能地提高了可靠性。

安装目录为/usr/local/frps,除了上面给出的命令之外,还有更新和卸载的命令:

$ ./install-frps.sh update         // 更新
$ ./install-frps.sh uninstall      // 卸载
1
2

使用Chrome浏览器打开http://111.111.111.111:6443地址,账号密码为 admin / dmmSEiiE,可以访问到管理面板。

frp管理面板

客户端配置:客户端从Releases里下载相应系统的版本,修改配置文件启动即可。https://github.com/fatedier/frp/releases/tag/v0.51.3 (opens new window)

$ wget https://github.com/fatedier/frp/releases/download/v0.51.3/frp_0.51.3_linux_amd64.tar.gz
$ tar -xzf frp_0.51.3_linux_amd64.tar.gz
$ cd ./frp_0.51.3_linux_amd64
$ vim frpc.ini
1
2
3
4

假设有个内网的http://127.0.0.1:3000服务需要开内网穿透,客户端配置如下:

[common]
server_addr = 111.111.111.111
server_port = 5443        
token = wbWhbDKpjZmlC01s    

[ssh]
type = tcp
local_ip = 127.0.0.1  
local_port = 3000       
remote_port = 3000   
1
2
3
4
5
6
7
8
9
10

注:server_addr是服务端的公网IP,server_port是服务端绑定的端口地址(与服务端一致),token是与服务端通信的Token(与服务端一致),local_port是内网服务的端口(与实际服务一致),remote_port是外网服务的端口(可以随便配)

配置完成之后,后台启动frp工具的客户端即可。

$ nohup ./frpc -c ./frpc.ini &
1

配置成功之后,使用Chrome浏览器打开http://111.111.111.111:3000地址,就可以访问到原来在内网的服务了。

# 5.5.3 抓包检查数据是否被混淆

在客户端安装抓包工具,由于Debian系统没有图形化界面,这里使用 tshark 代替常用的 wireshark 进行抓包。

$ sudo apt install tshark 
1

根据以上配置,我们的抓包规则为:

ip dst host 111.111.111.111 or tcp port 3000 or udp port 3000
1

捕获数据包:首先确保你已经用合适的过滤条件捕获了数据包

$ sudo tshark -i eth0 -f "ip dst host 111.111.111.111 or tcp port 3000 or udp port 3000"

Running as user "root" and group "root". This could be dangerous.
Capturing on 'eth0'
    1 0.000000000 222.222.222.222 → 111.111.111.111 TCP 66 171805003 [SYN] Seq=0 Win=64240 Len=0 MSS=1460 SACK_PERM=1 WS=128
    2 12.037029685 222.222.222.222 → 111.111.111.111 TLSv1.2 88 Application Data
    3 12.037170596 222.222.222.222 → 111.111.111.111 TLSv1.2 87 Application Data
    4 12.037993845 222.222.222.222 → 111.111.111.111 TCP 54 441585443 [ACK] Seq=68 Ack=35 Win=501 Len=0
    5 12.038056372 222.222.222.222 → 111.111.111.111 TCP 54 441585443 [ACK] Seq=68 Ack=68 Win=501 Len=0
    6 19.710702001 222.222.222.222 → 111.111.111.111 TCP 66 172425003 [SYN] Seq=0 Win=64240 Len=0 MSS=1460 SACK_PERM=1 WS=128
1
2
3
4
5
6
7
8
9
10

查看数据包:使用 -x 选项,你可以在捕获输出中查看数据的十六进制表示。

$ sudo tshark -i eth0 -f "ip dst host 111.111.111.111 or tcp port 3000 or udp port 3001" -x

Running as user "root" and group "root". This could be dangerous.
Capturing on 'eth0'
0000  10 0e 7e a5 5a a1 aa aa 00 18 74 07 08 00 45 00   ..~.Z.....t...E.
0010  00 34 bf a8 40 00 40 06 c7 ff 62 8e 8b 63 68 80   .4..@.@...b..ch.
0020  5c aa 1e 02 13 8b fe e4 a8 67 00 00 00 00 80 02   \........g......
0030  fa f0 b3 42 00 00 02 04 05 b4 01 01 04 02 01 03   ...B............
0040  03 07     
1
2
3
4
5
6
7
8
9

以上可以看到,数据包的协议标识为TLSv1.2,数据包是被加密的。查看十六进制输出,它不是明文或可轻易解读的格式,这与加密或混淆的数据特性一致。

# 6. 参考资料

[1] 50个最常用的Unix/Linux命令 from gywbd (opens new window)

[2] Linux 下十大命令行下载工具 from Linux中国 (opens new window)

[3] linux查看历史命令history from CSDN (opens new window)

[4] Shell Script 流程控制 from 简书 (opens new window)

[5] 一些简单的shell脚本实例 from CSDN (opens new window)

[6] 从0搭建ShadowsocksR与BBR加速 from bbaaz (opens new window)

[7] Trojan-Go一键安装脚本(Debian/Ubuntu)from ssr中文网 (opens new window)

[8] Linux查看并对外开放端口 from 简书 (opens new window)

[9] Debian/Ubuntu/Centos 防火墙放行指定端口 from SunPma'Blog (opens new window)

[10] Java 服务部署后浏览器无法访问,通过 curl 确可以访问 from V2EX (opens new window)

[11] Shell 判断文件或文件夹是否存在(不存在则创建)from CSDN (opens new window)

[12] shell数组追加元素的小技巧 from 51CTO (opens new window)

[13] LINUX乱码文件重命名 from CSDN (opens new window)

[14] cat/grep命令查看文件指定行数 from CSDN (opens new window)

[15] 使用Shell遍历目录及其子目录中的所有文件 from CSDN (opens new window)

[16] 用sed删除文件中指定行 from CSDN (opens new window)

[17] mysql 远程访问设置 from 华为云 (opens new window)

[18] Linux 杀死占用端口的所有进程 from 蓝蓝站点 (opens new window)

[19] 使用acme.sh开源项目申请 let‘s encrypt 的免费SSL证书 from Github (opens new window)

[20] 如何使用DNS API from Github (opens new window)

[21] namesilo域名通过acme.sh申请Let's Encrypt通配符HTTPS证书 from gmloc (opens new window)

[22] let's encrypt证书,Namesilo用acme申请免费永久,为网站添加ssl加密HTTPS from Bilibili (opens new window)

[23] scp带密码拷贝文件 from CSDN (opens new window)

[24] 搬瓦工VPS查看、修改、新增SWAP分区的大小 from 搬瓦工VPS (opens new window)

[25] Cloudflare 入门教程:使用 Cloudflare 免费 CDN 加速 & 保护自己的网站 from 知乎 (opens new window)

[26] Namesilo 域名购买及使用教程 from 知乎 (opens new window)

[27] 实例 IP 地址 ping 不通 from 腾讯云 (opens new window)

[28] linux下查看最消耗CPU、内存的进程 from CSDN (opens new window)

[29] Debian/Ubuntu Linux搭建SVN服务器,并设置开机默认启动 from ourjs (opens new window)

[30] SVN运维 from Github (opens new window)

[31] Debian 10 创建开机自启动脚本 from 心底的河流 (opens new window)

[32] 解决insserv: warning: script '服务名' missing LSB tags and overrides的问题 from Tan9le (opens new window)

[33] Linux系统如何设置开机自动运行脚本 from 良许Linux (opens new window)

[34] Hexo搭建个人博客并使用Git部署到VPS from 简书 (opens new window)

[35] VPS搭建Git服务器 from ocdman (opens new window)

[36] Squid极简搭建HTTP/HTTPS代理服务器 from Cooolin (opens new window)

[37] 在 Vim 中优雅地查找和替换 from Harttle Land (opens new window)

[38] 一文带你彻底学会 Git Hooks 配置 from segmentfault (opens new window)

[39] Hexo搭建个人博客并使用Git部署到VPS from 简书 (opens new window)

[40] nginx反向代理多个系统 from CSDN (opens new window)

[41] Debian9.5 系统配置NFS配置说明 from 博客园 (opens new window)

[42] 解决远程kafka本地无法连接问题 from IT Blog (opens new window)

[43] Shell中实现进度条的小脚本 from CSDN (opens new window)

[44] CloudFlare 关闭自适应 IPv6 解析的方法 from 老唐笔记 (opens new window)

[45] Linux修改系统时区 from 简书 (opens new window)

[46] Linux升级python至3.x from CSDN (opens new window)

[47] 如何在Debian 10上安装pip from myfreax (opens new window)

[48] Docker容器及其内应用自启动解决方案 from CSDN (opens new window)

[49] OCI runtime exec failed: exec failed:解决方法 from CSDN (opens new window)

[50] LVM技术简介 from archlinux (opens new window)

[51] Linux LVM简明教程 from Linux中国 (opens new window)

[52] ubuntu 中安装jdk脚本 from CSDN (opens new window)

[53] Ubuntu20中安装MySQL5.7 from Sail (opens new window)

[54] 访问后台出现重定向次数过多该怎么办 from CSDN (opens new window)

[55] Centos7.5安装java8 from 简书 (opens new window)

[56] 如何在 Debian 10 上安装和卸载 OpenJDK11/OpenJDK8 from linux265 (opens new window)

[57] Linux下部署jar包 from CSDN (opens new window)

[58] Cloudflare 5XX 错误故障排除 from Cloudflare官方文档 (opens new window)

[59] nohup执行的jar 怎么kill_Linux下java nohup 后台运行关闭后进程停止的原因,不挂断后台运行命令 from CSDN (opens new window)

[60] linux shell脚本 自动重启挂掉的jar包 from CSDN (opens new window)

[61] 使用curl获取URL的重定向目标 from QAStack (opens new window)

[62] 与 OneinStack 配合使用部署Halo from Halo官方文档 (opens new window)

[63] Linux Installation Date: How to Discover Your System’s Age from linuxiac (opens new window)

[64] Linux下Python程序Killed,分析其原因 from CSDN (opens new window)

[65] 查询CPU、GPU相关信息 from 51CTO博客 (opens new window)

[66] umount.nfs: XXX: device is busy from CSDN (opens new window)

[67] 如何利用mount命令挂载另一台服务器上的目录 from CSDN (opens new window)

[68] 如何在Debian 10 Linux上安装Node.js和npm from myfreax (opens new window)

[69] Ubuntu下crontab的安装和使用 from CSDN (opens new window)

[70] Linux统计文件夹下的文件数目 from SnailTyan (opens new window)

[71] 如何在两个服务器之间传输文件或者文件夹? from CSDN (opens new window)

[72] 如何在Debian 10上安装Anaconda Python发行版 from howtoing运维教程 (opens new window)

[73] 10 分钟上手 Vim,常用命令大盘点 from 知乎 (opens new window)

[74] 查看docker容器使用的资源 from 博客园 (opens new window)

[75] linux 下取进程占用 cpu/内存 最高的前10个进程 from CSDN (opens new window)

[76] 如何在Debian 11上安装Apache Maven from 云东方

[77] Linux 服务器日常巡检脚本分享 from 知乎 (opens new window)

[78] 如何快速删除指定的扩展名文件 from 腾讯云 (opens new window)

[79] 手把手教你Debian10安装配置Golang环境,并编译hello world程序 from 老牛博客 (opens new window)

[80] 2021 win10下beego的正确安装方法 from ICode9 (opens new window)

[81] linux下安装ffmpeg的详细教程 from 腾讯云 (opens new window)

[82] 错误:the input device is not a TTY from CSDN (opens new window)

[83] linux磁盘已满,查看哪个文件占用多 from CSDN (opens new window)

[84] Nvidia-smi简介及常用指令及其参数说明 from CSDN (opens new window)

[85] Linux shell脚本传参,传入数组 from CSDN (opens new window)

[86] 什么是swap空间?如何分配? from aqhi (opens new window)

[87] Linux SWAP交换分区应该设置多大?from CSDN (opens new window)

[88] 如何查看redis密码及修改 from 腾讯云 (opens new window)

[89] Linux 下安装Python报错:zlib not available from CSDN (opens new window)

[90] 如何解决 configure: error: no acceptable C compiler found in $PATH 错误 from BlueBear (opens new window)

[91] 如何查看linux是否打开虚拟化 from 博客园 (opens new window)

[92] 优秀运维脚本鉴赏 from 知乎 (opens new window)

[93] Screen命令详解。助力Linux使用和管理 from 腾讯云 (opens new window)

[94] Shadowsocks + Privoxy 搭建 http 代理服务 from Jim (opens new window)

[95] Linux系统轻松运行exe文件,实现跨平台应用 from linuxdown (opens new window)

[96] 70.3K Star!最强开源网络穿透工具推荐 from 知乎 (opens new window)

[97] 内网渗透代理之frp的应用与改造(一)from 安全客 (opens new window)

[98] 通过Frp内网穿透实现内网网络连接并创建vmess节点 from cnblogs (opens new window)

[99] missing python bz2 module from stackoverflow (opens new window)

[100] 更安全的 rm 替代方案,将文件和目录移至垃圾箱,而不是永久删除它们 from Github (opens new window)

[101] linux创建指定大小的文件 from CSDN (opens new window)

[102] 获取服务器出厂编号 from CSDN (opens new window)

Last Updated: 11/26/2024, 4:38:18 PM