mirror of
https://github.com/okxlin/appstore.git
synced 2026-09-27 16:01:05 +00:00
@@ -0,0 +1,23 @@
|
||||
PANEL_APP_PORT_HTTP=4000
|
||||
PANEL_DB_HOST=
|
||||
PANEL_DB_PORT=5432
|
||||
PANEL_DB_NAME=keila
|
||||
PANEL_DB_USER=keila
|
||||
PANEL_DB_USER_PASSWORD=
|
||||
KEILA_USER=root@localhost
|
||||
KEILA_PASSWORD=
|
||||
SECRET_KEY_BASE=
|
||||
URL_HOST=localhost
|
||||
URL_SCHEMA=http
|
||||
URL_PORT=4000
|
||||
APP_DATA_DIR=./data
|
||||
MAILER_SMTP_HOST=
|
||||
MAILER_SMTP_PORT=587
|
||||
MAILER_SMTP_FROM_EMAIL=
|
||||
MAILER_SMTP_USER=
|
||||
MAILER_SMTP_PASSWORD=
|
||||
MAILER_ENABLE_SSL=false
|
||||
MAILER_ENABLE_STARTTLS=false
|
||||
LOG_LEVEL=info
|
||||
TZ=Asia/Shanghai
|
||||
CONTAINER_NAME=
|
||||
@@ -0,0 +1,401 @@
|
||||
additionalProperties:
|
||||
formFields:
|
||||
- default: 4000
|
||||
edit: true
|
||||
envKey: PANEL_APP_PORT_HTTP
|
||||
labelEn: HTTP Port
|
||||
labelZh: HTTP 端口
|
||||
label:
|
||||
en: HTTP Port
|
||||
zh: HTTP 端口
|
||||
zh-Hant: HTTP 連接埠
|
||||
ja: HTTP ポート
|
||||
ko: HTTP 포트
|
||||
ru: HTTP-порт
|
||||
ms: Port HTTP
|
||||
pt-br: Porta HTTP
|
||||
required: true
|
||||
rule: paramPort
|
||||
type: number
|
||||
- default: postgresql
|
||||
envKey: PANEL_DB_TYPE
|
||||
labelEn: Database Runtime
|
||||
labelZh: 数据库 Runtime
|
||||
label:
|
||||
en: Database Runtime
|
||||
zh: 数据库 Runtime
|
||||
zh-Hant: 資料庫 Runtime
|
||||
ja: データベース Runtime
|
||||
ko: 데이터베이스 Runtime
|
||||
ru: Среда базы данных
|
||||
ms: Runtime Pangkalan Data
|
||||
pt-br: Runtime de banco de dados
|
||||
required: true
|
||||
type: apps
|
||||
values:
|
||||
- label: PostgreSQL
|
||||
value: postgresql
|
||||
child:
|
||||
default: ''
|
||||
envKey: PANEL_DB_HOST
|
||||
labelEn: PostgreSQL Service
|
||||
labelZh: PostgreSQL 服务
|
||||
label:
|
||||
en: PostgreSQL Service
|
||||
zh: PostgreSQL 服务
|
||||
zh-Hant: PostgreSQL 服務
|
||||
ja: PostgreSQL サービス
|
||||
ko: PostgreSQL 서비스
|
||||
ru: Сервис PostgreSQL
|
||||
ms: Perkhidmatan PostgreSQL
|
||||
pt-br: Serviço PostgreSQL
|
||||
required: true
|
||||
type: service
|
||||
- default: 5432
|
||||
edit: true
|
||||
envKey: PANEL_DB_PORT
|
||||
labelEn: Database Port
|
||||
labelZh: 数据库端口
|
||||
label:
|
||||
en: Database Port
|
||||
zh: 数据库端口
|
||||
zh-Hant: 資料庫連接埠
|
||||
ja: データベースポート
|
||||
ko: 데이터베이스 포트
|
||||
ru: Порт базы данных
|
||||
ms: Port Pangkalan Data
|
||||
pt-br: Porta do banco de dados
|
||||
required: true
|
||||
rule: paramPort
|
||||
type: number
|
||||
- default: keila
|
||||
edit: true
|
||||
envKey: PANEL_DB_NAME
|
||||
labelEn: Database Name
|
||||
labelZh: 数据库名
|
||||
label:
|
||||
en: Database Name
|
||||
zh: 数据库名
|
||||
zh-Hant: 資料庫名稱
|
||||
ja: データベース名
|
||||
ko: 데이터베이스 이름
|
||||
ru: Имя базы данных
|
||||
ms: Nama Pangkalan Data
|
||||
pt-br: Nome do banco de dados
|
||||
random: true
|
||||
required: true
|
||||
rule: paramCommon
|
||||
type: text
|
||||
- default: keila
|
||||
edit: true
|
||||
envKey: PANEL_DB_USER
|
||||
labelEn: Database User
|
||||
labelZh: 数据库用户
|
||||
label:
|
||||
en: Database User
|
||||
zh: 数据库用户
|
||||
zh-Hant: 資料庫使用者
|
||||
ja: データベースユーザー
|
||||
ko: 데이터베이스 사용자
|
||||
ru: Пользователь базы данных
|
||||
ms: Pengguna Pangkalan Data
|
||||
pt-br: Usuário do banco de dados
|
||||
random: true
|
||||
required: true
|
||||
rule: paramCommon
|
||||
type: text
|
||||
- default: ''
|
||||
edit: true
|
||||
envKey: PANEL_DB_USER_PASSWORD
|
||||
labelEn: Database Password
|
||||
labelZh: 数据库密码
|
||||
label:
|
||||
en: Database Password
|
||||
zh: 数据库密码
|
||||
zh-Hant: 資料庫密碼
|
||||
ja: データベースパスワード
|
||||
ko: 데이터베이스 비밀번호
|
||||
ru: Пароль базы данных
|
||||
ms: Kata Laluan Pangkalan Data
|
||||
pt-br: Senha do banco de dados
|
||||
required: true
|
||||
rule: paramComplexity
|
||||
type: password
|
||||
- default: root@localhost
|
||||
edit: true
|
||||
envKey: KEILA_USER
|
||||
labelEn: Initial Administrator Email
|
||||
labelZh: 初始管理员邮箱
|
||||
label:
|
||||
en: Initial Administrator Email
|
||||
zh: 初始管理员邮箱
|
||||
zh-Hant: 初始管理員電子郵件
|
||||
ja: 初期管理者メールアドレス
|
||||
ko: 초기 관리자 이메일
|
||||
ru: Email начального администратора
|
||||
ms: E-mel Pentadbir Awal
|
||||
pt-br: E-mail do administrador inicial
|
||||
required: true
|
||||
type: text
|
||||
- default: ''
|
||||
edit: true
|
||||
envKey: KEILA_PASSWORD
|
||||
labelEn: Initial Administrator Password (10+ characters)
|
||||
labelZh: 初始管理员密码(至少 10 个字符)
|
||||
label:
|
||||
en: Initial Administrator Password (10+ characters)
|
||||
zh: 初始管理员密码(至少 10 个字符)
|
||||
zh-Hant: 初始管理員密碼(至少 10 個字元)
|
||||
ja: 初期管理者パスワード(10 文字以上)
|
||||
ko: 초기 관리자 비밀번호(10자 이상)
|
||||
ru: Пароль начального администратора (не менее 10 символов)
|
||||
ms: Kata Laluan Pentadbir Awal (10+ aksara)
|
||||
pt-br: Senha do administrador inicial (10+ caracteres)
|
||||
required: true
|
||||
type: password
|
||||
- default: ''
|
||||
edit: true
|
||||
envKey: SECRET_KEY_BASE
|
||||
labelEn: Session Secret (64+ characters)
|
||||
labelZh: 会话密钥(至少 64 个字符)
|
||||
label:
|
||||
en: Session Secret (64+ characters)
|
||||
zh: 会话密钥(至少 64 个字符)
|
||||
zh-Hant: 工作階段密鑰(至少 64 個字元)
|
||||
ja: セッションシークレット(64 文字以上)
|
||||
ko: 세션 비밀 키(64자 이상)
|
||||
ru: Секрет сеанса (не менее 64 символов)
|
||||
ms: Rahsia Sesi (64+ aksara)
|
||||
pt-br: Segredo da sessão (64+ caracteres)
|
||||
required: true
|
||||
type: password
|
||||
- default: ''
|
||||
edit: true
|
||||
envKey: URL_HOST
|
||||
labelEn: Public Host (domain or IP)
|
||||
labelZh: 公开访问主机(域名或 IP)
|
||||
label:
|
||||
en: Public Host (domain or IP)
|
||||
zh: 公开访问主机(域名或 IP)
|
||||
zh-Hant: 公開存取主機(網域或 IP)
|
||||
ja: 公開ホスト(ドメインまたは IP)
|
||||
ko: 공개 호스트(도메인 또는 IP)
|
||||
ru: Публичный хост (домен или IP)
|
||||
ms: Hos Awam (domain atau IP)
|
||||
pt-br: Host público (domínio ou IP)
|
||||
required: true
|
||||
type: text
|
||||
- default: http
|
||||
edit: true
|
||||
envKey: URL_SCHEMA
|
||||
labelEn: Public URL Scheme
|
||||
labelZh: 公开 URL 协议
|
||||
label:
|
||||
en: Public URL Scheme
|
||||
zh: 公开 URL 协议
|
||||
zh-Hant: 公開 URL 通訊協定
|
||||
ja: 公開 URL スキーム
|
||||
ko: 공개 URL 스키마
|
||||
ru: Схема публичного URL
|
||||
ms: Skema URL Awam
|
||||
pt-br: Esquema da URL pública
|
||||
required: true
|
||||
type: select
|
||||
values:
|
||||
- label: http
|
||||
value: http
|
||||
- label: https
|
||||
value: https
|
||||
- default: 4000
|
||||
edit: true
|
||||
envKey: URL_PORT
|
||||
labelEn: Public URL Port
|
||||
labelZh: 公开 URL 端口
|
||||
label:
|
||||
en: Public URL Port
|
||||
zh: 公开 URL 端口
|
||||
zh-Hant: 公開 URL 連接埠
|
||||
ja: 公開 URL ポート
|
||||
ko: 공개 URL 포트
|
||||
ru: Порт публичного URL
|
||||
ms: Port URL Awam
|
||||
pt-br: Porta da URL pública
|
||||
required: true
|
||||
type: number
|
||||
- default: ./data
|
||||
edit: true
|
||||
envKey: APP_DATA_DIR
|
||||
labelEn: Data Directory
|
||||
labelZh: 数据目录
|
||||
label:
|
||||
en: Data Directory
|
||||
zh: 数据目录
|
||||
zh-Hant: 資料目錄
|
||||
ja: データディレクトリ
|
||||
ko: 데이터 디렉터리
|
||||
ru: Каталог данных
|
||||
ms: Direktori Data
|
||||
pt-br: Diretório de dados
|
||||
required: true
|
||||
type: text
|
||||
- default: ''
|
||||
edit: true
|
||||
envKey: MAILER_SMTP_HOST
|
||||
labelEn: SMTP Host
|
||||
labelZh: SMTP 主机
|
||||
label:
|
||||
en: SMTP Host
|
||||
zh: SMTP 主机
|
||||
zh-Hant: SMTP 主機
|
||||
ja: SMTP ホスト
|
||||
ko: SMTP 호스트
|
||||
ru: SMTP-хост
|
||||
ms: Hos SMTP
|
||||
pt-br: Host SMTP
|
||||
required: true
|
||||
type: text
|
||||
- default: 587
|
||||
edit: true
|
||||
envKey: MAILER_SMTP_PORT
|
||||
labelEn: SMTP Port
|
||||
labelZh: SMTP 端口
|
||||
label:
|
||||
en: SMTP Port
|
||||
zh: SMTP 端口
|
||||
zh-Hant: SMTP 連接埠
|
||||
ja: SMTP ポート
|
||||
ko: SMTP 포트
|
||||
ru: SMTP-порт
|
||||
ms: Port SMTP
|
||||
pt-br: Porta SMTP
|
||||
required: true
|
||||
type: number
|
||||
- default: ''
|
||||
edit: true
|
||||
envKey: MAILER_SMTP_FROM_EMAIL
|
||||
labelEn: SMTP From Email
|
||||
labelZh: SMTP 发件邮箱
|
||||
label:
|
||||
en: SMTP From Email
|
||||
zh: SMTP 发件邮箱
|
||||
zh-Hant: SMTP 寄件者電子郵件
|
||||
ja: SMTP 送信元メールアドレス
|
||||
ko: SMTP 발신 이메일
|
||||
ru: Email отправителя SMTP
|
||||
ms: E-mel Pengirim SMTP
|
||||
pt-br: E-mail do remetente SMTP
|
||||
required: true
|
||||
type: text
|
||||
- default: ''
|
||||
edit: true
|
||||
envKey: MAILER_SMTP_USER
|
||||
labelEn: SMTP Username
|
||||
labelZh: SMTP 用户名
|
||||
label:
|
||||
en: SMTP Username
|
||||
zh: SMTP 用户名
|
||||
zh-Hant: SMTP 使用者名稱
|
||||
ja: SMTP ユーザー名
|
||||
ko: SMTP 사용자 이름
|
||||
ru: Имя пользователя SMTP
|
||||
ms: Nama Pengguna SMTP
|
||||
pt-br: Usuário SMTP
|
||||
required: true
|
||||
type: text
|
||||
- default: ''
|
||||
edit: true
|
||||
envKey: MAILER_SMTP_PASSWORD
|
||||
labelEn: SMTP Password
|
||||
labelZh: SMTP 密码
|
||||
label:
|
||||
en: SMTP Password
|
||||
zh: SMTP 密码
|
||||
zh-Hant: SMTP 密碼
|
||||
ja: SMTP パスワード
|
||||
ko: SMTP 비밀번호
|
||||
ru: Пароль SMTP
|
||||
ms: Kata Laluan SMTP
|
||||
pt-br: Senha SMTP
|
||||
required: true
|
||||
type: password
|
||||
- default: 'false'
|
||||
edit: true
|
||||
envKey: MAILER_ENABLE_SSL
|
||||
labelEn: Enable SMTP SSL/TLS
|
||||
labelZh: 启用 SMTP SSL/TLS
|
||||
label:
|
||||
en: Enable SMTP SSL/TLS
|
||||
zh: 启用 SMTP SSL/TLS
|
||||
zh-Hant: 啟用 SMTP SSL/TLS
|
||||
ja: SMTP SSL/TLS を有効化
|
||||
ko: SMTP SSL/TLS 활성화
|
||||
ru: Включить SMTP SSL/TLS
|
||||
ms: Dayakan SMTP SSL/TLS
|
||||
pt-br: Ativar SMTP SSL/TLS
|
||||
required: true
|
||||
type: select
|
||||
values:
|
||||
- label: 'false'
|
||||
value: 'false'
|
||||
- label: 'true'
|
||||
value: 'true'
|
||||
- default: 'false'
|
||||
edit: true
|
||||
envKey: MAILER_ENABLE_STARTTLS
|
||||
labelEn: Enable SMTP STARTTLS
|
||||
labelZh: 启用 SMTP STARTTLS
|
||||
label:
|
||||
en: Enable SMTP STARTTLS
|
||||
zh: 启用 SMTP STARTTLS
|
||||
zh-Hant: 啟用 SMTP STARTTLS
|
||||
ja: SMTP STARTTLS を有効化
|
||||
ko: SMTP STARTTLS 활성화
|
||||
ru: Включить SMTP STARTTLS
|
||||
ms: Dayakan SMTP STARTTLS
|
||||
pt-br: Ativar SMTP STARTTLS
|
||||
required: true
|
||||
type: select
|
||||
values:
|
||||
- label: 'false'
|
||||
value: 'false'
|
||||
- label: 'true'
|
||||
value: 'true'
|
||||
- default: info
|
||||
edit: true
|
||||
envKey: LOG_LEVEL
|
||||
labelEn: Log Level
|
||||
labelZh: 日志级别
|
||||
label:
|
||||
en: Log Level
|
||||
zh: 日志级别
|
||||
zh-Hant: 日誌層級
|
||||
ja: ログレベル
|
||||
ko: 로그 수준
|
||||
ru: Уровень журналирования
|
||||
ms: Tahap Log
|
||||
pt-br: Nível de log
|
||||
required: true
|
||||
type: select
|
||||
values:
|
||||
- label: debug
|
||||
value: debug
|
||||
- label: info
|
||||
value: info
|
||||
- label: error
|
||||
value: error
|
||||
- default: Asia/Shanghai
|
||||
edit: true
|
||||
envKey: TZ
|
||||
labelEn: Timezone
|
||||
labelZh: 时区
|
||||
label:
|
||||
en: Timezone
|
||||
zh: 时区
|
||||
zh-Hant: 時區
|
||||
ja: タイムゾーン
|
||||
ko: 시간대
|
||||
ru: Часовой пояс
|
||||
ms: Zon Waktu
|
||||
pt-br: Fuso horário
|
||||
required: true
|
||||
type: text
|
||||
@@ -0,0 +1,44 @@
|
||||
services:
|
||||
keila:
|
||||
image: "pentacent/keila:0.30.2"
|
||||
container_name: ${CONTAINER_NAME}
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- 1panel-network
|
||||
ports:
|
||||
- "${PANEL_APP_PORT_HTTP}:4000"
|
||||
environment:
|
||||
- DB_URL=postgres://${PANEL_DB_USER}:${PANEL_DB_USER_PASSWORD}@${PANEL_DB_HOST}:${PANEL_DB_PORT}/${PANEL_DB_NAME}
|
||||
- DB_ENABLE_SSL=false
|
||||
- KEILA_USER=${KEILA_USER}
|
||||
- KEILA_PASSWORD=${KEILA_PASSWORD}
|
||||
- SECRET_KEY_BASE=${SECRET_KEY_BASE}
|
||||
- URL_HOST=${URL_HOST}
|
||||
- URL_SCHEMA=${URL_SCHEMA}
|
||||
- URL_PORT=${URL_PORT}
|
||||
- USER_CONTENT_DIR=/opt/app/uploads
|
||||
- MAILER_SMTP_HOST=${MAILER_SMTP_HOST}
|
||||
- MAILER_SMTP_PORT=${MAILER_SMTP_PORT}
|
||||
- MAILER_SMTP_FROM_EMAIL=${MAILER_SMTP_FROM_EMAIL}
|
||||
- MAILER_SMTP_USER=${MAILER_SMTP_USER}
|
||||
- MAILER_SMTP_PASSWORD=${MAILER_SMTP_PASSWORD}
|
||||
- MAILER_ENABLE_SSL=${MAILER_ENABLE_SSL}
|
||||
- MAILER_ENABLE_STARTTLS=${MAILER_ENABLE_STARTTLS}
|
||||
- LOG_LEVEL=${LOG_LEVEL}
|
||||
- TZ=${TZ}
|
||||
volumes:
|
||||
- "${APP_DATA_DIR}/uploads:/opt/app/uploads"
|
||||
healthcheck:
|
||||
test:
|
||||
- CMD-SHELL
|
||||
- wget --quiet --tries=1 --spider http://127.0.0.1:4000/auth/login || exit 1
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
start_period: 90s
|
||||
retries: 5
|
||||
labels:
|
||||
createdBy: "Apps"
|
||||
|
||||
networks:
|
||||
1panel-network:
|
||||
external: true
|
||||
Executable
+111
@@ -0,0 +1,111 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd -P)"
|
||||
ENV_FILE="${ENV_FILE:-${ROOT_DIR}/.env}"
|
||||
|
||||
fail() {
|
||||
printf '%s\n' "$1" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
strip_matching_quotes() {
|
||||
local value="$1"
|
||||
|
||||
if [[ ${#value} -ge 2 ]]; then
|
||||
if [[ "${value:0:1}" == '"' && "${value: -1}" == '"' ]]; then
|
||||
value="${value:1:${#value}-2}"
|
||||
elif [[ "${value:0:1}" == "'" && "${value: -1}" == "'" ]]; then
|
||||
value="${value:1:${#value}-2}"
|
||||
fi
|
||||
fi
|
||||
printf '%s\n' "$value"
|
||||
}
|
||||
|
||||
read_env_value() {
|
||||
local key="$1"
|
||||
local value=""
|
||||
|
||||
if [[ -f "$ENV_FILE" ]]; then
|
||||
value="$(grep -E "^${key}=" "$ENV_FILE" | tail -n 1 | cut -d '=' -f 2- || true)"
|
||||
fi
|
||||
strip_matching_quotes "$value"
|
||||
}
|
||||
|
||||
set_env_value() {
|
||||
local key="$1"
|
||||
local value="$2"
|
||||
local temp_file
|
||||
|
||||
temp_file="$(mktemp "${ENV_FILE}.tmp.XXXXXX")"
|
||||
awk -v key="$key" -v value="$value" '
|
||||
BEGIN { updated = 0 }
|
||||
$0 ~ ("^" key "=") {
|
||||
if (!updated) {
|
||||
print key "=" value
|
||||
updated = 1
|
||||
}
|
||||
next
|
||||
}
|
||||
{ print }
|
||||
END {
|
||||
if (!updated) print key "=" value
|
||||
}
|
||||
' "$ENV_FILE" > "$temp_file"
|
||||
chmod --reference="$ENV_FILE" "$temp_file"
|
||||
mv -f -- "$temp_file" "$ENV_FILE"
|
||||
}
|
||||
|
||||
ensure_secret_key_base() {
|
||||
local secret_key_base
|
||||
|
||||
secret_key_base="$(read_env_value SECRET_KEY_BASE)"
|
||||
if [[ ${#secret_key_base} -lt 64 ]]; then
|
||||
secret_key_base="$(od -An -N64 -tx1 /dev/urandom | tr -d ' \n')"
|
||||
set_env_value SECRET_KEY_BASE "$secret_key_base"
|
||||
fi
|
||||
}
|
||||
|
||||
path_is_dotenv_safe() {
|
||||
local value="$1"
|
||||
|
||||
case "$value" in
|
||||
*$'\n'* | *$'\r'* | *\\* | *'$'* | *'#'* | *'"'* | *"'"*) return 1 ;;
|
||||
*) return 0 ;;
|
||||
esac
|
||||
}
|
||||
|
||||
[[ -f "$ENV_FILE" ]] || fail "Environment file not found: ${ENV_FILE}"
|
||||
ensure_secret_key_base
|
||||
|
||||
if [[ ${APP_DATA_DIR+x} ]]; then
|
||||
APP_DATA_DIR_RAW="$APP_DATA_DIR"
|
||||
else
|
||||
APP_DATA_DIR_RAW="$(read_env_value APP_DATA_DIR)"
|
||||
fi
|
||||
APP_DATA_DIR_RAW="$(strip_matching_quotes "${APP_DATA_DIR_RAW:-./data}")"
|
||||
|
||||
[[ -n "$APP_DATA_DIR_RAW" ]] || fail "APP_DATA_DIR must not be empty"
|
||||
path_is_dotenv_safe "$APP_DATA_DIR_RAW" || fail "APP_DATA_DIR contains unsupported dotenv characters"
|
||||
|
||||
case "$APP_DATA_DIR_RAW" in
|
||||
/*)
|
||||
APP_DATA_DIR_ABS="$(realpath -m -- "$APP_DATA_DIR_RAW")"
|
||||
;;
|
||||
*)
|
||||
APP_DATA_DIR_ABS="$(realpath -m -- "${ROOT_DIR}/${APP_DATA_DIR_RAW#./}")"
|
||||
case "$APP_DATA_DIR_ABS" in
|
||||
"${ROOT_DIR}" | "${ROOT_DIR}"/*) ;;
|
||||
*) fail "Relative APP_DATA_DIR must stay inside the application directory" ;;
|
||||
esac
|
||||
;;
|
||||
esac
|
||||
|
||||
[[ "$APP_DATA_DIR_ABS" != "/" ]] || fail "APP_DATA_DIR must not be the filesystem root"
|
||||
[[ ! -L "$APP_DATA_DIR_ABS" ]] || fail "APP_DATA_DIR must not be a symbolic link"
|
||||
if [[ -e "$APP_DATA_DIR_ABS" && ! -d "$APP_DATA_DIR_ABS" ]]; then
|
||||
fail "APP_DATA_DIR must be a directory"
|
||||
fi
|
||||
|
||||
mkdir -p -- "${APP_DATA_DIR_ABS}/uploads"
|
||||
chmod 750 -- "$APP_DATA_DIR_ABS" "${APP_DATA_DIR_ABS}/uploads"
|
||||
Executable
+8
@@ -0,0 +1,8 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
if command -v docker-compose >/dev/null 2>&1; then
|
||||
docker-compose down --volumes --remove-orphans
|
||||
else
|
||||
docker compose down --volumes --remove-orphans
|
||||
fi
|
||||
Executable
+5
@@ -0,0 +1,5 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd -P)"
|
||||
exec bash "${SCRIPT_DIR}/init.sh"
|
||||
@@ -0,0 +1,74 @@
|
||||
# Keila
|
||||
|
||||
## 产品介绍
|
||||
|
||||
Keila 是一款开源的自托管新闻简报与邮件营销平台,可用于管理联系人、订阅表单、邮件模板和营销活动,并支持 SMTP、AWS SES、SendGrid、Mailgun 与 Postmark 等发送渠道。
|
||||
|
||||
## 主要功能
|
||||
|
||||
- 管理联系人、分组、订阅表单、模板和新闻简报活动。
|
||||
- 提供可视化、Markdown 和纯文本邮件编辑能力。
|
||||
- 支持公开订阅页面、活动统计和 API。
|
||||
- 业务数据保存在 PostgreSQL,本地上传文件保存在独立持久化目录。
|
||||
|
||||
## 部署拓扑
|
||||
|
||||
- 本应用包只运行一个 Keila service,使用上游官方 `pentacent/keila` 镜像。
|
||||
- 安装时必须选择同一 1Panel 中已运行的 PostgreSQL Runtime;1Panel 会为 Keila 创建独立数据库和独立用户。
|
||||
- 上游示例 Compose 中的 PostgreSQL service 已替换为 1Panel Runtime 联动,不会在应用包中重复部署数据库。
|
||||
- SMTP 是生产启动的必填依赖,但属于用户提供的外部服务,不会作为 sidecar 安装。
|
||||
|
||||
## 访问说明
|
||||
|
||||
默认 Web 端口为 `4000`。安装后访问 `http://服务器地址:安装端口/auth/login`,使用安装表单中的初始管理员邮箱和密码登录。
|
||||
|
||||
- `公开访问主机` 只填写域名或 IP,不包含 `http://`、`https://` 或路径。
|
||||
- 直接按端口访问时,公开 URL 端口通常与 Web 端口相同。
|
||||
- 通过反向代理发布 HTTPS 时,公开 URL 协议应设为 `https`,公开 URL 端口通常设为 `443`;反向代理必须正确转发 WebSocket。
|
||||
- 初始管理员只在空数据库第一次启动时创建。后续修改安装参数不会重置已有管理员密码,请在 Keila 中管理账号。
|
||||
- 上游要求管理员密码至少 10 个字符;会话密钥应为至少 64 个字符的强随机值。
|
||||
|
||||
## SMTP
|
||||
|
||||
Keila 在生产模式启动时必须配置系统 SMTP,用于注册、激活和密码重置等邮件。
|
||||
|
||||
- SMTP 用户名在上游可回退为发件邮箱;本应用包要求显式填写,以兼容用户名与发件邮箱不同的服务。
|
||||
- 端口 `587` 通常配合 STARTTLS,端口 `465` 通常配合 SSL/TLS。具体组合以邮件服务商文档为准。
|
||||
- SMTP 密码、数据库密码、管理员密码和会话密钥都会写入 1Panel 生成的运行时 `.env`,不得提交到 Git 或复制到公开日志。
|
||||
|
||||
## 数据、备份与升级
|
||||
|
||||
- Keila 会在启动时自动执行 PostgreSQL schema migration,并在空数据库中创建初始 root 用户。
|
||||
- 联系人、活动、模板、账号和任务队列数据位于所选 PostgreSQL Runtime 的独立数据库中。
|
||||
- 用户上传文件位于 `${APP_DATA_DIR}/uploads`,容器内路径为 `/opt/app/uploads`。
|
||||
- 升级前必须同时备份 PostgreSQL 数据库和 `${APP_DATA_DIR}/uploads`。升级期间等待数据库 migration 完成后再停止或重启容器。
|
||||
- 固定版和 `latest` 使用相同的持久化边界;回滚时应恢复与目标版本匹配的升级前数据库及上传文件备份。
|
||||
- 卸载应用不会删除所选 PostgreSQL Runtime 本身;是否删除 Keila 的独立数据库和用户取决于 1Panel 卸载选项。卸载前请完成备份。
|
||||
|
||||
## 安全与许可证
|
||||
|
||||
- Compose 不启用 privileged、host network、额外 capability、设备映射或 Docker Socket。
|
||||
- 建议通过 1Panel 反向代理启用 HTTPS,并限制管理入口的公网暴露范围。
|
||||
- Keila 源代码采用 GNU Affero General Public License v3.0 或更高版本。部署、修改或向网络用户提供服务时,请遵守上游许可证义务。
|
||||
- 上游 README 说明 Keila 标志不包含在 AGPL 授权中;标志权利归其权利人,本应用包仅将其用于识别对应产品。
|
||||
|
||||
## 参考资料
|
||||
|
||||
- 官网:<https://www.keila.io/>
|
||||
- 官方安装文档:<https://www.keila.io/docs/installation>
|
||||
- 官方配置文档:<https://www.keila.io/docs/configuration>
|
||||
- 官方首次启动文档:<https://www.keila.io/docs/setup>
|
||||
- 源码与官方 Compose:<https://github.com/pentacent/keila>
|
||||
|
||||
## Introduction
|
||||
|
||||
Keila is an open-source self-hosted newsletter and email marketing platform. This package runs one official Keila container, links it to a selectable PostgreSQL Runtime managed by 1Panel, and persists local uploads separately.
|
||||
|
||||
Production startup requires SMTP configuration. Keila automatically runs database migrations and creates the initial root user on an empty database. Back up both PostgreSQL and `${APP_DATA_DIR}/uploads` before upgrades.
|
||||
|
||||
## Features
|
||||
|
||||
- Contact, segment, subscription-form, template, and newsletter campaign management.
|
||||
- Visual, Markdown, and plain-text email editing.
|
||||
- PostgreSQL-backed application data and a persistent local upload directory.
|
||||
- Explicit initial administrator, public URL, SMTP, and session-secret configuration.
|
||||
@@ -0,0 +1,30 @@
|
||||
name: Keila
|
||||
tags:
|
||||
- Email
|
||||
title: 开源的自托管新闻简报与邮件营销平台
|
||||
description: 开源的自托管新闻简报与邮件营销平台
|
||||
additionalProperties:
|
||||
key: keila
|
||||
name: Keila
|
||||
tags:
|
||||
- Email
|
||||
type: tool
|
||||
website: https://www.keila.io/
|
||||
document: https://www.keila.io/docs/installation
|
||||
github: https://github.com/pentacent/keila
|
||||
shortDescZh: 开源的自托管新闻简报与邮件营销平台
|
||||
shortDescEn: An open-source self-hosted newsletter and email marketing platform
|
||||
crossVersionUpdate: true
|
||||
limit: 0
|
||||
recommend: 0
|
||||
architectures:
|
||||
- amd64
|
||||
description:
|
||||
en: An open-source self-hosted newsletter and email marketing platform
|
||||
zh: 开源的自托管新闻简报与邮件营销平台
|
||||
zh-Hant: 開源的自託管電子報與電子郵件行銷平台
|
||||
ja: オープンソースのセルフホスト型ニュースレター・メールマーケティングプラットフォーム
|
||||
ko: 오픈 소스 자체 호스팅 뉴스레터 및 이메일 마케팅 플랫폼
|
||||
ru: Самостоятельно размещаемая платформа с открытым исходным кодом для рассылок и email-маркетинга
|
||||
ms: Platform sumber terbuka yang dihos sendiri untuk surat berita dan pemasaran e-mel
|
||||
pt-br: Plataforma de código aberto auto-hospedada para newsletters e marketing por e-mail
|
||||
@@ -0,0 +1,23 @@
|
||||
PANEL_APP_PORT_HTTP=4000
|
||||
PANEL_DB_HOST=
|
||||
PANEL_DB_PORT=5432
|
||||
PANEL_DB_NAME=keila
|
||||
PANEL_DB_USER=keila
|
||||
PANEL_DB_USER_PASSWORD=
|
||||
KEILA_USER=root@localhost
|
||||
KEILA_PASSWORD=
|
||||
SECRET_KEY_BASE=
|
||||
URL_HOST=localhost
|
||||
URL_SCHEMA=http
|
||||
URL_PORT=4000
|
||||
APP_DATA_DIR=./data
|
||||
MAILER_SMTP_HOST=
|
||||
MAILER_SMTP_PORT=587
|
||||
MAILER_SMTP_FROM_EMAIL=
|
||||
MAILER_SMTP_USER=
|
||||
MAILER_SMTP_PASSWORD=
|
||||
MAILER_ENABLE_SSL=false
|
||||
MAILER_ENABLE_STARTTLS=false
|
||||
LOG_LEVEL=info
|
||||
TZ=Asia/Shanghai
|
||||
CONTAINER_NAME=
|
||||
@@ -0,0 +1,401 @@
|
||||
additionalProperties:
|
||||
formFields:
|
||||
- default: 4000
|
||||
edit: true
|
||||
envKey: PANEL_APP_PORT_HTTP
|
||||
labelEn: HTTP Port
|
||||
labelZh: HTTP 端口
|
||||
label:
|
||||
en: HTTP Port
|
||||
zh: HTTP 端口
|
||||
zh-Hant: HTTP 連接埠
|
||||
ja: HTTP ポート
|
||||
ko: HTTP 포트
|
||||
ru: HTTP-порт
|
||||
ms: Port HTTP
|
||||
pt-br: Porta HTTP
|
||||
required: true
|
||||
rule: paramPort
|
||||
type: number
|
||||
- default: postgresql
|
||||
envKey: PANEL_DB_TYPE
|
||||
labelEn: Database Runtime
|
||||
labelZh: 数据库 Runtime
|
||||
label:
|
||||
en: Database Runtime
|
||||
zh: 数据库 Runtime
|
||||
zh-Hant: 資料庫 Runtime
|
||||
ja: データベース Runtime
|
||||
ko: 데이터베이스 Runtime
|
||||
ru: Среда базы данных
|
||||
ms: Runtime Pangkalan Data
|
||||
pt-br: Runtime de banco de dados
|
||||
required: true
|
||||
type: apps
|
||||
values:
|
||||
- label: PostgreSQL
|
||||
value: postgresql
|
||||
child:
|
||||
default: ''
|
||||
envKey: PANEL_DB_HOST
|
||||
labelEn: PostgreSQL Service
|
||||
labelZh: PostgreSQL 服务
|
||||
label:
|
||||
en: PostgreSQL Service
|
||||
zh: PostgreSQL 服务
|
||||
zh-Hant: PostgreSQL 服務
|
||||
ja: PostgreSQL サービス
|
||||
ko: PostgreSQL 서비스
|
||||
ru: Сервис PostgreSQL
|
||||
ms: Perkhidmatan PostgreSQL
|
||||
pt-br: Serviço PostgreSQL
|
||||
required: true
|
||||
type: service
|
||||
- default: 5432
|
||||
edit: true
|
||||
envKey: PANEL_DB_PORT
|
||||
labelEn: Database Port
|
||||
labelZh: 数据库端口
|
||||
label:
|
||||
en: Database Port
|
||||
zh: 数据库端口
|
||||
zh-Hant: 資料庫連接埠
|
||||
ja: データベースポート
|
||||
ko: 데이터베이스 포트
|
||||
ru: Порт базы данных
|
||||
ms: Port Pangkalan Data
|
||||
pt-br: Porta do banco de dados
|
||||
required: true
|
||||
rule: paramPort
|
||||
type: number
|
||||
- default: keila
|
||||
edit: true
|
||||
envKey: PANEL_DB_NAME
|
||||
labelEn: Database Name
|
||||
labelZh: 数据库名
|
||||
label:
|
||||
en: Database Name
|
||||
zh: 数据库名
|
||||
zh-Hant: 資料庫名稱
|
||||
ja: データベース名
|
||||
ko: 데이터베이스 이름
|
||||
ru: Имя базы данных
|
||||
ms: Nama Pangkalan Data
|
||||
pt-br: Nome do banco de dados
|
||||
random: true
|
||||
required: true
|
||||
rule: paramCommon
|
||||
type: text
|
||||
- default: keila
|
||||
edit: true
|
||||
envKey: PANEL_DB_USER
|
||||
labelEn: Database User
|
||||
labelZh: 数据库用户
|
||||
label:
|
||||
en: Database User
|
||||
zh: 数据库用户
|
||||
zh-Hant: 資料庫使用者
|
||||
ja: データベースユーザー
|
||||
ko: 데이터베이스 사용자
|
||||
ru: Пользователь базы данных
|
||||
ms: Pengguna Pangkalan Data
|
||||
pt-br: Usuário do banco de dados
|
||||
random: true
|
||||
required: true
|
||||
rule: paramCommon
|
||||
type: text
|
||||
- default: ''
|
||||
edit: true
|
||||
envKey: PANEL_DB_USER_PASSWORD
|
||||
labelEn: Database Password
|
||||
labelZh: 数据库密码
|
||||
label:
|
||||
en: Database Password
|
||||
zh: 数据库密码
|
||||
zh-Hant: 資料庫密碼
|
||||
ja: データベースパスワード
|
||||
ko: 데이터베이스 비밀번호
|
||||
ru: Пароль базы данных
|
||||
ms: Kata Laluan Pangkalan Data
|
||||
pt-br: Senha do banco de dados
|
||||
required: true
|
||||
rule: paramComplexity
|
||||
type: password
|
||||
- default: root@localhost
|
||||
edit: true
|
||||
envKey: KEILA_USER
|
||||
labelEn: Initial Administrator Email
|
||||
labelZh: 初始管理员邮箱
|
||||
label:
|
||||
en: Initial Administrator Email
|
||||
zh: 初始管理员邮箱
|
||||
zh-Hant: 初始管理員電子郵件
|
||||
ja: 初期管理者メールアドレス
|
||||
ko: 초기 관리자 이메일
|
||||
ru: Email начального администратора
|
||||
ms: E-mel Pentadbir Awal
|
||||
pt-br: E-mail do administrador inicial
|
||||
required: true
|
||||
type: text
|
||||
- default: ''
|
||||
edit: true
|
||||
envKey: KEILA_PASSWORD
|
||||
labelEn: Initial Administrator Password (10+ characters)
|
||||
labelZh: 初始管理员密码(至少 10 个字符)
|
||||
label:
|
||||
en: Initial Administrator Password (10+ characters)
|
||||
zh: 初始管理员密码(至少 10 个字符)
|
||||
zh-Hant: 初始管理員密碼(至少 10 個字元)
|
||||
ja: 初期管理者パスワード(10 文字以上)
|
||||
ko: 초기 관리자 비밀번호(10자 이상)
|
||||
ru: Пароль начального администратора (не менее 10 символов)
|
||||
ms: Kata Laluan Pentadbir Awal (10+ aksara)
|
||||
pt-br: Senha do administrador inicial (10+ caracteres)
|
||||
required: true
|
||||
type: password
|
||||
- default: ''
|
||||
edit: true
|
||||
envKey: SECRET_KEY_BASE
|
||||
labelEn: Session Secret (64+ characters)
|
||||
labelZh: 会话密钥(至少 64 个字符)
|
||||
label:
|
||||
en: Session Secret (64+ characters)
|
||||
zh: 会话密钥(至少 64 个字符)
|
||||
zh-Hant: 工作階段密鑰(至少 64 個字元)
|
||||
ja: セッションシークレット(64 文字以上)
|
||||
ko: 세션 비밀 키(64자 이상)
|
||||
ru: Секрет сеанса (не менее 64 символов)
|
||||
ms: Rahsia Sesi (64+ aksara)
|
||||
pt-br: Segredo da sessão (64+ caracteres)
|
||||
required: true
|
||||
type: password
|
||||
- default: ''
|
||||
edit: true
|
||||
envKey: URL_HOST
|
||||
labelEn: Public Host (domain or IP)
|
||||
labelZh: 公开访问主机(域名或 IP)
|
||||
label:
|
||||
en: Public Host (domain or IP)
|
||||
zh: 公开访问主机(域名或 IP)
|
||||
zh-Hant: 公開存取主機(網域或 IP)
|
||||
ja: 公開ホスト(ドメインまたは IP)
|
||||
ko: 공개 호스트(도메인 또는 IP)
|
||||
ru: Публичный хост (домен или IP)
|
||||
ms: Hos Awam (domain atau IP)
|
||||
pt-br: Host público (domínio ou IP)
|
||||
required: true
|
||||
type: text
|
||||
- default: http
|
||||
edit: true
|
||||
envKey: URL_SCHEMA
|
||||
labelEn: Public URL Scheme
|
||||
labelZh: 公开 URL 协议
|
||||
label:
|
||||
en: Public URL Scheme
|
||||
zh: 公开 URL 协议
|
||||
zh-Hant: 公開 URL 通訊協定
|
||||
ja: 公開 URL スキーム
|
||||
ko: 공개 URL 스키마
|
||||
ru: Схема публичного URL
|
||||
ms: Skema URL Awam
|
||||
pt-br: Esquema da URL pública
|
||||
required: true
|
||||
type: select
|
||||
values:
|
||||
- label: http
|
||||
value: http
|
||||
- label: https
|
||||
value: https
|
||||
- default: 4000
|
||||
edit: true
|
||||
envKey: URL_PORT
|
||||
labelEn: Public URL Port
|
||||
labelZh: 公开 URL 端口
|
||||
label:
|
||||
en: Public URL Port
|
||||
zh: 公开 URL 端口
|
||||
zh-Hant: 公開 URL 連接埠
|
||||
ja: 公開 URL ポート
|
||||
ko: 공개 URL 포트
|
||||
ru: Порт публичного URL
|
||||
ms: Port URL Awam
|
||||
pt-br: Porta da URL pública
|
||||
required: true
|
||||
type: number
|
||||
- default: ./data
|
||||
edit: true
|
||||
envKey: APP_DATA_DIR
|
||||
labelEn: Data Directory
|
||||
labelZh: 数据目录
|
||||
label:
|
||||
en: Data Directory
|
||||
zh: 数据目录
|
||||
zh-Hant: 資料目錄
|
||||
ja: データディレクトリ
|
||||
ko: 데이터 디렉터리
|
||||
ru: Каталог данных
|
||||
ms: Direktori Data
|
||||
pt-br: Diretório de dados
|
||||
required: true
|
||||
type: text
|
||||
- default: ''
|
||||
edit: true
|
||||
envKey: MAILER_SMTP_HOST
|
||||
labelEn: SMTP Host
|
||||
labelZh: SMTP 主机
|
||||
label:
|
||||
en: SMTP Host
|
||||
zh: SMTP 主机
|
||||
zh-Hant: SMTP 主機
|
||||
ja: SMTP ホスト
|
||||
ko: SMTP 호스트
|
||||
ru: SMTP-хост
|
||||
ms: Hos SMTP
|
||||
pt-br: Host SMTP
|
||||
required: true
|
||||
type: text
|
||||
- default: 587
|
||||
edit: true
|
||||
envKey: MAILER_SMTP_PORT
|
||||
labelEn: SMTP Port
|
||||
labelZh: SMTP 端口
|
||||
label:
|
||||
en: SMTP Port
|
||||
zh: SMTP 端口
|
||||
zh-Hant: SMTP 連接埠
|
||||
ja: SMTP ポート
|
||||
ko: SMTP 포트
|
||||
ru: SMTP-порт
|
||||
ms: Port SMTP
|
||||
pt-br: Porta SMTP
|
||||
required: true
|
||||
type: number
|
||||
- default: ''
|
||||
edit: true
|
||||
envKey: MAILER_SMTP_FROM_EMAIL
|
||||
labelEn: SMTP From Email
|
||||
labelZh: SMTP 发件邮箱
|
||||
label:
|
||||
en: SMTP From Email
|
||||
zh: SMTP 发件邮箱
|
||||
zh-Hant: SMTP 寄件者電子郵件
|
||||
ja: SMTP 送信元メールアドレス
|
||||
ko: SMTP 발신 이메일
|
||||
ru: Email отправителя SMTP
|
||||
ms: E-mel Pengirim SMTP
|
||||
pt-br: E-mail do remetente SMTP
|
||||
required: true
|
||||
type: text
|
||||
- default: ''
|
||||
edit: true
|
||||
envKey: MAILER_SMTP_USER
|
||||
labelEn: SMTP Username
|
||||
labelZh: SMTP 用户名
|
||||
label:
|
||||
en: SMTP Username
|
||||
zh: SMTP 用户名
|
||||
zh-Hant: SMTP 使用者名稱
|
||||
ja: SMTP ユーザー名
|
||||
ko: SMTP 사용자 이름
|
||||
ru: Имя пользователя SMTP
|
||||
ms: Nama Pengguna SMTP
|
||||
pt-br: Usuário SMTP
|
||||
required: true
|
||||
type: text
|
||||
- default: ''
|
||||
edit: true
|
||||
envKey: MAILER_SMTP_PASSWORD
|
||||
labelEn: SMTP Password
|
||||
labelZh: SMTP 密码
|
||||
label:
|
||||
en: SMTP Password
|
||||
zh: SMTP 密码
|
||||
zh-Hant: SMTP 密碼
|
||||
ja: SMTP パスワード
|
||||
ko: SMTP 비밀번호
|
||||
ru: Пароль SMTP
|
||||
ms: Kata Laluan SMTP
|
||||
pt-br: Senha SMTP
|
||||
required: true
|
||||
type: password
|
||||
- default: 'false'
|
||||
edit: true
|
||||
envKey: MAILER_ENABLE_SSL
|
||||
labelEn: Enable SMTP SSL/TLS
|
||||
labelZh: 启用 SMTP SSL/TLS
|
||||
label:
|
||||
en: Enable SMTP SSL/TLS
|
||||
zh: 启用 SMTP SSL/TLS
|
||||
zh-Hant: 啟用 SMTP SSL/TLS
|
||||
ja: SMTP SSL/TLS を有効化
|
||||
ko: SMTP SSL/TLS 활성화
|
||||
ru: Включить SMTP SSL/TLS
|
||||
ms: Dayakan SMTP SSL/TLS
|
||||
pt-br: Ativar SMTP SSL/TLS
|
||||
required: true
|
||||
type: select
|
||||
values:
|
||||
- label: 'false'
|
||||
value: 'false'
|
||||
- label: 'true'
|
||||
value: 'true'
|
||||
- default: 'false'
|
||||
edit: true
|
||||
envKey: MAILER_ENABLE_STARTTLS
|
||||
labelEn: Enable SMTP STARTTLS
|
||||
labelZh: 启用 SMTP STARTTLS
|
||||
label:
|
||||
en: Enable SMTP STARTTLS
|
||||
zh: 启用 SMTP STARTTLS
|
||||
zh-Hant: 啟用 SMTP STARTTLS
|
||||
ja: SMTP STARTTLS を有効化
|
||||
ko: SMTP STARTTLS 활성화
|
||||
ru: Включить SMTP STARTTLS
|
||||
ms: Dayakan SMTP STARTTLS
|
||||
pt-br: Ativar SMTP STARTTLS
|
||||
required: true
|
||||
type: select
|
||||
values:
|
||||
- label: 'false'
|
||||
value: 'false'
|
||||
- label: 'true'
|
||||
value: 'true'
|
||||
- default: info
|
||||
edit: true
|
||||
envKey: LOG_LEVEL
|
||||
labelEn: Log Level
|
||||
labelZh: 日志级别
|
||||
label:
|
||||
en: Log Level
|
||||
zh: 日志级别
|
||||
zh-Hant: 日誌層級
|
||||
ja: ログレベル
|
||||
ko: 로그 수준
|
||||
ru: Уровень журналирования
|
||||
ms: Tahap Log
|
||||
pt-br: Nível de log
|
||||
required: true
|
||||
type: select
|
||||
values:
|
||||
- label: debug
|
||||
value: debug
|
||||
- label: info
|
||||
value: info
|
||||
- label: error
|
||||
value: error
|
||||
- default: Asia/Shanghai
|
||||
edit: true
|
||||
envKey: TZ
|
||||
labelEn: Timezone
|
||||
labelZh: 时区
|
||||
label:
|
||||
en: Timezone
|
||||
zh: 时区
|
||||
zh-Hant: 時區
|
||||
ja: タイムゾーン
|
||||
ko: 시간대
|
||||
ru: Часовой пояс
|
||||
ms: Zon Waktu
|
||||
pt-br: Fuso horário
|
||||
required: true
|
||||
type: text
|
||||
@@ -0,0 +1,44 @@
|
||||
services:
|
||||
keila:
|
||||
image: "pentacent/keila:latest"
|
||||
container_name: ${CONTAINER_NAME}
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- 1panel-network
|
||||
ports:
|
||||
- "${PANEL_APP_PORT_HTTP}:4000"
|
||||
environment:
|
||||
- DB_URL=postgres://${PANEL_DB_USER}:${PANEL_DB_USER_PASSWORD}@${PANEL_DB_HOST}:${PANEL_DB_PORT}/${PANEL_DB_NAME}
|
||||
- DB_ENABLE_SSL=false
|
||||
- KEILA_USER=${KEILA_USER}
|
||||
- KEILA_PASSWORD=${KEILA_PASSWORD}
|
||||
- SECRET_KEY_BASE=${SECRET_KEY_BASE}
|
||||
- URL_HOST=${URL_HOST}
|
||||
- URL_SCHEMA=${URL_SCHEMA}
|
||||
- URL_PORT=${URL_PORT}
|
||||
- USER_CONTENT_DIR=/opt/app/uploads
|
||||
- MAILER_SMTP_HOST=${MAILER_SMTP_HOST}
|
||||
- MAILER_SMTP_PORT=${MAILER_SMTP_PORT}
|
||||
- MAILER_SMTP_FROM_EMAIL=${MAILER_SMTP_FROM_EMAIL}
|
||||
- MAILER_SMTP_USER=${MAILER_SMTP_USER}
|
||||
- MAILER_SMTP_PASSWORD=${MAILER_SMTP_PASSWORD}
|
||||
- MAILER_ENABLE_SSL=${MAILER_ENABLE_SSL}
|
||||
- MAILER_ENABLE_STARTTLS=${MAILER_ENABLE_STARTTLS}
|
||||
- LOG_LEVEL=${LOG_LEVEL}
|
||||
- TZ=${TZ}
|
||||
volumes:
|
||||
- "${APP_DATA_DIR}/uploads:/opt/app/uploads"
|
||||
healthcheck:
|
||||
test:
|
||||
- CMD-SHELL
|
||||
- wget --quiet --tries=1 --spider http://127.0.0.1:4000/auth/login || exit 1
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
start_period: 90s
|
||||
retries: 5
|
||||
labels:
|
||||
createdBy: "Apps"
|
||||
|
||||
networks:
|
||||
1panel-network:
|
||||
external: true
|
||||
Executable
+111
@@ -0,0 +1,111 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd -P)"
|
||||
ENV_FILE="${ENV_FILE:-${ROOT_DIR}/.env}"
|
||||
|
||||
fail() {
|
||||
printf '%s\n' "$1" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
strip_matching_quotes() {
|
||||
local value="$1"
|
||||
|
||||
if [[ ${#value} -ge 2 ]]; then
|
||||
if [[ "${value:0:1}" == '"' && "${value: -1}" == '"' ]]; then
|
||||
value="${value:1:${#value}-2}"
|
||||
elif [[ "${value:0:1}" == "'" && "${value: -1}" == "'" ]]; then
|
||||
value="${value:1:${#value}-2}"
|
||||
fi
|
||||
fi
|
||||
printf '%s\n' "$value"
|
||||
}
|
||||
|
||||
read_env_value() {
|
||||
local key="$1"
|
||||
local value=""
|
||||
|
||||
if [[ -f "$ENV_FILE" ]]; then
|
||||
value="$(grep -E "^${key}=" "$ENV_FILE" | tail -n 1 | cut -d '=' -f 2- || true)"
|
||||
fi
|
||||
strip_matching_quotes "$value"
|
||||
}
|
||||
|
||||
set_env_value() {
|
||||
local key="$1"
|
||||
local value="$2"
|
||||
local temp_file
|
||||
|
||||
temp_file="$(mktemp "${ENV_FILE}.tmp.XXXXXX")"
|
||||
awk -v key="$key" -v value="$value" '
|
||||
BEGIN { updated = 0 }
|
||||
$0 ~ ("^" key "=") {
|
||||
if (!updated) {
|
||||
print key "=" value
|
||||
updated = 1
|
||||
}
|
||||
next
|
||||
}
|
||||
{ print }
|
||||
END {
|
||||
if (!updated) print key "=" value
|
||||
}
|
||||
' "$ENV_FILE" > "$temp_file"
|
||||
chmod --reference="$ENV_FILE" "$temp_file"
|
||||
mv -f -- "$temp_file" "$ENV_FILE"
|
||||
}
|
||||
|
||||
ensure_secret_key_base() {
|
||||
local secret_key_base
|
||||
|
||||
secret_key_base="$(read_env_value SECRET_KEY_BASE)"
|
||||
if [[ ${#secret_key_base} -lt 64 ]]; then
|
||||
secret_key_base="$(od -An -N64 -tx1 /dev/urandom | tr -d ' \n')"
|
||||
set_env_value SECRET_KEY_BASE "$secret_key_base"
|
||||
fi
|
||||
}
|
||||
|
||||
path_is_dotenv_safe() {
|
||||
local value="$1"
|
||||
|
||||
case "$value" in
|
||||
*$'\n'* | *$'\r'* | *\\* | *'$'* | *'#'* | *'"'* | *"'"*) return 1 ;;
|
||||
*) return 0 ;;
|
||||
esac
|
||||
}
|
||||
|
||||
[[ -f "$ENV_FILE" ]] || fail "Environment file not found: ${ENV_FILE}"
|
||||
ensure_secret_key_base
|
||||
|
||||
if [[ ${APP_DATA_DIR+x} ]]; then
|
||||
APP_DATA_DIR_RAW="$APP_DATA_DIR"
|
||||
else
|
||||
APP_DATA_DIR_RAW="$(read_env_value APP_DATA_DIR)"
|
||||
fi
|
||||
APP_DATA_DIR_RAW="$(strip_matching_quotes "${APP_DATA_DIR_RAW:-./data}")"
|
||||
|
||||
[[ -n "$APP_DATA_DIR_RAW" ]] || fail "APP_DATA_DIR must not be empty"
|
||||
path_is_dotenv_safe "$APP_DATA_DIR_RAW" || fail "APP_DATA_DIR contains unsupported dotenv characters"
|
||||
|
||||
case "$APP_DATA_DIR_RAW" in
|
||||
/*)
|
||||
APP_DATA_DIR_ABS="$(realpath -m -- "$APP_DATA_DIR_RAW")"
|
||||
;;
|
||||
*)
|
||||
APP_DATA_DIR_ABS="$(realpath -m -- "${ROOT_DIR}/${APP_DATA_DIR_RAW#./}")"
|
||||
case "$APP_DATA_DIR_ABS" in
|
||||
"${ROOT_DIR}" | "${ROOT_DIR}"/*) ;;
|
||||
*) fail "Relative APP_DATA_DIR must stay inside the application directory" ;;
|
||||
esac
|
||||
;;
|
||||
esac
|
||||
|
||||
[[ "$APP_DATA_DIR_ABS" != "/" ]] || fail "APP_DATA_DIR must not be the filesystem root"
|
||||
[[ ! -L "$APP_DATA_DIR_ABS" ]] || fail "APP_DATA_DIR must not be a symbolic link"
|
||||
if [[ -e "$APP_DATA_DIR_ABS" && ! -d "$APP_DATA_DIR_ABS" ]]; then
|
||||
fail "APP_DATA_DIR must be a directory"
|
||||
fi
|
||||
|
||||
mkdir -p -- "${APP_DATA_DIR_ABS}/uploads"
|
||||
chmod 750 -- "$APP_DATA_DIR_ABS" "${APP_DATA_DIR_ABS}/uploads"
|
||||
Executable
+8
@@ -0,0 +1,8 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
if command -v docker-compose >/dev/null 2>&1; then
|
||||
docker-compose down --volumes --remove-orphans
|
||||
else
|
||||
docker compose down --volumes --remove-orphans
|
||||
fi
|
||||
Executable
+5
@@ -0,0 +1,5 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd -P)"
|
||||
exec bash "${SCRIPT_DIR}/init.sh"
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 1.9 KiB |
Reference in New Issue
Block a user