mirror of
https://github.com/lkddi/nexusphp.git
synced 2026-04-24 20:17:24 +08:00
add docker
This commit is contained in:
@@ -0,0 +1,10 @@
|
|||||||
|
FROM openresty/openresty:alpine
|
||||||
|
|
||||||
|
# 安装基础依赖
|
||||||
|
RUN apk add --no-cache gettext bash
|
||||||
|
|
||||||
|
# 拷贝 entrypoint
|
||||||
|
COPY ./entrypoint.sh /usr/local/bin/entrypoint.sh
|
||||||
|
RUN chmod +x /usr/local/bin/entrypoint.sh
|
||||||
|
|
||||||
|
CMD ["/bin/sh", "/usr/local/bin/entrypoint.sh"]
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
set -e
|
||||||
|
|
||||||
|
if [ -z "$DOMAIN" ]; then
|
||||||
|
echo "❌ 错误:必须设置 DOMAIN 环境变量!"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "当前域名是: $DOMAIN"
|
||||||
|
|
||||||
|
# 设定证书目录
|
||||||
|
CLOUDFLARE_CERT_DIR="/certs/cloudflare"
|
||||||
|
FINAL_CERT_DIR="/certs/live"
|
||||||
|
FULLCHAIN="fullchain.pem"
|
||||||
|
PRIVATE_KEY="private.key"
|
||||||
|
|
||||||
|
# 检查 Cloudflare 证书是否存在
|
||||||
|
if [ -f "$FINAL_CERT_DIR/$FULLCHAIN" ] && [ -f "$FINAL_CERT_DIR/$PRIVATE_KEY" ]; then
|
||||||
|
echo "ssl certs already exists at: ${FINAL_CERT_DIR}"
|
||||||
|
else
|
||||||
|
if [ -f "$CLOUDFLARE_CERT_DIR/$FULLCHAIN" ] && [ -f "$CLOUDFLARE_CERT_DIR/$PRIVATE_KEY" ]; then
|
||||||
|
echo "⚡️ Cloudflare certs exists at: $CLOUDFLARE_CERT_DIR, copy to: $FINAL_CERT_DIR ..."
|
||||||
|
mkdir -p "$FINAL_CERT_DIR"
|
||||||
|
cp "$CLOUDFLARE_CERT_DIR/$FULLCHAIN" "$FINAL_CERT_DIR/$FULLCHAIN"
|
||||||
|
cp "$CLOUDFLARE_CERT_DIR/$PRIVATE_KEY" "$FINAL_CERT_DIR/$PRIVATE_KEY"
|
||||||
|
else
|
||||||
|
echo "🔍 Cloudflare certs not exists at: $CLOUDFLARE_CERT_DIR,use acme.sh to apply ..."
|
||||||
|
|
||||||
|
# 安装 acme.sh(如果还没装)
|
||||||
|
if [ ! -d "/root/.acme.sh" ]; then
|
||||||
|
curl https://get.acme.sh | sh
|
||||||
|
source ~/.bashrc
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 申请证书
|
||||||
|
~/.acme.sh/acme.sh --issue --standalone -d "$DOMAIN" --keylength ec-256
|
||||||
|
|
||||||
|
# 安装证书到目标目录
|
||||||
|
~/.acme.sh/acme.sh --install-cert -d "$DOMAIN" --ecc \
|
||||||
|
--key-file "$FINAL_CERT_DIR/$PRIVATE_KEY" \
|
||||||
|
--fullchain-file "$FINAL_CERT_DIR/$FULLCHAIN"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "✅ ssl certs done."
|
||||||
|
|
||||||
|
# 组合子域名变量
|
||||||
|
export PHPMYADMIN_SERVER_NAME="phpmyadmin.${DOMAIN}"
|
||||||
|
|
||||||
|
# 清空旧配置
|
||||||
|
rm -rf /etc/nginx/conf.d/*.conf
|
||||||
|
|
||||||
|
# 生成配置
|
||||||
|
envsubst '$DOMAIN' < /etc/nginx/conf.d/sites/app.conf.template > /etc/nginx/conf.d/app.conf
|
||||||
|
envsubst '$PHPMYADMIN_SERVER_NAME' < /etc/nginx/conf.d/sites/phpmyadmin.conf.template > /etc/nginx/conf.d/phpmyadmin.conf
|
||||||
|
|
||||||
|
exec openresty -g 'daemon off;'
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
server {
|
||||||
|
listen 443 ssl http2;
|
||||||
|
server_name ${DOMAIN};
|
||||||
|
|
||||||
|
root /var/www/html/public;
|
||||||
|
index index.php index.html;
|
||||||
|
|
||||||
|
ssl_certificate /certs/live/fullchain.pem;
|
||||||
|
ssl_certificate_key /certs/live/privkey.pem;
|
||||||
|
|
||||||
|
location = /favicon.ico {
|
||||||
|
log_not_found off;
|
||||||
|
access_log off;
|
||||||
|
}
|
||||||
|
|
||||||
|
location = /robots.txt {
|
||||||
|
allow all;
|
||||||
|
log_not_found off;
|
||||||
|
access_log off;
|
||||||
|
}
|
||||||
|
|
||||||
|
location / {
|
||||||
|
try_files $uri $uri/ /nexus.php?$query_string;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Filament
|
||||||
|
location ^~ /filament {
|
||||||
|
try_files $uri $uri/ /nexus.php$is_args$args;
|
||||||
|
}
|
||||||
|
|
||||||
|
location ~ \.php$ {
|
||||||
|
fastcgi_pass php:9000;
|
||||||
|
fastcgi_index index.php;
|
||||||
|
include fastcgi_params;
|
||||||
|
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
|
||||||
|
fastcgi_param REQUEST_ID $request_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
error_log /dev/stderr;
|
||||||
|
access_log /dev/stdout;
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
server {
|
||||||
|
listen 443 ssl http2;
|
||||||
|
server_name ${PHPMYADMIN_SERVER_NAME};
|
||||||
|
|
||||||
|
ssl_certificate /certs/live/fullchain.pem;
|
||||||
|
ssl_certificate_key /certs/live/privkey.pem;
|
||||||
|
|
||||||
|
location / {
|
||||||
|
proxy_pass http://phpmyadmin:80;
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
error_log /dev/stderr;
|
||||||
|
access_log /dev/stdout;
|
||||||
|
}
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
# 👷♀️ 第一阶段:构建阶段,包含所有开发依赖
|
||||||
|
FROM php:8.2-fpm-alpine AS builder
|
||||||
|
|
||||||
|
RUN apk add --no-cache \
|
||||||
|
$PHPIZE_DEPS \
|
||||||
|
libzip-dev \
|
||||||
|
libpng-dev \
|
||||||
|
libjpeg-turbo-dev \
|
||||||
|
freetype-dev \
|
||||||
|
icu-dev \
|
||||||
|
libxml2-dev \
|
||||||
|
libwebp-dev \
|
||||||
|
gmp-dev \
|
||||||
|
oniguruma-dev \
|
||||||
|
linux-headers
|
||||||
|
|
||||||
|
RUN docker-php-ext-configure gd --with-freetype --with-jpeg --with-webp
|
||||||
|
|
||||||
|
RUN docker-php-ext-install -j$(nproc) \
|
||||||
|
bcmath \
|
||||||
|
pdo_mysql \
|
||||||
|
mysqli \
|
||||||
|
gd \
|
||||||
|
pcntl \
|
||||||
|
sockets \
|
||||||
|
gmp \
|
||||||
|
zip \
|
||||||
|
intl \
|
||||||
|
opcache
|
||||||
|
|
||||||
|
# 安装 redis 扩展
|
||||||
|
RUN pecl install redis && docker-php-ext-enable redis
|
||||||
|
|
||||||
|
# 👨🍳 第二阶段:运行阶段,仅包含必要运行环境
|
||||||
|
FROM php:8.2-fpm-alpine
|
||||||
|
|
||||||
|
# 复制已构建的扩展
|
||||||
|
COPY --from=builder /usr/local/lib/php/extensions /usr/local/lib/php/extensions
|
||||||
|
COPY --from=builder /usr/local/etc/php/conf.d/ /usr/local/etc/php/conf.d/
|
||||||
|
|
||||||
|
# 安装运行时所需依赖
|
||||||
|
RUN apk add --no-cache \
|
||||||
|
wget \
|
||||||
|
rsync \
|
||||||
|
libzip \
|
||||||
|
libpng \
|
||||||
|
libjpeg-turbo \
|
||||||
|
libwebp \
|
||||||
|
freetype \
|
||||||
|
icu \
|
||||||
|
libxml2 \
|
||||||
|
gmp \
|
||||||
|
oniguruma
|
||||||
|
|
||||||
|
# 配置 www.conf
|
||||||
|
RUN sed -i \
|
||||||
|
-e 's/;catch_workers_output = .*/catch_workers_output = yes/g' \
|
||||||
|
-e 's/;php_admin_flag\[log_errors\] = .*/php_admin_flag\[log_errors\] = on/g' \
|
||||||
|
-e 's/;php_admin_value\[error_log\] = .*/php_admin_value\[error_log\] = \/dev\/stderr/g' \
|
||||||
|
/usr/local/etc/php-fpm.d/www.conf
|
||||||
|
|
||||||
|
# 配置 PHP 错误日志输出到 stderr
|
||||||
|
RUN echo "error_log = /dev/stderr" >> /usr/local/etc/php/conf.d/error-logging.ini
|
||||||
|
|
||||||
|
# 安装 Composer
|
||||||
|
RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
|
||||||
|
|
||||||
|
COPY entrypoint.sh /usr/local/bin/entrypoint.sh
|
||||||
|
RUN chmod +x /usr/local/bin/entrypoint.sh
|
||||||
|
|
||||||
|
ENTRYPOINT ["entrypoint.sh"]
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
ROOT_PATH="/var/www/html"
|
||||||
|
|
||||||
|
SOURCE_DIR="${ROOT_PATH}/nexus/Install/install"
|
||||||
|
TARGET_DIR="${ROOT_PATH}/public"
|
||||||
|
ENV_FILE="${ROOT_PATH}/.env"
|
||||||
|
VENDOR_DIR="${ROOT_PATH}/vendor"
|
||||||
|
#COMPOSER_FILE="${ROOT_PATH}/composer.json"
|
||||||
|
|
||||||
|
# 检查目标文件是否存在
|
||||||
|
if [ ! -f "$ENV_FILE" ]; then
|
||||||
|
echo "🔧 .env file: $ENV_FILE not exists, copy $SOURCE_DIR to $TARGET_DIR ..."
|
||||||
|
cp -r "$SOURCE_DIR" "$TARGET_DIR"
|
||||||
|
else
|
||||||
|
echo "✅ .env file: $ENV_FILE already exists, skip copy install file ..."
|
||||||
|
fi
|
||||||
|
|
||||||
|
# composer install
|
||||||
|
if [ ! -d "$VENDOR_DIR" ]; then
|
||||||
|
echo "🔧 vendor dir: $VENDOR_DIR not exists, run composer install ..."
|
||||||
|
composer install --working-dir=${ROOT_PATH}
|
||||||
|
else
|
||||||
|
echo "✅ vendor dir: $VENDOR_DIR already exists, skip run composer install ..."
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 最后启动 PHP-FPM
|
||||||
|
exec php-fpm
|
||||||
@@ -31,3 +31,10 @@ auth.json
|
|||||||
/.history
|
/.history
|
||||||
/public/dev.php
|
/public/dev.php
|
||||||
crowdin.yml
|
crowdin.yml
|
||||||
|
install.lock
|
||||||
|
update.lock
|
||||||
|
.env.bak
|
||||||
|
attachments
|
||||||
|
bitbucket
|
||||||
|
/public/attachments
|
||||||
|
/public/bitbucket
|
||||||
|
|||||||
@@ -0,0 +1,157 @@
|
|||||||
|
services:
|
||||||
|
php:
|
||||||
|
build:
|
||||||
|
context: ./.docker/php
|
||||||
|
container_name: nexusphp-php
|
||||||
|
volumes:
|
||||||
|
- .:/var/www/html
|
||||||
|
depends_on:
|
||||||
|
- mysql
|
||||||
|
- redis
|
||||||
|
logging:
|
||||||
|
driver: "json-file"
|
||||||
|
options:
|
||||||
|
max-size: "1024m"
|
||||||
|
max-file: "3"
|
||||||
|
networks:
|
||||||
|
- appnet
|
||||||
|
|
||||||
|
queue:
|
||||||
|
image: nexusphp-php
|
||||||
|
container_name: nexusphp-queue
|
||||||
|
command: >
|
||||||
|
sh -c '
|
||||||
|
echo "Start Queue Worker...";
|
||||||
|
while true; do
|
||||||
|
if [ -f /var/www/html/.env ] && [ -d /var/www/html/vendor ]; then
|
||||||
|
echo "[Queue] Run queue:work at $(date '+%Y-%m-%d %H:%M:%S')";
|
||||||
|
php artisan queue:work --verbose --tries=3;
|
||||||
|
else
|
||||||
|
echo "[Queue] .env or vendor not exists,wait 5 seconds ...";
|
||||||
|
sleep 5;
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
'
|
||||||
|
volumes:
|
||||||
|
- .:/var/www/html
|
||||||
|
depends_on:
|
||||||
|
- php
|
||||||
|
- redis
|
||||||
|
- mysql
|
||||||
|
logging:
|
||||||
|
driver: "json-file"
|
||||||
|
options:
|
||||||
|
max-size: "1024m"
|
||||||
|
max-file: "3"
|
||||||
|
networks:
|
||||||
|
- appnet
|
||||||
|
|
||||||
|
scheduler:
|
||||||
|
image: nexusphp-php
|
||||||
|
container_name: nexusphp-scheduler
|
||||||
|
command: >
|
||||||
|
sh -c '
|
||||||
|
echo "Start Scheduler ...";
|
||||||
|
while true; do
|
||||||
|
if [ -f /var/www/html/.env ] && [ -d /var/www/html/vendor ]; then
|
||||||
|
echo "[Scheduler] Run schedule:run at $(date '+%Y-%m-%d %H:%M:%S')";
|
||||||
|
php artisan schedule:run --verbose --no-interaction;
|
||||||
|
sleep 60;
|
||||||
|
else
|
||||||
|
echo "[Scheduler] .env or vendor not exists,wait 5 seconds...";
|
||||||
|
sleep 5;
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
'
|
||||||
|
volumes:
|
||||||
|
- .:/var/www/html
|
||||||
|
depends_on:
|
||||||
|
- php
|
||||||
|
- redis
|
||||||
|
- mysql
|
||||||
|
logging:
|
||||||
|
driver: "json-file"
|
||||||
|
options:
|
||||||
|
max-size: "1024m"
|
||||||
|
max-file: "3"
|
||||||
|
networks:
|
||||||
|
- appnet
|
||||||
|
|
||||||
|
openresty:
|
||||||
|
build:
|
||||||
|
context: ./.docker/openresty
|
||||||
|
container_name: nexusphp-openresty
|
||||||
|
ports:
|
||||||
|
- "8080:80"
|
||||||
|
environment:
|
||||||
|
DOMAIN: ${DOMAIN}
|
||||||
|
volumes:
|
||||||
|
- ./.docker/openresty/sites:/etc/nginx/conf.d/sites
|
||||||
|
- ./.docker/openresty/certs:/certs
|
||||||
|
- ./.docker/openresty/entrypoint.sh:/usr/local/bin/entrypoint.sh
|
||||||
|
- .:/var/www/html
|
||||||
|
depends_on:
|
||||||
|
- php
|
||||||
|
- phpmyadmin
|
||||||
|
command: ["/bin/sh", "/usr/local/bin/entrypoint.sh"]
|
||||||
|
logging:
|
||||||
|
driver: "json-file"
|
||||||
|
options:
|
||||||
|
max-size: "1024m"
|
||||||
|
max-file: "3"
|
||||||
|
networks:
|
||||||
|
- appnet
|
||||||
|
|
||||||
|
redis:
|
||||||
|
image: redis:alpine
|
||||||
|
container_name: nexusphp-redis
|
||||||
|
command: redis-server
|
||||||
|
volumes:
|
||||||
|
- redis-data:/data
|
||||||
|
logging:
|
||||||
|
driver: "json-file"
|
||||||
|
options:
|
||||||
|
max-size: "1024m"
|
||||||
|
max-file: "3"
|
||||||
|
networks:
|
||||||
|
- appnet
|
||||||
|
|
||||||
|
mysql:
|
||||||
|
image: mysql:9
|
||||||
|
container_name: nexusphp-mysql
|
||||||
|
environment:
|
||||||
|
MYSQL_ROOT_PASSWORD: root
|
||||||
|
MYSQL_DATABASE: nexusphp
|
||||||
|
MYSQL_USER: nexusphp
|
||||||
|
MYSQL_PASSWORD: secret
|
||||||
|
volumes:
|
||||||
|
- mysql-data:/var/lib/mysql
|
||||||
|
logging:
|
||||||
|
driver: "json-file"
|
||||||
|
options:
|
||||||
|
max-size: "1024m"
|
||||||
|
max-file: "3"
|
||||||
|
networks:
|
||||||
|
- appnet
|
||||||
|
|
||||||
|
phpmyadmin:
|
||||||
|
image: phpmyadmin/phpmyadmin
|
||||||
|
container_name: nexusphp-phpmyadmin
|
||||||
|
environment:
|
||||||
|
PMA_HOST: mysql
|
||||||
|
depends_on:
|
||||||
|
- mysql
|
||||||
|
logging:
|
||||||
|
driver: "json-file"
|
||||||
|
options:
|
||||||
|
max-size: "1024m"
|
||||||
|
max-file: "3"
|
||||||
|
networks:
|
||||||
|
- appnet
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
mysql-data:
|
||||||
|
redis-data:
|
||||||
|
|
||||||
|
networks:
|
||||||
|
appnet:
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
<?php
|
<?php
|
||||||
defined('VERSION_NUMBER') || define('VERSION_NUMBER', '1.9.0');
|
defined('VERSION_NUMBER') || define('VERSION_NUMBER', '1.9.0');
|
||||||
defined('RELEASE_DATE') || define('RELEASE_DATE', '2025-04-24');
|
defined('RELEASE_DATE') || define('RELEASE_DATE', '2025-04-27');
|
||||||
defined('IN_TRACKER') || define('IN_TRACKER', false);
|
defined('IN_TRACKER') || define('IN_TRACKER', false);
|
||||||
defined('PROJECTNAME') || define("PROJECTNAME","NexusPHP");
|
defined('PROJECTNAME') || define("PROJECTNAME","NexusPHP");
|
||||||
defined('NEXUSPHPURL') || define("NEXUSPHPURL","https://nexusphp.org");
|
defined('NEXUSPHPURL') || define("NEXUSPHPURL","https://nexusphp.org");
|
||||||
|
|||||||
@@ -2980,7 +2980,7 @@ function logincookie($id, $authKey, $duration = 0)
|
|||||||
$tokenJson = json_encode($tokenData);
|
$tokenJson = json_encode($tokenData);
|
||||||
$signature = hash_hmac('sha256', $tokenJson, $authKey);
|
$signature = hash_hmac('sha256', $tokenJson, $authKey);
|
||||||
$authToken = base64_encode($tokenJson . '.' . $signature);
|
$authToken = base64_encode($tokenJson . '.' . $signature);
|
||||||
setcookie("c_secure_pass", $authToken, $expires, "/", "", true, true);
|
setcookie("c_secure_pass", $authToken, $expires, "/", "", isHttps(), true);
|
||||||
$update = [
|
$update = [
|
||||||
'last_login' => now(),
|
'last_login' => now(),
|
||||||
];
|
];
|
||||||
|
|||||||
+4
-4
@@ -118,14 +118,14 @@ if (!$az = $Cache->get_value('user_passkey_'.$passkey.'_content')){
|
|||||||
}
|
}
|
||||||
if (!$az) {
|
if (!$az) {
|
||||||
$redis->set("$passkeyInvalidKey:$passkey", TIMENOW, ['ex' => 24*3600]);
|
$redis->set("$passkeyInvalidKey:$passkey", TIMENOW, ['ex' => 24*3600]);
|
||||||
warn("Invalid passkey! Re-download the .torrent from $BASEURL");
|
err("Invalid passkey! Re-download the .torrent from $BASEURL");
|
||||||
}
|
}
|
||||||
if ($az["enabled"] == "no")
|
if ($az["enabled"] == "no")
|
||||||
warn("Your account is disabled!", 300);
|
err("Your account is disabled!", 300);
|
||||||
elseif ($az["parked"] == "yes")
|
elseif ($az["parked"] == "yes")
|
||||||
warn("Your account is parked! (Read the FAQ)", 300);
|
err("Your account is parked! (Read the FAQ)", 300);
|
||||||
elseif ($az["downloadpos"] == "no")
|
elseif ($az["downloadpos"] == "no")
|
||||||
warn("Your downloading privileges have been disabled! (Read the rules)", 300);
|
err("Your downloading privileges have been disabled! (Read the rules)", 300);
|
||||||
|
|
||||||
$userid = intval($az['id'] ?? 0);
|
$userid = intval($az['id'] ?? 0);
|
||||||
unset($GLOBALS['CURUSER']);
|
unset($GLOBALS['CURUSER']);
|
||||||
|
|||||||
Reference in New Issue
Block a user