How to Setup NGINX as Reverse Proxy Using Docker

本文介绍如何使用Docker搭建NGINX反向代理服务器,并为多个内部Web服务提供负载均衡及SSL终止等功能。通过示例演示了容器化反向代理的设置过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

A reverse proxy server is a server that typically position itself behind the firewall in a private network and retrieves resources on behalf of a client from one or more servers. A reverse proxy provides an additional level of abstraction like SSL termination, load balancing, request routing, caching, compression etc. It also provides control to ensure smooth flow of traffic between clients and servers. In this tutorial we will setup a reverse proxy in NGINX that will serve two upstream servers, all inside a docker.

The setup

Our setup includes three containers, two containers for two upstream servers and one container for a reverse proxy. The client request will be intercepted by proxy and forwards the same to the upstream.

4624570-c660795e1ed9f5cd.png
nginx reverse proxy inside docker

Inside container, ports and IP's are private and cannot be accessed externally unless they are bound to the host. So only one container can bind to port 80 of the docker host. So how can you access multiple web applications running on multiple container through port 80 of docker host ? The answer is through reverse proxy and we will use nginx reverse proxy inside a container which will bind its port 80 to the docker host's port 80 and forwards request to web application running across multiple containers.

Setup web services

Since we will setup two containers for two web services therefore each of them will have its own docker-composer.yml, one for site1 and another for site2. Remember these web services will not bind to any external ports, the communication with outside world will be done through reverse proxy. For this tutorial these web services will return a simple HTML using nginx, although it can be PHP/JSP/Python apps as well. Also we will connect these two web services using the name site1.test and site2.test

Let us create folders and files for webservice1 i.e for site1

site1
├── docker-compose.yml
└── index.html

root@demohost:~# cd ~
root@demohost:~# mkdir site1
root@demohost:~# cd site1
root@demohost:~/site1# vi docker-compose.yml

version: '2'
services:
app:
image: nginx:1.9
volumes:
- .:/usr/share/nginx/html/
expose:
- "80"

Create a index file for web service 1

root@demohost:~/site1# vi index.html

<!DOCTYPE html>
<html>
<head>
<title>Site 1</title>
</head>
<body>
<h1>This is a sample "site1" response</h1>
</body>
</html>

The docker-compose.yml is pretty straight forward. This web service is a "app" service and will pull nginx version 1.9 . The root of site1 from docker host is mounted to /usr/share/nginx/html/ and exposed the port 80. Build the web service 1 with the following command.

root@demohost:~/site1# docker-compose build

Now start the container for services.

root@demohost:~/site1# docker-compose up -d

List the container

root@demohost:~# docker ps -a

Similarly create second container i.e web service 2

site2
├── docker-compose.yml
└── index.html

root@demohost:~# cd ~
root@demohost:~# mkdir site2
root@demohost:~# cd site2
root@demohost:~/site2# vi docker-compose.yml

version: '2'
services:
app:
image: nginx:1.9
volumes:
- .:/usr/share/nginx/html/
expose:
- "80"

Create an index file for web service 2

root@demohost:~/site2# vi index.html

<!DOCTYPE html>
<html>
<head>
<title>Site 2</title>
</head>
<body>
<h1>This is a sample "site2" response</h1>
</body>
</html>

Build the web service 2 with the following command.

root@demohost:~/site2# docker-compose build

Now start the container for services.

root@demohost:~/site2# docker-compose up -d

List the container

root@demohost:~# docker ps -a

Setup Proxy

Now that two web services are up and running inside container, we proceed to configuring reverse proxy inside a container. We will start by creating folders and files for proxy.

proxy/
├── backend-not-found.html
├── default.conf
├── docker-compose.yml
├── Dockerfile
├── includes
│ ├── proxy.conf
│ └── ssl.conf
└── ssl
├── site1.crt
├── site1.key
├── site2.crt
└── site2.key

root@demohost:~# mkdir proxy
root@demohost:~# cd proxy/
root@demohost:~/proxy# touch Dockerfile
root@demohost:~/proxy# touch backend-not-found.html
root@demohost:~/proxy# touch default.conf
root@demohost:~/proxy# touch docker-compose.yml
root@demohost:~/proxy# mkdir includes
root@demohost:~/proxy# mkdir ssl
root@demohost:~/proxy# cd ../includes
root@demohost:~/proxy/includes# touch proxy.conf
root@demohost:~/proxy/includes# touch ssl.conf

Edit the Dockerfile with the following contents

root@demohost:~/proxy# vi Dockerfile

