mirror of
https://github.com/ChrispyBacon-dev/DockFlare.git
synced 2026-04-28 03:39:32 +00:00
156 lines
6.7 KiB
Python
156 lines
6.7 KiB
Python
# app/config.py
|
|
# DockFlare: Automates Cloudflare Tunnel ingress from Docker labels.
|
|
# Copyright (C) 2025 ChrispyBacon-Dev <https://github.com/ChrispyBacon-dev/DockFlare>
|
|
#
|
|
# This program is free software: you can redistribute it and/or modify
|
|
# it under the terms of the GNU General Public License as published by
|
|
# the Free Software Foundation, either version 3 of the License, or
|
|
# (at your option) any later version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
#
|
|
# dockflare/app/config.py
|
|
import os
|
|
import logging
|
|
from app.core.container_name import build_cloudflared_container_name
|
|
|
|
def _get_int_env(name, default, minimum=None):
|
|
raw_value = os.getenv(name)
|
|
if raw_value is None:
|
|
return default
|
|
try:
|
|
parsed = int(raw_value)
|
|
if minimum is not None and parsed < minimum:
|
|
logging.warning(f"Environment variable {name} must be >= {minimum}. Using default {default}.")
|
|
return default
|
|
return parsed
|
|
except ValueError:
|
|
logging.warning(f"Environment variable {name} must be an integer. Using default {default}.")
|
|
return default
|
|
|
|
# --- DockFlare Version ---
|
|
APP_VERSION = "v3.0.9"
|
|
# --- web: https://dockflare.app ---
|
|
# --- github: https://github.com/ChrispyBacon-dev/DockFlare ---
|
|
|
|
# --- Logging Configuration ---
|
|
# Options: DEBUG, INFO, WARNING, ERROR, CRITICAL
|
|
# Set via environment variable LOG_LEVEL (default: INFO)
|
|
LOG_LEVEL = os.getenv('LOG_LEVEL', 'WARNING').upper()
|
|
|
|
MAX_CF_UPDATE_RETRIES = 3
|
|
CF_UPDATE_RETRY_DELAY = 2
|
|
CF_UPDATE_BACKOFF_FACTOR = 2
|
|
|
|
# --- Dynamic Configuration ---
|
|
# These variables are now loaded dynamically from the encrypted configuration file
|
|
# at startup. They are initialized here with default values.
|
|
CF_API_TOKEN = None
|
|
CF_ACCOUNT_ID = None
|
|
CF_ZONE_ID = None
|
|
TUNNEL_NAME = "dockflare-tunnel"
|
|
GRACE_PERIOD_SECONDS = 600
|
|
TUNNEL_DNS_SCAN_ZONE_NAMES = []
|
|
MASTER_API_KEY = os.getenv('DOCKFLARE_API_KEY')
|
|
|
|
# --- Static & Environment-Based Configuration ---
|
|
CF_API_BASE_URL = "https://api.cloudflare.com/client/v4"
|
|
|
|
CF_HEADERS = {
|
|
"Content-Type": "application/json",
|
|
}
|
|
|
|
USE_EXTERNAL_CLOUDFLARED = os.getenv('USE_EXTERNAL_CLOUDFLARED', 'false').lower() in ['true', '1', 't', 'yes']
|
|
EXTERNAL_TUNNEL_ID = os.getenv('EXTERNAL_TUNNEL_ID')
|
|
|
|
if not USE_EXTERNAL_CLOUDFLARED:
|
|
CLOUDFLARED_NETWORK_NAME = os.getenv('CLOUDFLARED_NETWORK_NAME', 'cloudflare-net')
|
|
|
|
CLOUDFLARED_CONTAINER_NAME = os.getenv('CLOUDFLARED_CONTAINER_NAME', build_cloudflared_container_name(TUNNEL_NAME))
|
|
else:
|
|
CLOUDFLARED_NETWORK_NAME = None
|
|
CLOUDFLARED_CONTAINER_NAME = None
|
|
|
|
CLOUDFLARED_IMAGE = "cloudflare/cloudflared:latest"
|
|
|
|
PRIMARY_LABEL_PREFIX = 'dockflare.'
|
|
LEGACY_LABEL_PREFIX = 'cloudflare.tunnel.'
|
|
CUSTOM_LABEL_PREFIX = os.getenv('LABEL_PREFIX')
|
|
|
|
LABEL_PREFIX = CUSTOM_LABEL_PREFIX or PRIMARY_LABEL_PREFIX
|
|
|
|
CLEANUP_INTERVAL_SECONDS = int(os.getenv('CLEANUP_INTERVAL_SECONDS', 60))
|
|
AGENT_STATUS_UPDATE_INTERVAL_SECONDS = int(os.getenv('AGENT_STATUS_UPDATE_INTERVAL_SECONDS', 30))
|
|
STATE_FILE_PATH = os.getenv('STATE_FILE_PATH', '/app/data/state.json')
|
|
MAX_LOG_QUEUE_SIZE = 200
|
|
MAX_CONCURRENT_DNS_OPS = int(os.getenv('MAX_CONCURRENT_DNS_OPS', 5))
|
|
RECONCILIATION_BATCH_SIZE = int(os.getenv('RECONCILIATION_BATCH_SIZE', 5))
|
|
ACCOUNT_EMAIL_CACHE_TTL = 3600
|
|
SCAN_ALL_NETWORKS = os.getenv('SCAN_ALL_NETWORKS', 'false').lower() in ['true', '1', 't', 'yes']
|
|
|
|
# Waitress / web server tuning
|
|
WAITRESS_HOST = os.getenv('WAITRESS_HOST', '0.0.0.0')
|
|
WAITRESS_PORT = _get_int_env('WAITRESS_PORT', 5000, minimum=1)
|
|
WAITRESS_THREADS = _get_int_env('WAITRESS_THREADS', 128, minimum=1)
|
|
WAITRESS_CONNECTION_LIMIT = _get_int_env('WAITRESS_CONNECTION_LIMIT', 256, minimum=1)
|
|
WAITRESS_BACKLOG = _get_int_env('WAITRESS_BACKLOG', 2048, minimum=1)
|
|
WAITRESS_CHANNEL_TIMEOUT = _get_int_env('WAITRESS_CHANNEL_TIMEOUT', 360, minimum=1)
|
|
|
|
# If set, enables the Prometheus metrics endpoint on the specified port.
|
|
# The IP is hardcoded to 0.0.0.0 to be accessible within Docker networks.
|
|
CLOUDFLARED_METRICS_PORT = os.getenv('CLOUDFLARED_METRICS_PORT')
|
|
if CLOUDFLARED_METRICS_PORT:
|
|
try:
|
|
port = int(CLOUDFLARED_METRICS_PORT)
|
|
if not (1 <= port <= 65535):
|
|
logging.warning(f"Metrics port {port} is outside the valid range (1-65535). Disabling.")
|
|
CLOUDFLARED_METRICS_PORT = None
|
|
except ValueError:
|
|
logging.warning(f"Invalid value for CLOUDFLARED_METRICS_PORT: '{CLOUDFLARED_METRICS_PORT}'. Must be a number. Disabling.")
|
|
CLOUDFLARED_METRICS_PORT = None
|
|
|
|
# --- Auto-restore (self-heal) settings ---
|
|
# If true, the Master will attempt to recreate rules reported by Agents when the rule has been removed on Master.
|
|
AUTO_RESTORE_AGENT_RULES = os.getenv('AUTO_RESTORE_AGENT_RULES', 'true').lower() in ['true', '1', 't', 'yes']
|
|
# Cooldown (seconds) between automatic restore operations per-agent to avoid flapping/loops.
|
|
AUTO_RESTORE_COOLDOWN_SECONDS = int(os.getenv('AUTO_RESTORE_COOLDOWN_SECONDS', '60'))
|
|
|
|
# --- Multi-server / Agent support settings ---
|
|
# URL prefix for agent API endpoints (kept here for consistency; routing will use this in the Master)
|
|
AGENT_API_PREFIX = os.getenv('AGENT_API_PREFIX', '/api/v2/agents')
|
|
|
|
# Seconds without heartbeat before an agent is considered offline
|
|
AGENT_HEARTBEAT_TIMEOUT = int(os.getenv('AGENT_HEARTBEAT_TIMEOUT', 60))
|
|
|
|
# Whether agents must be manually enrolled via the UI (recommended: true)
|
|
AGENT_ENROLLMENT_REQUIRED = os.getenv('AGENT_ENROLLMENT_REQUIRED', 'true').lower() in ['true', '1', 't', 'yes']
|
|
|
|
# Optional path for storing agent API key metadata (defaults to encrypted config storage if None)
|
|
AGENT_KEY_STORAGE_PATH = os.getenv('AGENT_KEY_STORAGE_PATH', None)
|
|
|
|
# Polling interval (seconds) recommended for agents to poll the Master for commands
|
|
AGENT_COMMAND_POLL_INTERVAL = int(os.getenv('AGENT_COMMAND_POLL_INTERVAL', 10))
|
|
|
|
REDIS_DB_INDEX = int(os.getenv('REDIS_DB_INDEX', 0))
|
|
|
|
USE_REUSABLE_POLICIES = os.getenv('USE_REUSABLE_POLICIES', 'true').lower() in ['true', '1', 't', 'yes']
|
|
|
|
SYNC_ALL_CLOUDFLARE_POLICIES = os.getenv('SYNC_ALL_CLOUDFLARE_POLICIES', 'false').lower() in ['true', '1', 't', 'yes']
|
|
PRESERVE_UNMANAGED_CF_INGRESS_FIELDS = False
|
|
|
|
DOCKFLARE_PUBLIC_URL = os.getenv('DOCKFLARE_PUBLIC_URL', '')
|
|
|
|
EMAIL_ENABLED = False
|
|
EMAIL_CONFIG = {}
|
|
MAIL_MANAGER_INTERNAL_URL = os.getenv('MAIL_MANAGER_INTERNAL_URL', 'http://dockflare-mail-manager:8025')
|
|
EMAIL_JWT_ALGORITHM = 'EdDSA'
|
|
EMAIL_JWT_ISSUER = 'dockflare-master'
|
|
EMAIL_JWT_AUDIENCE = 'dockflare-mail'
|
|
EMAIL_JWT_EXPIRY_SECONDS = 3600
|
|
|