Reputation: 3262
I have 4 Docker containers:
Until now I was using nginx only to serve the Laravel API for testing - so I can directly call the API with Postman, and the Next.js frontend pages (the node container) were accessed directly by the host via localhost:3000
. But now I want nginx to serve the frontend Next.js project, and then the node container will call the Laravel API, but I still want to leave the testing server for Postman, so I added a second server block to my default.conf
file, and adjusted the docker-compose.yml
file but it broke everything, now nothing is working.
This was my setup (that worked) until now:
The docker-compose.yml
:
networks:
laravel:
driver: bridge
services:
nginx:
image: nginx:stable-alpine
container_name: nginx
ports:
- "8088:80"
volumes:
- ./laravel-api:/var/www/html
- ./nginx/default.conf:/etc/nginx/conf.d/default.conf
depends_on:
- php
- mysql
- node
networks:
- laravel
mysql:
image: mysql
container_name: mysql
restart: unless-stopped
tty: true
ports:
- "4306:3306"
volumes:
- ./mysql:/var/lib/mysql
environment:
MYSQL_DATABASE: laravel
MYSQL_ROOT_PASSWORD: password
SERVICE_TAGS: dev
SERVICE_NAME: mysql
networks:
- laravel
php:
build:
context: .
dockerfile: Dockerfile
container_name: php
volumes:
- ./laravel-api:/var/www/html
ports:
- "9000:9000"
networks:
- laravel
node:
build:
context: ./nextjs
dockerfile: Dockerfile
container_name: next
volumes:
- ./nextjs:/var/www/html
ports:
- "3000:3000"
- "49153:49153"
networks:
- laravel
and nginx default.conf
file:
server {
listen 80;
index index.php index.html;
server_name localhost;
error_log /var/log/nginx/error.log;
access_log /var/log/nginx/access.log;
root /var/www/html/public;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
try_files $uri = 404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass php:9000;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
}
}
So what is happening is that I access the node container directly on port 3000, and any call to the Laravel API is handled by nginx - redirecting requests from the host on port 8088 to the container of nginx on port 80.
What I tried to do was to add server block for reverse proxy from localhost:3000 to the nginx container like I do with the Laravel API calls:
This is the updated default.conf
, added second server block:
server {
listen 80;
index index.php index.html;
server_name localhost;
error_log /var/log/nginx/error.log;
access_log /var/log/nginx/access.log;
root /var/www/html/public;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
try_files $uri = 404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass php:9000;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
}
}
server {
listen 80;
server_name nextjs;
access_log logs/nextjs.access.log main;
location /nextjs {
proxy_pass node:3000;
}
}
And adjusted the docker-compose.yml
file:
networks:
laravel:
driver: bridge
services:
nginx:
image: nginx:stable-alpine
container_name: nginx
ports:
- "8088:80"
- "3000:80"
volumes:
- ./nextjs:/var/www/html/nextjs
- ./laravel-api:/var/www/html
- ./nginx/default.conf:/etc/nginx/conf.d/default.conf
depends_on:
- php
- mysql
- node
networks:
- laravel
mysql:
image: mysql
container_name: mysql
restart: unless-stopped
tty: true
ports:
- "4306:3306"
volumes:
- ./mysql:/var/lib/mysql
environment:
MYSQL_DATABASE: laravel
MYSQL_ROOT_PASSWORD: password
SERVICE_TAGS: dev
SERVICE_NAME: mysql
networks:
- laravel
php:
build:
context: .
dockerfile: Dockerfile
container_name: php
volumes:
- ./laravel-api:/var/www/html
ports:
- "9000:9000"
networks:
- laravel
node:
build:
context: ./nextjs
dockerfile: Dockerfile
container_name: next
volumes:
- ./nextjs:/var/www/html
ports:
- "49153:49153"
networks:
- laravel
I removed the port 3000 from the node container, and added to the nginx and mapped to the port 80 of the nginx container, so any requests to port 3000 from my host will be handled by port 80 of nginx - just like Laravel, so now both Laravel and Nextjs are redirected to port 80 on the nginx container (Again, I leave the Laravel server so I can test API directly from the host as well - and not only from the Next.js website)
Also, I created a link for the nextjs project on the nginx container: - ./nextjs:/var/www/html/nextjs
But now nothing works when I go to either localhost:3000
or localhost:8088
from my host
Upvotes: 0
Views: 510
Reputation: 3847
You'll need to change multiple things in order to use Nginx as a reverse proxy for your NextJS app.
First, in your docker-compose.yml
, you must update the Nginx service:
services:
nginx:
image: nginx:stable-alpine
container_name: nginx
ports:
- "3000:80"
As you can see, I removed the "8088:80"
mapping. Why? Because, remember, this is used to map one port of the host to the service (it's always <host>:<container>
). It means "if you open your browser and type http://localhost:8088
, forward this request to the Nginx container, port 80".
Since you mapped two ports of your host to the port 80 in the Nginx container, doing http://localhost:8088
and http://localhost:3000
was exactly the same.
To fix this, we remove the unused port 8088. Let's keep only the port 3000.
Next, we'll update your first server block and make a change in the port it listens. Instead of the port 80, we'll now listen to the port 8088 (any available port is ok).
server {
listen 8088;
index index.php index.html;
...
}
Because you don't have any server_name
configured (it would involve extra steps), we have to use different ports for each server blocks. By convention, since the frontend app will be accessed first before the API, we'll keep the port 80 on the Nextjs server block... so we had to choose another one for the API (and we chose 8088).
At this point, every requests made to http://localhost:3000
will land in your Nginx container on the port 80. Your second server block listens to the port 80, so let's dive into it:
server {
listen 80;
location / {
proxy_pass http://node:3000;
}
}
I removed the /nextjs
, we want all requests from http://localhost:3000
be reverse proxied, not only those starting with http://localhost:3000/nextjs
.
We also add http://
before node:3000
because it'll be a HTTP.
I also removed the server_name
and the access log (doesn't strictly needed and might not exist, it can be added later when you have a working app).
The last change you'll have to make will be to tell your node app to send API requests to http://nginx:8088
(e.g. http://nginx:8088/api/products
...).
To summarize what should happen:
http://localhost:3000/my-pretty-url
"3000":"80"
)proxy_pass http://node:3000;
. Note that the port 3000 used here could have been totally different from the port used by your node app. If you start your node app with the port 6000, just replace http://node:3000
with http://node:6000
/api/products
), they should be done to http://nginx:8088/api/products
fastcgi_pass php:9000;
And we are done!
I don't specifically know Nextjs. You might need to proxy additional headers to your node app, but that could be totally fine for development purposes with proxy_pass node:3000
only.
There is a lot of "might happen problems" that could occur, but the general idea is here. If you have any problems, tell me in comments.
Upvotes: 2