Skip to content
Advertisement

Session Problem on Redis with Docker + Nginx + Yii2

The question is, i am having a problem with session using Docker with Nginx + Yii2 + Redis.

I want use same login on banckend and frontend in Yii2 advanced template.

I just configured all its ok, its work when i do not use Redis, but when i use Redis, dont work.

My configuration is:

  • Yii2 advanced 2.0.43
  • Nginx 1.17.8
  • Redis 4-alpine

My files: docker-compose.yml

version: "3.2"
services:
   nginx:
       container_name: nginx
       image: nginx:1.17.8
       ports:
           - 805:80 #Yes, i use on port 805, its better for me ;-)
       volumes:
           - ./vhosts/nginx.conf:/etc/nginx/conf.d/site.conf
           - ./:/app
       links:
           - php
           - db
           - redis
   php:
       build: .
       container_name: php
       volumes:
           - ./:/app
       environment:
           - SESSION_HANDLER=redis
           - SESSION_PATH=tcp://redis:${REDIS_PORT}?auth=${REDIS_PASSWORD}
           - SESSION_MAX_TIME_LIFE=86400
   db:
       image: mysql:8
       ports:
           - '33065:3306' #Its my way, i use on port 33065, depending on each project
       volumes:
           - /var/lib/mysql
       environment:
           - MYSQL_ROOT_PASSWORD=654321
           - MYSQL_DATABASE=my-project-5

   redis:
       image: redis:4-alpine
       container_name: redis
       command: redis-server --requirepass ${REDIS_PASSWORD}
       ports:
           - ${REDIS_PORT}:${REDIS_PORT}

Dockerfile

FROM php:7.4-fpm-alpine
 

RUN apk add --no-cache --virtual .build-deps 
g++ make autoconf yaml-dev

RUN pecl install igbinary-3.1.2
RUN pecl install redis-5.1.1 
pecl install xdebug-2.9.0

#se for usar o redis
COPY frontend/web/php.ini /usr/local/etc/php/php.ini

RUN docker-php-ext-install intl
RUN docker-php-ext-install pcntl
RUN docker-php-ext-install pdo_mysql
RUN docker-php-ext-install mbstring
RUN docker-php-ext-enable igbinary.so
RUN docker-php-ext-enable redis.so
RUN docker-php-ext-enable xdebug

