Two document roots with nginx and fastcgi

2019-07-07 17:17发布

I am using nginx and php in a docker-environment, which works fine for a single application. Now I want to develop an application based in yii2/php as backend and angular as frontend, so I need one webserver serving the client, and another one serving the API backend. The directory structure looks as follows:

/var/www/html/ $ tree -L 3
.
├── client
│   ├── dist
│   │   ├── 0.chunk.js
│   │   ├── 0.chunk.js.map
│   │   ├── assets
│   │   ├── index.html
│   │   ├── ...
│   ├── e2e
│   │   ├── ...
│   ├── node_modules
│   │   ├── ...
├── docker
│   ├── mysql
│   │   ├── Dockerfile
│   │   └── my.cnf
│   ├── nginx
│   │   ├── Dockerfile
│   │   └── default.conf
│   └── php7
│       └── Dockerfile
├── docker-compose.yml
└── server
    ├── api
    │   ├── common
    │   ├── config
    │   ├── modules
    │   └── web
    │   │   └── index.php 
    ├── common
    ├── composer.json
    ├── console
    └── vendor

The frontend application is located in `/var/www/html/client/dist/, the nginx config looks as follows:

server {
    listen 80 default_server;
    root /var/www/html/client/dist/;
    index index.html index.php;

    charset utf-8;

    location / {
            # Redirect everything that isn't a real file to index.php
            try_files $uri $uri/ /index.php$is_args$args;
        }

    location /api {
        root /var/www/html/server/api/web/;
        try_files $uri $uri/ /index.php$is_args$args;
    }

    location = /favicon.ico { access_log off; log_not_found off; }
    location = /robots.txt  { access_log off; log_not_found off; }

    sendfile off;

    client_max_body_size 100m;

    location ~ \.php$ {
        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_intercept_errors off;
        fastcgi_buffer_size 16k;
        fastcgi_buffers 4 16k;
        fastcgi_read_timeout 300s;
    }

    location ~ /\.ht {
        deny all;
    }
}

Using this config, the frontend works (URL: /), however the API does not. What I need is:

Request "/": serve the angular app from /var/www/html/client/dist/ Request "/api": use index.php from /var/www/html/server/api/web/

How to configure this? Thank you.

//Edit: New configuration file:

server {
    listen 80 default_server;
    root /var/www/html/client/dist/;
    index index.html;

    charset utf-8;

    location ~ ^/api(.*) {
        alias /var/www/html/server/api/web/;

        # Redirect everything that isn't a real file to index.php
        try_files $uri $uri/ /index.php$1$args;
        index index.php;

        location ~ \.php$ {
            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_intercept_errors off;
            fastcgi_buffer_size 16k;
            fastcgi_buffers 4 16k;
            fastcgi_read_timeout 300s;
        }

        location ~ /\.ht {
            deny all;
        }
    }

    location = /favicon.ico { access_log off; log_not_found off; }
    location = /robots.txt  { access_log off; log_not_found off; }

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

    sendfile off;

    client_max_body_size 100m;
}

Calling http://localhost/api/v1/users should be redirected to /var/www/html/server/api/web/index.php with v1/users as parameter (or however Yii2 handles the pretty URLs), but returns a 404 not found instead.

Error Log shows this message, so it looks like the alias directive is not taking effect:

2017/07/11 16:51:57 [error] 5#5: *1 open() "/var/www/html/client/dist/index.php" failed (2: No such file or directory), client: 172.17.0.1, server: , request: "GET /api/v1/users HTTP/1.1", host: "localhost"

1条回答
放我归山
2楼-- · 2019-07-07 17:32

Not exactly sure what you need to rewrite the pretty URIs to, but you need to use the URI of index.php which includes the /api prefix.

The alias directive works best with a prefix location, otherwise you will need to construct the path with captured variables.

For example:

location ^~ /api/ {
    alias /var/www/html/server/api/web/;

    index index.php;

    if (!-e $request_filename) { 
        rewrite ^/api(.*) /api/index.php?uri=$1 last;
    }

    location ~ \.php$ {
        if (!-f $request_filename) { return 404; }

        fastcgi_pass php:9000;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $request_filename;
        fastcgi_intercept_errors off;
        fastcgi_buffer_size 16k;
        fastcgi_buffers 4 16k;
        fastcgi_read_timeout 300s;
    }

    location ~ /\.ht {
        deny all;
    }
}
查看更多
登录 后发表回答