The author selected the Electronic Frontier Foundation to receive a donation as part of the Write for DOnations program.
Apache and Nginx are two popular open-source web servers often used with PHP. It can be useful to run both of them on the same virtual machine when hosting multiple websites that have varied requirements. The general solution for running two web servers on a single system is to either use multiple IP addresses or different port numbers.
Servers that have both IPv4 and IPv6 addresses can be configured to serve Apache sites on one protocol and Nginx sites on the other, but this isn’t currently practical, as IPv6 adoption by ISPs is still not widespread. Having a different port number like 81
or 8080
for the second web server is another solution, but sharing URLs with port numbers (such as http://your_domain:81
) isn’t always reasonable or ideal.
In this tutorial you’ll configure Nginx as both a web server and as a reverse proxy for Apache – all on a single server.
Depending on the web application, code changes might be required to keep Apache reverse-proxy-aware, especially when SSL sites are configured. To avoid this, you will install an Apache module called mod_rpaf
which rewrites certain environment variables so it appears that Apache is directly handling requests from web clients.
We will host four domain names on one server. Two will be served by Nginx: nginx1.your_domain
(the default virtual host) and nginx2.your_domain
. The remaining two, apache1.your_domain
and apache2.your_domain
, will be served by Apache. We’ll also configure Apache to serve PHP applications using PHP-FPM, which offers better performance over mod_php
.
To complete this tutorial, you’ll need the following:
Let’s start by installing Apache and PHP-FPM.
In addition to Apache and PHP-FPM, we will also install the PHP FastCGI Apache module, libapache2-mod-fastcgi
, to support FastCGI web applications.
First, update your package list to ensure you have the latest packages.
- sudo apt update
Next, install the Apache and PHP-FPM packages:
- sudo apt install apache2 php-fpm
The FastCGI Apache module isn’t available in Ubuntu’s repository so download it from kernel.org and install it using the dpkg
command.
- 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
Next, let’s change Apache’s default configuration to use PHP-FPM.
In this step we will change Apache’s port number to 8080
and configure it to work with PHP-FPM using the mod_fastcgi
module. Rename Apache’s ports.conf
configuration file:
- sudo mv /etc/apache2/ports.conf /etc/apache2/ports.conf.default
Create a new ports.conf
file with the port set to 8080
:
- echo "Listen 8080" | sudo tee /etc/apache2/ports.conf
Note: Web servers are generally set to listen on 127.0.0.1:8080
when configuring a reverse proxy but doing so would set the value of PHP’s environment variable SERVER_ADDR to the loopback IP address instead of the server’s public IP. Our aim is to set up Apache in such a way that its websites do not see a reverse proxy in front of it. So, we will configure it to listen on 8080
on all IP addresses.
Next we’ll create a virtual host file for Apache. The <VirtualHost>
directive in this file will be set to serve sites only on port 8080
.
Disable the default virtual host:
- sudo a2dissite 000-default
Then create a new virtual host file, using the existing default site:
- sudo cp /etc/apache2/sites-available/000-default.conf /etc/apache2/sites-available/001-default.conf
Now open the new configuration file:
- sudo nano /etc/apache2/sites-available/001-default.conf
Change the listening port to 8080
:
<VirtualHost *:8080>
ServerAdmin webmaster@localhost
DocumentRoot /var/www/html
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>
Save the file and activate the new configuration file:
- sudo a2ensite 001-default
Then reload Apache:
- sudo systemctl reload apache2
Install the net-tools
package which contains the netstat
command:
- sudo apt install net-tools
Verify that Apache is now listening on 8080
:
- sudo netstat -tlpn
The output should look like the following example, with apache2
listening on 8080
:
OutputActive 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
Once you verify that Apache is listening on the correct port, you can configure support for PHP and FastCGI.
mod_fastcgi
Apache serves PHP pages using mod_php
by default, but it requires additional configuration to work with PHP-FPM.
Note: If you are trying this tutorial on an existing installation of LAMP with mod_php
, disable it first with sudo a2dismod php7.4
.
We will be adding a configuration block for mod_fastcgi
, which depends on mod_action
. mod_action
is disabled by default, so we first need to enable it:
- sudo a2enmod actions
Rename the existing FastCGI configuration file:
- sudo mv /etc/apache2/mods-enabled/fastcgi.conf /etc/apache2/mods-enabled/fastcgi.conf.default
Create a new configuration file:
- sudo nano /etc/apache2/mods-enabled/fastcgi.conf
Add the following directives to the file to pass requests for .php
files to the PHP-FPM UNIX socket:
<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.4-fpm.sock -pass-header Authorization
<Directory /usr/lib/cgi-bin>
Require all granted
</Directory>
</IfModule>
Save the changes and perform a configuration test:
- sudo apachectl -t
Note: If you see the warning 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.
, you can safely ignore it for now. We’ll configure server names later.
Reload Apache as long as Syntax OK
is displayed:
- sudo systemctl reload apache2
Now let’s make sure we can serve PHP from Apache.
Let’s make sure that PHP works by creating a phpinfo()
file and accessing it from a web browser.
Create the file /var/www/html/info.php
, which contains a call to the phpinfo
function:
- echo "<?php phpinfo(); ?>" | sudo tee /var/www/html/info.php
Note that if you followed the initial server setup in the Prerequisites section, then you likely enabled the Apache firewall. Let’s go ahead and make sure that we can access our IP on port 8080
, which is not currently accessible. We’ll restrict public access to this port in Step 10.
First allow port 8080
through the firewall:
- sudo ufw allow 8080
Since we are going to secure our Apache domains, let’s go ahead and make sure TLS traffic on port 443
can enter.
Allow Apache Full
to permit traffic on ports 80
and 443
:
- sudo ufw allow "Apache Full"
Now check your firewall status:
- sudo ufw status
If you followed the prerequisites, then the output will look like this:
OutputTo Action From
-- ------ ----
OpenSSH ALLOW Anywhere
Apache Full ALLOW Anywhere
8080 ALLOW Anywhere
OpenSSH (v6) ALLOW Anywhere (v6)
Apache Full (v6) ALLOW Anywhere (v6)
8080 (v6) ALLOW Anywhere (v6)
You will see that port 8080
and Apache Full
are allowed alongside any other firewall rules. Now let’s view our info.php
page.
To see the info.php
in a browser, go to http://your_server_ip:8080/info.php
. This will give you a list of the configuration settings PHP is using. You’ll see output similar to this:
At the top of the page, check that Server API says FPM/FastCGI. About two-thirds of the way down the page, the PHP Variables section will tell you the SERVER_SOFTWARE is Apache on Ubuntu. These confirm that mod_fastcgi
is active and Apache is using PHP-FPM to process PHP files.
Let’s create Apache virtual host files for the domains apache1.your_domain
and apache2.your_domain
. To do that, we’ll first create document root directories for both sites and place some default files in those directories so we can easily test our configuration.
First, create the document root directories:
- sudo mkdir -v /var/www/apache1.your_domain /var/www/apache2.your_domain
Then create an index
file for each site:
- echo "<h1 style='color: green;'>Apache 1</h1>" | sudo tee /var/www/apache1.your_domain/index.html
- echo "<h1 style='color: red;'>Apache 2</h1>" | sudo tee /var/www/apache2.your_domain/index.html
Then create a phpinfo()
file for each site so we can test that PHP is configured properly.
- echo "<?php phpinfo(); ?>" | sudo tee /var/www/apache1.your_domain/info.php
- echo "<?php phpinfo(); ?>" | sudo tee /var/www/apache2.your_domain/info.php
Now create the virtual host file for apache1.your_domain
:
- sudo nano /etc/apache2/sites-available/apache1.your_domain.conf
Add the following code to the file to define the host:
<VirtualHost *:8080>
ServerName apache1.your_domain
ServerAlias www.apache1.your_domain
DocumentRoot /var/www/apache1.your_domain
<Directory /var/www/apache1.your_domain>
AllowOverride All
</Directory>
</VirtualHost>
The line AllowOverride All
enables .htaccess
support.
These are only the most basic directives. For a complete guide on setting up virtual hosts in Apache, see How To Set Up Apache Virtual Hosts on Ubuntu 18.04.
Save and close the file. Then create a similar configuration for apache2.your_domain
. First create the file:
- sudo nano /etc/apache2/sites-available/apache2.your_domain.conf
Then add the configuration to the file:
<VirtualHost *:8080>
ServerName apache2.your_domain
ServerAlias www.apache2.your_domain
DocumentRoot /var/www/apache2.your_domain
<Directory /var/www/apache2.your_domain
AllowOverride All
</Directory>
</VirtualHost>
Save the file and exit the editor.
Now that both Apache virtual hosts are set up, enable the sites using the a2ensite
command. This creates a symbolic link to the virtual host file in the sites-enabled
directory:
- sudo a2ensite apache1.your_domain
- sudo a2ensite apache2.your_domain
Check Apache for configuration errors again:
- sudo apachectl -t
You’ll see Syntax OK
displayed if there are no errors. If you see anything else, review the configuration and try again.
Reload Apache to apply the changes once your configuration is error-free:
- sudo systemctl reload apache2
To confirm the sites are working, open http://apache1.your_domain:8080
and http://apache2.your_domain:8080
in your browser and verify that each site displays its index.html
file.
You’ll see the following results:
Also, ensure that PHP is working by accessing the info.php
files for each site. Visit http://apache1.your_domain:8080/info.php
and http://apache2.your_domain:8080/info.php
in your browser.
You’ll see the same PHP configuration spec list on each site as you saw in Step 4.
We now have two websites hosted on Apache at port 8080
. Let’s configure Nginx next.
In this step we’ll install Nginx and configure the domains nginx1.your_domain
and nginx2.your_domain
as Nginx’s virtual hosts. For a complete guide on setting up virtual hosts in Nginx, see How To Set Up Nginx Server Blocks (Virtual Hosts) on Ubuntu 20.04.
Install Nginx using the apt
package manager:
- sudo apt install nginx
Then remove the default virtual host’s symlink since we won’t be using it any more:
- sudo rm /etc/nginx/sites-enabled/default
We’ll create our own default site later (nginx1.your_domain
).
Now we’ll create virtual hosts for Nginx using the same procedure we used for Apache. First create document root directories for both the websites:
- sudo mkdir -v /usr/share/nginx/nginx1.your_domain /usr/share/nginx/nginx2.your_domain
We’ll keep the Nginx web sites in /usr/share/nginx
, which is where Nginx wants them by default. You could put them under /var/www/html
with the Apache sites, but this separation may help you associate sites with Nginx.
As you did with Apache’s virtual hosts, create index
and phpinfo()
files for testing after setup is complete:
- echo "<h1 style='color: green;'>Nginx 1</h1>" | sudo tee /usr/share/nginx/nginx1.your_domain/index.html
- echo "<h1 style='color: red;'>Nginx 2</h1>" | sudo tee /usr/share/nginx/nginx2.your_domain/index.html
- echo "<?php phpinfo(); ?>" | sudo tee /usr/share/nginx/nginx1.your_domain/info.php
- echo "<?php phpinfo(); ?>" | sudo tee /usr/share/nginx/nginx2.your_domain/info.php
Now create a virtual host file for the domain nginx1.your_domain
:
- sudo nano /etc/nginx/sites-available/nginx1.your_domain
Nginx calls server {. . .}
areas of a configuration file server blocks. Create a server block for the primary virtual host, nginx1.your_domain
. The default_server
configuration directive makes this the default virtual host which processes HTTP requests which do not match any other virtual host.
server {
listen 80 default_server;
root /usr/share/nginx/nginx1.your_domain;
index index.php index.html index.htm;
server_name nginx1.your_domain www.nginx1.your_domain;
location / {
try_files $uri $uri/ /index.php;
}
location ~ \.php$ {
fastcgi_pass unix:/run/php/php7.4-fpm.sock;
include snippets/fastcgi-php.conf;
}
}
Save and close the file. Now create a virtual host file for Nginx’s second domain, nginx2.your_domain
:
- sudo nano /etc/nginx/sites-available/nginx2.your_domain
Add the following to the file:
server {
root /usr/share/nginx/nginx2.your_domain;
index index.php index.html index.htm;
server_name nginx2.your_domain www.nginx2.your_domain;
location / {
try_files $uri $uri/ /index.php;
}
location ~ \.php$ {
fastcgi_pass unix:/run/php/php7.4-fpm.sock;
include snippets/fastcgi-php.conf;
}
}
Save and close the file.
Enable both sites by creating symbolic links to the sites-enabled
directory:
- sudo ln -s /etc/nginx/sites-available/nginx1.your_domain /etc/nginx/sites-enabled/nginx1.your_domain
- sudo ln -s /etc/nginx/sites-available/nginx2.your_domain /etc/nginx/sites-enabled/nginx2.your_domain
Test the Nginx configuration to ensure there are no configuration issues:
- sudo nginx -t
Then reload Nginx if there are no errors:
- sudo systemctl reload nginx
Now access the phpinfo()
file for both Nginx virtual hosts in a web browser by visiting http://nginx1.your_domain/info.php and http://nginx2.your_domain/info.php. Look under the PHP Variables sections again.
[“SERVER_SOFTWARE”] should say nginx
, indicating that the files were directly served by Nginx. [“DOCUMENT_ROOT”] should point to the directory you created earlier in this step for each Nginx site.
At this point, we have installed Nginx and created two virtual hosts. Next we will configure Nginx to proxy requests meant for domains hosted on Apache.
Let’s create an additional Nginx virtual host with multiple domain names in the server_name
directives. Requests for these domain names will be proxied to Apache.
Create a new Nginx virtual host file to forward requests to Apache:
- sudo nano /etc/nginx/sites-available/apache
Add the following code block; it specifies the names of both Apache virtual host domains and proxies their requests to Apache. Remember to use the public IP address in proxy_pass
:
server {
listen 80;
server_name apache1.your_domain www.apache1.your_domain apache2.your_domain www.apache2.your_domain;
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;
}
}
Save the file and enable this new virtual host by creating a symbolic link:
- sudo ln -s /etc/nginx/sites-available/apache /etc/nginx/sites-enabled/apache
Test the configuration to ensure there are no errors:
- sudo nginx -t
If there are no errors, reload Nginx:
- sudo systemctl reload nginx
Open the browser and access the URL http://apache1.your_domain/info.php
in your browser. Scroll down to the PHP Variables section and check the values displayed.
The variables SERVER_SOFTWARE and DOCUMENT_ROOT confirm that this request was handled by Apache. The variables HTTP_X_REAL_IP and HTTP_X_FORWARDED_FOR were added by Nginx and should show the public IP address of the computer you’re using to access the URL (if you accessed Apache directly on port 8080
you would not see these variables).
We have successfully set up Nginx to proxy requests for specific domains to Apache. Next, let’s configure Apache to set the REMOTE_ADDR
variable as if it were handling these requests directly.
mod_rpaf
In this step you’ll install an Apache module called mod_rpaf
which rewrites the values of REMOTE_ADDR, HTTPS and HTTP_PORT based on the values provided by a reverse proxy. Without this module, some PHP applications would require code changes to work seamlessly from behind a proxy. This module is present in Ubuntu’s repository as libapache2-mod-rpaf
but it is outdated and doesn’t support certain configuration directives. Instead, we will install it from source.
Move to your home directory and install the packages needed to build the module:
- sudo apt install unzip build-essential apache2-dev
Download the latest stable release from GitHub:
- wget https://github.com/gnif/mod_rpaf/archive/stable.zip
Extract the downloaded file:
- unzip stable.zip
Change into the new directory containing the files:
- cd mod_rpaf-stable
Compile and install the module:
- make
- sudo make install
Next, create a file in the mods-available
directory that will load the rpaf
module:
- sudo nano /etc/apache2/mods-available/rpaf.load
Add the following code to the file to load the module:
LoadModule rpaf_module /usr/lib/apache2/modules/mod_rpaf.so
Save the file and exit the editor.
Create another file in this directory called rpaf.conf
that will contain the configuration directives for mod_rpaf
:
- sudo nano /etc/apache2/mods-available/rpaf.conf
Add the following code block to configure mod_rpaf
, making sure to specify the IP address of your server:
<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>
Here’s a brief description of each directive. See the mod_rpaf
README file for more information.
ServerName
and ServerAlias
work.HTTPS
environment variable based on the value contained in X-Forwarded-Proto
.SERVER_PORT
environment variable. Useful for when Apache is behind a SSL proxy.Save rpaf.conf
and enable the module:
- sudo a2enmod rpaf
This creates symbolic links of the files rpaf.load
and rpaf.conf
in the mods-enabled
directory. Now do a configuration test:
- sudo apachectl -t
Reload Apache if there are no errors:
- sudo systemctl reload apache2
Access the phpinfo()
pages http://apache1.your_domain/info.php
and http://apache2.your_domain/info.php
in your browser and check the PHP Variables section. The REMOTE_ADDR variable will now also be that of your local computer’s public IP address.
Now let’s set up TLS/SSL encryption for each site.
In this step we will configure TLS/SSL certificates for both the domains hosted on Apache. We’ll obtain the certificates through [Let’s Encrypt](https://letsencrypt.org]. Nginx supports SSL termination so we can set up SSL without modifying Apache’s configuration files. The mod_rpaf
module ensures that the required environment variables are set on Apache to make applications work seamlessly behind a SSL reverse proxy.
First we will separate the server {...}
blocks of both the domains so that each of them can have their own SSL certificates. Open the file /etc/nginx/sites-available/apache
in your editor:
- sudo nano /etc/nginx/sites-available/apache
Modify the file so that it looks like this, with apache1.your_domain
and apache2.your_domain
in their own server
blocks:
server {
listen 80;
server_name apache1.your_domain www.apache1.your_domain;
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;
}
}
server {
listen 80;
server_name apache2.your_domain www.apache2.your_domain;
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;
}
}
We’ll use Certbot to generate our TLS/SSL certificates. Its Nginx plugin will take care of reconfiguring Nginx and reloading the config whenever necessary.
Install certbot
using snapd
- sudo snap install --classic certbot
Once it’s installed, use the certbot
command to generate the certificates for apache1.your_domain
and www.apache1.your_domain
:
- sudo certbot --agree-tos --no-eff-email --email your-email --nginx -d apache1.your_domain -d www.apache1.your_domain
This command tells Certbot to use the nginx
plugin, using -d
to specify the names we’d like the certificate to be valid for.
Now execute the command for the second domain:
- sudo certbot --agree-tos --no-eff-email --email your-email --nginx -d apache2.your_domain -d www.apache2.your_domain
Access one of Apache’s domains in your browser using the https://
prefix; visit https://apache1.your_domain/info.php
or https://apache2.your_domain/info.php
.
Look in the PHP Variables section. The variable SERVER_PORT has been set to 443 and HTTPS set to on, as though Apache was directly accessed over HTTPS. With these variables set, PHP applications do not have to be specially configured to work behind a reverse proxy.
Now let’s disable direct access to Apache.
Since Apache is listening on port 8080
on the public IP address, it is accessible by everyone. It can be blocked by working the following IPtables command into your firewall rule set.
- sudo iptables -I INPUT -p tcp --dport 8080 ! -s your_server_ip -j REJECT --reject-with tcp-reset
Be sure to use your server’s IP address in place of the highlighted example. Once port 8080
is blocked in your firewall, test that Apache is unreachable on it. Open your web browser and try accessing one of Apache’s domain names on port 8080
. For example: http://apache1.your_domain:8080
The browser should display an “Unable to connect” or “Webpage is not available” error message. With the IPtables tcp-reset
option in place, an outsider would see no difference between port 8080
and a port that doesn’t have any service on it.
Note: IPtables rules do not survive a system reboot by default. There are multiple ways to preserve IPtables rules, but the easiest is to use iptables-persistent
in Ubuntu’s repository. Explore this article to learn more about how to configure IPTables.
Now let’s configure Nginx to serve static files for the Apache sites.
When Nginx proxies requests for Apache’s domains, it sends every file request for that domain to Apache. Nginx is faster than Apache at serving static files like images, JavaScript and style sheets. So let’s configure Nginx’s apache
virtual host file to directly serve static files but send PHP requests on to Apache.
Open the file /etc/nginx/sites-available/apache
in your editor:
- sudo nano /etc/nginx/sites-available/apache
You’ll need to add two additional location
blocks to each server block, as well as modify the existing location
sections. Additionally, you’ll need to tell Nginx where to find the static files for each site.
If you’ve decided not to use SSL and TLS certificates, modify your file so it looks like this:
server {
listen 80;
server_name apache2.your_domain www.apache2.your_domain;
root /var/www/your_domain;
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 apache1.your_domain www.apache1.your_domain;
root /var/www/your_domain;
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;
}
}
If you also want HTTPS to be available, use the following configuration instead:
server {
listen 80;
server_name apache2.your_domain www.apache2.your_domain;
root /var/www/your_domain;
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/your_domain/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/your_domain/privkey.pem;
include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
}
server {
listen 80;
server_name apache1.your_domain www.apache1.your_domain;
root /var/www/your_domain;
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/your_domain/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/your_domain/privkey.pem;
include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
}
The try_files
directive makes Nginx look for files in the document root and directly serve them. If the file has a .php
extension, the request is passed to Apache. Even if the file is not found in the document root, the request is passed on to Apache so that application features like permalinks work without problems.
Warning: The location ~ /\.ht
directive is very important; this prevents Nginx from serving the contents of Apache configuration files like .htaccess
and .htpasswd
, which contain sensitive information.
Save the file and perform a configuration test:
- sudo nginx -t
Reload Nginx if the test succeeds:
- sudo service nginx reload
To verify things are working, you can examine Apache’s log files in /var/log/apache2
and see the GET
requests for the info.php
files of apache2.your_domain
and apache1.your_domain
. Use the tail
command to see the last few lines of the file, and use the -f
switch to watch the file for changes:
- sudo tail -f /var/log/apache2/other_vhosts_access.log
Now visit apache1.your_domain/info.php
or apache2.your_domain/info.php
in your browser and then look at the output from the log. You’ll see that Apache is indeed replying (your port will be 80
or 443
depending on whether or not you secured the instance):
Output apache2.your_domain:80 your_server_ip - - [27/Aug/2020: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/84.0.4147.135 Safari/537.36"
Then visit the index.html
page for each site and you won’t see any log entries from Apache. Nginx is serving them.
When you’re done observing the log file, press CTRL+C
to stop tailing it.
With this setup, Apache will not be able to restrict access to static files. Access control for static files would need to be configured in Nginx’s apache
virtual host file, but that’s beyond the scope of this tutorial.
You now have one Ubuntu server with Nginx serving nginx1.your_domain
and nginx2.your_domain
, along with Apache serving apache1.your_domain
and apache2.your_domain
. Though Nginx is acting as a reverse-proxy for Apache, Nginx’s proxy service is transparent and connections to Apache’s domains appear be served directly from Apache itself. You can use this method to serve secure and static sites.
Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.
This textbox defaults to using Markdown to format your answer.
You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!
Thanks you very much for this guide.
I was trying to get this done on Ubuntu 22.04 and got stuck at step 4.
Can’t figure out why the info.php is not beeing executed (server returns plain source code).
Any ideas? Could it be a rights problem?
Thanks very much for this!!!
Side note: no biggie, but there is a syntax error on line 5 in the vhosts file for apache2.your_domain:
/etc/apache2/sites-available/apache2.your_domain.conf
The directory opening tag is missing a closing chevron “>”.
Thanks for this tutorial, I successfully installed apache2 and nginx. But I would like to ask how should I proceed when installing wordpress?
Hello Friends, I have stuck at Step 5 of this tutorial after setting up virtual host for apache1.example.com:8080, and apache2.example.com:8080 not working for me… but example.com:8080 work well… I follow exact steps as mentioned in this tutorial. But don’t understand where it goes wrong. Please help!
AH00112: Warning: DocumentRoot [/var/www/apache1.your_domain] does not exist (Removed This Directory) AH00112: Warning: DocumentRoot [/var/www/apache2.your_domain] does not exist (Removed This Directory) AH00558: 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 Syntax OK
anand@doname:/etc/apache2/sites-available$ ls -la total 40 drwxr-xr-x 2 root root 4096 Dec 9 17:51 . drwxr-xr-x 8 root root 4096 Dec 9 14:36 … -rw-r–r-- 1 root root 1332 Sep 30 2020 000-default.conf -rw-r–r-- 1 root root 1334 Dec 9 14:55 001-default.conf -rw-r–r-- 1 root root 249 Dec 9 16:18 apache1.example.com.conf -rw-r–r-- 1 root root 245 Dec 9 15:08 apache1.your_domain.conf -rw-r–r-- 1 root root 249 Dec 9 17:13 apache2.example.com.conf -rw-r–r-- 1 root root 245 Dec 9 15:11 apache2.your_domain.conf -rw-r–r-- 1 root root 6338 Sep 30 2020 default-ssl.conf
Please help me…
This is by far the best and most complete tutorial I’ve seen on this topic. Does exactly as advertised.
However, having done some further reading and seeing as how this article was first published in 2020, I was wondering why you’re using
mod_fastcgi
instead ofmod_proxy_fcgi
to communicate with PHP-FMP andmod_rpaf
instead ofmod_remoteip
to rewriteREMOTE_ADDR
. Is it down to their availability only in Apache 2.4 or is there some other reason?Many thanks, Steve.
So, I’m having trouble getting this configuration to work with .htaccess its a pretty simple file it just points connections to a subfolder but for some reason I’m getting a 403. All permissions in the structure are at 755.
mydomain.com/public/index.php
RewriteEngine on RewriteRule ^(.*) public/$1 [NC,L,QSA]
2020/09/02 05:07:56 [error] 26261#26261: *144 directory index of “/var/www/mydomain.com/” is forbidden, client: 1.1.1.1, server: mydomain.com, request: “GET / HTTP/1.1”, host: “mydomain.com”
Without the .htaccess file everything works just fine as a normal directory, meaning I can type mydomain.com/public/index.php or html etc and it works fine, but my application requires that it work through mod rewrite for other reasons, you shouldn’t even know public exists.
I ensured the mod_rewrite module was enabled and I’ve evaluated just about every step of the tutorial and can not figure out why .htaccess would not work. I tried removing the section in the nginx/sites-available/apache config file
location ~ /.ht { deny all; }
that didn’t have any effect. I can’t figure out what is blocking. And if I type in mydomain.com/.htaccess I literally can download the file directly, which the tutorial says shouldn’t be accessible with the config above added, so I’m not sure where to go from here.
I also tried editing the location / file to this location / { try_files $uri $uri/ /index.php?$args; } as I was looking into how nginx handles .htaccess or equivalent which I found they do not.
Yall did the lords work with this one.