linux下web高性能服务器搭建及部署Nginx


简介


(百度百科- 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依赖以下模块

  1. gzip模块需要 zlib 库
  2. rewrite模块需要 pcre 库
  3. ssl 功能需要openssl库

安装pcre

  1. 获取pcre编译安装包,在http://www.pcre.org/上可以获取当前最新的版本
  2. 解压缩pcre-xx.tar.gz包
  3. 进入解压缩目录,执行./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
  1. make & make install

安装openssl

  1. 获取openssl编译安装包,在http://www.openssl.org/source/上可以获取当前最新的版本。
  2. 解压缩openssl-xx.tar.gz包。
  3. 进入解压缩目录,执行./configure,配置安装位置及交叉编译器根据自己使用修改
  4. make & make install

安装zlib

  1. 获取zlib编译安装包,在http://www.zlib.net/上可以获取当前最新的版本
  2. 解压缩openssl-xx.tar.gz包
  3. 进入解压缩目录,执行./configure,配置安装位置及交叉编译器根据自己使用修改
  4. make & make install

安装nginx

  1. 获取nginx,在http://nginx.org/en/download.html上可以获取当前最新的版本
  2. 解压缩nginx-xx.tar.gz包。
  3. 进入解压缩目录,执行./configure
  4. 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;
    #    }
    #}

}


  1. worker_process表示工作进程的数量,一般设置为cpu的核数
  2. worker_connections表示每个工作进程的最大连接数
  3. server{}块定义了虚拟主机
  4. listener监听端口
  5. server_name监听域名
  6. location{}是用来为匹配的 URI 进行配置,URI 即语法中的“/uri/”。location / {
    }匹配任何查询,因为所有请求都以 / 开头。
  7. root指定对应uri的资源查找路径,这里html为相对路径,完整路径为/opt/ /opt/nginx-1.26.2/html/
  8. 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_ADDRclient端的host名称
REMOTE_HOSTclient端的IP位址
REMOTE_USERclient端送出来的使用者名称
REMOTE_METHODclient端发出请求的方法(如get、post)
SCRIPT_NAMECGI程式所在的虚拟路径,如/cgi-bin/echo
SERVER_NAMEserver的host名称或IP地址
SERVER_PORT收到request的server端口
SERVER_PROTOCOL所使用的通讯协定和版本编号
SERVER_SOFTWAREserver程序的名称和版本

标准输入

环境变量的大小是有一定的限制的,当需要传送的数据量大时,储存环境变量的空间可能会不足,造成数据接收不完全,甚至无法执行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进程管理器。

  1. spawn-fcgi
    spawn-fcgi是一个通用的FastCGI进程管理器,简单小巧,原先是属于lighttpd的一部分,后来由于使用比较广泛,所以就迁移出来作为独立项目了。spawn-fcgi使用pre-fork 模型,功能主要是打开监听端口,绑定地址,然后fork-and-exec创建我们编写的fastcgi应用程序进程,退出完成工作。fastcgi应用程序初始化,然后进入死循环侦听socket的连接请求。
  2. 安装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等。

  1. 编写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 
  1. 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。

  1. 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
  1. nginx fcgiwrap配置

在nginx.conf中增加下面的loaction配置块,这样所有的xxx.cgi请求都会走到fcgiwrap,然后fcgiwrap会执行cgi-bin目录下的cgi程序。

  1. 编写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 配置

  1. 后端服务
    首先,你需要一个后端服务来处理用户的请求,并与设备进行交互。这里我们使用 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)
  1. 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>
  1. 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
  1. 运行后端服务
    确保你的后端服务正在运行:
python app.py
  1. 测试
    现在,你可以通过浏览器访问 http://your_domain_or_ip 来配置设备的无线网通信参数。

  2. 安全性考虑
    为了确保安全性,建议采取以下措施:
    SSL/TLS:使用 HTTPS 保护数据传输。你可以使用 Let’s Encrypt 为你的域名免费获取 SSL 证书。
    身份验证:添加用户认证机制,确保只有授权用户可以访问和修改配置。
    防火墙:配置防火墙规则,限制对外网的访问。
    通过以上步骤,你可以在 Linux 下开发一个 Web 界面,允许用户通过外网浏览并配置设备程序参数。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

lengkp

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值