FROM nginx:1.9

# default conf for proxy service
COPY ./default.conf /etc/nginx/conf.d/default.conf

# NOT FOUND response
COPY ./backend-not-found.html /var/www/html/backend-not-found.html

# Proxy and SSL configurations
COPY ./includes/ /etc/nginx/includes/

# Proxy SSL certificates
COPY ./ssl/ /etc/ssl/certs/nginx/

Edit backend-not-found.html

root@demohost:~/proxy# vi backend-not-found.html

<html>
<head><title>Proxy Backend Not Found</title></head>
<body >
<h2>Proxy Backend Not Found</h2>
</body>
</html>

Edit default.conf

root@demohost:~/proxy# vi default.conf

# web service1 config.
server {
listen 80;
listen 443 ssl http2;
server_name site1.test;

# Path for SSL config/key/certificate
ssl_certificate /etc/ssl/certs/nginx/site1.crt;
ssl_certificate_key /etc/ssl/certs/nginx/site1.key;
include /etc/nginx/includes/ssl.conf;

location / {
include /etc/nginx/includes/proxy.conf;
proxy_pass http://site1_app_1;
}

access_log off;
error_log /var/log/nginx/error.log error;
}

# web service2 config.
server {
listen 80;
listen 443 ssl http2;
server_name site2.test;

# Path for SSL config/key/certificate
ssl_certificate /etc/ssl/certs/nginx/site2.crt;
ssl_certificate_key /etc/ssl/certs/nginx/site2.key;
include /etc/nginx/includes/ssl.conf;

location / {
include /etc/nginx/includes/proxy.conf;
proxy_pass http://site2_app_1;
}

access_log off;
error_log /var/log/nginx/error.log error;
}

# Default
server {
listen 80 default_server;

server_name _;
root /var/www/html;

charset UTF-8;

error_page 404 /backend-not-found.html;
location = /backend-not-found.html {
allow all;
}
location / {
return 404;
}

access_log off;
log_not_found off;
error_log /var/log/nginx/error.log error;
}

In nginx configuration, each of the two web services have its own server block. This block instructs nginx to pass requests to the appropriate web services apps container and they are namely site1_app_1 and site2_app_1. Find this name in the output of docker ps -a under name column. The proxy_intercept_errors option is set to on so that nginx return error from the web apps container itself rather than the default nginx response. The path for SSL configuration/key/certificates instructs nginx from where to pick these files.

Edit docker-compose.yml

version: '2'
services:
proxy:
build: ./
networks:

  • site1
  • site2
    ports:
  • 80:80
  • 443:443

The above docker-compose.yml will create a proxy service and that connects to two external network namely our two web services. This is due to fact that the proxy service need to connect to these external networks for proxy the request it receives from web services docker container. The binding of port no 80/443 of proxy service is done to the docker host's port 80/443. The name of the two external web services/containers are site1_default and site2_default.

Generate certificates and keys for both the web services inside ssl folder.

For Site1

root@demohost:~/proxy# cd ssl
root@demohost:~/proxy/ssl# sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout site1.key -out site1.crt
Generating a 2048 bit RSA private key
..........................+++
..............+++
writing new private key to 'site1.key'
-----

For Site2

root@demohost:~/proxy/ssl# sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout site2.key -out site2.crt
Generating a 2048 bit RSA private key
....................+++
..........................................+++
writing new private key to 'site2.key'
-----

Edit proxy.conf inside include directory.

root@demohost:~/proxy/includes# vi proxy.conf

proxy_set_header Host remote_addr;
proxy_set_header X-Forwarded-For scheme;
proxy_buffering off;
proxy_request_buffering off;
proxy_http_version 1.1;
proxy_intercept_errors on;

Edit SSL configuration inside include folder

root@demohost:~/proxy/includes# vi ssl.conf

ssl_session_timeout 1d;
ssl_session_cache shared:SSL:50m;
ssl_session_tickets off;

ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers 'ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-
ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-
SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-
GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-
AES128-SHAECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-
SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:
DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-
DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:
AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-
CBC3-SHA:!DSS';
ssl_prefer_server_ciphers on;

For name resolution for two web services, add the following two lines in /etc/hosts

root@demohost:~/proxy# vi /etc/hosts

172.31.30.78 site1.test
172.31.30.78 site2.test

The above IP address is the private IP of docker-host. Remember, the request from client will arrive at port 80 of dockerhost which will be mapped to port 80 of nginx container.

Build the proxy container

