forked from DevOps/deploy.stack
feat(couchdb): 添加 CouchDB 配置文件和生成脚本
- 添加 CouchDB 的 Docker 配置文件和环境变量配置 - 添加用于生成 Obsidian LiveSync 配置的 Python 脚本
This commit is contained in:
2
dbSer/couchdb/env.cfg
Normal file
2
dbSer/couchdb/env.cfg
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
IMAGE_TAG=couchdb:3.5
|
||||||
|
|
||||||
38
dbSer/couchdb/etc/couchdb/local.d/local.ini
Normal file
38
dbSer/couchdb/etc/couchdb/local.d/local.ini
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
# CouchDB 配置文件
|
||||||
|
# 此文件包含 Obsidian LiveSync 所需的 CouchDB 配置
|
||||||
|
|
||||||
|
[couchdb]
|
||||||
|
# 单节点模式设置
|
||||||
|
single_node=true
|
||||||
|
# 最大文档大小(字节)
|
||||||
|
max_document_size = 50000000
|
||||||
|
|
||||||
|
[chttpd]
|
||||||
|
# 要求有效用户认证
|
||||||
|
require_valid_user = true
|
||||||
|
# 最大 HTTP 请求大小(字节)
|
||||||
|
max_http_request_size = 4294967296
|
||||||
|
|
||||||
|
[chttpd_auth]
|
||||||
|
# 要求有效用户认证
|
||||||
|
require_valid_user = true
|
||||||
|
# 认证重定向页面
|
||||||
|
authentication_redirect = /_utils/session.html
|
||||||
|
|
||||||
|
[httpd]
|
||||||
|
# 基本认证领域
|
||||||
|
WWW-Authenticate = Basic realm="couchdb"
|
||||||
|
# 启用 CORS
|
||||||
|
enable_cors = true
|
||||||
|
|
||||||
|
[cors]
|
||||||
|
# 允许的源(用逗号分隔)
|
||||||
|
origins = app://obsidian.md,capacitor://localhost,http://localhost
|
||||||
|
# 允许发送认证信息
|
||||||
|
credentials = true
|
||||||
|
# 允许的请求头
|
||||||
|
headers = accept, authorization, content-type, origin, referer
|
||||||
|
# 允许的 HTTP 方法
|
||||||
|
methods = GET, PUT, POST, HEAD, DELETE
|
||||||
|
# CORS 预检请求缓存时间(秒)
|
||||||
|
max_age = 3600
|
||||||
305
dbSer/couchdb/generate_config.py
Normal file
305
dbSer/couchdb/generate_config.py
Normal file
@@ -0,0 +1,305 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Obsidian LiveSync CouchDB 配置生成器
|
||||||
|
|
||||||
|
此脚本用于生成运行 CouchDB 所需的配置文件,特别针对 Obsidian LiveSync 插件进行了优化配置。
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import re
|
||||||
|
import getpass
|
||||||
|
import platform
|
||||||
|
from typing import Dict, Any, Optional, Tuple
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
def get_current_user_ids() -> Tuple[str, str]:
|
||||||
|
"""
|
||||||
|
获取当前用户的 UID 和 GID。
|
||||||
|
在 Windows 上返回默认值,在 Linux/macOS 上返回实际值。
|
||||||
|
"""
|
||||||
|
if platform.system() in ['Linux', 'Darwin']: # Linux 或 macOS
|
||||||
|
try:
|
||||||
|
return str(os.getuid()), str(os.getgid())
|
||||||
|
except AttributeError:
|
||||||
|
pass
|
||||||
|
# Windows 或其他系统返回默认值
|
||||||
|
return "99", "100"
|
||||||
|
|
||||||
|
# 常量定义
|
||||||
|
DEFAULT_CONFIG = {
|
||||||
|
"couchdb_user": "obsidian_user",
|
||||||
|
"host_port": "5984",
|
||||||
|
"volume_name": "couchdb_data",
|
||||||
|
"config_host_path": "./etc/couchdb/local.d",
|
||||||
|
"single_node": "true",
|
||||||
|
"cors_origins": "app://obsidian.md,capacitor://localhost,http://localhost",
|
||||||
|
"puid": get_current_user_ids()[0], # 自动获取当前用户的 UID
|
||||||
|
"pgid": get_current_user_ids()[1], # 自动获取当前用户的 GID
|
||||||
|
"tz": "Asia/Shanghai"
|
||||||
|
}
|
||||||
|
|
||||||
|
COMMON_TIMEZONES = {
|
||||||
|
"1": "Asia/Shanghai",
|
||||||
|
"2": "Asia/Singapore",
|
||||||
|
"3": "America/New_York",
|
||||||
|
"4": "Europe/London",
|
||||||
|
"5": "Asia/Tokyo"
|
||||||
|
}
|
||||||
|
|
||||||
|
def validate_port(port: str) -> bool:
|
||||||
|
"""验证端口号是否有效。"""
|
||||||
|
try:
|
||||||
|
port_num = int(port)
|
||||||
|
return 1 <= port_num <= 65535
|
||||||
|
except ValueError:
|
||||||
|
return False
|
||||||
|
|
||||||
|
def validate_username(username: str) -> bool:
|
||||||
|
"""验证用户名是否有效。"""
|
||||||
|
return bool(re.match(r'^[a-zA-Z0-9_-]{3,32}$', username))
|
||||||
|
|
||||||
|
def validate_password(password: str) -> bool:
|
||||||
|
"""验证密码是否满足最低安全要求。"""
|
||||||
|
if len(password) < 8:
|
||||||
|
return False
|
||||||
|
if not re.search(r'[A-Z]', password):
|
||||||
|
return False
|
||||||
|
if not re.search(r'[a-z]', password):
|
||||||
|
return False
|
||||||
|
if not re.search(r'[0-9]', password):
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
def get_input_with_default(prompt: str, default: str, validator: Optional[callable] = None) -> str:
|
||||||
|
"""获取用户输入,支持默认值和验证。"""
|
||||||
|
while True:
|
||||||
|
value = input(f"{prompt} [{default}]:").strip()
|
||||||
|
if not value:
|
||||||
|
value = default
|
||||||
|
if validator and not validator(value):
|
||||||
|
print(f"输入无效,请重试。")
|
||||||
|
continue
|
||||||
|
return value
|
||||||
|
|
||||||
|
def get_password() -> str:
|
||||||
|
"""安全地获取密码输入并进行确认。"""
|
||||||
|
while True:
|
||||||
|
password = getpass.getpass("请输入密码:").strip()
|
||||||
|
if not validate_password(password):
|
||||||
|
print("密码必须至少8个字符,并包含大写字母、小写字母和数字。")
|
||||||
|
continue
|
||||||
|
confirm = getpass.getpass("请确认密码:").strip()
|
||||||
|
if password == confirm:
|
||||||
|
return password
|
||||||
|
print("两次输入的密码不一致,请重试。")
|
||||||
|
|
||||||
|
def get_timezone() -> str:
|
||||||
|
"""获取用户选择的时区。"""
|
||||||
|
print("\n可用的时区:")
|
||||||
|
for key, value in COMMON_TIMEZONES.items():
|
||||||
|
print(f" {key}. {value}")
|
||||||
|
print(" (或输入自定义时区名称,例如:'Asia/Kuala_Lumpur')")
|
||||||
|
|
||||||
|
while True:
|
||||||
|
choice = input(f"选择时区 [{DEFAULT_CONFIG['tz']}]:").strip()
|
||||||
|
if not choice:
|
||||||
|
return DEFAULT_CONFIG['tz']
|
||||||
|
if choice in COMMON_TIMEZONES:
|
||||||
|
return COMMON_TIMEZONES[choice]
|
||||||
|
# 基本验证自定义时区
|
||||||
|
if '/' in choice and all(part.isalnum() or part in '_-' for part in choice.split('/')):
|
||||||
|
return choice
|
||||||
|
print("时区格式无效,请重试。")
|
||||||
|
|
||||||
|
def generate_docker_compose(config: Dict[str, Any]) -> str:
|
||||||
|
"""生成 docker-compose.yml 内容。"""
|
||||||
|
return f"""# 为 Obsidian LiveSync 生成的 docker-compose.yml
|
||||||
|
# 使用最新的 Docker Compose 规范
|
||||||
|
|
||||||
|
services:
|
||||||
|
couchdb-obsidian-livesync:
|
||||||
|
container_name: couchdb-obsidian-livesync
|
||||||
|
image: couchdb:3.3.3
|
||||||
|
environment:
|
||||||
|
PUID: {config['puid']}
|
||||||
|
PGID: {config['pgid']}
|
||||||
|
UMASK: 0022
|
||||||
|
TZ: {config['tz']}
|
||||||
|
COUCHDB_USER: {config['couchdb_user']}
|
||||||
|
COUCHDB_PASSWORD: {config['couchdb_password']}
|
||||||
|
volumes:
|
||||||
|
- {config['volume_name']}:/opt/couchdb/data
|
||||||
|
- {config['config_host_path']}:/opt/couchdb/etc/local.d
|
||||||
|
ports:
|
||||||
|
- "{config['host_port']}:5984"
|
||||||
|
restart: unless-stopped
|
||||||
|
networks:
|
||||||
|
- couchdb_network
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
{config['volume_name']}:
|
||||||
|
|
||||||
|
networks:
|
||||||
|
couchdb_network:
|
||||||
|
driver: bridge
|
||||||
|
"""
|
||||||
|
|
||||||
|
def generate_couchdb_config(config: Dict[str, Any]) -> str:
|
||||||
|
"""生成 CouchDB local.ini 内容。"""
|
||||||
|
return f"""[couchdb]
|
||||||
|
single_node={config['single_node']}
|
||||||
|
max_document_size = 50000000
|
||||||
|
|
||||||
|
[chttpd]
|
||||||
|
require_valid_user = true
|
||||||
|
max_http_request_size = 4294967296
|
||||||
|
|
||||||
|
[chttpd_auth]
|
||||||
|
require_valid_user = true
|
||||||
|
authentication_redirect = /_utils/session.html
|
||||||
|
|
||||||
|
[httpd]
|
||||||
|
WWW-Authenticate = Basic realm="couchdb"
|
||||||
|
enable_cors = true
|
||||||
|
|
||||||
|
[cors]
|
||||||
|
origins = {config['cors_origins']}
|
||||||
|
credentials = true
|
||||||
|
headers = accept, authorization, content-type, origin, referer
|
||||||
|
methods = GET, PUT, POST, HEAD, DELETE
|
||||||
|
max_age = 3600
|
||||||
|
"""
|
||||||
|
|
||||||
|
def save_config_files(config: Dict[str, Any]) -> None:
|
||||||
|
"""保存所有配置文件。"""
|
||||||
|
# 创建配置目录
|
||||||
|
config_dir = Path(config['config_host_path'])
|
||||||
|
config_dir.mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
|
# 保存 docker-compose.yml
|
||||||
|
with open('docker-compose.yml', 'w') as f:
|
||||||
|
f.write(generate_docker_compose(config))
|
||||||
|
print(f"\n✓ 已生成 docker-compose.yml")
|
||||||
|
|
||||||
|
# 保存 CouchDB 配置
|
||||||
|
config_path = config_dir / "my_obsidian_config.ini"
|
||||||
|
with open(config_path, 'w') as f:
|
||||||
|
f.write(generate_couchdb_config(config))
|
||||||
|
print(f"✓ 已生成 {config_path}")
|
||||||
|
|
||||||
|
def main():
|
||||||
|
"""主函数,运行配置生成器。"""
|
||||||
|
print("=== Obsidian LiveSync CouchDB 配置生成器 ===")
|
||||||
|
print("此脚本将帮助您设置用于 Obsidian LiveSync 的 CouchDB。")
|
||||||
|
print("随时可以按 Ctrl+C 退出。\n")
|
||||||
|
|
||||||
|
try:
|
||||||
|
config = DEFAULT_CONFIG.copy()
|
||||||
|
|
||||||
|
# 获取用户名
|
||||||
|
config['couchdb_user'] = get_input_with_default(
|
||||||
|
"请输入 CouchDB 管理员用户名",
|
||||||
|
DEFAULT_CONFIG['couchdb_user'],
|
||||||
|
validate_username
|
||||||
|
)
|
||||||
|
|
||||||
|
# 获取密码
|
||||||
|
print("\n请输入 CouchDB 管理员密码(必须至少8个字符,包含大写字母、小写字母和数字)")
|
||||||
|
config['couchdb_password'] = get_password()
|
||||||
|
|
||||||
|
# 获取时区
|
||||||
|
config['tz'] = get_timezone()
|
||||||
|
|
||||||
|
# 获取端口
|
||||||
|
config['host_port'] = get_input_with_default(
|
||||||
|
"请输入 CouchDB 主机端口",
|
||||||
|
DEFAULT_CONFIG['host_port'],
|
||||||
|
validate_port
|
||||||
|
)
|
||||||
|
|
||||||
|
# 获取卷名称
|
||||||
|
config['volume_name'] = get_input_with_default(
|
||||||
|
"请输入 CouchDB 数据卷名称",
|
||||||
|
DEFAULT_CONFIG['volume_name']
|
||||||
|
)
|
||||||
|
|
||||||
|
# 获取配置路径
|
||||||
|
config['config_host_path'] = get_input_with_default(
|
||||||
|
"请输入配置文件目录路径",
|
||||||
|
DEFAULT_CONFIG['config_host_path']
|
||||||
|
)
|
||||||
|
|
||||||
|
# 获取单节点模式
|
||||||
|
single_node = get_input_with_default(
|
||||||
|
"是否使用单节点模式(true/false)",
|
||||||
|
DEFAULT_CONFIG['single_node']
|
||||||
|
).lower()
|
||||||
|
config['single_node'] = "true" if single_node in ["true", "t", "yes", "y"] else "false"
|
||||||
|
|
||||||
|
# 获取 CORS 源
|
||||||
|
config['cors_origins'] = get_input_with_default(
|
||||||
|
"请输入允许的 CORS 源(用逗号分隔)",
|
||||||
|
DEFAULT_CONFIG['cors_origins']
|
||||||
|
)
|
||||||
|
|
||||||
|
# 获取 PUID/PGID
|
||||||
|
current_uid, current_gid = get_current_user_ids()
|
||||||
|
if platform.system() in ['Linux', 'Darwin']:
|
||||||
|
print(f"\n检测到当前用户 ID:UID={current_uid}, GID={current_gid}")
|
||||||
|
print("这些值将用于设置容器内的文件权限。")
|
||||||
|
use_current = get_input_with_default(
|
||||||
|
"是否使用当前用户的 UID/GID(推荐)",
|
||||||
|
"yes"
|
||||||
|
).lower() in ["yes", "y", "true", "t"]
|
||||||
|
|
||||||
|
if use_current:
|
||||||
|
config['puid'] = current_uid
|
||||||
|
config['pgid'] = current_gid
|
||||||
|
else:
|
||||||
|
print("\n请输入自定义的 PUID/PGID")
|
||||||
|
config['puid'] = get_input_with_default(
|
||||||
|
"请输入 PUID",
|
||||||
|
current_uid,
|
||||||
|
lambda x: x.isdigit()
|
||||||
|
)
|
||||||
|
config['pgid'] = get_input_with_default(
|
||||||
|
"请输入 PGID",
|
||||||
|
current_gid,
|
||||||
|
lambda x: x.isdigit()
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
print("\n当前系统不支持自动获取用户 ID,将使用默认值(99/100)")
|
||||||
|
print("如果需要自定义,请手动输入。")
|
||||||
|
config['puid'] = get_input_with_default(
|
||||||
|
"请输入 PUID",
|
||||||
|
DEFAULT_CONFIG['puid'],
|
||||||
|
lambda x: x.isdigit()
|
||||||
|
)
|
||||||
|
config['pgid'] = get_input_with_default(
|
||||||
|
"请输入 PGID",
|
||||||
|
DEFAULT_CONFIG['pgid'],
|
||||||
|
lambda x: x.isdigit()
|
||||||
|
)
|
||||||
|
|
||||||
|
# 保存所有配置文件
|
||||||
|
save_config_files(config)
|
||||||
|
|
||||||
|
print("\n=== 配置完成 ===")
|
||||||
|
print(f"✓ CouchDB 将在 http://localhost:{config['host_port']}/_utils/ 访问")
|
||||||
|
print(f"✓ 用户名:{config['couchdb_user']}")
|
||||||
|
print(f"✓ 文件权限:UID={config['puid']}, GID={config['pgid']}")
|
||||||
|
print("\n要启动 CouchDB,请运行:")
|
||||||
|
print(" docker-compose up -d")
|
||||||
|
print("\n要查看日志,请运行:")
|
||||||
|
print(" docker-compose logs -f")
|
||||||
|
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
print("\n\n配置已取消。")
|
||||||
|
sys.exit(1)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"\n错误:{str(e)}")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
17
dbSer/couchdb/stack.yml
Normal file
17
dbSer/couchdb/stack.yml
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
services:
|
||||||
|
couchdb:
|
||||||
|
image: ${IMAGE_TAG:-couchdb:3.5}
|
||||||
|
container_name: couchdb
|
||||||
|
restart: unless-stopped
|
||||||
|
ports:
|
||||||
|
- 5984:5984
|
||||||
|
volumes:
|
||||||
|
- ./etc/couchdb/local.d:/opt/couchdb/etc/local.d
|
||||||
|
- ./couchdb:/opt/couchdb/data
|
||||||
|
environment:
|
||||||
|
TZ: Asia/Shanghai
|
||||||
|
PUID: 99
|
||||||
|
PGID: 100
|
||||||
|
UMASK: 0022
|
||||||
|
COUCHDB_USER: your_custom_user
|
||||||
|
COUCHDB_PASSWORD: your_strong_password
|
||||||
Reference in New Issue
Block a user