How to create correct endpoints within an isolated network in Docker, NextJS and Nginx - docker

I have a Docker network that is an isolated network and reverse proxy that serves the NextJS app to the localhost. Unfortunately, fetch to the backend gets failed whenever I open the browser. However, curl http://rustserver-dc:10000/ responds with the data. I do not want the DB and backend to get exposed, only is available from NextJS app when browsing.
Nginx conf:
worker_processes 1;
events {
worker_connections 1024;
}
http {
sendfile on;
upstream api {
server nextjs-app:3000;
}
server {
listen 80 default_server;
location / {
proxy_pass http://api;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
}
docker-compose:
version: '3.8'
services:
nginx:
image: nginx:latest
restart: always
depends_on:
- rust-server
- nextjs-app
volumes:
- ./nginx/nginx.conf:/etc/nginx/nginx.conf
ports:
- "80:80"
networks:
- app_network
nextjs-app:
build:
context: ./client
dockerfile: Dockerfile
container_name: nextjs-app
environment:
- CHOKIDAR_USEPOLLING=true
- DB_USER=${DB_USER}
- DB_PASS=${DB_PASS}
expose:
- "3000"
networks:
- app_network
rust-server:
build:
context: ./userserver
dockerfile: Dockerfile
container_name: rustserver-dc
expose:
- "10000"
networks:
- app_network
volumes:
- './userserver:/usr/src/userserver'
- '/usr/src/userserver/target'
environment:
- MY_LOG_LEVEL=info
- MY_LOG_STYLE=Always
- DATABASE_URL=${DATABASE_URL}
- STRIPE_SECRET_KEY=${STRIPE_SECRET_KEY}
- STRIPE_PUBLISH_KEY=${STRIPE_PUBLISH_KEY}
- ACCESS_TOKEN_SECRET=${ACCESS_TOKEN_SECRET}
- REFRESH_TOKEN_SECRET=${REFRESH_TOKEN_SECRET}
- RESET_PASSWORD_SECRET=${RESET_PASSWORD_SECRET}
- REDIS_URL=${REDIS_URL}
surrealdb:
image: surrealdb/surrealdb
environment:
- DB_USER=${DB_USER}
- DB_PASSWORD=${DB_PASSWORD}
expose:
- "8000"
networks:
- app_network
volumes:
- data:/var/lib/surrealdb/data
command: "start --user ${DB_USER} --pass {DB_PASSWORD} --log full
file://var/lib/surreal/data"
networks:
app_network:
driver: bridge
volumes:
data:
Next js index page:
import Head from 'next/head'
import axios from 'axios';
import { useState, useEffect } from 'react';
export default function Home() {
const [data, setData] = useState(null);
useEffect(() => {
axios.get('http://rustserver-dc:10000')
.then(res => {
setData(res.data);
})
.catch(err => {
console.log(err);
})
}, []);
console.log(data);
return (
<>
<Head>
<title>Create Next App</title>
<meta name="description" content="Generated by create next app" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="icon" href="/favicon.ico" />
</Head>
<main>
<div>Welcome to the app</div>
</main>
</>
)
}
Error occurring in console:
Failed to load resource: net::ERR_NAME_NOT_RESOLVED rustserver-dc:10000/:1
Had the same issue when I was trying to connect two nodes in Kubernetes, and exposing only NextJS app via Nginx reverse proxy

Related

Communication Refused between 2 Docker Express Microservices

I am trying to deploy a full stack application with docker containers, currently I have various express microservice images, and a react nginx image that are all being proxied by nginx, when react makes a call to one of my microservices it has to make a synchronous request to another but I am getting connection refused and not sure why, i have tried to do this with both relative and absolute urls to no avail.
Here is my docker compose:
networks:
my_network:
driver: bridge
services:
nginx-service:
image: sahilhakimi/topshelf-nginx:latest
ports:
- 80:80
depends_on:
- identity-service
- client-service
- product-service
- cart-service
networks:
- my_network
client-service:
image: sahilhakimi/topshelf-frontend:latest
networks:
- my_network
identity-service:
image: sahilhakimi/topshelf-identity:latest
environment:
TOKEN_KEY: 7e44d0deaa035296b0cb10b3ea46ac627707e51c277908b609c0739d1adafc22e7e543faf9d43028ae64cccdf506e7994a1b0075880aae61a6cdb87d087bc082759a12c398d7e3291fd54539f1b260c7a5f6c79e2c4d586a180ed42b93866583c8da85acf261939d2171ef4b18765a205ee35f8cd1b989a8473589642176f6d1
REFRESH_TOKEN_KEY: b7fb9c5209f55dc4b50d0faef5b4a0b3bdaa81db1e813779ef6c064de0a934e0c2e027fe5e2a9ab7b6d6c06a5d7099ccd837f7698ba9b5a8bee5e1acd86823c0eb29945d4965fe0db59d95c2defb60dbebb1b034dd22132115f14a50e175bd44bc919a91b7b6731e25908fc3b8800d06e90c6b1288b42c8b2378c2a619931e33
AWS_ACCESS_KEY_ID: AKIATQAAJCDKIHEBIK5B
AWS_SECRET_ACCESS_KEY: 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
MONGO_URI: mongodb://root:rootpassword#mongodb_container:27017/Users?authSource=admin
REDIS_PASSWORD: eYVX7EwVmmxKPCDmwMtyKVge8oLd2t81
REDIS_HOST: cache
REDIS_PORT: 6379
clientUrl: http://client-service:5173
depends_on:
- mongodb_container
- cache
networks:
- my_network
product-service:
image: sahilhakimi/topshelf-product:latest
environment:
TOKEN_KEY: 7e44d0deaa035296b0cb10b3ea46ac627707e51c277908b609c0739d1adafc22e7e543faf9d43028ae64cccdf506e7994a1b0075880aae61a6cdb87d087bc082759a12c398d7e3291fd54539f1b260c7a5f6c79e2c4d586a180ed42b93866583c8da85acf261939d2171ef4b18765a205ee35f8cd1b989a8473589642176f6d1
REFRESH_TOKEN_KEY: b7fb9c5209f55dc4b50d0faef5b4a0b3bdaa81db1e813779ef6c064de0a934e0c2e027fe5e2a9ab7b6d6c06a5d7099ccd837f7698ba9b5a8bee5e1acd86823c0eb29945d4965fe0db59d95c2defb60dbebb1b034dd22132115f14a50e175bd44bc919a91b7b6731e25908fc3b8800d06e90c6b1288b42c8b2378c2a619931e33
AWS_ACCESS_KEY_ID: AKIATQAAJCDKIHEBIK5B
AWS_SECRET_ACCESS_KEY: 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
MONGO_URI: mongodb://root:rootpassword#mongodb_container:27017/Products?authSource=admin
KAFKA_HOST: kafka:9092
depends_on:
- mongodb_container
- kafka
networks:
- my_network
cart-service:
image: sahilhakimi/topshelf-cart:latest
environment:
TOKEN_KEY: 7e44d0deaa035296b0cb10b3ea46ac627707e51c277908b609c0739d1adafc22e7e543faf9d43028ae64cccdf506e7994a1b0075880aae61a6cdb87d087bc082759a12c398d7e3291fd54539f1b260c7a5f6c79e2c4d586a180ed42b93866583c8da85acf261939d2171ef4b18765a205ee35f8cd1b989a8473589642176f6d1
REFRESH_TOKEN_KEY: b7fb9c5209f55dc4b50d0faef5b4a0b3bdaa81db1e813779ef6c064de0a934e0c2e027fe5e2a9ab7b6d6c06a5d7099ccd837f7698ba9b5a8bee5e1acd86823c0eb29945d4965fe0db59d95c2defb60dbebb1b034dd22132115f14a50e175bd44bc919a91b7b6731e25908fc3b8800d06e90c6b1288b42c8b2378c2a619931e33
REDIS_PASSWORD: eYVX7EwVmmxKPCDmwMtyKVge8oLd2t81
REDIS_HOST: cache
REDIS_PORT: 6379
KAFKA_HOST: kafka:9092
depends_on:
- cache
- kafka
networks:
- my_network
mongodb_container:
image: mongo:latest
environment:
MONGO_INITDB_ROOT_USERNAME: root
MONGO_INITDB_ROOT_PASSWORD: rootpassword
ports:
- 27017:27017
volumes:
- mongodb_data_container:/data/db
networks:
- my_network
cache:
image: redis:6.2-alpine
restart: always
ports:
- "6379:6379"
command: redis-server --save 20 1 --loglevel warning --requirepass eYVX7EwVmmxKPCDmwMtyKVge8oLd2t81
volumes:
- cache:/data
networks:
- my_network
zookeeper:
image: zookeeper:latest
networks:
- my_network
kafka:
image: wurstmeister/kafka:latest
networks:
- my_network
ports:
- 29092:29092
environment:
KAFKA_LISTENERS: EXTERNAL_SAME_HOST://:29092,INTERNAL://:9092
KAFKA_ADVERTISED_LISTENERS: INTERNAL://kafka:9092,EXTERNAL_SAME_HOST://localhost:29092
KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: INTERNAL:PLAINTEXT,EXTERNAL_SAME_HOST:PLAINTEXT
KAFKA_INTER_BROKER_LISTENER_NAME: INTERNAL
KAFKA_CREATE_TOPICS: "addToCart:1:1,invalidCartProduct:1:1"
KAFKA_AUTO_CREATE_TOPICS_ENABLE: "true"
KAFKA_HEAP_OPTS: "-Xmx256M -Xms128M"
KAFKA_JVM_PERFORMANCE_OPTS: " -Xmx256m -Xms256m"
KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
depends_on:
- zookeeper
volumes:
mongodb_data_container:
cache:
driver: local
The request that is giving me trouble is in the cart service and currently looks like this:
const response = await axios.post(
"http://product-service:3001/api/product/checkout",
{
cart: JSON.parse(cart),
token: req.body.token,
},
{
headers: {
"Content-Type": "application/json",
Cookie: `accessToken=${cookies.accessToken}; refreshToken=${cookies.refreshToken}`,
},
}
);
and here is my nginx configuration as well,
upstream client{
server client-service;
}
upstream identity{
server identity-service:3000;
}
upstream product{
server product-service:3001;
}
upstream cart{
server cart-service:3002;
}
server {
listen 80;
location / {
client_max_body_size 100M;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
proxy_pass http://client;
}
location /api/user/ {
client_max_body_size 100M;
proxy_pass http://identity;
}
location /api/product/{
client_max_body_size 100M;
proxy_pass http://product;
}
location /api/cart/{
client_max_body_size 100M;
proxy_pass http://cart;
}
}
The error log in my docker container is :
cause: Error: connect ECONNREFUSED 127.0.0.1:3001
at TCPConnectWrap.afterConnect [as oncomplete] (node:net:1495:16) {
errno: -111,
code: 'ECONNREFUSED',
syscall: 'connect',
address: '127.0.0.1',
port: 3001
}
}
I tried the above and was expecting my request to properly be made to product service without connection refused, i know that the request is initially being proxied to cart service as wanted by nginx

How to setup phpmyadmin docker container Vultr

I'm trying to get phpmyadmin to work on my live server in Vultr. I have a full-stack react app for the front-end and express Node Js for the back-end as well as mysql for database and phpmyadmin to create tables and stuff. Both React app and Express Node js work, but phpmyadmin doesn't work.
Below is my docker-compose file:
version: '3.7'
services:
mysql_db:
image: mysql
container_name: mysql_container
restart: always
cap_add:
- SYS_NICE
volumes:
- ./data:/var/lib/mysql
ports:
- "3306:3306"
env_file:
- .env
environment:
MYSQL_ROOT_PASSWORD: "${MYSQL_ROOT_PASSWORD}"
MYSQL_HOST: "${MYSQL_HOST}"
MYSQL_DATABASE: "${MYSQL_DATABASE}"
MYSQL_USER: "${MYSQL_USER}"
MYSQL_PASSWORD: "${MYSQL_PASSWORD}"
networks:
- react_network
phpmyadmin:
depends_on:
- mysql_db
image: phpmyadmin/phpmyadmin:latest
container_name: phpmyadmin_container
restart: always
ports:
- "8080:80"
env_file:
- .env
environment:
- PMA_HOST=mysql_db
- PMA_PORT=3306
- PMA_ABSOLUTE_URI=https://my-site.com/admin
- PMA_ARBITRARY=1
- MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD}
networks:
- react_network
api:
restart: always
image: mycustomimage
ports:
- "3001:80"
container_name: server_container
env_file:
- .env
depends_on:
- mysql_db
environment:
MYSQL_HOST_IP: mysql_db
networks:
- react_network
client:
image: mycustomimage
ports:
- "3000:80"
restart: always
stdin_open: true
environment:
- CHOKIDAR_USEPOLLING=true
container_name: client_container
networks:
- react_network
nginx:
depends_on:
- api
- client
build: ./nginx
container_name: nginx_container
restart: always
ports:
- "443:443"
- "80"
volumes:
- ./nginx/conf/certificate.crt:/etc/ssl/certificate.crt:ro
- ./nginx/certs/private.key:/etc/ssl/private.key:ro
- ./nginx/html:/usr/share/nginx/html
networks:
- react_network
volumes:
data:
conf:
certs:
webconf:
html:
networks:
react_network:
Below is my nginx configuration file:
upstream client {
server client:3000;
}
upstream api {
server api:3001;
}
server {
listen 443 ssl http2;
server_name my-site.com;
ssl_certificate /etc/ssl/certificate.crt;
ssl_certificate_key /etc/ssl/private.key;
location / {
proxy_pass http://client;
}
location /admin {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header Host $host;
proxy_pass http://phpmyadmin:8080;
}
location /sockjs-node {
proxy_pass http://client;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
}
location /api {
rewrite /api/(.*) /$1 break;
proxy_pass http://api;
}
}
server {
listen 80;
server_name my-site.com www.my-site.com;
return 301 https://my-site.com$request_uri;
}
I honestly don't know what I'm missing here! If anyone can help me please!!
I get a 502 Bad Gateway error!

