Docker + Nginx + Yii2 在 Redis 上的会话问题
Session Problem on Redis with Docker + Nginx + Yii2
问题是,我在使用 Docker 和 Nginx + Yii2 + Redis 的会话时遇到问题。
我想在 Yii2 高级模板的后台和前端使用相同的登录。
我刚刚配置一切正常,当我不使用 Redis 时它可以工作,但是当我使用 Redis 时,不工作。
我的配置是:
- Yii2高级版2.0.43
- Nginx 1.17.8
- Redis 4-高山
我的文件:
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}
Docker文件
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 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' => 'yii\redis\Cache',
],
'redis' => [
'class' => 'yii\redis\Connection',
'hostname' => 'redis',
'port' => env("REDIS_PORT"),
'password' => env("REDIS_PASSWORD"),
'database' => 0,
],
'session' => [
'class' => 'yii\redis\Session',
],
...
PS:要工作,我必须禁用它并禁用 Redis
frontend/config/main.php
...
'components' => [
'user' => [
'identityClass' => 'common\models\Admin',
'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' => 'common\models\Admin',
'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',
],
...
项目工作于 URL:
当我说这很有魅力时,但只有当我不使用 Redis 时才会如此。
如果我使用 Redis,会话不会持续存在于后端和前端
Backend without Redis
Frontend without Redis
有人可以帮我吗...
首先,我不认为你在使用 Redis 时需要 frontend/web/php.ini
因为你会处理来自 Yii 的一切,而不是来自 php 配置,所以我只是说它没用.
其次,由于您在两个应用程序之间共享大量组件,您可能希望将通用配置放入一些通用的 php 文件中,并将它们包含在两个应用程序中。示例:
将此添加到前端和后端配置中:
<?php
'session' => require(__DIR__ . '/../../common/config/session.php'),
并创建 common/config/session.php
,内容如下:
<?php
return [
'class' => 'yii\redis\Session',
'name' => 'my-app-name',
// ...
];
所以这种方式你只定义一次组件,并且在两个地方加载完全相同的配置。
然后一一检查user
、session
、request
组件配置,同时在IDE或文档中打开框架的文件并检查如果缺少任何参数,您可能需要调整。
此外,post 还提供了检查 Redis 并查看是否以及哪些数据生成到数据库中的提示:
https://www.cloudways.com/blog/yii2-redis-configuration/
它可能会帮助您调试问题。
更进一步,阅读对此的评论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;
您可以看到 Redis 会话 class 有这个 keyPrefix
配置,如果留空,则默认为您的应用程序 ID。据我所知,使用高级模板,每个应用程序都有自己的 ID:
<?php
return [
'id' => 'app-frontend',
// ...
所以这件小事可以让 Redis 为每个应用程序保存具有单独前缀的会话。为了统一它,你必须设置 keyPrefix
.
我还建议从头开始并设置一个新的高级应用程序并实施所有内容,直到您使其正常工作。之后,返回您的应用并检查差异。
问题是,我在使用 Docker 和 Nginx + Yii2 + Redis 的会话时遇到问题。
我想在 Yii2 高级模板的后台和前端使用相同的登录。
我刚刚配置一切正常,当我不使用 Redis 时它可以工作,但是当我使用 Redis 时,不工作。
我的配置是:
- Yii2高级版2.0.43
- Nginx 1.17.8
- Redis 4-高山
我的文件: 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}
Docker文件
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 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' => 'yii\redis\Cache',
],
'redis' => [
'class' => 'yii\redis\Connection',
'hostname' => 'redis',
'port' => env("REDIS_PORT"),
'password' => env("REDIS_PASSWORD"),
'database' => 0,
],
'session' => [
'class' => 'yii\redis\Session',
],
...
PS:要工作,我必须禁用它并禁用 Redis
frontend/config/main.php
...
'components' => [
'user' => [
'identityClass' => 'common\models\Admin',
'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' => 'common\models\Admin',
'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',
],
...
项目工作于 URL:
当我说这很有魅力时,但只有当我不使用 Redis 时才会如此。
如果我使用 Redis,会话不会持续存在于后端和前端
Backend without Redis
Frontend without Redis
有人可以帮我吗...
首先,我不认为你在使用 Redis 时需要 frontend/web/php.ini
因为你会处理来自 Yii 的一切,而不是来自 php 配置,所以我只是说它没用.
其次,由于您在两个应用程序之间共享大量组件,您可能希望将通用配置放入一些通用的 php 文件中,并将它们包含在两个应用程序中。示例:
将此添加到前端和后端配置中:
<?php
'session' => require(__DIR__ . '/../../common/config/session.php'),
并创建 common/config/session.php
,内容如下:
<?php
return [
'class' => 'yii\redis\Session',
'name' => 'my-app-name',
// ...
];
所以这种方式你只定义一次组件,并且在两个地方加载完全相同的配置。
然后一一检查user
、session
、request
组件配置,同时在IDE或文档中打开框架的文件并检查如果缺少任何参数,您可能需要调整。
此外,post 还提供了检查 Redis 并查看是否以及哪些数据生成到数据库中的提示:
https://www.cloudways.com/blog/yii2-redis-configuration/
它可能会帮助您调试问题。
更进一步,阅读对此的评论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;
您可以看到 Redis 会话 class 有这个 keyPrefix
配置,如果留空,则默认为您的应用程序 ID。据我所知,使用高级模板,每个应用程序都有自己的 ID:
<?php
return [
'id' => 'app-frontend',
// ...
所以这件小事可以让 Redis 为每个应用程序保存具有单独前缀的会话。为了统一它,你必须设置 keyPrefix
.
我还建议从头开始并设置一个新的高级应用程序并实施所有内容,直到您使其正常工作。之后,返回您的应用并检查差异。