root@demohost:~/proxy# docker-compose build
Building proxy
Step 1 : FROM nginx:1.9
---> c8c29d842c09
Step 2 : COPY ./default.conf /etc/nginx/conf.d/default.conf
---> Using cache
---> 4c459326c3a2
Step 3 : COPY ./backend-not-found.html /var/www/html/backend-not-found.html
---> Using cache
---> e3d817f5fb8e
Step 4 : COPY ./includes/ /etc/nginx/includes/
---> Using cache
---> 0c5ca9eb16d8
Step 5 : COPY ./ssl/ /etc/ssl/certs/nginx/
---> Using cache
---> 92007e83d405
Successfully built 92007e83d405

Run the proxy container

root@demohost:~/proxy# docker-compose up -d
Building proxy
Step 1 : FROM nginx:1.9
---> c8c29d842c09
Step 2 : COPY ./default.conf /etc/nginx/conf.d/default.conf
---> 4c459326c3a2
Removing intermediate container 86c1ea72022e
Step 3 : COPY ./backend-not-found.html /var/www/html/backend-not-found.html
---> e3d817f5fb8e
Removing intermediate container 51b12caded59
Step 4 : COPY ./includes/ /etc/nginx/includes/
---> 0c5ca9eb16d8
Removing intermediate container 66f2c8dd0d56
Step 5 : COPY ./ssl/ /etc/ssl/certs/nginx/
---> 92007e83d405
Removing intermediate container 29bca9e3ba0a
Successfully built 92007e83d405
Creating proxy_proxy_1

Now list all the running containers.

root@demohost:~/# docker ps -a

The above command will list all the three containers.

4624570-fe11d34e62956e9d.png
Show running containers

To verify that, we have set up reverse proxy correctly, use curl to get a response from two web services from docker host.

root@demohost:~/proxy# curl site1.test
<!DOCTYPE html>
<html>
<head>
<title>Site1</title>
</head>
<body>
<h1>This is a sample "Site1" response</h1>
</body>
</html>
root@demohost:~/proxy# curl site2.test
<!DOCTYPE html>
<html>
<head>
<title>Site2</title>
</head>
<body>
<h1>This is a sample "Site2" response</h1>
</body>
</html>

Conclusion

Since we have containerized reverse proxy, you can add more web services when you need. But this method needs to start and stop container each time you add services. This can be automated using the Docker APIs and some basic template. This leads to painless deployments as well as improve availability.

