5

I have a React frontend and a Symfony backend I'm trying to serve on the same domain. The React frontend needs to serve assets if they exist otherwise fallback to serve index.html.

I'd like to serve the php Symfony app when /api is in the request uri. Similar to the React app, I need all requests to go to the index.php file.

The frontend is being served correctly but not the api. I get a 404 from nginx when i hit /api in the browser.

I feel like i'm close but for some reason nginx doesn't have the correct $document_root. I'm adding a header(X-script) to test what the variables are and I'm getting the following:

X-script: /usr/share/nginx/html/index.php

Here's my nginx config.

server {
    listen 80 default_server;
    index index.html index.htm;

    access_log /var/log/nginx/my-site.com.log;
    error_log /var/log/nginx/my-site.com-error.log error;

    charset utf-8;

    location /api {
        root /var/www/my-site.com/backend;
        try_files $uri $uri/ /index.php$is_args$args;
    }
    location / {
        root /var/www/my-site.com/frontend;
        try_files $uri /index.html;
    }
    location ~* \.php$ {
        add_header X-script "$document_root$fastcgi_script_name" always;
        try_files $fastcgi_script_name =404;
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass unix:/var/run/php/php7.0-fpm.sock;
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param HTTPS off;
    }
}

Any help would be much appreciated.

David
  • 10,418
  • 17
  • 72
  • 122

3 Answers3

1

The web root of a Symfony 4 project must include the public subfolder. I am not using NGINX but I think this is the correct configuration:

location /api {
    root /var/www/my-site.com/backend/public;
Francesco Abeni
  • 4,190
  • 1
  • 19
  • 30
  • hey thanks but that's not the problem. i took symfony out of the equation and it still didn't work. `/var/www/my-site.com/backend/index.php` exists and just has `phpinfo();` in it but it's still not being served. – David Sep 24 '18 at 13:17
1

In the following vhost, the most important changes I made are :

  • commented out index directive in server block : it is handled directly in locations blocks
  • added a slash after location /api/ and remove unnecessary $uri/ in the same api location block
  • moved the php_fpm logic to index.php location block : you want all requests to be passed to front controller in Symfony app
  • For the same reason, moved the 404 logic to a general php block, which will handle any other php file request

server {
    listen 80 default_server;

    access_log /var/log/nginx/my-site.com.log;
    error_log /var/log/nginx/my-site.com-error.log error;

    charset utf-8;

    location /api/ {
        root /var/www/my-site.com/backend;
        try_files $uri  /index.php$is_args$args;
    }

    location / {
        root /var/www/my-site.com/frontend;
        try_files $uri /index.html;
    }

    location ~ ^/index\.php(/|$) {
        fastcgi_pass unix:/var/run/php/php7.0-fpm.sock;
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param DOCUMENT_ROOT $realpath_root;
        fastcgi_param HTTPS off;

        internal;
    }

    # return 404 for all other php files not matching the front controller
    # this prevents access to other php files you don't want to be accessible.
    location ~ \.php$ {
        return 404;
    }
}

Last, I bet you'll have to add symfony public folder into api location block root directive.

This vhost was tested fine on my localhost with following tree.

api_test
  - backend
    - index.php
  - frontend
    - index.html

I can successfully access to

  • backend/index.php from api_test.dv/api
  • frontend/index.html from api_test.dv/
Kojo
  • 315
  • 1
  • 10
  • 22
0

Kojos answer is excellent, but to make it completely functional a root directive needs to be added under server or an error message “primary script unknown” will be observed. This is almost always related to a wrongly set SCRIPT_FILENAME in the nginx fastcgi_param directive.

# Nginx configuration
server {
    listen 80 default_server;
    listen [::]:80 default_server;
    server_name ${NGINX_HOST};

    root /var/www/html/backend/public;

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

    charset utf-8;

    location / {
        root /var/www/html/frontend/build;
        try_files $uri /index.html;
    }

    location /api {
        alias /var/www/html/backend/public;
        try_files $uri /index.php$is_args$args;
    }

    location ~ ^/index\.php(/|$) {
        fastcgi_pass php-fpm:9000;
        fastcgi_split_path_info ^(.+\.php)(/.*)$;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
        fastcgi_param DOCUMENT_ROOT $realpath_root;

        internal;
    }

    # return 404 for all other php files not matching the front controller
    # this prevents access to other php files you don't want to be accessible.
    location ~ \.php$ {
        return 404;
    }
}
Tom
  • 4,070
  • 4
  • 22
  • 50