There is another workaround exists which can be used when an alias
directive is used in conjunction with the try_files
one (see this answer for an example). Can you try the following config?
server {
listen 443 http2;
listen [::]:443 http2;
server_name api.com;
root /srv/default/public/; # default root when no version
location ~ ^/api/v1(?<v1route>/.*)? {
alias /srv/api-v1/public;
try_files $v1route /api/v1/index.php$is_args$args;
location ~ ^/api/v1/index\.php$ {
internal;
include /etc/nginx/fastcgi.conf;
fastcgi_param SCRIPT_FILENAME /srv/api-v1/public/index.php;
fastcgi_read_timeout 300;
fastcgi_pass unix:/run/php-fpm-php7.2.socket;
}
}
location ~ ^/api/v2(?<v2route>/.*)? {
alias /srv/api-v2/public;
try_files $v2route /api/v2/index.php$is_args$args;
location ~ ^/api/v2/index\.php$ {
internal;
include /etc/nginx/fastcgi.conf;
fastcgi_param SCRIPT_FILENAME /srv/api-v2/public/index.php;
fastcgi_read_timeout 300;
fastcgi_pass unix:/run/php-fpm-php7.2.socket;
}
}
}
Temporary update (to be expanded with explanation)
OP asks an additional question:
There's one slight issue with the defaults Symfony expects. The following three server variables $_SERVER['DOCUMENT_URI']
, $_SERVER['SCRIPT_NAME']
and $_SERVER['PHP_SELF']
equal /api/v1/index.php
but default Symfony nginx generates /index.php
, is there a way to tweak that in the above?
I don't think this is the reason of incorrect Symfony behavior. While this variables of course can be tweaked, the most probable reason is incorrect $_SERVER['REQUEST_URI']
value. With the configuration above it will be equal to /api/v1/some/path
but most likely Symfony expects just /some/path
instead. Here is the configuration you can try to overwrite that variable:
map $request_uri $api_ver {
~^/api/v([12])/? $1;
}
map $request_uri $api_route {
~^/api/v[12](/[^?]*)?(?:$|\?) $1;
}
server {
listen 443 http2;
listen [::]:443 http2;
server_name api.com;
root /srv/default/public; # default root when no version
location ~ ^/api/v[12]/? {
alias /srv/api-v$api_ver/public;
try_files $api_route /api/v$api_ver/index.php$is_args$args;
location ~ ^/api/v[12]/index\.php$ {
internal;
include /etc/nginx/fastcgi.conf;
fastcgi_param REQUEST_URI $api_route$is_args$args;
fastcgi_param SCRIPT_FILENAME /srv/api-v$api_ver/public/index.php;
fastcgi_read_timeout 300;
fastcgi_pass unix:/run/php-fpm-php7.2.socket;
}
}
}
I think this should fix your issues, but if you really want to tweak $_SERVER['DOCUMENT_URI']
, $_SERVER['SCRIPT_NAME']
and $_SERVER['PHP_SELF']
, you can add two additional lines to the nested location:
location ~ ^/api/v[12]/index\.php$ {
internal;
include /etc/nginx/fastcgi.conf;
fastcgi_param REQUEST_URI $api_route$is_args$args;
fastcgi_param DOCUMENT_URI /index.php;
fastcgi_param SCRIPT_NAME /index.php;
fastcgi_param SCRIPT_FILENAME /srv/api-v$api_ver/public/index.php;
fastcgi_read_timeout 300;
fastcgi_pass unix:/run/php-fpm-php7.2.socket;
}
but I don't think it is required for correct Symfony behavior.
Update 2
To prevent $_SERVER['REQUEST_URI']
variable from being an empty string, you have the following options:
Redirect the request from /api/v1
or /api/v2
to /api/v1/
or /api/v2/
(seems the best as for me):
map $request_uri $api_ver {
~^/api/v([12])/ $1;
}
map $request_uri $api_route {
~^/api/v[12](/[^?]*)(?:$|\?) $1;
}
server {
...
location ~ ^/api/v[12]$ {
return 301 https://$host$uri/$is_args$args;
}
location ~ ^/api/v[12]/ {
alias /srv/api-v$api_ver/public;
try_files $api_route /api/v$api_ver/index.php$is_args$args;
location ~ ^/api/v[12]/index\.php$ {
internal;
include /etc/nginx/fastcgi.conf;
fastcgi_param REQUEST_URI $api_route$is_args$args;
fastcgi_param SCRIPT_FILENAME /srv/api-v$api_ver/public/index.php;
fastcgi_read_timeout 300;
fastcgi_pass unix:/run/php-fpm-php7.2.socket;
}
}
}
Explicitly add the trailing slash to the exact /api/v1
or /api/v2
requests:
map $request_uri $api_ver {
~^/api/v([12])/? $1;
}
map $request_uri $api_route {
~^/api/v[12](?:/([^?]*))?(?:$|\?) /$1;
}
server {
...
location ~ ^/api/v[12]/? {
alias /srv/api-v$api_ver/public;
try_files $api_route /api/v$api_ver/index.php$is_args$args;
location ~ ^/api/v[12]/index\.php$ {
internal;
include /etc/nginx/fastcgi.conf;
fastcgi_param REQUEST_URI $api_route$is_args$args;
fastcgi_param SCRIPT_FILENAME /srv/api-v$api_ver/public/index.php;
fastcgi_read_timeout 300;
fastcgi_pass unix:/run/php-fpm-php7.2.socket;
}
}
}
If the $_SERVER['REQUEST_URI']
variable value should be prepended with /api
string, you can try fastcgi_param REQUEST_URI /api$api_route$is_args$args;
instead of fastcgi_param REQUEST_URI $api_route$is_args$args;
.
If you want to tweak $_SERVER['DOCUMENT_URI']
, $_SERVER['SCRIPT_NAME']
and $_SERVER['PHP_SELF']
variables, add the
fastcgi_param DOCUMENT_URI /index.php;
fastcgi_param SCRIPT_NAME /index.php;
lines to the nested location.
if
and$request_filename
withalias
to avoid usingtry_files
. You also need to use nested locations for the PHP URIs. See this answer. – Wayfarer