diff --git a/.docker/openresty/Dockerfile b/.docker/openresty/Dockerfile index 477be2d8..c29e6b27 100644 --- a/.docker/openresty/Dockerfile +++ b/.docker/openresty/Dockerfile @@ -1,7 +1,7 @@ FROM openresty/openresty:alpine # 安装基础依赖 -RUN apk add --no-cache gettext bash +RUN apk add --no-cache gettext bash curl openssl socat # 拷贝 entrypoint COPY ./entrypoint.sh /usr/local/bin/entrypoint.sh diff --git a/.docker/openresty/certs/cloudflare/.gitkeep b/.docker/openresty/certs/.gitkeep similarity index 100% rename from .docker/openresty/certs/cloudflare/.gitkeep rename to .docker/openresty/certs/.gitkeep diff --git a/.docker/openresty/entrypoint.sh b/.docker/openresty/entrypoint.sh index 6989f7fd..193b4a4d 100644 --- a/.docker/openresty/entrypoint.sh +++ b/.docker/openresty/entrypoint.sh @@ -1,57 +1,73 @@ #!/bin/sh set -e +# 定义颜色 +COLOR_RED='\033[0;31m' +COLOR_GREEN='\033[0;32m' +COLOR_YELLOW='\033[1;33m' +COLOR_BLUE='\033[0;34m' +COLOR_RESET='\033[0m' + +# 封装彩色输出函数 +echo_info() { + echo -e "${COLOR_BLUE}[INFO]${COLOR_RESET} $*" +} + +echo_success() { + echo -e "${COLOR_GREEN}[SUCCESS]${COLOR_RESET} $*" +} + +echo_warn() { + echo -e "${COLOR_YELLOW}[WARN]${COLOR_RESET} $*" +} + +echo_error() { + echo -e "${COLOR_RED}[ERROR]${COLOR_RESET} $*" +} + + +# 设定证书目录 +CERT_DIR="/certs" +FULLCHAIN="fullchain.pem" +PRIVATE_KEY="private.key" +USE_HTTPS="1" + if [ -z "$DOMAIN" ]; then - echo "❌ 错误:必须设置 DOMAIN 环境变量!" + echo_error "❌ 错误:必须设置 DOMAIN 环境变量!" exit 1 fi -echo "当前域名是: $DOMAIN" +echo_info "DOMAIN: $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}" +# 检查证书是否存在 +if [ -f "$CERT_DIR/$FULLCHAIN" ] && [ -f "$CERT_DIR/$PRIVATE_KEY" ]; then + echo_info "ssl certs already exists at: ${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 + echo_info "no ssl certs at: ${CERT_DIR}" + USE_HTTPS="0" fi -echo "✅ ssl certs done." +echo_info "USE_HTTPS: $USE_HTTPS" # 组合子域名变量 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 +APP_CONF="/etc/nginx/conf.d/app.conf" +PMA_CONF="/etc/nginx/conf.d/phpmyadmin.conf" +envsubst '$DOMAIN' < /etc/nginx/conf.d/sites/app.conf.template > "$APP_CONF" +envsubst '$PHPMYADMIN_SERVER_NAME' < /etc/nginx/conf.d/sites/phpmyadmin.conf.template > "$PMA_CONF" + +# if no certs, remove ssl configuration +if [ "$USE_HTTPS" = "0" ]; then + echo_info "remove https related configuration ..." + sed -i '/ssl_certificate/d' "$APP_CONF" + sed -i 's/listen.*/listen 80;/g' "$APP_CONF" + + sed -i '/ssl_certificate/d' "$PMA_CONF" + sed -i 's/listen.*/listen 80;/g' "$PMA_CONF" +fi + +openresty -T exec openresty -g 'daemon off;' diff --git a/.docker/openresty/sites/app.conf.template b/.docker/openresty/sites/app.conf.template index 9654b35e..8ea4bb44 100644 --- a/.docker/openresty/sites/app.conf.template +++ b/.docker/openresty/sites/app.conf.template @@ -5,8 +5,8 @@ server { root /var/www/html/public; index index.php index.html; - ssl_certificate /certs/live/fullchain.pem; - ssl_certificate_key /certs/live/privkey.pem; + ssl_certificate /certs/fullchain.pem; + ssl_certificate_key /certs/privkey.pem; location = /favicon.ico { log_not_found off; diff --git a/.docker/openresty/sites/phpmyadmin.conf.template b/.docker/openresty/sites/phpmyadmin.conf.template index 8380d06f..7558347a 100644 --- a/.docker/openresty/sites/phpmyadmin.conf.template +++ b/.docker/openresty/sites/phpmyadmin.conf.template @@ -2,8 +2,8 @@ server { listen 443 ssl http2; server_name ${PHPMYADMIN_SERVER_NAME}; - ssl_certificate /certs/live/fullchain.pem; - ssl_certificate_key /certs/live/privkey.pem; + ssl_certificate /certs/fullchain.pem; + ssl_certificate_key /certs/privkey.pem; location / { proxy_pass http://phpmyadmin:80; diff --git a/.docker/php/entrypoint.sh b/.docker/php/entrypoint.sh index 10d8038f..e3a37e3b 100644 --- a/.docker/php/entrypoint.sh +++ b/.docker/php/entrypoint.sh @@ -1,28 +1,85 @@ #!/bin/sh +# 定义颜色 +COLOR_RED='\033[0;31m' +COLOR_GREEN='\033[0;32m' +COLOR_YELLOW='\033[1;33m' +COLOR_BLUE='\033[0;34m' +COLOR_RESET='\033[0m' + +# 封装彩色输出函数 +echo_info() { + echo -e "${COLOR_BLUE}[INFO]${COLOR_RESET} $*" +} + +echo_success() { + echo -e "${COLOR_GREEN}[SUCCESS]${COLOR_RESET} $*" +} + +echo_warn() { + echo -e "${COLOR_YELLOW}[WARN]${COLOR_RESET} $*" +} + +echo_error() { + echo -e "${COLOR_RED}[ERROR]${COLOR_RESET} $*" +} + +# 正式开始 +echo_info "Starting container for SERVICE_NAME=$SERVICE_NAME..." + 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" +if [ "$SERVICE_NAME" = "php" ]; then + if [ ! -f "$ENV_FILE" ]; then + echo_info ".env file: $ENV_FILE not exists, copy $SOURCE_DIR to $TARGET_DIR ..." + cp -r "$SOURCE_DIR" "$TARGET_DIR" + else + echo_success ".env file: $ENV_FILE already exists, skip copy install file ..." + fi + + # composer install + if [ ! -d "$VENDOR_DIR" ]; then + echo_info "vendor dir: $VENDOR_DIR not exists, run composer install ..." + composer install --working-dir=${ROOT_PATH} + else + echo_success "vendor dir: $VENDOR_DIR already exists, skip run composer install ..." + fi + + # 最后启动 PHP-FPM + exec php-fpm +elif [ "$SERVICE_NAME" = "queue" ]; then + echo_info "Start Queue Worker..."; + while true; do + if [ -f "$ENV_FILE" ] && [ -d "$VENDOR_DIR" ]; then + echo_success "[Queue] Run queue:work at $(date '+%Y-%m-%d %H:%M:%S')"; + php artisan queue:work --verbose --tries=3; + else + echo_info "[Queue] .env or vendor not exists,wait 5 seconds ..."; + sleep 5; + fi + done +elif [ "$SERVICE_NAME" = "scheduler" ]; then + echo_info "Start Scheduler ..."; + while true; do + if [ -f "$ENV_FILE" ] && [ -d "$VENDOR_DIR" ]; then + echo_success "[Scheduler] Run schedule:run at $(date '+%Y-%m-%d %H:%M:%S')"; + php artisan schedule:run --verbose --no-interaction; + sleep 60; + else + echo_info "[Scheduler] .env or vendor not exists,wait 5 seconds..."; + sleep 5; + fi + done else - echo "✅ .env file: $ENV_FILE already exists, skip copy install file ..." + echo_error "Unknown SERVICE_NAME: $SERVICE_NAME, exiting." + exit 1 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 + + diff --git a/app/Console/Kernel.php b/app/Console/Kernel.php index 366ebd0d..9b782b1e 100644 --- a/app/Console/Kernel.php +++ b/app/Console/Kernel.php @@ -11,6 +11,7 @@ use Carbon\Carbon; use Illuminate\Console\Scheduling\Event; use Illuminate\Console\Scheduling\Schedule; use Illuminate\Foundation\Console\Kernel as ConsoleKernel; +use Illuminate\Support\Facades\Schema; class Kernel extends ConsoleKernel { @@ -65,6 +66,9 @@ class Kernel extends ConsoleKernel private function registerScheduleCleanup(Schedule $schedule): void { + if (!Schema::hasTable("settings")) { + return; + } $interval = get_setting("main.autoclean_interval_one"); if (!$interval || $interval < 60) { $interval = 7200; diff --git a/app/Policies/UserPolicy.php b/app/Policies/UserPolicy.php index 2c526a01..3c2b58a3 100644 --- a/app/Policies/UserPolicy.php +++ b/app/Policies/UserPolicy.php @@ -31,7 +31,7 @@ class UserPolicy extends BasePolicy */ public function view(User $user, User $model) { - return $model->privacy != "strong" || $user->id == $model->id|| Permission::canManageUserBasicInfo(); + return $model->privacy != "strong" || $user->id == $model->id || Permission::canManageUserBasicInfo(); } public function viewEmail(User $user, User $model) diff --git a/docker-compose.yml b/docker-compose.yml index 674f0789..6d9bcb75 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -2,7 +2,10 @@ services: php: build: context: ./.docker/php + image: nexusphp_php container_name: nexusphp-php + environment: + SERVICE_NAME: php volumes: - .:/var/www/html depends_on: @@ -17,21 +20,10 @@ services: - appnet queue: - image: nexusphp-php + 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 - ' + environment: + SERVICE_NAME: queue volumes: - .:/var/www/html depends_on: @@ -47,22 +39,10 @@ services: - appnet scheduler: - image: nexusphp-php + 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 - ' + environment: + SERVICE_NAME: scheduler volumes: - .:/var/www/html depends_on: @@ -81,8 +61,6 @@ services: build: context: ./.docker/openresty container_name: nexusphp-openresty - ports: - - "8080:80" environment: DOMAIN: ${DOMAIN} volumes: @@ -94,6 +72,8 @@ services: - php - phpmyadmin command: ["/bin/sh", "/usr/local/bin/entrypoint.sh"] + ports: + - "${NP_PORT:-80}:80" logging: driver: "json-file" options: @@ -120,10 +100,10 @@ services: image: mysql:9 container_name: nexusphp-mysql environment: - MYSQL_ROOT_PASSWORD: root - MYSQL_DATABASE: nexusphp - MYSQL_USER: nexusphp - MYSQL_PASSWORD: secret + MYSQL_ROOT_PASSWORD: ${NP_MYSQL_ROOT_PWD:-root} + MYSQL_DATABASE: ${NP_MYSQL_DB:-nexusphp} + MYSQL_USER: ${NP_MYSQL_USER:-nexusphp} + MYSQL_PASSWORD: ${NP_MYSQL_PWD:-nexusphp} volumes: - mysql-data:/var/lib/mysql logging: diff --git a/public/takeinvite.php b/public/takeinvite.php index 24143f59..fed2f270 100644 --- a/public/takeinvite.php +++ b/public/takeinvite.php @@ -91,7 +91,7 @@ $title = $SITENAME.$lang_takeinvite['mail_tilte']; $signupUrl = getSchemeAndHttpHost() . "/signup.php?type=invite&invitenumber=$hash"; $siteName = \App\Models\Setting::getSiteName(); -$mailTwo = sprintf($lang_takeinvite['mail_two'], $siteName); +$mailTwo = sprintf($lang_takeinvite['mail_two'], $siteName, $siteName); $mailFour = sprintf($lang_takeinvite['mail_four'], $siteName); $mailSix = sprintf($lang_takeinvite['mail_six'], $REPORTMAIL, $siteName); $message = <<