Nginx config for Yii 2 Advanced App Template

serghei picture serghei · Jul 5, 2014 · Viewed 13k times · Source

I would like to configure the Nginx web-server in such a way that:

  • Requests to the /index.php URI should be handled by public_html/frontend/web/index.php
  • Requests to the /admin/index.php URI should be handled by public_html/backend/web/index.php

Advice please where I'm wrong. Here is my config:

server {
    listen        80;
    server_name   yii2.lo;
    server_tokens off;

    client_max_body_size 128M;
    charset       utf-8;

    access_log    /var/log/nginx/yii2-access.log main buffer=50k;
    error_log     /var/log/nginx/yii2-error.log notice;

    set           $host_path      "/srv/http/yii2/public";
    set           $yii_bootstrap  "index.php";

    index         $yii_bootstrap;

    location / {
        root          $host_path/frontend/web;
        try_files $uri $uri/ /$yii_bootstrap?$args;

    }

    location /admin {
        root          $host_path/backend/web;
        try_files $uri $uri/ /$yii_bootstrap?$args;
    }

    location ~ \.php$ {
        try_files $uri =404;

        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_index           $yii_bootstrap;

        # Connect to php-fpm via socket
        fastcgi_pass unix:/run/php-fpm/php-fpm.sock;

        fastcgi_connect_timeout     30s;
        fastcgi_read_timeout        30s;
        fastcgi_send_timeout        60s;
        fastcgi_ignore_client_abort on;
        fastcgi_pass_header         "X-Accel-Expires";

        fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
        fastcgi_param  PATH_INFO        $fastcgi_path_info;
        fastcgi_param  HTTP_REFERER     $http_referer;
        include fastcgi_params;
    }

    location ~* \.(js|css|less|png|jpg|jpeg|gif|ico|woff|ttf|svg|tpl)$ {
        expires 24h;
        access_log off;
    }

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

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

    location ~ /\. {
        deny all;
        access_log off;
        log_not_found off;
    }
}

Answer

Arthur Aslanyan picture Arthur Aslanyan · Jan 11, 2015

Long story short: use the first method provided below.

The rest of the answer is a list of recommendations.

I'm going to separate my answer in two sections. In the first part, I will tell you the easiest and the fastest way to achieve your goal according to your desired URL requests, but it partly breaks the app structure, nothing serious, though.

In the second part, I will describe you where you made mistakes in your configuration file and I will show you a poorly written configuration for your needs which works.

I. Shared Hosting deployment

I highly encourage you to use this. This is an official way from Yii 2 documentation to make backend work at the same domain, although it helps to deploy a project to a shared hosting. And it doesn't require any additional nginx configuration, just a basic one for frontend root.

Let me write a simple list according to this guide:

  1. Move contents from /backend/web to /frontend/web/admin.
  2. Correct scripts' paths in /frontend/web/admin/index.php (and index-test.php, if you use it)

That's all, you have your backend at the same domain at /admin URL. Additionally, read the last section of the guide regarding cookies. The advanced template was designed to use different domains for each environment, therefore the guide describes backend config for shared hosting to keep cookies from frontend and backend separate.

Of course, don't forget to modify your /environments files for proper initialization of your project with /init script.

II. Nginx configuration

Mistakes

I'm not a profressional nginx administrator, but I can describe what's wrong in your configuration based on my personal experience and the documentation. Unfortunately, I won't be able to provide links to the documentation, because my current rating won't allow me to post more than 2 links.

Server context root

You do not have root directive in your server context. Thus, when ~ \.php$ location is matched, it doesn't have root at all and uses default nginx root. Try setting common root directive in the server context, then all locations will have it by default. For example:

server {
    # Beginning of your configuration
    # ...

    root /srv/http/yii2/public/frontend/web;

    # The rest of your configuration
    # ...
}

Not having a higher context root is a common pitfall.

root instead of alias

Secondly, when a location is matched, the uri is appended to the location's root and that's the path the server attempts to look for. Thus, your /admin location suggests that the server search for $host_path/backend/web/admin. In your situation, you should use alias directive which tells the server that the matched location uri refers to alias path, not appended to root:

location /admin {
    alias          $host_path/backend/web;

    # The rest of location
    # ...
}

I recommend that you read related nginx documentation about location, root and alias directives.

Working but poorly written configuration

I post this sample configuration with comments for your understanding only, not for production use, I dicourage you to apply it for your production (until you're positive it's safe and sound).

It works, but it has an annoying defect: backend cannot find Yii2 entry script if you request it directly (like /admin/index.php), so it must be used with enablePrettyUrl set to true and showScriptName set to false, however it finds any other PHP script in the backend web root.

server {
    # The beginning of your configuration
    # ...

    # By default we will provide frontend
    root /srv/http/yii2/public/frontend/web;
    index index.php;

    location / {
        try_files $uri $uri/ /index.php?$args;
    }

    location /admin {
        # We use /web/index here to make backend call to php scripts
        # distinct from frontend call
        index /web/index.php;
        alias $root_base/backend/web;
        try_files $uri $uri/ /web/index.php?$args;

        # Rewrite PHP requests from /admin to /web
        # However, Yii2 entry script returns 404
        location ~ ^/admin/.*\.php$ {
            rewrite ^/admin/(.*)$ /web/$1;
        }

    }

    location ~ ^/web/.*\.php$ {
        # Make sure this location cannot be called externally
        internal;

        # Remember, that the uri of this location
        # will be appended to this root!
        root $root_base/backend;

        # PHP settings for backend
    }

    location ~ \.php$ {
        # PHP settings for frontend
    }

    # The rest of your configuration
    # ...
}

Additionally, add baseUrl property to the request component in your Yii2 backend config and set it to /admin.

I hope my answer will help you deploying your Yii2 advanced project and understanding nginx more, nevertheless your question is 6 months old.