2

I'm running two services (backend and api) on the same port inside Docker. However, whenever I send requests, NGINX routes all requests to the backend service, and I cannot access the api service properly.

I suspect it's a problem with my NGINX configuration.

Here are my files:

docker-compose.yml

version: '3.8' services: backend: build: context: . dockerfile: ./backend/Dockerfile.dev volumes: - ./backend:/var/www/html/backend environment: - APP_ENV=development networks: - bysooq-network expose: - 9000 env_file: - .env api: build: context: . dockerfile: ./api/Dockerfile.dev volumes: - ./api:/var/www/html/api environment: - APP_ENV=development networks: - bysooq-network expose: - 9000 env_file: - .env postgres: image: postgres:13 restart: always volumes: - ~/bysooq-data/postgres:/var/lib/postgresql/data environment: POSTGRES_DB: xxx POSTGRES_USER: xx POSTGRES_PASSWORD: xxx networks: - bysooq-network redis: image: redis:latest ports: - "6380:6379" restart: always networks: - bysooq-network nginx: image: nginx:latest volumes: - ./nginx/default.conf:/etc/nginx/conf.d/default.conf - ./api:/var/www/html/api - ./backend:/var/www/html/backend ports: - 80:80 depends_on: - backend - api networks: - bysooq-network networks: bysooq-network: driver: bridge 

nginx default.conf

nginx

server { listen 80; server_name localhost; client_max_body_size 100M; index index.php; # API Service - Must come first with strict matching location ~ ^/api(/.*)?$ { root /var/www/html/api/web; try_files $1 $1/ /index.php$is_args$args; location ~ \.php$ { fastcgi_pass api:9000; include fastcgi_params; fastcgi_param SCRIPT_FILENAME $document_root/index.php; fastcgi_param REQUEST_URI $1$is_args$args; } } # Backend Service location / { root /var/www/html/backend/web; try_files $uri $uri/ /index.php$is_args$args; location ~ \.php$ { fastcgi_pass backend:9000; include fastcgi_params; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; } } } 

What I expect:

Requests to /api/* should go to the api service.

Other requests should go to the backend service.

What happens:

All requests (even /api/...) are handled by the backend.

Question: How can I correctly configure NGINX to route /api/* requests to the API service and other requests to the backend service?

Thanks in advance!

2
  • Why not use a single top level location and change your directory struture to match? Why the regex when all you need is location /api/? Commented Apr 29 at 8:20
  • @symcbean I think the OP arrived at this configuration because both the backend and API engines are PHP-based, and the location ~ \.php$ { ... } block would overtake both backend and API requests being rewritten to index.php. And yes, there is no need for such a complex setup — the configuration can be flattened if the /api/ location is defined with the ^~ modifier, as I’ve shown in my answer. Commented Apr 30 at 8:23

1 Answer 1

2

With the try_files directive fallback URI specified as /index.php$is_args$args, you are performing an internal redirect. The rewritten request processing starts from the beginning, choosing the second location to handle it.

If you don't expect any API request to be served with a static file (which is 99% of all cases), don't use all that try_files and nested location setup at all. Instead, you need to unconditionally serve any API request with the /var/www/html/api/web/index.php script. Try the following location:

location ^~ /api/ { root /var/www/html/api/web; rewrite ^/api(/.*)$ $1 break; fastcgi_pass api:9000; include fastcgi_params; fastcgi_param SCRIPT_FILENAME $document_root/index.php; fastcgi_param REQUEST_URI $uri$is_args$args; } 

Only if your case falls under the remaining 1% — and you can receive a request with the /api/ prefix that should be served with a static file — then you can fix your configuration the following way:

location ^~ /api/ { root /var/www/html/api/web; rewrite ^/api(/.*)$ $1 break; try_files $uri $uri/ /api/index.php$is_args$args; location ~ \.php$ { rewrite ^/api(/.*)$ $1 break; fastcgi_pass api:9000; include fastcgi_params; fastcgi_param SCRIPT_FILENAME $document_root/index.php; fastcgi_param REQUEST_URI $uri$is_args$args; } } 

The first correction is to add the /api prefix to the try_files fallback URI, ensuring the rewritten request is processed within the same location. The second is to strip that same prefix using the rewrite directive, making the URI without the /api prefix available via the $uri built-in nginx variable. Even when using nested locations, only a single location is selected to process the request. So if the rewritten URI becomes /api/index.php, the regular expression from the outer location will not apply, and the $1 variable will always be empty within your nested location.

6
  • “API requests won't match any physical file or directory” — but they could since there is mount ./api:/var/www/html/api Commented Apr 30 at 7:03
  • @AlexeyTen I highly doubt it - the OP strips the /api prefix from any /api/... request. Commented Apr 30 at 8:15
  • But the root directive is set to /var/www/html/api/web. So request /api/style.css will look for file /var/www/html/api/web/style.css. Commented Apr 30 at 8:18
  • @AlexeyTen Okay, have it your way :) Updated the answer. Commented Apr 30 at 9:02
  • @IvanShatsky Thank you man :D Commented Apr 30 at 14:22

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.