<think>好的,我现在需要帮助用户解决Nginx服务器启动失败的问题。首先,我应该回想一下用户提供的引用内容,看看有没有相关的信息。用户提到了引用[1],其中提到停止Nginx的命令是`sudo systemctl stop nginx`,但这可能和启动失败关系不大。不过用户的问题是关于启动失败的解决方案,所以我需要根据常见的Nginx启动问题来分析。 首先,常见的Nginx启动失败原因可能包括配置文件错误、端口冲突、权限问题或者依赖缺失。我应该一步步引导用户检查这些方面。 第一步是检查配置文件是否正确。Nginx在启动时会检测配置文件的语法,用户可以使用`sudo nginx -t`命令来测试配置。如果配置文件有语法错误,这里会显示具体的错误位置,比如某个行号,用户可以根据提示修改。例如,如果用户不小心在配置中漏掉了分号或者括号,这个命令能帮助快速定位问题。 接下来,如果配置文件没问题,可能需要查看日志文件。Nginx的错误日志通常位于`/var/log/nginx/error.log`,用户可以用`tail`命令查看最近的日志,比如`tail -n 50 /var/log/nginx/error.log`。日志可能会显示更详细的错误信息,比如权限被拒绝、文件不存在等。比如,如果用户配置中的某个路径指向了不存在的文件或目录,这里就会提示。 然后,检查端口占用情况。Nginx默认使用80和443端口,如果这些端口被其他程序(比如Apache、其他Nginx实例或者Docker容器)占用,Nginx就无法启动。用户可以使用`sudo lsof -i :80`或`sudo netstat -tulnp | grep :80`来查看端口占用情况。如果发现被占用,需要停止占用端口的进程或修改Nginx的监听端口。 权限问题也是一个常见原因。Nginx需要访问某些目录和文件,比如网站根目录、SSL证书等。用户需要确保Nginx的运行用户(通常是www-data或nginx)对这些目录有读取权限。例如,如果网站文件属于root用户,可能需要更改所有权,使用`chown -R www-data:www-data /var/www/html`。 另外,SELinux或AppArmor等安全模块有时会阻止Nginx访问资源。用户可以暂时禁用这些模块来测试是否是它们导致的问题,但生产环境中建议正确配置策略而不是完全禁用。 还有可能是依赖的模块缺失。如果用户编译安装Nginx时缺少依赖库,或者动态模块加载失败,也可能导致启动失败。这时需要检查安装过程是否正确,或者重新安装依赖包。 如果用户最近修改过配置,可以尝试回退到之前的备份配置,或者使用默认配置测试。比如,将配置文件替换为默认的,然后逐步添加自定义配置,找出问题所在。 最后,确保Nginx相关的服务没有冲突。比如,同时运行了Apache和Nginx,或者有残留的Nginx进程,可以使用`sudo pkill nginx`结束所有进程后再启动。 用户提到的其他引用中,引用[3]提到使用`GIT_CURL_VERBOSE=1`来调试git问题,这可能对Nginx问题帮助不大,但类似的思路,可以通过详细日志来排查。引用[4]关于Docker的命令,如果用户是在Docker中运行Nginx,可能需要检查容器配置或镜像是否正确。 总结一下,解决步骤应该是:检查配置语法 -> 查看错误日志 -> 检查端口占用 -> 检查权限 -> 处理安全模块 -> 检查依赖和模块 -> 回退配置。需要逐步引导用户排查,确保每个步骤都清晰,并给出具体的命令示例,帮助用户执行。</think>### Nginx启动失败解决方案与排查步骤 Nginx启动失败通常由配置错误、端口冲突或权限问题导致。以下是系统化的排查流程: --- #### **1. 检查配置文件语法** 使用命令测试Nginx配置文件的语法正确性: ```bash sudo nginx -t ``` - **正确输出示例**: `nginx: configuration file /etc/nginx/nginx.conf test is successful` - **错误输出示例**: `nginx: [emerg] unexpected "}" in /etc/nginx/sites-enabled/default:25` 此时需根据提示的行号(如第25行)检查语法错误[^1]。 --- #### **2. 查看错误日志定位问题** Nginx错误日志通常位于`/var/log/nginx/error.log`,运行以下命令查看实时日志: ```bash sudo tail -f /var/log/nginx/error.log ``` - **常见日志类型**: - *权限问题*:`Permission denied`(检查文件/目录权限) - *端口占用*:`bind() to 0.0.0.0:80 failed (98: Address already in use)` - *路径错误*:`open() "/var/www/html/index.nginx" failed (2: No such file or directory)` --- #### **3. 检查端口冲突** Nginx默认使用80(HTTP)和443(HTTPS)端口。若端口被占用,需终止占用进程或修改Nginx监听端口: ```bash # 查看80端口占用进程 sudo lsof -i :80 # 或使用netstat sudo netstat -tulnp | grep :80 # 终止进程(替换PID) sudo kill -9 <PID> ``` - **修改监听端口**: 编辑配置文件(如`/etc/nginx/sites-enabled/default`),将`listen 80`改为其他端口(如`8080`)。 --- #### **4. 检查文件权限** 确保Nginx用户(通常为`www-data`或`nginx`)对相关目录有访问权限: ```bash # 检查Nginx运行用户 ps aux | grep nginx # 修改网站目录权限 sudo chown -R www-data:www-data /var/www/html sudo chmod -R 755 /var/www/html ``` --- #### **5. 处理SELinux/AppArmor限制** 若系统启用了安全模块(如SELinux),可能需调整策略: ```bash # 临时禁用SELinux(测试用) sudo setenforce 0 # 永久修改SELinux策略(需重启) sudo vi /etc/selinux/config # 将SELINUX=enforcing改为SELINUX=disabled ``` --- #### **6. 检查依赖与模块** 若通过源码编译安装Nginx,需确认依赖库(如OpenSSL、PCRE)已正确安装: ```bash # 示例:Ubuntu系统安装依赖 sudo apt install libpcre3 libpcre3-dev zlib1g zlib1g-dev openssl libssl-dev ``` --- #### **7. 回退配置文件** 如果问题出现在修改配置后,可尝试恢复备份或默认配置: ```bash # 备份当前配置 sudo cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.bak # 使用默认配置测试 sudo cp /usr/share/nginx/nginx.conf /etc/nginx/ sudo systemctl restart nginx ``` --- #### **8. 完整重启Nginx服务** 完成修复后,重启服务并检查状态: ```bash sudo systemctl restart nginx sudo systemctl status nginx ``` - **正常状态示例**: `Active: active (running)` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值