简介
(百度百科- http://www.dwz.cn/x32kG)
Nginx安装
环境:64位 Ubuntu 18.04.1
uisrc@ubuntu:/proc$ cat version
Linux version 4.15.0-91-generic (buildd@lgw01-amd64-013) (gcc version 7.4.0 (Ubuntu 7.4.0-1ubuntu1~18.04.1)) #92-Ubuntu SMP Fri Feb 28 11:09:48 UTC 2020
uisrc@ubuntu:/proc$
nginx依赖以下模块
- gzip模块需要 zlib 库
- rewrite模块需要 pcre 库
- ssl 功能需要openssl库
安装pcre
- 获取pcre编译安装包,在http://www.pcre.org/上可以获取当前最新的版本
- 解压缩pcre-xx.tar.gz包
- 进入解压缩目录,执行./configure,配置安装位置及交叉编译器根据自己使用修改
uisrc@ubuntu:~/web/pcre2-10.44$ ls
132html CleanTxt config.log depcomp libpcre2-16.pc libpcre2-8.pc.in m4 NON-AUTOTOOLS-BUILD RunGrepTest test-driver
aclocal.m4 cmake config.status Detrail libpcre2-16.pc.in libpcre2-posix.pc Makefile pcre2-config RunGrepTest.bat vms
ar-lib CMakeLists.txt config.sub doc libpcre2-32.pc libpcre2-posix.pc.in Makefile.am pcre2-config.in RunTest
AUTHORS compile configure HACKING libpcre2-32.pc.in libtool Makefile.in perltest.sh RunTest.bat
ChangeLog config-cmake.h.in configure.ac INSTALL libpcre2-8.la LICENCE missing PrepareRelease src
CheckMan config.guess COPYING install-sh libpcre2-8.pc ltmain.sh NEWS README testdata
uisrc@ubuntu:~/web/pcre2-10.44$ ./configure
- make & make install
安装openssl
- 获取openssl编译安装包,在http://www.openssl.org/source/上可以获取当前最新的版本。
- 解压缩openssl-xx.tar.gz包。
- 进入解压缩目录,执行./configure,配置安装位置及交叉编译器根据自己使用修改
- make & make install
安装zlib
- 获取zlib编译安装包,在http://www.zlib.net/上可以获取当前最新的版本
- 解压缩openssl-xx.tar.gz包
- 进入解压缩目录,执行./configure,配置安装位置及交叉编译器根据自己使用修改
- make & make install
安装nginx
- 获取nginx,在http://nginx.org/en/download.html上可以获取当前最新的版本
- 解压缩nginx-xx.tar.gz包。
- 进入解压缩目录,执行./configure
- make & make install
若安装时找不到上述依赖模块,使用–with-openssl=<openssl_dir>、–with-pcre=<pcre_dir>、–with-zlib=<zlib_dir>指定依赖的模块目录。如已安装过,此处的路径为安装目录;若未安装,则此路径为编译安装包路径,nginx将执行模块的默认编译安装。
我的编译脚本及编译路径如下:根据自己使用修改
uisrc@ubuntu:~/web$ ls
boa-0.94.14rc21 FastCGI.com-master modifyAPN.c openssl-3.4.0 pcre2-10.44.tar.bz2 testconfig.cgi zlib-1.3.1.tar.gz
boa-0.94.14rc21.tar fcgi nginx-1.26.2 openssl-3.4.0.tar.gz spawn-fcgi-1.6.5 testconfig.cgi.c
buildnginx.sh fcgiwrap-master nginx-1.26.2.tar.gz pcre2-10.44 spawn-fcgi-1.6.5.tar.gz zlib-1.3.1
uisrc@ubuntu:~/web$ cat buildnginx.sh
# 进入nginx源码包的命令
cd nginx-1.26.2
# 配置编译 Nginx的临时编译器
export PATH=$PATH:/home/uisrc/SDK/toolchains/aarch64-linux/bin/
./configure --prefix=/opt/nginx-1.26.2 --with-pcre=/home/uisrc/web/pcre2-10.44 --with-zlib=/home/uisrc/web/zlib-1.3.1 --with-openssl=/home/uisrc/web/openssl-3.4.0 --with-http_ssl_module --with-http_v2_module --with-http_realip_module --with-http_gzip_static_module --with-http_stub_status_module
# 编译和配置 Nginx 的命令
#./configure \
# 设置 Nginx 的安装路径为 /usr/local/nginx
#--prefix=/opt/nginx-1.26.2 \
# 指定 Nginx 进程将以 nginx 用户身份运行
#--user=nginx \
# 指定 Nginx 进程的组为 nginx
#--group=nginx \
#编译依赖项pcre
#--with-pcre=/home/uisrc/web/pcre2-10.44 \
#编译依赖项zlib
#--with-zlib=/home/uisrc/web/zlib-1.3.1 \
#编译依赖项openssl
#--with-openssl=/home/uisrc/web/openssl-3.4.0 \
# 启用 HTTP SSL 模块,使得 Nginx 支持 HTTPS 连接
#--with-http_ssl_module \
# 启用 HTTP/2 模块,支持 HTTP/2 协议
#--with-http_v2_module \
# 启用 Real IP 模块,这对于处理反向代理的情况非常有用
#--with-http_realip_module \
# 启用 GZIP 静态文件压缩模块,可以自动对静态文件进行压缩
#--with-http_gzip_static_module \
# 启用 stub status 模块,可以提供基本的服务器状态页面
#--with-http_stub_status_module \
# 使用系统 PCRE 库
#--with-pcre \
# 启用 Stream 模块,用于处理 TCP 和 UDP 流量
#--with-stream \
# 启用 Stream SSL 模块,使得 Stream 模块支持 TLS/SSL 加密连接
#--with-stream_ssl_module\
uisrc@ubuntu:~/web$
验证安装
启动nginx之后,浏览器中输入http://localhost可以验证是否安装启动成功
Nginx配置
安装完成之后,配置目录conf下有以下配置文件,过滤掉了xx.default配置:
除了nginx.conf,其余配置文件,一般只需要使用默认提供即可。
uisrc@ubuntu:/opt/nginx-1.26.2/conf$ tree |grep -v default
.
├── fastcgi.conf
├── fastcgi_params
├── koi-utf
├── koi-win
├── mime.types
├── nginx.conf
├── scgi_params
├── uwsgi_params
└── win-utf
0 directories, 15 files
uisrc@ubuntu:/opt/nginx-1.26.2/conf$
nginx.conf
nginx.conf是主配置文件,内容如下图所示:
user root;
worker_processes 1;
#error_log logs/error.log;
#error_log logs/error.log notice;
#error_log logs/error.log info;
#pid logs/nginx.pid;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
#log_format main '$remote_addr - $remote_user [$time_local] "$request" '
# '$status $body_bytes_sent "$http_referer" '
# '"$http_user_agent" "$http_x_forwarded_for"';
#access_log logs/access.log main;
sendfile on;
#tcp_nopush on;
#keepalive_timeout 0;
keepalive_timeout 65;
#gzip on;
server {
listen 80;
server_name localhost;
#charset koi8-r;
#access_log logs/host.access.log main;
location / {
root html;
index index.html index.htm;
# #index main_APN.html;
}
# 设置CGI脚本
# = 表示精确匹配。
# ~ 表示区分大小写的正则匹配。
# ~* 表示不区分大小写的正则匹配。
# ^~ 表示非正则匹配,如果该选项匹配,则不再进行正则匹配。( ^ 表示“非”,~ 表示“正则”,字符意思是:不会继续匹配正则)
# @ 定义一个命名的 location,通常用于内部重定向。
location ~ \.cgi$ {
# 设置CGI脚本的查找路径
root /opt/nginx-1.26.2/cgi-bin;
fastcgi_pass 127.0.0.1:8081;
# 设置CGI参数
fastcgi_index testconfig.cgi;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
#include fastcgi.conf;
include fastcgi_params;
}
#error_page 404 /404.html;
# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
# proxy the PHP scripts to Apache listening on 127.0.0.1:80
#
#location ~ \.php$ {
# proxy_pass http://127.0.0.1;
#}
# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
#
#location ~ \.php$ {
# root html;
# fastcgi_pass 127.0.0.1:9000;
# fastcgi_index index.php;
# fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name;
# include fastcgi_params;
#}
# deny access to .htaccess files, if Apache's document root
# concurs with nginx's one
#
#location ~ /\.ht {
# deny all;
#}
}
# another virtual host using mix of IP-, name-, and port-based configuration
#
#server {
# listen 8000;
# listen somename:8080;
# server_name somename alias another.alias;
# location / {
# root html;
# index index.html index.htm;
# }
#}
# HTTPS server
#
#server {
# listen 443 ssl;
# server_name localhost;
# ssl_certificate cert.pem;
# ssl_certificate_key cert.key;
# ssl_session_cache shared:SSL:1m;
# ssl_session_timeout 5m;
# ssl_ciphers HIGH:!aNULL:!MD5;
# ssl_prefer_server_ciphers on;
# location / {
# root html;
# index index.html index.htm;
# }
#}
}
- worker_process表示工作进程的数量,一般设置为cpu的核数
- worker_connections表示每个工作进程的最大连接数
- server{}块定义了虚拟主机
- listener监听端口
- server_name监听域名
- location{}是用来为匹配的 URI 进行配置,URI 即语法中的“/uri/”。location / {
}匹配任何查询,因为所有请求都以 / 开头。 - root指定对应uri的资源查找路径,这里html为相对路径,完整路径为/opt/ /opt/nginx-1.26.2/html/
- index指定首页index文件的名称,可以配置多个,以空格分开。如有多个,按配置顺序查找。
从配置可以看出,nginx监听了80端口、域名为localhost、跟路径为html文件夹(我的安装路径为/opt/nginx-1.26.2,所以/opt/nginx-1.26.2/html)、默认index文件为index.html, index.htm、服务器错误重定向到50x.html页面。
可以看到/opt/nginx-1.26.2/html/有以下文件:
uisrc@ubuntu:/opt/nginx-1.26.2/html$ ls
50x.html index.html
这也是上面在浏览器中输入http://localhost,能够显示欢迎页面的原因。实际上访问的是/opt/nginx-1.26.2/html/index.html文件。
mime.types
文件扩展名与文件类型映射表,nginx根据映射关系,设置http请求响应头的Content-Type值。当在映射表找不到时,使用nginx.conf中default-type指定的默认值。例如,默认配置中的指定的default-type为application/octet-stream。
include mime.types;
default_type application/octet-stream;
完整的请自行查看 cat mime.types
uisrc@ubuntu:~/web/nginx-1.26.2/conf$ cat mime.types
types {
text/html html htm shtml;
text/css css;
text/xml xml;
image/gif gif;
image/jpeg jpeg jpg;
application/javascript js;
application/atom+xml atom;
application/rss+xml rss;
text/mathml mml;
text/plain txt;
text/vnd.sun.j2me.app-descriptor jad;
text/vnd.wap.wml wml;
text/x-component htc;
image/avif avif;
image/png png;
image/svg+xml svg svgz;
image/tiff tif tiff;
image/vnd.wap.wbmp wbmp;
image/webp webp;
image/x-icon ico;
image/x-jng jng;
image/x-ms-bmp bmp;
font/woff woff;
font/woff2 woff2;
application/java-archive jar war ear;
application/json json;
application/mac-binhex40 hqx;
application/msword doc;
application/pdf pdf;
application/postscript ps eps ai;
application/rtf rtf;
application/vnd.apple.mpegurl m3u8;
application/vnd.google-earth.kml+xml kml;
application/vnd.google-earth.kmz kmz;
application/vnd.ms-excel xls;
application/vnd.ms-fontobject eot;
application/vnd.ms-powerpoint ppt;
application/vnd.oasis.opendocument.graphics odg;
application/vnd.oasis.opendocument.presentation odp;
application/vnd.oasis.opendocument.spreadsheet ods;
application/vnd.oasis.opendocument.text odt;
application/vnd.openxmlformats-officedocument.presentationml.presentation
........
fastcgi_params
nginx配置Fastcgi解析时会调用fastcgi_params配置文件来传递服务器变量,这样CGI中可以获取到这些变量的值。默认传递以下变量:
uisrc@ubuntu:~/web/nginx-1.26.2/conf$ 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;
uisrc@ubuntu:~/web/nginx-1.26.2/conf$
这些变量的作用从其命名可以看出。
fastcgi.conf
对比下fastcgi.conf与fastcgi_params文件,可以看出只有以下差异:
uisrc@ubuntu:~/web/nginx-1.26.2/conf$ diff fastcgi.conf fastcgi_params
2d1
< fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
即fastcgi.conf只比fastcgi_params多了一行“fastcgi_param SCRIPT_FILENAME d o c u m e n t r o o t document_root documentrootfastcgi_script_name;”
原本只有fastcgi_params文件,fastcgi.conf是nginx 0.8.30 (released: 15th of December 2009)才引入的。主要为是解决以下问题(参考:http://www.dwz.cn/x3GIJ):
原本Nginx只有fastcgi_params,后来发现很多人在定义SCRIPT_FILENAME时使用了硬编码的方式。例如,fastcgi_param SCRIPT_FILENAME /var/www/foo$fastcgi_script_name。于是为了规范用法便引入了fastcgi.conf。
不过这样的话就产生一个疑问:为什么一定要引入一个新的配置文件,而不是修改旧的配置文件?这是因为fastcgi_param指令是数组型的,和普通指令相同的是:内层替换外层;和普通指令不同的是:当在同级多次使用的时候,是新增而不是替换。换句话说,如果在同级定义两次SCRIPT_FILENAME,那么它们都会被发送到后端,这可能会导致一些潜在的问题,为了避免此类情况,便引入了一个新的配置文件。
因此不再建议大家使用以下方式(搜了一下,网上大量的文章,并且nginx.conf的默认配置也是使用这种方式):
fastcgi_param SCRIPT_FILENAME d o c u m e n t r o o t document_root documentrootfastcgi_script_name;
include fastcgi_params;
而使用最新的方式:
include fastcgi.conf;
uwsgi_params
与fastcgi_params一样,传递哪些服务器变量,只有前缀不一样,以uwsgi_param开始而非fastcgi_param。
scgi_params
与fastcgi_params一样,传递哪些服务器变量,只有前缀不一样,以uwsgi_param开始而非fastcgi_param。
koi-utf、koi-win、win-utf
这三个文件都是与编码转换映射文件,用于在输出内容到客户端时,将一种编码转换到另一种编码。
koi-win: charset_map koi8-r < – > windows-1251
koi-utf: charset_map koi8-r < – > utf-8
win-utf: charset_map windows-1251 < – > utf-8
koi8-r是斯拉夫文字8位元编码,供俄语及保加利亚语使用。在Unicode未流行之前,KOI8-R 是最为广泛使用的俄语编码,使用率甚至起ISO/IEC 8859-5还高。这3个文件存在是因为作者是俄国人的原因。
nginx常用命令
uisrc@ubuntu:~/web$ sudo /opt/nginx-1.26.2/sbin/nginx -h
nginx version: nginx/1.26.2
Usage: nginx [-?hvVtTq] [-s signal] [-p prefix]
[-e filename] [-c filename] [-g directives]
Options:
-?,-h : this help
-v : show version and exit
-V : show version and configure options then exit
-t : test configuration and exit
-T : test configuration, dump it and exit
-q : suppress non-error messages during configuration testing
-s signal : send signal to a master process: stop, quit, reopen, reload
-p prefix : set prefix path (default: /opt/nginx-1.26.2/)
-e filename : set error log file (default: logs/error.log)
-c filename : set configuration file (default: conf/nginx.conf)
-g directives : set global directives out of configuration file
sudo /opt/nginx-1.26.2/sbin/nginx -s reload 重启
CGI/FASTCGI的原理、及如何使用C/C++编写简单的CGI/FastCGI,部署CGI/FASTCGI到nginx
CGI
通用网关接口(Common Gateway Interface/CGI)描述了客户端和服务器程序之间传输数据的一种标准,可以让一个客户端,从网页浏览器向执行在网络服务器上的程序请求数据。CGI 独立于任何语言的,CGI 程序可以用任何脚本语言或者是完全独立编程语言实现,只要这个语言可以在这个系统上运行。Unix shell script, Python, Ruby, PHP, perl, Tcl, C/C++, 和 Visual Basic 都可以用来编写 CGI 程序。(http://www.dwz.cn/yFFgQ)
最初,CGI 是在 1993 年由美国国家超级电脑应用中心(NCSA)为 NCSA HTTPd Web 服务器开发的。这个 Web 服务器使用了 UNIX shell 环境变量 来保存从 Web 服务器传递出去的参数,然后生成一个运行 CGI 的独立的进程。cgi的处理流程如下图所示:
l step1. web 服务器收到客户端(浏览器)的请求Http Request,启动CGI程序,并通过环境变量、标准输入传递数据
l step2. cgi进程启动解析器、加载配置(如业务相关配置)、连接其它服务器(如数据库服务器)、逻辑处理等
l step3. cgi程将处理结果通过标准输出、标准错误,传递给web 服务器
l step4. web 服务器收到cgi返回的结果,构建Http Response返回给客户端,并杀死cgi进程
web服务器与cgi通过环境变量、标准输入、标准输出、标准错误互相传递数据。
环境变量
GET请求,它将数据打包放置在环境变量QUERY_STRING中,CGI从环境变量QUERY_STRING中获取数据。常见的环境变量如下表所示:
环境变数 | 内容 |
---|---|
AUTH_TYPE | 存取认证类型 |
CONTENT_LENGTH | 由标准输入传递给CGI程序的数据长度,以bytes或字元数来计算 |
CONTENT_TYPE | 请求的MIME类型 |
GATEWAY_INTERFACE | 服务器的CGI版本编号 |
HTTP_ACCEPT | 浏览器能直接接收的Content-types, 可以有HTTP Accept header定义 |
HTTP_USER_AGENT | 递交表单的浏览器的名称、版本 和其他平台性的附加信息 |
HTTP_REFERER | 递交表单的文本的 URL,不是所有的浏览器都发出这个信息,不要依赖它 |
PATH_INFO | 传递给cgi程式的路径信息 |
QUERY_STRING | 传递给CGI程式的请求参数,也就是用"?"隔开,添加在URL后面的字串 |
REMOTE_ADDR | client端的host名称 |
REMOTE_HOST | client端的IP位址 |
REMOTE_USER | client端送出来的使用者名称 |
REMOTE_METHOD | client端发出请求的方法(如get、post) |
SCRIPT_NAME | CGI程式所在的虚拟路径,如/cgi-bin/echo |
SERVER_NAME | server的host名称或IP地址 |
SERVER_PORT | 收到request的server端口 |
SERVER_PROTOCOL | 所使用的通讯协定和版本编号 |
SERVER_SOFTWARE | server程序的名称和版本 |
标准输入
环境变量的大小是有一定的限制的,当需要传送的数据量大时,储存环境变量的空间可能会不足,造成数据接收不完全,甚至无法执行CGI程序。因此后来又发展出另外一种方法:POST,也就是利用I/O重新导向的技巧,让CGI程序可以由STDIN和STDOUT直接跟浏览器沟通。
当我们指定用这种方法传递请求的数据时,web 服务器收到数据后会先放在一块输入缓冲区中,并且将数据的大小记录在CONTENT_LENGTH这个环境变数,然后调用CGI程式并将CGI程序的STDIN指向这块缓冲区,于是我们就可以很顺利的通过STDIN和环境变数CONTENT_LENGTH得到所有的资料,再没有资料大小的限制了。
总结:CGI使外部程序与Web服务器之间交互成为可能。CGI程式运行在独立的进程中,并对每个Web请求建立一个进程,这种方法非常容易实现,但效率很差,难以扩展。面对大量请求,进程的大量建立和消亡使操作系统性能大大下降。此外,由于地址空间无法共享,也限制了资源重用。
FastCGI
快速通用网关接口(Fast Common Gateway Interface/FastCGI)是通用网关接口(CGI)的改进,描述了客户端和服务器程序之间传输数据的一种标准。FastCGI致力于减少Web服务器与CGI程式之间互动的开销,从而使服务器可以同时处理更多的Web请求。与为每个请求创建一个新的进程不同,FastCGI使用持续的进程来处理一连串的请求。这些进程由FastCGI进程管理器管理,而不是web服务器。(http://www.dwz.cn/yFMap)
当进来一个请求时,Web 服务器把环境变量和这个页面请求通过一个unix domain socket(都位于同一物理服务器)或者一个IP Socket(FastCGI部署在其它物理服务器)传递给FastCGI进程。
-
step1. Web 服务器启动时载入初始化FastCGI执行环境 。 例如IIS ISAPI、apache mod_fastcgi、nginx ngx_http_fastcgi_module、lighttpd mod_fastcgi
-
step2. FastCGI进程管理器自身初始化,启动多个CGI解释器进程并等待来自Web 服务器的连接。启动FastCGI进程时,可以配置以ip和UNIX 域socket两种方式启动。
-
step3. 当客户端请求到达Web 服务器时, Web 服务器将请求采用socket方式转发到 FastCGI主进程,FastCGI主进程选择并连接到一个CGI解释器。Web 服务器将CGI环境变量和标准输入发送到FastCGI子进程。
-
step4. FastCGI子进程完成处理后将标准输出和错误信息从同一socket连接返回Web 服务器。当FastCGI子进程关闭连接时,请求便处理完成。
-
step5. FastCGI子进程接着等待并处理来自Web 服务器的下一个连接。
由于 FastCGI 程序并不需要不断的产生新进程,可以大大降低服务器的压力并且产生较高的应用效率。它的速度效率最少要比CGI 技术提高 5 倍以上。它还支持分布式的部署, 即 FastCGI 程序可以在web 服务器以外的主机上执行。
总结:CGI 就是所谓的短生存期应用程序,FastCGI 就是所谓的长生存期应用程序。FastCGI像是一个常驻(long-live)型的CGI,它可以一直执行着,不会每次都要花费时间去fork一次(这是CGI最为人诟病的fork->and->exec 模式)。
nginx cgi/fastcgi
nginx 不能像apache那样直接执行外部可执行程序,但nginx可以作为代理服务器,将请求转发给后端服务器,这也是nginx的主要作用之一。其中nginx就支持FastCGI代理,接收客户端的请求,然后将请求转发给后端fastcgi进程。下面介绍如何使用C/C++编写cgi/fastcgi,并部署到nginx中。
nginx + fastcgi
通过前面的介绍知道,fastcgi进程由FastCGI进程管理器管理,而不是nginx。这样就需要一个FastCGI管理,管理我们编写fastcgi程序。本文使用spawn-fcgi作为FastCGI进程管理器。
- spawn-fcgi
spawn-fcgi是一个通用的FastCGI进程管理器,简单小巧,原先是属于lighttpd的一部分,后来由于使用比较广泛,所以就迁移出来作为独立项目了。spawn-fcgi使用pre-fork 模型,功能主要是打开监听端口,绑定地址,然后fork-and-exec创建我们编写的fastcgi应用程序进程,退出完成工作。fastcgi应用程序初始化,然后进入死循环侦听socket的连接请求。 - 安装spawn-fcgi:
-
获取spawn-fcgi编译安装包,在http://redmine.lighttpd.net/projects/spawn-fcgi/wiki上可以获取当前最新的版本。
-
解压缩spawn-fcgi-x.x.x.tar.gz包。
-
进入解压缩目录,执行./configure。
-
make & make install
如果遇到以下错误:“ ./autogen.sh: x: autoreconf: not found”,因为没有安装automake 工具,ubuntu用下面的命令安装好就可以了:sudo apt-get install autoconf automake libtool 。
spawn-fcgi的帮助信息可以通过man spawn-fcgi或spawn-fcgi –h获得,下面是部分常用spawn-fcgi参数信息:
-
-f 指定调用FastCGI的进程的执行程序位置
-
-a 绑定到地址addr。
-
-p 绑定到端口port。
-
-s
绑定到unix domain socket -
-C 指定产生的FastCGI的进程数,默认为5。(仅用于PHP)
-
-P
指定产生的进程的PID文件路径。 -
-F 指定产生的FastCGI的进程数(C的CGI用这个)
-u和-g FastCGI使用什么身份(-u 用户 -g 用户组)运行,CentOS下可以使用apache用户,其他的根据情况配置,如nobody、www-data等。
- 编写fastcgi应用程序
使用C/C++编写fastcgi应用程序,可以使用FastCGI软件开发套件或者其它开发框架,如fastcgi++。
本文使用FastCGI软件开发套件——fcgi(http://www.fastcgi.com/drupal/node/6?q=node/21),通过此套件可以轻松编写fastcgi应用程序,安装fcgi:
-
获取fcgi编译安装包,在http://www.fastcgi.com/drupal/node/5上可以获取当前最新的版本。
-
解压缩fcgi-x.x.x.tar.gz包。
-
进入解压缩目录,执行./configure。
-
make & make install
如果编译提示一下错误:
fcgio.cpp: In destructor 'virtual fcgi_streambuf::~fcgi_streambuf()':
fcgio.cpp:50: error: 'EOF' was not declared in this scope
fcgio.cpp: In member function 'virtual int fcgi_streambuf::overflow(int)':
fcgio.cpp:70: error: 'EOF' was not declared in this scope
fcgio.cpp:75: error: 'EOF' was not declared in this scope
fcgio.cpp: In member function 'virtual int fcgi_streambuf::sync()':
fcgio.cpp:86: error: 'EOF' was not declared in this scope
fcgio.cpp:87: error: 'EOF' was not declared in this scope
fcgio.cpp: In member function 'virtual int fcgi_streambuf::underflow()':
fcgio.cpp:113: error: 'EOF' was not declared in this scope
make[2]: *** [fcgio.lo] Error 1
make[2]: Leaving directory `/root/downloads/fcgi-2.4.1-SNAP-0910052249/libfcgi'
make[1]: *** [all-recursive] Error 1
make[1]: Leaving directory `/root/downloads/fcgi-2.4.1-SNAP-0910052249'
make: *** [all] Error 2
解决办法:在/include/fcgio.h文件中加上 #include ,然后再编译安装就通过了。
如果提示找不到动态库,请在LD_LIBRARY_PATH或/etc/ld.so.conf中添加fcgi的安装路径,如/usr/local/lib,并执行ldconfig更新一下。
#include "fcgi_stdio.h"
#include <stdlib.h>
int main(void)
{
int count = 0;
while (FCGI_Accept() >= 0)
printf("Content-type: text/html\r\n"
"\r\n"
"<title>FastCGI Hello!</title>"
"<h1>FastCGI Hello!</h1>"
"Request number %d running on host <i>%s</i>\n",
++count, getenv("SERVER_NAME"));
return 0;
}
编译并将demo部署到/opt/nginx-1.26.3/cgi-bin/目录
g++ main.cpp -o demo -L /opt/fcgi-2.4.1/include –lfcg
通过spawn-fcgi启动c/c++编写好的fastcgi程序:
/opt/spawn-fcgi-1.6.5/bin/spawn-fcgi -a 127.0.0.1 -p 8081 -f /opt/nginx-1.26.3/cgi-bin/demo
- nginx fastcgi配置
关于nginx的几个配置文件解析,可以参阅《Nginx安装与使用》http://www.cnblogs.com/skynet/p/4146083.html,在上篇的nginx.conf基础上增加下面的fastcgi配置。
这样nginx收到http://localhost/demo.cgi请求时,会匹配到location = /demo.cgi块,将请求传到后端的fastcgi应用程序处理。
nginx + cgi
nginx 不能直接执行外部可执行程序,并且cgi是接收到请求时才会启动cgi进程,不像fastcgi会在一开就启动好,这样nginx天生是不支持 cgi 的。nginx 虽然不支持cgi,但它支持 fastCGI。所以,我们可以考虑使用fastcgi包装来支持 cgi。原理大致如下图所示:pre-fork几个通用的代理fastcgi程序——fastcgi-wrapper,fastcgi-wrapper启动执行cgi然后将cgi的执行结果返回给nginx(fork-and-exec)。
明白原理之后,编写一个fastcgi-warpper也比较简单。网上流传比较多的一个解决方案是,来自nginx wiki(http://wiki.nginx.org/SimpleCGI)上的使用perl的fastcgi包装脚本cgiwrap-fcgi.pl。但我对perl不是很感冒,下面给出一个C/C++写的fastcgi-wrapper。
- fastcgi-wrapper
其实编写C/C++的fastcgi-wrapper,就是写一个C/C++的fastcgi,步骤和原理跟前面的小节(nginx+fastcgi)一样。github上已经有人开源了,C写的fastcgi-wrapper:https://github.com/gnosek/fcgiwrap。
安装fcgiwrap:
-
下载(https://github.com/gnosek/fcgiwrap.git)
-
解压缩fcgiwrap,进入解压目录
autoreconf -i
./configure
make && make install
- 启动fastcgi-wrapper:
/opt/spawn-fcgi-1.6.5/bin/spawn-fcgi -f /usr/local/sbin/fcgiwrap -p 8081
- nginx fcgiwrap配置
在nginx.conf中增加下面的loaction配置块,这样所有的xxx.cgi请求都会走到fcgiwrap,然后fcgiwrap会执行cgi-bin目录下的cgi程序。
- 编写cgi应用程序
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int count = 0;
printf("Content-type: text/html\r\n"
"\r\n"
"<title>CGI Hello!</title>"
"<h1>CGI Hello!</h1>"
"Request number %d running on host <i>%s</i>\n",
++count, getenv("SERVER_NAME"));
return 0;
}
g++ cgi.cpp -o cgidemo -lfcgi
sudo cp cgidemo /opt/nginx-1.26.2/cgi-bin/
注意:cgi的模式是fork->and->exec,每次都是一个新的进程。
在 Linux 下开发一个 Web 界面,允许用户通过外网浏览并配置设备程序参数(如无线网通信参数)
可以分为几个步骤来实现。以下是一个详细的指南,包括后端服务、Web 前端和 Nginx 配置
- 后端服务
首先,你需要一个后端服务来处理用户的请求,并与设备进行交互。这里我们使用 Python 的 Flask 框架来实现一个简单的后端服务。
安装 Flask
pip install flask
创建后端服务
创建一个文件 app.py:
from flask import Flask, request, jsonify
app = Flask(__name__)
# 模拟设备的无线网通信参数
device_config = {
'ssid': '',
'password': ''
}
@app.route('/config', methods=['GET'])
def get_config():
return jsonify(device_config)
@app.route('/config', methods=['POST'])
def set_config():
data = request.json
if 'ssid' in data and 'password' in data:
device_config['ssid'] = data['ssid']
device_config['password'] = data['password']
# 这里可以调用实际的设备配置函数
return jsonify({'status': 'success'})
else:
return jsonify({'status': 'error', 'message': 'Invalid parameters'}), 400
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000)
- Web 前端
接下来,创建一个简单的 HTML 页面,允许用户输入无线网通信参数并提交。
创建前端文件
在同一个目录下创建 index.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Device Configuration</title>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
</head>
<body>
<h1>Configure Device Wireless Parameters</h1>
<form id="config-form">
<label for="ssid">SSID:</label>
<input type="text" id="ssid" name="ssid" required><br><br>
<label for="password">Password:</label>
<input type="password" id="password" name="password" required><br><br>
<button type="submit">Submit</button>
</form>
<div id="response"></div>
<script>
$(document).ready(function() {
$('#config-form').on('submit', function(event) {
event.preventDefault();
const ssid = $('#ssid').val();
const password = $('#password').val();
$.ajax({
url: '/config',
method: 'POST',
contentType: 'application/json',
data: JSON.stringify({ ssid: ssid, password: password }),
success: function(response) {
$('#response').text('Configuration successful');
},
error: function(error) {
$('#response').text('Error: ' + error.responseJSON.message);
}
});
});
// Fetch current configuration
$.get('/config', function(data) {
$('#ssid').val(data.ssid);
$('#password').val(data.password);
});
});
</script>
</body>
</html>
- Nginx 配置
为了使 Web 界面可以通过外网访问,我们需要配置 Nginx 作为反向代理。
配置 Nginx
编辑 Nginx 配置文件 /etc/nginx/sites-available/default:
server {
listen 80;
server_name your_domain_or_ip;
location / {
proxy_pass http://127.0.0.1:5000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
location /static/ {
alias /path/to/your/static/files/;
}
}
确保将 your_domain_or_ip 替换为你的域名或 IP 地址,并将 /path/to/your/static/files/ 替换为你的静态文件目录。
重启 Nginx
sudo systemctl restart nginx
- 运行后端服务
确保你的后端服务正在运行:
python app.py
-
测试
现在,你可以通过浏览器访问 http://your_domain_or_ip 来配置设备的无线网通信参数。 -
安全性考虑
为了确保安全性,建议采取以下措施:
SSL/TLS:使用 HTTPS 保护数据传输。你可以使用 Let’s Encrypt 为你的域名免费获取 SSL 证书。
身份验证:添加用户认证机制,确保只有授权用户可以访问和修改配置。
防火墙:配置防火墙规则,限制对外网的访问。
通过以上步骤,你可以在 Linux 下开发一个 Web 界面,允许用户通过外网浏览并配置设备程序参数。