Apache和Nginx是目前比较流行的两种常用于PHP的开源Web服务器。当托管具有不同要求的多个网站时,在同一虚拟机上运行它们会很有用。在单个系统上运行两个Web服务器的一般解决方案是使用多个IP地址或不同的端口号。
同时具有IPv4和IPv6地址的服务器可以配置为在一种协议上为Apache站点服务,在另一种协议上为Nginx站点服务,但这目前还不实用,因为ISP对IPv6的采用仍然不普遍。拥有一个不同的端口号比如81
或8080
,对于第二web服务器来说是另一种解决方案,但与端口号分享的网址(例如http://example.com:81
)并不总是合理的或是理想的。
在本教程中,您将Nginx配置为Web服务器和Apache的反向代理 - 并且所有的这些都会在一台服务器上实现。
根据Web应用程序的不同,可能需要更改代码以保持Apache反向代理感知,尤其是在配置SSL站点时。为避免这种情况,您将安装一个名为mod_rpaf
的Apache模块,该模块会重写某些环境变量,让Apache看起来似乎是在直接处理来自Web客户端的请求。
我们将在一台服务器上托管四个域名。两个将由Nginx服务: example.com
(默认的虚拟主机)和sample.org
。Apache将服务剩下的两个域名:foobar.net
并且test.io
。我们还将使用PHP-FPM配置Apache,然后来为PHP应用程序提供服务,这样可以比mod_php
提供更好的性能。
要完成本教程,您需要以下内容:
让我们从安装Apache和PHP-FPM开始。
除了Apache和PHP-FPM之外,我们还将安装PHP FastCGI Apache模块,libapache2-mod-fastcgi
,以支持FastCGI Web应用程序。
首先,更新您的包列表以确保您拥有最新的包。
sudo apt update
接下来,安装Apache和PHP-FPM包:
sudo apt install apache2 php-fpm
FastCGI Apache模块在Ubuntu的存储库中不可用,因此从kernel.org下载并使用dpkg
命令安装它。
wget https://mirrors.edge.kernel.org/ubuntu/pool/multiverse/liba/libapache-mod-fastcgi/libapache2-mod-fastcgi_2.4.7~0910052141-1.2_amd64.deb
sudo dpkg -i libapache2-mod-fastcgi_2.4.7~0910052141-1.2_amd64.deb
接下来,让我们更改Apache的默认配置以使用PHP-FPM。
在此步骤中,我们将把Apache的端口号更改为8080
并将其配置为使用mod_fastcgi
模块与PHP-FPM配合使用。重命名Apache的ports.conf
配置文件:
sudo mv /etc/apache2/ports.conf /etc/apache2/ports.conf.default
创建一个端口设置8080
为的新文件ports.conf
:
echo "Listen 8080" | sudo tee /etc/apache2/ports.conf
注意: Web服务器通常设置为在配置反向代理时监听127.0.0.1:8080
,但这样做会将PHP的环境变量SERVER_ADDR的值设置为环回IP地址而不是服务器的公共IP。我们的目标是以这样的方式设置Apache,使其网站不会在其前面看到反向代理。因此,我们将其配置为所有IP地址都侦听8080
。
接下来,我们将为Apache创建一个虚拟主机文件。此<VirtualHost>
文件中的指令将设置为仅在端口8080
上提供站点。
禁用默认虚拟主机:
sudo a2dissite 000-default
然后使用现有的默认站点创建一个新的虚拟主机文件:
sudo cp /etc/apache2/sites-available/000-default.conf /etc/apache2/sites-available/001-default.conf
现在打开新的配置文件:
sudo nano /etc/apache2/sites-available/001-default.conf
将侦听端口更改为8080
:
<VirtualHost *:8080>
ServerAdmin webmaster@localhost
DocumentRoot /var/www/html
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>
保存文件并激活新配置文件:
sudo a2ensite 001-default
然后重新加载Apache:
sudo systemctl reload apache2
验证Apache现在正在侦听8080
:
sudo netstat -tlpn
输出的内容应该类似于以下示例,并通过apache2
监听8080
:
Output
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 1086/sshd
tcp6 0 0 :::8080 :::* LISTEN 4678/apache2
tcp6 0 0 :::22 :::* LISTEN 1086/sshd
一旦验证Apache正在侦听正确的端口,就可以配置对PHP和FastCGI的支持。
Apache默认使用 mod_php
来提供PHP页面,但它需要额外的配置才能使用PHP-FPM。
注意:如果您在使用mod_php的现有LAMP安装上尝试本教程,请首先禁用sudo a2dismod php7.2
。
我们将添加一个依赖于mod_action
的配置块mod_fastcgi
。在默认情况下mod_action
已禁用,因此我们首先需要启用它:
sudo a2enmod actions
重命名现有的FastCGI配置文件:
sudo mv /etc/apache2/mods-enabled/fastcgi.conf /etc/apache2/mods-enabled/fastcgi.conf.default
创建一个新的配置文件:
sudo nano /etc/apache2/mods-enabled/fastcgi.conf
将以下指令添加到文件以将.php
文件的请求传递到PHP-FPM UNIX套接字:
<IfModule mod_fastcgi.c>
AddHandler fastcgi-script .fcgi
FastCgiIpcDir /var/lib/apache2/fastcgi
AddType application/x-httpd-fastphp .php
Action application/x-httpd-fastphp /php-fcgi
Alias /php-fcgi /usr/lib/cgi-bin/php-fcgi
FastCgiExternalServer /usr/lib/cgi-bin/php-fcgi -socket /run/php/php7.2-fpm.sock -pass-header Authorization
<Directory /usr/lib/cgi-bin>
Require all granted
</Directory>
</IfModule>
保存更改并进行配置测试:
sudo apachectl -t
如果显示Syntax OK 则重新加载Apache :
sudo systemctl reload apache2
如果您看到警告Could not reliably determine the server's fully qualified domain name, using 127.0.1.1. Set the 'ServerName' directive globally to suppress this message.
,您现在可以放心地忽略它。我们稍后会配置服务器名称。
现在让我们确保我们可以从Apache提供PHP。
我们确保PHP能正常工作的原理是,创建一个phpinfo()
文件并从Web浏览器访问它。
创建包含能够调用phpinfo
函数的/var/www/html/info.php
文件:
echo "<?php phpinfo(); ?>" | sudo tee /var/www/html/info.php
要在浏览器中查看文件,请转到http://your_server_ip:8080/info.php
。这将为您提供PHP正在使用的配置设置列表。您将看到类似于此的输出:
在页面的顶部,检查服务器API设置为FPM / FastCGI。接下来大约三分之二的页面,PHP变量部分将告诉你SERVER_SOFTWARE是Ubuntu上的Apache。这些将用来确认mod_fastcgi
是活动的,并且Apache正在使用PHP-FPM来处理PHP文件。
现在让我们为域foobar.net
和域test.io
创建Apache虚拟主机文件。为了完成这项任务,我们首先为两个站点创建文档根目录,并将一些默认文件放在这些目录中,以便我们可以轻松地测试我们的配置。
首先,创建文档根目录:
sudo mkdir -v /var/www/foobar.net /var/www/test.io
然后为每个站点创建一个index
文件:
echo "<h1 style='color: green;'>Foo Bar</h1>" | sudo tee /var/www/foobar.net/index.html
echo "<h1 style='color: red;'>Test IO</h1>" | sudo tee /var/www/test.io/index.html
然后为每个站点创建一个phpinfo()
文件,以便我们可以测试PHP配置是否正确。
echo "<?php phpinfo(); ?>" | sudo tee /var/www/foobar.net/info.php
echo "<?php phpinfo(); ?>" | sudo tee /var/www/test.io/info.php
现在为foobar.net
域创建虚拟主机文件:
sudo nano /etc/apache2/sites-available/foobar.net.conf
将以下代码添加到文件中以定义主机:
<VirtualHost *:8080>
ServerName foobar.net
ServerAlias www.foobar.net
DocumentRoot /var/www/foobar.net
<Directory /var/www/foobar.net>
AllowOverride All
</Directory>
</VirtualHost>
该AllowOverride All
线使.htaccess
可以提供支持。
保存并关闭文件。然后为test.io
创建一个类似的配置。首先创建文件:
sudo nano /etc/apache2/sites-available/test.io.conf
然后将配置添加到文件中:
<VirtualHost *:8080>
ServerName test.io
ServerAlias www.test.io
DocumentRoot /var/www/test.io
<Directory /var/www/test.io>
AllowOverride All
</Directory>
</VirtualHost>
保存文件并退出编辑器。
现在已设置两个Apache虚拟主机,请使用命令a2ensite
启用站点。这将创建指向sites-enabled
目录中虚拟主机文件的符号链接:
sudo a2ensite foobar.net
sudo a2ensite test.io
再次检查Apache的配置错误:
sudo apachectl -t
如果没有错误,您将看到SyntaxOK。如果您看到其他内容,请查看配置并重试。
重新加载Apache以在配置无错误后应用更改:
sudo systemctl reload apache2
为了证实该网站是否在运作,在浏览器中打开http://foobar.net:8080
和http://test.io:8080
,验证每个站点显示其index.html文件。
您将看到以下结果:
此外,通过访问每个站点的info.php文件来确保PHP正常工作。并在您的浏览器中访问http://foobar.net:8080/info.php
和http://test.io:8080/info.php
。
您将在步骤4中看到每个站点上的相同PHP配置规范列表。
我们现在就在端口8080
上已经有了两个托管在Apache上的网站。接下来让我们配置Nginx。
在这一步中,我们将安装Nginx并配置域example.com
和域sample.org
成为Nginx的虚拟主机。
使用包管理器安装Nginx:
sudo apt install nginx
然后删除默认虚拟主机的符号链接,因为我们将不再使用它:
sudo rm /etc/nginx/sites-enabled/default
我们稍后会创建自己的默认网站(example.com
)。
现在我们将为Nginx创建虚拟主机,该过程与为Apache创建虚拟主机的过程。首先为两个网站创建文档根目录:
sudo mkdir -v /usr/share/nginx/example.com /usr/share/nginx/sample.org
我们将在/usr/share/nginx
上保留Nginx网站,这是Nginx默认需要的网站。您可以将它们和Apache站点一起放在/var/www/html
下,但这种分离可以帮助您将站点与Nginx相关联。
正如您在Apache的虚拟主机上所做的那样,在安装完成后创建index
和phpinfo()
文件以进行测试:
echo "<h1 style='color: green;'>Example.com</h1>" | sudo tee /usr/share/nginx/example.com/index.html
echo "<h1 style='color: red;'>Sample.org</h1>" | sudo tee /usr/share/nginx/sample.org/index.html
echo "<?php phpinfo(); ?>" | sudo tee /usr/share/nginx/example.com/info.php
echo "<?php phpinfo(); ?>" | sudo tee /usr/share/nginx/sample.org/info.php
现在为域example.com
创建一个虚拟主机文件:
sudo nano /etc/nginx/sites-available/example.com
Nginx调用server {. . .}
使其成为配置文件服务器块的的区域。为主虚拟主机example.com
创建服务器块。该default_server
配置指令使得该处理HTTP请求的默认虚拟主机,不与其他任何虚拟主机相匹配。
server {
listen 80 default_server;
root /usr/share/nginx/example.com;
index index.php index.html index.htm;
server_name example.com www.example.com;
location / {
try_files $uri $uri/ /index.php;
}
location ~ \.php$ {
fastcgi_pass unix:/run/php/php7.2-fpm.sock;
include snippets/fastcgi-php.conf;
}
}
保存并关闭文件。现在为Nginx的第二个域sample.org
创建一个虚拟主机文件:
sudo nano etc/nginx/sites-available/sample.org
将以下内容添加到文件中:
server {
root /usr/share/nginx/sample.org;
index index.php index.html index.htm;
server_name sample.org www.sample.org;
location / {
try_files $uri $uri/ /index.php;
}
location ~ \.php$ {
fastcgi_pass unix:/run/php/php7.2-fpm.sock;
include snippets/fastcgi-php.conf;
}
}
保存并关闭文件。
然后通过创建指向sites-enabled
目录的符号链接来启用这两个站点:
sudo ln -s /etc/nginx/sites-available/example.com /etc/nginx/sites-enabled/example.com
sudo ln -s /etc/nginx/sites-available/sample.org /etc/nginx/sites-enabled/sample.org
然后测试Nginx配置以确保没有配置问题:
sudo nginx -t
如果没有错误,则重新加载Nginx:
sudo systemctl reload nginx
现在通过在Nginx虚拟主机的Web浏览器中访问http://example.com/info.php>和http://sample.org/info.php来进入phpinfo()
文件。现在再次转向PHP Variables部分。
[“SERVER_SOFTWARE”]应该说nginx
,表明这些文件是由Nginx直接提供的。[“DOCUMENT_ROOT”]应指向您在此步骤中为每个Nginx站点创建的目录。
此时,我们已经安装了Nginx并创建了两个虚拟主机。接下来,我们将配置Nginx以代理针对Apache上托管的域的请求。
让我们在server_name
指令中创建一个具有多个域名的额外Nginx虚拟主机。对这些域名的请求将代理到Apache。
创建一个新的Nginx虚拟主机文件以将请求转发给Apache:
sudo nano /etc/nginx/sites-available/apache
添加以下代码块,该代码块指定两个Apache虚拟主机域的名称,并将其请求代理到Apache。请记住在proxy_pass
中使用公共IP地址:
server {
listen 80;
server_name foobar.net www.foobar.net test.io www.test.io;
location / {
proxy_pass http://your_server_ip:8080;
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;
}
}
保存文件并通过创建符号链接启用此新虚拟主机:
sudo ln -s /etc/nginx/sites-available/apache /etc/nginx/sites-enabled/apache
测试配置以确保没有错误:
sudo nginx -t
如果没有错误,请重新加载Nginx:
sudo systemctl reload nginx
打开浏览器并访问浏览器中的URLhttp://foobar.net/info.php
。向下滚动到PHP Variables部分并检查显示的值。
变量SERVER_SOFTWARE和DOCUMENT_ROOT的出现就表明此请求是由Apache处理的。变量HTTP_X_REAL_IP和HTTP_X_FORWARDED_FOR由Nginx添加,并应显示您用于访问URL的计算机的公共IP地址。
我们已成功设置Nginx以将特定域的请求代理到Apache。接下来,让我们配置Apache来设置REMOTE_ADDR
变量,以使它看起来像是在直接处理这些请求一样。
在此步骤中,您将安装一个名为mod\_rpaf
的Apache模块,该模块根据反向代理提供的值重写REMOTE_ADDR,HTTPS和HTTP_PORT的值。如果没有此模块,某些PHP应用程序将需要更改代码才能从代理后面无缝地工作。该模块以libapache2-mod-rpaf
的形式存在于Ubuntu的存储库中,但它现在已过时,并且不支持某些配置指令。因此,我们将从源代码安装它。
安装构建模块所需的包:
sudo apt install unzip build-essential apache2-dev
从GitHub下载最新的稳定版本:
wget https://github.com/gnif/mod_rpaf/archive/stable.zip
解压缩下载的文件:
unzip stable.zip
切换到包含文件的新目录:
cd mod_rpaf-stable
编译并安装模块:
make
sudo make install
接下来,在目录mods-available
中创建一个可以加载rpaf
模块的文件:
sudo nano /etc/apache2/mods-available/rpaf.load
将以下代码添加到文件以加载模块:
LoadModule rpaf_module /usr/lib/apache2/modules/mod_rpaf.so
保存文件并退出编辑器。
在此目录中创建另一个名为rpaf.conf
的文件,该文件包含着给mod_rpaf
的配置指令:
sudo nano /etc/apache2/mods-available/rpaf.conf
添加以下代码块来配置mod_rpaf
,并且确保指定服务器的IP地址:
<IfModule mod_rpaf.c>
RPAF_Enable On
RPAF_Header X-Real-Ip
RPAF_ProxyIPs your_server_ip
RPAF_SetHostName On
RPAF_SetHTTPS On
RPAF_SetPort On
</IfModule>
以下是每个指令的简要说明。有关更多信息,请参阅mod_rpaf
自述文件。
ServerName
和ServerAlias
工作。X-Forwarded-Proto
中包含的值来设置HTTPS
环境变量。SERVER_PORT
环境变量。该项设置将在Apache位于SSL代理之后时变得非常有用。保存rpaf.conf
并启用该模块:
sudo a2enmod rpaf
这将为mods-enabled
目录中的rpaf.load
和rpaf.conf
文件创建符号链接。现在进行配置测试:
sudo apachectl -t
如果没有错误,请重新加载Apache:
sudo systemctl reload apache2
在你的浏览器中的http://foobar.net/info.php
和http://test.io/info.php
中访问 phpinfo()
并查看PHP变量部分。该REMOTE_ADDR变量现在也将是你的本地计算机的公网IP地址。
现在让我们为每个站点设置TLS / SSL加密。
由于Apache正在端口8080
上侦听公共IP地址,因此每个人都可以访问它。可以通过将以下IPtables命令用于防火墙规则集来阻止它。
sudo iptables -I INPUT -p tcp --dport 8080 ! -s your_server_ip -j REJECT --reject-with tcp-reset
请务必使用服务器的IP地址代替红色的示例。在防火墙中阻止端口8080
后,将无法用它来测试Apache。打开Web浏览器,尝试在端口8080
上访问Apache的一个域名。例如:http:// example.com:8080
浏览器应显示“无法连接”或“网页不可用”错误消息。有了IPtables tcp-reset
选项,外人就会发现在有端口8080
和没有任何服务的端口之间并没有区别。
注意:默认情况下,IPtables规则在系统重新引导后无法生存。有多种方法可以保留IPtables规则,但最简单的方法是在Ubuntu的存储库中使用iptables-persistent
。现在让我们配置Nginx为Apache站点提供静态文件。
当Nginx代理对Apache域的请求时,它会将该域的每个文件请求发送给Apache。在提供图像,JavaScript和样式表等静态文件时,Nginx比Apache更快。因此,让我们配置Nginx的apache
虚拟主机文件来直接提供静态文件,但是却将PHP请求发送到Apache。
在编辑器中打开文件/etc/nginx/sites-available/apache
:
sudo nano /etc/nginx/sites-available/apache
您需要为每个服务器块添加两个附加location
块,以及修改现有location
部分。此外,您还需要告诉Nginx在哪里可以找到每个站点的静态文件。
如果您决定不使用SSL和TLS证书,请修改您的文件,使其如下所示:
server {
listen 80;
server_name test.io www.test.io;
root /var/www/test.io;
index index.php index.htm index.html;
location / {
try_files $uri $uri/ /index.php;
}
location ~ \.php$ {
proxy_pass http://your_server_ip:8080;
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 ~ /\.ht {
deny all;
}
}
server {
listen 80;
server_name foobar.net www.foobar.net;
root /var/www/foobar.net;
index index.php index.htm index.html;
location / {
try_files $uri $uri/ /index.php;
}
location ~ \.php$ {
proxy_pass http://your_ip_address:8080;
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 ~ /\.ht {
deny all;
}
}
如果您还希望HTTPS可用,请改用以下配置:
server {
listen 80;
server_name test.io www.test.io;
root /var/www/test.io;
index index.php index.htm index.html;
location / {
try_files $uri $uri/ /index.php;
}
location ~ \.php$ {
proxy_pass http://your_server_ip:8080;
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 ~ /\.ht {
deny all;
}
listen 443 ssl;
ssl_certificate /etc/letsencrypt/live/test.io/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/test.io/privkey.pem;
include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
}
server {
listen 80;
server_name foobar.net www.foobar.net;
root /var/www/foobar.net;
index index.php index.htm index.html;
location / {
try_files $uri $uri/ /index.php;
}
location ~ \.php$ {
proxy_pass http://your_ip_address:8080;
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 ~ /\.ht {
deny all;
}
listen 443 ssl;
ssl_certificate /etc/letsencrypt/live/foobar.net/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/foobar.net/privkey.pem;
include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
}
该try_files
指令使Nginx在文档根目录中查找文件并直接为它们提供服务。如果文件具有.php
扩展名,则将请求传递给Apache。即使在文档根目录中找不到该文件,该请求也会传递给Apache,因此永久链接等应用程序功能可以正常工作。
警告:该location ~ /\.ht
指令非常重要; 这防止Nginx为含有敏感信息的Apache配置文件提供服务,比如.htaccess
和.htpasswd
。
保存文件并执行配置测试:
sudo nginx -t
如果测试成功,请重新加载Nginx:
sudo service nginx reload
为了验证一切正常,你可以在/var/log/apache2
中检查Apache的日志文件,看到info.php
文件中为test.io
和foobar.net
提供的GET
的请求。使用该tail
命令查看文件的最后几行,并使用-f
开关查看文件以进行更改:
sudo tail -f /var/log/apache2/other_vhosts_access.log
现在您的浏览器中访问http://test.io/info.php
,然后查看日志中的输出。您会看到Apache确实在回复:
Output
test.io:80 your_server_ip - - [01/Jul/2016:18:18:34 -0400] "GET /info.php HTTP/1.0" 200 20414 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.111 Safari/537.36"
然后访问每个站点的index.html
页面,您将看不到Apache的任何日志条目。因为Nginx正在为他们服务。
完成观察日志文件后,按CTRL+C
停止拖尾。
通过此设置,Apache将无法限制对静态文件的访问。需要在Nginx中的apache
虚拟主机文件中配置静态文件的访问控制,但这超出了本教程的范围。
你现在有一个Ubuntu的服务器并且用Nginx为example.com
和sample.org
提供服务,同时与Apache一起服务foobar.net
和test.io
。虽然Nginx充当Apache的反向代理,但Nginx的代理服务是透明的,与Apache域的连接似乎直接来自Apache本身。您可以使用此方法来提供安全和静态站点。
更多Ubuntu教程请前往腾讯云+社区学习更多知识。
参考文献:《How To Configure Nginx as a Web Server and Reverse Proxy for Apache on One Ubuntu 18.04 Server》
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。