文章轉載自:https://me.jinchuang.org/archives/114.html ,有修改
步驟總結
1.安裝好nginx,假設其html根路徑為/usr/share/nginx/html
2.准備工作:關閉防火牆,關閉selinux,安裝epel源
3.yum安裝依賴包:dh-autoreconf fcgi fcgi-devel
4.源碼安裝spawn-fcgi和fcgiwrap
(這倆其實也可以直接通過yum方式安裝,不過安裝后沒法通過systemctl的方式啟動fcgiwrap,還是得用腳本文件,啟動的時候會報錯:spawn-fcgi: child exited with: 127,因此還是使用源碼安裝比較穩妥)
5.配置nginx的location路徑
把下載好的linux-shell模板放在nginx的html根路徑下,設置用戶和用戶組為nginx,然后腳本目錄文件增加可執行權限,添加location規則
location規則中配置的root是nginx的html根路徑,並不是實際程序所在路徑,因為執行的時候會在設置root路徑也就是nginx的html根路徑下查找linux-shell/page/script/(.*)$
路徑里的文件進行執行。
chown -R nginx:nginx /usr/share/nginx/html/linux-shell
cd /usr/share/nginx/html/linux-shell/page/script/
chmod +x */*
location ~ ^/linux-shell/page/script/(.*)$ {
gzip off;
root /usr/share/nginx/html;
fastcgi_pass unix:/var/run/fcgiwrap.socket;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root/$fastcgi_script_name;
}
路徑:/usr/share/nginx/html
下有api文件夾,api文件夾下有一個disk的文件
cd `/usr/share/nginx/html/
chown -R nginx:nginx api
chmod a+x api/disk
訪問路徑是:http://localhost/api/disk,就會在設置的root路徑下,也就是/usr/share/nginx/html
路徑下找api開頭的文件夾,進而找到disk文件進行執行
location ~ ^/api/(.*)$ {
gzip off;
default_type text/plain;
root /usr/share/nginx/html;
fastcgi_pass unix:/var/run/fcgiwrap.socket;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root/$fastcgi_script_name;
}
如上倆,模板和參數可以合並起來,linux-shell模板可以參考disk里的文件內容寫法接收傳遞過來的參數
使用說明
1,shell命令 | python命令 | 系統支持的都可以
2,不支持交互式顯示 | 不支持動態內容顯示
3,傻瓜式操作(頁面點擊鏈接一次,執行一次腳本內容)|可以設置頁面自動刷新,實現重復執行腳本
准備工作
##關閉防火牆
##(centos6)
service iptables stop
chkconfig iptables off
##(centos7)
systemctl stop firewalld
systemctl disable firewalld
#關閉selinux
sed -i 's/SELINUX=enforcing/SELINUX=disabled/' /etc/selinux/config
setenforce 0
#已有epel源的跳過此步驟,直接安裝依賴開始
#centos6 添加epel yum源
wget -O /etc/yum.repos.d/epel-6.repo http://mirrors.aliyun.com/repo/epel-6.repo
#centos7 添加epel yum源
wget -O /etc/yum.repos.d/epel-7.repo http://mirrors.aliyun.com/repo/epel-7.repo
#清除緩存 重新生成緩存
yum clean all
yum makecache
安裝依賴包
#安裝開發包組和相關的依賴包
yum install dh-autoreconf fcgi fcgi-devel -y
安裝spawn-fcgi 和 fcgiwrap
#創建存放包的目錄(包下載到哪個目錄都可以,這里放在/source/目錄下)
mkdir /source/ && cd /source/
#安裝spawn-fcgi
#github下載最新代碼 https://github.com/lighttpd/spawn-fcgi
本地下載:wget https://www.jinchuang.org/novel/lnmp/spawn-fcgi.zip
最新版:wget https://github.com/lighttpd/spawn-fcgi/archive/refs/tags/spawn-fcgi-1.6.4.zip
解壓:unzip spawn-fcgi-1.6.4.zip
安裝:
cd spawn-fcgi-spawn-fcgi-1.6.4
./autogen.sh
./configure
make && make install
#安裝fcgiwrap
#github下載最新代碼 https://github.com/gnosek/fcgiwrap
本地下載:wget https://www.jinchuang.org/novel/lnmp/fcgiwrap.zip
最新版: wget https://github.com/gnosek/fcgiwrap/archive/refs/tags/1.1.0.zip
解壓: unzip 1.1.0.zip
安裝:
cd fcgiwrap-1.1.0
autoreconf -i
./configure
make && make install
創建fcgiwrap啟動腳本
【nginx通過轉發請求到這里來執行腳本命令】,腳本啟動用戶要和你nginx啟動用戶一致,注意下腳本中2個命令的路徑是否和你的一致
vim /etc/init.d/fcgiwrap
#! /bin/bash
### BEGIN INIT INFO
# Provides: fcgiwrap
# Required-Start: $remote_fs
# Required-Stop: $remote_fs
# Should-Start:
# Should-Stop:
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: FastCGI wrapper
# Description: Simple server for running CGI applications over FastCGI
### END INIT INFO
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
SPAWN_FCGI="/usr/local/bin/spawn-fcgi"
DAEMON="/usr/local/sbin/fcgiwrap"
NAME="fcgiwrap"
PIDFILE="/var/run/$NAME.pid"
FCGI_SOCKET="/var/run/$NAME.socket" # 注意:這里跟原文不一樣
FCGI_USER="nginx"
FCGI_GROUP="nginx"
FORK_NUM=5
SCRIPTNAME=/etc/init.d/$NAME
case "$1" in
start)
echo -n "Starting $NAME... "
PID=`pidof $NAME`
if [ ! -z "$PID" ]; then
echo " $NAME already running"
exit 1
fi
$SPAWN_FCGI -u $FCGI_USER -g $FCGI_GROUP -s $FCGI_SOCKET -P $PIDFILE -F $FORK_NUM -f $DAEMON
if [ "$?" != 0 ]; then
echo " failed"
exit 1
else
echo " done"
fi
;;
stop)
echo -n "Stoping $NAME... "
PID=`pidof $NAME`
if [ ! -z "$PID" ]; then
kill `pidof $NAME`
if [ "$?" != 0 ]; then
echo " failed. re-quit"
exit 1
else
rm -f $pid
echo " done"
fi
else
echo "$NAME is not running."
exit 1
fi
;;
status)
PID=`pidof $NAME`
if [ ! -z "$PID" ]; then
echo "$NAME (pid $PID) is running..."
else
echo "$NAME is stopped"
exit 0
fi
;;
restart)
$SCRIPTNAME stop
sleep 1
$SCRIPTNAME start
;;
*)
echo "Usage: $SCRIPTNAME {start|stop|restart|status}"
exit 1
;;
esac
啟動fcgiwrap服務
增加可執行權限
chmod +x /etc/init.d/fcgiwrap
#添加到服務里面(centos6系統執行,centos7跳過此步驟)
chkconfig --add fcgiwrap
chkconfig --level 2345 fcgiwrap on
#啟動服務
/etc/init.d/fcgiwrap start
Starting fcgiwrap... spawn-fcgi: child spawned successfully: PID: 22416
spawn-fcgi: child spawned successfully: PID: 22417
spawn-fcgi: child spawned successfully: PID: 22418
spawn-fcgi: child spawned successfully: PID: 22419
spawn-fcgi: child spawned successfully: PID: 22420
done
nginx配置轉發 (系統安裝好nginx)
這一步的含義是下載現成的模板放在一個目錄下,然后nginx中配置location路徑進行訪問
#注意下修改為你的目錄路徑
#location ~ ^/linux-shell/page/script/.*\.(cgi) { #這里的cgi后綴匹配根據需要修改,后綴自定義即可
# linux-shell 為模板程序目錄,放在nginx網站根目錄下面
location ~ ^/linux-shell/page/script/ { #我這里調用的文件是沒有后綴的就用這個配置
gzip off;
fastcgi_pass unix:/var/run/fcgiwrap.socket; # 注意:這里跟原文不一樣
root /usr/share/nginx/html; # 注意:這里跟原文不一樣,nginx的html目錄
include fastcgi_params;
fastcgi_param SCRIPT_NAME $document_root/$fastcgi_script_name; # 注意:這里跟原文不一樣
}
#重啟nginx:
nginx -s reload
模板目錄結構
# 下載模板,放在網站根目錄下
# 目錄結構:
linux-shell
├── css
│ ├── iconfont.css
│ ├── iconfont.eot
│ ├── iconfont.svg
│ ├── iconfont.ttf
│ ├── iconfont.woff
│ ├── iconfont.woff2
│ ├── page.css
│ └── style.css
├── favicon.ico
├── images
│ ├── b.jpg
│ ├── body.cur
│ ├── b.png
│ ├── content.jpg
│ ├── hua.gif
│ ├── link.cur
│ ├── logo.png
│ ├── nav.jpg
│ └── page.cur
├── index.html
├── js
│ ├── jquery-2.1.1.min.js
│ └── nav.js
└── page
├── content
│ ├── index.html
│ ├── script.js
│ └── TweenMax.min.js
├── h5
│ ├── 161
│ │ └── 161.html
│ ├── 188
│ │ └── 188.html
│ └── local
│ └── local.html
└── script
├── 161
│ ├── disk
│ ├── info
│ ├── mem
│ ├── ps
│ ├── server
│ ├── ssh
│ └── uptime
├── 188
│ ├── disk
│ ├── info
│ ├── mem
│ ├── ps
│ ├── server
│ ├── ssh
│ └── uptime
└── local
├── disk
├── info
├── mem
├── ps
├── server
├── ssh
└── uptime
shell代碼示例文件(查看磁盤使用情況):
#!/bin/bash
echo "Content-Type:text/html;charset=utf-8"
echo ""
# 自動刷新
#echo "<script>window.setInterval(function(){
# window.location.reload();
#},1000);</script>"
#echo "<meta http-equiv="refresh" content="60">"
# html頁面css樣式
echo '<style>
body{color:#cecece;}
.title{color: #FF9800;border-left: 4px solid;padding: 4px;}
pre{font-size:14px;border-left: 4px solid #4CAF50;padding: 5px;}
</style>'
# 定義變量
ip="192.168.x.x"
# 內容代碼(命令返回結果放在<pre>標簽中)
echo '<div style="padding-left:10px;">'
echo '<h1 class="title">硬盤使用情況</h1>'
echo '<h5 style="color:#848484;">'
dd=`date`
echo "統計時間: $dd 【當前機器ip: $ip】"
echo '</h5>'
echo '<pre>'
# 查看磁盤使用(本機)
df -hT
# 查看磁盤使用(遠程機器,可以使用ansible|sshpass等遠程工具)
sshpass -p "password" ssh root@$ip -o StrictHostKeyChecking=no 'df -hT'
echo '</pre>'
html模板下載
如果訪問彈出下載,先檢查fcgiwrap服務是否正常,再檢查nginx匹配規則
下載地址:https://files.cnblogs.com/files/sanduzxcvbnm/linux-shell.zip
# 程序html模板使用:(腳本文件要加執行權限,不然會提示403 錯誤)
cd linux-shell/page/script/
chmod +x */*
# 腳本文件說明:
# disk
查看硬盤使用情況
# info
提示信息內容
# mem
內存使用情況
# ps
系統進程概覽
# server
自定義服務進程查看
# ssh
ssh連接用戶情況
# uptime
系統負載cpu和內存使用概覽
傳遞參數
nginx配置
location ~ ^/api/(.*)$ {
gzip off;
default_type text/plain;
root /usr/share/nginx/html;
fastcgi_pass unix:/var/run/fcgiwrap.socket;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root/$fastcgi_script_name;
}
在/usr/share/nginx/html
路徑下有api文件夾,api文件夾下有一個disk的文件,其內容如下:
#!/bin/sh
echo "Content-Type:text/html;charset=utf-8"
echo ""
for i in a b c; do
echo $i
done
echo "$QUERY_STRING" | awk -F '=' '{print $1}'
echo "$QUERY_STRING" | awk -F '=' '{print $2}'
訪問測試,用瀏覽器訪問效果是一樣的
# curl http://localhost/api/disk
a
b
c
# curl http://10.16.16.101/api/disk?abc=123
a
b
c
abc
123
關於使用nginx用戶,不使用root用戶的問題
首先,在寫fcgiwrap啟動腳本文件,也就是/etc/init.d/fcgiwrap
的時候里面指定的是nginx用戶,這個用戶是啟動nginx使用的用戶是一致的。
若是該腳本文件中使用root用戶,啟動的時候會報錯:
stderr, "spawn-fcgi: I will not set uid to 0
因為用spawn-fcgi 啟動不能使用 -u root
啟動FastCGI進程。若是想使用root用戶啟動,需要修改源代碼:
在文件src/spawn-fcgi.c
中注釋掉一段代碼, 總共有三處需要注釋
/*
if (my_uid == 0) {
fprintf(stderr, "spawn-fcgi: I will not set uid to 0\n");
return -1;
}
*/
然后再編譯源碼進行安裝
這樣一來spawn-fcgi就行使用root啟動了,修改啟動腳本,把nginx修改成root,刪除使用nginx用戶生成的fcgiwrap.socket文件。
還需要修改nginx配置文件中nginx啟動使用的用戶,也修改為root。
然后重新啟動fcgiwrap和nginx,就能實現使用root用戶了
寫好shell腳本訪問報錯:An error occurred while parsing CGI reply,nginx日志顯示是502 bad gateway
shell腳本開頭內容中加上如下:
echo "Content-Type:text/html;charset=utf-8"
echo ""
關於傳遞參數的進一步分析
在nginx的location配置文件中,比如如下:
location ~ ^/api/(.*)$ {
gzip off;
root /usr/share/nginx/html;
fastcgi_pass unix:/var/run/fcgiwrap.socket;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root/$fastcgi_script_name;
}
里面有 include fastcgi_params;
, fastcgi_params文件內容如下:
# cat fastcgi_params
fastcgi_param QUERY_STRING $query_string;
fastcgi_param REQUEST_METHOD $request_method;
fastcgi_param CONTENT_TYPE $content_type;
fastcgi_param CONTENT_LENGTH $content_length;
fastcgi_param SCRIPT_NAME $fastcgi_script_name;
fastcgi_param REQUEST_URI $request_uri;
fastcgi_param DOCUMENT_URI $document_uri;
fastcgi_param DOCUMENT_ROOT $document_root;
fastcgi_param SERVER_PROTOCOL $server_protocol;
fastcgi_param REQUEST_SCHEME $scheme;
fastcgi_param HTTPS $https if_not_empty;
fastcgi_param GATEWAY_INTERFACE CGI/1.1;
fastcgi_param SERVER_SOFTWARE nginx/$nginx_version;
fastcgi_param REMOTE_ADDR $remote_addr;
fastcgi_param REMOTE_PORT $remote_port;
fastcgi_param SERVER_ADDR $server_addr;
fastcgi_param SERVER_PORT $server_port;
fastcgi_param SERVER_NAME $server_name;
# PHP only, required if PHP was built with --enable-force-cgi-redirect
fastcgi_param REDIRECT_STATUS 200;
看到這一行:fastcgi_param QUERY_STRING $query_string;
,聯想到接收參數的腳本內容寫法,里面同樣有變量:$QUERY_STRING
:
#!/bin/bash
echo "Content-Type:text/html;charset=utf-8"
echo ""
echo "$QUERY_STRING" | awk -F '=' '{print $1}'
echo "$QUERY_STRING" | awk -F '=' '{print $2}'
這就很好理解了, 傳遞的參數是給變量$QUERY_STRING
賦值,然后進一步使用該變量進行其他操作。
從安全性上考慮,nginx的location配置文件中沒必要指定引用fastcgi_param文件,可以只配置其中需要使用到的變量參數。比如:
location ~ ^/api/(.*)$ {
gzip off;
root /usr/share/nginx/html;
fastcgi_pass unix:/var/run/fcgiwrap.socket;
#include fastcgi_params;
fastcgi_param QUERY_STRING $query_string;
fastcgi_param SCRIPT_FILENAME $document_root/$fastcgi_script_name;
}
此時,就只能傳遞參數使用,而不是獲取其他默認變量的值了。
舉例說明:
nginx的location配置如下:
location ~ ^/api/(.*)$ {
gzip off;
root /usr/share/nginx/html;
fastcgi_pass unix:/var/run/fcgiwrap.socket;
include fastcgi_params;
#fastcgi_param QUERY_STRING $query_string;
fastcgi_param SCRIPT_FILENAME $document_root/$fastcgi_script_name;
}
shell腳本內容如下:
#!/bin/bash
echo "Content-Type:text/html;charset=utf-8"
echo ""
for i in a b c; do
echo $i
done
echo "$QUERY_STRING" | awk -F '=' '{print $1}'
echo "$QUERY_STRING" | awk -F '=' '{print $2}'
echo "$REQUEST_METHOD"
echo "$SCRIPT_NAME"
echo "$DOCUMENT_ROOT"
此時訪問該腳本內容,結果如下:
# curl http://10.16.16.101/api/disk?name=123
a
b
c
name
123
GET
/api/disk
/usr/share/nginx/html
若是修改nginx的location配置如下:
location ~ ^/api/(.*)$ {
gzip off;
root /usr/share/nginx/html;
fastcgi_pass unix:/var/run/fcgiwrap.socket;
#include fastcgi_params;
fastcgi_param QUERY_STRING $query_string;
fastcgi_param SCRIPT_FILENAME $document_root/$fastcgi_script_name;
}
shell腳本內容不變,此時訪問該腳本內容,結果如下:
# curl http://10.16.16.101/api/disk?name=123
a
b
c
name
123
可以看到,nginx的location中未被引用的變量則不再輸出變量值
nginx和fcgiwrap都配置啟動了,但是訪問報錯,nginx日志中找不到fcgiwrap.socket文件
解決辦法:如果把該文件放在/tmp
路徑下,比如是:/tmp/fcgiwrap.socket
,此時就算nginx和fcgiwrap都配置啟動了,訪問的時候查看nginx日志,會提示找不到/tmp/fcgiwrap.socket
文件。
給該文件換個路徑就行了,比如上文中說的路徑:/var/run/fcgiwrap.socket