Nginx does not redirect to the correct port

I am using a docker-compose to run my frontend application, backend application and nginx webserver. I would like to redirect the requests to the correct port (backend or frontend), but for some reason I just get Internal Server errors.
This is my docker-compose:
version: "3"
services:
webserver:
image: nginx:alpine
ports:
- "80:80"
- "443:443"
networks:
- project
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf
- ./nginx/error.log:/etc/nginx/error_log.log
- ./nginx/cache/:/etc/nginx/cache
- /etc/letsencrypt/:/etc/letsencrypt/
backend:
build:
context: ./project-backend
dockerfile: stage.Dockerfile
env_file:
- ./project-backend/environments/stage.env
volumes:
- ./project-backend/src:/usr/src/app/src
ports:
- "3000:3000"
networks:
- project
frontend:
build:
context: ./project-frontend
dockerfile: stage.Dockerfile
ports:
- "4200:80"
networks:
- project
networks:
project:
This works fine. I can access both of the frontend and backend.
This is my nginx.conf file:
events {}
http {
client_max_body_size 20m;
proxy_cache_path /etc/nginx/cache keys_zone=one:500m max_size=1000m;
server {
proxy_cache one;
proxy_cache_key $request_method$request_uri;
proxy_cache_min_uses 1;
proxy_cache_methods GET;
proxy_cache_valid 200 1y;
listen 80;
server_name localhost;
location /api {
proxy_pass http://localhost:3000/api;
rewrite ^/api(.*)$ $1 break;
}
location / {
proxy_pass http://localhost:4200;
rewrite ^/(.*)$ $1 break;
}
}
}
Try to reach by service name, instead of localhost.
example:
Change proxy_pass http://localhost:3000/api; -> proxy_pass http://backend:3000/api;
Change proxy_pass http://localhost:4200; -> proxy_pass http://frontend:4200;