RUN rm -rf /var/cache/apk/*
RUN apk del --purge .build-deps

RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/bin --filename=composer

CMD ["php-fpm"]

/vhosts/nginx.conf

server {
    listen 80 default_server;
    listen [::]:80 default_server ipv6only=on; ## listen for ipv6
    server_name proj5.local;

    set $base_root /app;
    root $base_root;

    error_log /var/log/nginx/advanced.local.error.log warn;
    access_log /var/log/nginx/advanced.local.access.log main;
    
    charset UTF-8;
    index index.php index.html;
    client_max_body_size 200m;
    fastcgi_read_timeout 2500;

    location / {
        root $base_root/frontend/web;
        try_files $uri $uri/ /frontend/web/index.php$is_args$args;

        location ~ ^/assets/.+.php(/|$) {
            deny all;
        }
    }

    location /painel {
        alias $base_root/backend/web/;

        # prevent the directory redirect to the URL with a trailing slash
        location = /painel {
            # if your location is "/backend", try use "/backend/backend/web/index.php$is_args$args"
            # bug ticket: https://trac.nginx.org/nginx/ticket/97
            try_files $uri /backend/web/index.php$is_args$args;
        }

        try_files $uri $uri/ /backend/web/index.php$is_args$args;

        location ~ ^/painel/assets/.+.php(/|$) {
            deny all;
        }
    }

    location ~ ^/.+.php(/|$) {
        rewrite (?!^/((frontend|backend)/web|painel))^ /frontend/web$uri break;
        rewrite (?!^/backend/web)^/painel(/.+)$ /backend/web$1 break;

        fastcgi_pass php:9000; # proxy requests to a TCP socket
        #fastcgi_pass unix:/var/run/php-fpm.sock; # proxy requests to a UNIX domain socket (check your www.conf file)
        fastcgi_split_path_info ^(.+.php)(.*)$;
        include /etc/nginx/fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        try_files $fastcgi_script_name =404;
    }

    location ~ /. {
        deny all;
    }
}

frontend/web/php.ini

session.save_handler = ${SESSION_HANDLER}
session.save_path = ${SESSION_PATH}
session.gc_maxlifetime = ${SESSION_MAX_TIME_LIFE}

common/config/main.php

'components' => [
    'cache' => [
         'class' => 'yiiredisCache',
    ],
    'redis' => [
         'class' => 'yiiredisConnection',
         'hostname' => 'redis',
         'port' => env("REDIS_PORT"),
         'password' => env("REDIS_PASSWORD"),
         'database' => 0,
     ],
    'session' => [
        'class' => 'yiiredisSession',
    ],
...

PS: To work, i have to disable this and disable Redis too

frontend/config/main.php

...
'components' => [
        'user' => [
            'identityClass' => 'commonmodelsAdmin',
            'enableAutoLogin' => false,
            'identityCookie' => [
                'name' => 'backend-same-frontend',
                'httpOnly' => false,
            ],
        ],
        'session' => [
            'name' => 'advanced-backend-frontend',
            'savePath' => sys_get_temp_dir(),
        ],
        'request' => [
            'csrfParam' => '_csrf-frontend',
            'baseUrl' => '',
            'cookieValidationKey' => 'jhkbYUITFRuytkjHBkjhvguytRDuytcdIYUTdfiyOUgoligoiuytguioyFGOU',
        ],
...

backend/config/main.php

...
'components' => [
        'user' => [
            'identityClass' => 'commonmodelsAdmin',
            'enableAutoLogin' => true,
            'identityCookie' => [
                'name' => 'backend-same-frontend',
                'httpOnly' => false,
            ],
        ],
        'session' => [
            // this is the name of the session cookie used for login on the backend
            'name' => 'advanced-backend-frontend',
            'savePath' => sys_get_temp_dir(),
        ],
        'request' => [
            'cookieValidationKey' => 'kjhIKUYTiyuRTIYUfkjhbVGFKJHGf87654HJGFKHGfkjyhgft',
            'csrfParam' => '_csrf-backend',
            'baseUrl' => '/painel',
        ],
...

The projects works on URL:

When i say this works like a charm, but only when i don’t use Redis.

If i use Redis, the session do not persists on banckend and frontend

Backend without Redis

Frontend without Redis

Can someone help me please…

Advertisement

Answer

First, I don’t think you need the frontend/web/php.ini when using Redis cause you will handle everything from Yii, not from php configuration, so I’m just saying that it is useless.

Second, since you’re sharing a lot of components between the two applications, you might want to put the common configuration into some common php files and include them in both applications. Example:

Add this to both frontend and backend configs:

<?php

'session' => require(__DIR__ . '/../../common/config/session.php'),

And create common/config/session.php with contents as:

<?php

return [
    'class' => 'yiiredisSession',
    'name' => 'my-app-name',
    // ...
];

So this way you only define the component once, and same exact configuration is loaded in both places.

Then check one by one the user, session, and request components configuration, and also open the framework’s files either in IDE or the docs and check if there are any missing parameters you might have to tweak.

Also from this post there’s a tip to check Redis and see if and what data gets generated into the database:

https://www.cloudways.com/blog/yii2-redis-configuration/

It might help you debug the problem.

Going further, reading the comments on this class:

https://github.com/yiisoft/yii2-redis/blob/master/src/Session.php

<?php

// ...

    /**
     * @var string a string prefixed to every cache key so that it is unique. If not set,
     * it will use a prefix generated from [[Application::id]]. You may set this property to be an empty string
     * if you don't want to use key prefix. It is recommended that you explicitly set this property to some
     * static value if the cached data needs to be shared among multiple applications.
     */
    public $keyPrefix;


You can see there’s this keyPrefix configuration for the Redis Session class, that if left empty, defaults to your application’s ID. And as far as I can remember, with advanced template each app has its own ID:

<?php

return [
    'id' => 'app-frontend',
// ...

So this little thing could be making Redis save the sessions with separate prefix for each application. In order to unify it, you must set that keyPrefix.

I would also suggest to start from scratch and setup a new advanced application and implement everything until you make it work. After that, come back to your app and check the differences.

User contributions licensed under: CC BY-SA
10 People found this is helpful
Advertisement