GET http://api:1337/games net::ERR_NAME_NOT_RESOLVED for nuxt.js pages using asyncData

I have somewhat complicated setup with docker. Everything's working as expected except I have this weird problem.
Visiting index page or /pages/_id pages I have no errors. But when I try to open /other-page it crashes. All are using the same API url.
Error found in the console when opening /other-page:
GET http://api:1337/games net::ERR_NAME_NOT_RESOLVED
Not sure what to do, any suggestions?
nuxt.config.js
axios: {
baseURL: 'http://api:1337'
},
docker-compose.yml
version: '3'
services:
api:
build: .
image: strapi/strapi
environment:
- APP_NAME=strapi-app
- DATABASE_CLIENT=mongo
- DATABASE_HOST=db
- DATABASE_PORT=27017
- DATABASE_NAME=strapi
- DATABASE_USERNAME=
- DATABASE_PASSWORD=
- DATABASE_SSL=false
- DATABASE_AUTHENTICATION_DATABASE=strapi
- HOST=api
- NODE_ENV=production
ports:
- 1337:1337
volumes:
- ./strapi-app:/usr/src/api/strapi-app
#- /usr/src/api/strapi-app/node_modules
depends_on:
- db
restart: always
links:
- db
nuxt:
# build: ./app/
image: "registry.gitlab.com/username/package:latest"
container_name: nuxt
restart: always
ports:
- "3000:3000"
links:
- api:api
command:
"npm run start"
nginx:
image: nginx:1.14.2
expose:
- 80
container_name: nginx
restart: always
ports:
- "80:80"
volumes:
- ./nginx:/etc/nginx/conf.d
depends_on:
- nuxt
links:
- nuxt
index.vue
...
async asyncData({ store, $axios }) {
const games = await $axios.$get('/games')
store.commit('games/emptyList')
games.forEach(game => {
store.commit('games/add', {
id: game.id || game._id,
...game
})
})
return { games }
},
...
page.vue
...
async asyncData({ store, $axios }) {
const games = await $axios.$get('/games')
store.commit('games/emptyList')
games.forEach(game => {
store.commit('games/add', {
id: game.id || game._id,
...game
})
})
return { games }
},
...
Nginx conf
upstream webserver {
ip_hash;
server nuxt:3000;
}
server {
listen 80;
access_log off;
connection_pool_size 512k;
large_client_header_buffers 4 512k;
location / {
proxy_pass http://webserver;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
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;
proxy_max_temp_file_size 0;
}
UPDATE:
Tried what Thomasleveil suggested. Now I'm receiving following error:
nuxt | [2:09:35 PM] Error: connect ECONNREFUSED 127.0.0.1:80
So, it seems like now /api is being forwarded to 127.0.0.1:80. Not sure why ^^
nuxt.config.js
axios: {
baseURL: '/api'
},
server: {
proxyTable: {
'/api': {
target: 'http://localhost:1337',
changeOrigin: true,
pathRewrite: {
"^/api": ""
}
}
}
}
docker-compose.yml
version: '3'
services:
reverse-proxy:
image: traefik # The official Traefik docker image
command: --api --docker # Enables the web UI and tells Traefik to listen to docker
ports:
- "80:80" # The HTTP port
- "8080:8080" # The Web UI (enabled by --api)
volumes:
- /var/run/docker.sock:/var/run/docker.sock # listen to the Docker events
networks:
- mynet
api:
build: .
image: strapi/strapi
container_name: api
environment:
- APP_NAME=strapi-app
- DATABASE_CLIENT=mongo
- DATABASE_HOST=db
- DATABASE_PORT=27017
- DATABASE_NAME=strapi
- DATABASE_USERNAME=
- DATABASE_PASSWORD=
- DATABASE_SSL=false
- DATABASE_AUTHENTICATION_DATABASE=strapi
- HOST=api
- NODE_ENV=development
ports:
- 1337:1337
volumes:
- ./strapi-app:/usr/src/api/strapi-app
#- /usr/src/api/strapi-app/node_modules
depends_on:
- db
restart: always
networks:
- mynet
labels:
- "traefik.backend=api"
- "traefik.docker.network=mynet"
- "traefik.frontend.rule=Host:example.com;PathPrefixStrip:/api"
- "traefik.port=1337"
db:
image: mongo
environment:
- MONGO_INITDB_DATABASE=strapi
ports:
- 27017:27017
volumes:
- ./db:/data/db
restart: always
networks:
- mynet
nuxt:
# build: ./app/
image: "registry.gitlab.com/username/package:latest"
container_name: nuxt
restart: always
ports:
- "3000:3000"
command:
"npm run start"
networks:
- mynet
labels:
- "traefik.backend=nuxt"
- "traefik.frontend.rule=Host:example.com;PathPrefixStrip:/"
- "traefik.docker.network=web"
- "traefik.port=3000"
networks:
mynet:
external: true
Visiting index page or /pages/_id pages I have no errors. But when I try to open /other-page it crashes.
To reformulate:
I have a main page at / that shows some links targeting pages at /pages/_id (where _id is a valid game id)
When I open / or /pages/_id, the content shows up
But if I click a link from page / targeting /pages/xxx (where xxx is a valid id), I got an error
Furthermore if I refresh the page, I then see the content and not the error
content for those pages comes from an api server. Pages are supposed to fetch the content by calling the api server and then render the page contents with the response.
What's happening here?
AsyncData
The way asyncData works in nuxt.js is the following:
on first page load
the user enters the url http://yourserver/pages/123 in its browser
the nuxt web server handles the request, resolve the route and mount the vue component for that page
the asyncData method from the vue component is called from the nuxt.js server side
the nuxt.js server (not the user browser) then fetch the content by making different call to http://api:1337/games/123, receive the response and the content renders.
when the user clicks a link for another page
Something a bit different happens now.
The user is still on the page http://api:1337/games/123 which has a link to the main page listing all the games (http://yourserver/) and click it.
the browser does not load any new page. Instead, the user browser makes an ajax call to http://api:1337/games to try to fetch the new content. And fails due to a name resolution error
Why?
This is a feature brought to you by nuxt.js to speed up page content loading time. from the documentation, the important bit of information is:
asyncData is called every time before loading the page component. It will be called server-side once (on the first request to the Nuxt app) and client-side when navigating to further routes.
server-side means the call is made from the nuxt server to the api server
client-side means the call is made from the user browser to the api server
Now the fun part:
the nuxt server is running in a first container
the api server is running in a second container and is listening on port 1337
from the nuxt container, the url for calling the api server is http://api:1337/, and this works fine
from the user browser, calling http://api:1337 fails (net::ERR_NAME_NOT_RESOLVED) because the user computer does not know how to translate the domain name api to an IP address. And even if it could, this IP Address would be unreachable anyway.
What can be done?
You need to set up a reverse proxy that will forward requests made by the user browsers to url starting with http://yourserver/api/ to the api container on port 1337.
And you need to configure nuxt.js so that links to the api made client-side (from the user browser) use the url http://yourserver/api instead of http://api:1337/
And you need to configure nuxt.js so that it keeps calling http://api:1337 for calls made server-side.
adding a reverse proxy for calls made from nuxt (server-side)
Since you are using the nuxt.js Axios module to make calls to the api container, you are half way there.
The Axios module has a proxy option that can be set to true in nuxtjs.config.js
Bellow is an example of setting up a reverse proxy for your project using Traefik, but the documentation state that the proxy is incompatible with the usage of the baseURL option. The prefix option must be used instead.
Your nuxt.config.js should then look like this:
axios: {
prefix: '/api',
proxy: true
},
proxy: {
'/api/': {
target: 'http://localhost:1337',
pathRewrite: {
'^/api/': ''
}
}
},
This works fine from your development computer, where if strapi is running and responding at http://localhost:1337. But this won't work in a container because we there need to replace http://localhost:1337 with http://api:1337.
To do so, we can introduce an environment variable (STRAPI_URL):
axios: {
prefix: '/api',
proxy: true
},
proxy: {
'/api/': {
target: process.env.STRAPI_URL || 'http://localhost:1337',
pathRewrite: {
'^/api/': ''
}
}
},
We will later set the STRAPI_URL in the docker-compose.yml file.
adding a reverse proxy for calls made from the user browser (client-side)
Since I gave up on implementing reverse proxies with nginx when using docker, here's an example with Traefik:
docker-compose.yml:
version: '3'
services:
reverseproxy: # see https://docs.traefik.io/#the-traefik-quickstart-using-docker
image: traefik:1.7
command: --docker
ports:
- "80:80"
volumes:
- /var/run/docker.sock:/var/run/docker.sock
api:
image: strapi/strapi
environment:
- ...
expose:
- 1337
labels:
traefik.frontend.rule: PathPrefixStrip:/api
traefik.port: 1337
nuxt:
image: ...
expose:
- 3000
command:
"npm run start"
labels:
traefik.frontend.rule: PathPrefixStrip:/
traefik.port: 3000
Now all HTTP requests made by the user browser to http://yourserver will be handled by the Traefik reverse proxy.
Traefik will configure forwarding rules by looking at labels starting with traefik. on the nuxt and api containers.
What changed?
You now have 2 reverse proxies:
one for server-side requests (the nuxt.js Proxy module)
one for client-side requests (Traefik)
It's not done yet
We now need to instruct the nuxt.js Proxy module that it must forward requests to http://api:1337/. We are going to use the STRAPI_URL environment variable for that.
And we need to instruct nuxt Axios module that the user browser must call the api on http://yourserver/api. This is done with the API_URL_BROWSER environment variable.
All together
nuxt.config.js
axios: {
prefix: '/api',
proxy: true
},
proxy: {
'/api/': {
target: process.env.STRAPI_URL || 'http://localhost:1337',
pathRewrite: {
'^/api/': ''
}
}
},
docker-compose.yml
version: '3'
services:
reverseproxy: # see https://docs.traefik.io/#the-traefik-quickstart-using-docker
image: traefik:1.7
command: --docker
ports:
- "80:80"
volumes:
- /var/run/docker.sock:/var/run/docker.sock
api:
image: strapi/strapi
environment:
- ...
expose:
- 1337
labels:
traefik.frontend.rule: PathPrefixStrip:/api
traefik.port: 1337
nuxt:
image: ...
expose:
- 3000
command:
"npm run start"
environment:
NUXT_HOST: 0.0.0.0
STRAPI_URL: http://api:1337/
API_URL_BROWSER: /api
labels:
traefik.frontend.rule: PathPrefixStrip:/
traefik.port: 3000

nginx/docker routing config

I have a digital ocean droplet. In the root of it are the following files
apps/
-main/
-index.html
nginx.conf
docker-compose.yml
My docker-compose.yml file has the following
version: '3'
networks:
proxy:
external: true
internal:
external: false
services:
traefik:
image: traefik:alpine
ports:
- "8080:8080"
- "80:80"
- "443:443"
restart: always
labels:
- logLevel="DEBUG"
- "traefik.backend=monitor"
- "traefik.frontend.rule=Host:monitor.domain.com"
- "traefik.port=8080"
- "traefik.frontend.entryPoints=http,https"
- "traefik.enable=true"
volumes:
- "/var/run/docker.sock:/var/run/docker.sock"
- "./traefik.toml:/traefik.toml"
- "./acme.json:/acme.json"
expose:
- "8080"
networks:
- internal
- proxy
custom-badge:
image: user/app
environment:
PORT: 3000
ports:
- "3000:3000"
labels:
- traefik.enabled=true
- traefik.backend=app
- traefik.frontend.rule=Host:app.domain.com
- traefik.docker.network=proxy
- traefik.port=3000
networks:
- internal
- proxy
server:
image: nginx:alpine
labels:
- traefik.enabled=true
- traefik.backend=
- traefik.frontend.rule=Host:domain.com
- traefik.docker.network=proxy
- traefik.port=80
volumes:
- "./apps:/etc/nginx/html:ro"
- "./nginx.conf:/etc/nginx/nginx.conf:ro"
command: [nginx-debug, '-g', 'daemon off;']
depends_on:
- traefik
and my nginx.conf
events {
worker_connections 1024; ## Default: 1024
}
http {
server {
listen 80;
server_name domain.com www.domain.com;
location / {
root /etc/nginx/html/main;
proxy_pass domain.com:8080/;
}
}
}
Problem is, when I run docker-compose up everything starts up and I can see all 3 containers started but when I go to domain.com I am not seeing my index.html file. What have I done wrong ?
The other domains work fine: app.domain.com & monitor.domain.com which makes me think it must be something wrong with the nginx config and what files need to be served.
You have a loop - remove proxy_pass. Nginx should serve the data from root folder, not proxy the requests to another service.

Resources