Compare commits

2 Commits

Author SHA1 Message Date
Scott Idem
bb437ce5cb chore(env): add .env.default template and track it in .gitignore
The Docker env project had no committed .env template — new contributors
had to reverse-engineer the required variables from the compose files.

Added .env.default with all required variables, secrets replaced with XXXX,
and comments explaining each section. Notable: AE_API_GUNICORN_TIMEOUT is
documented as 900 (needed for long ffmpeg video jobs like clip_video).

Updated .gitignore to whitelist .env.default via !.env.default.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-26 14:08:11 -04:00
Scott Idem
bd035f8c17 fix(nginx,gunicorn): raise send_timeout and proxy_send_timeout for long-running endpoints
Nginx was closing the client connection after exactly 60 seconds on requests
like clip_video (ffmpeg, 5-40 min) because send_timeout and proxy_send_timeout
both default to 60s. proxy_read_timeout was already 2100s but the other two
timeouts were still at defaults.

With proxy_buffering off, Nginx holds the write path to the client open as soon
as the upstream connection is established. If the upstream sends no data for 60s
(e.g. ffmpeg processing), Nginx treats the idle write path as stalled and closes
the client connection, logging 499 (Client Closed Request).

Fixed: raise proxy_send_timeout and send_timeout to 2100s to match
proxy_read_timeout in the main location block.

Also raised the Gunicorn default timeout from 30s to 120s in gunicorn_conf.py
as a belt-and-suspenders measure (AE_API_GUNICORN_TIMEOUT env var takes precedence).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-26 14:05:22 -04:00
4 changed files with 183 additions and 1 deletions

177
.env.default Normal file
View File

@@ -0,0 +1,177 @@
# ------------------------------------------------------------------------------
# AETHER FRAMEWORK - DOCKER ENVIRONMENT CONFIGURATION TEMPLATE
# ------------------------------------------------------------------------------
# Copy this file to .env and fill in real values.
# .env is gitignored — never commit the live file.
# Profile: Scott's Workstation (Arch Linux)
# ------------------------------------------------------------------------------
# ------------------------------------------------------------------------------
# SYSTEM SETTINGS
# ------------------------------------------------------------------------------
# System timezone for all containers
TZ=US/Eastern
# Environment mode (development, testing, production)
OSIT_ENV=development
# Logging level for the API and background workers (debug, info, warning, error)
AE_LOG_LVL=debug
# Docker Compose Profiles
# 'database' includes: mariadb, phpmyadmin, ae_ops
# Comment out or leave empty for "app-only" nodes that connect to a remote DB
# COMPOSE_PROFILES=database
# ------------------------------------------------------------------------------
# CONTAINER NAMES
# ------------------------------------------------------------------------------
# Internal Docker container names (should be unique per environment)
CONTAINER_WEB=ae_web_dev
CONTAINER_AE_API=ae_api_dev
CONTAINER_AE_APP=ae_app_dev
CONTAINER_REDIS=ae_redis_dev
CONTAINER_MARIADB=ae_mariadb_dev
CONTAINER_PMA=ae_pma_dev
# ------------------------------------------------------------------------------
# NETWORK & PROXY SETTINGS
# ------------------------------------------------------------------------------
# Local Nginx listener ports on the host system
OSIT_WEB_HTTP_PORT=8888
OSIT_WEB_HTTPS_PORT=443
# Maximum allowed file upload size (Global for Nginx)
OSIT_WEB_MAX_BODY_SIZE=5120M
# AE API (Node SvelteKit) Gateway Port for External Reverse Proxy
# Used when a master proxy (e.g. Home Server) forwards traffic to this node
# The gateway port has Docker with Nginx running the internal reverse proxy
AE_API_GATEWAY_PORT=5060
# DNS Overrides (Injected into containers' /etc/hosts)
# Format: DOMAIN:IP_ADDRESS
# Useful for container-to-container routing when using real domain names
DOCKER_AE_SERVER_EXTRA_HOST=dev.oneskyit.com:XXXX
DOCKER_AE_APP_SERVER_EXTRA_HOST=dev-app.oneskyit.com:XXXX
DOCKER_AE_API_SERVER_EXTRA_HOST=dev-api.oneskyit.com:XXXX
DOCKER_AE_API_BAK_SERVER_EXTRA_HOST=test-api.oneskyit.com:XXXX
DOCKER_AE_DB_SERVER_EXTRA_HOST=vpn-db.oneskyit.com:XXXX
# Nginx Server Names (Used in vhost configuration templates)
DOCKER_AE_API_SERVER_NAME=dev-api.oneskyit.com
DOCKER_AE_APP_SERVER_NAME=dev-example.oneskyit.com
DOCKER_PHPMYADMIN_SERVER_NAME=dev-phpmyadmin.oneskyit.com
DOCKER_OSIT_SERVER_NAME=dev.oneskyit.com
# ------------------------------------------------------------------------------
# DATABASE SETTINGS (MariaDB)
# ------------------------------------------------------------------------------
# To use an EXTERNAL database:
# 1. Set COMPOSE_PROFILES= (empty) above to disable local DB containers.
# 2. Set AE_DB_SERVER to the external IP or Hostname.
# 3. Ensure the external DB allows connections from this host's IP.
# DB Hostname (use 'mariadb' for the local container, or a remote IP/FQDN)
AE_DB_SERVER=vpn-db.oneskyit.com
# AE_DB_SERVER=mariadb
AE_DB_PORT=3306
# Port to expose on the host system if running a local MariaDB container
AE_DB_EXTERNAL_PORT=3306
# Database credentials
AE_DB_NAME=aether_dev
AE_DB_USERNAME=aether_dev
AE_DB_PASSWORD=XXXX
AE_DB_ROOT_PASSWORD=XXXX
# Connection Tuning
AE_DB_CONNECTION_TIMEOUT=7
AE_DB_POOL_RECYCLE=900
# ------------------------------------------------------------------------------
# REDIS SETTINGS
# ------------------------------------------------------------------------------
# Redis is used for caching, ID resolution, and messaging
AE_REDIS_SERVER=redis
AE_REDIS_PORT=6379
# ------------------------------------------------------------------------------
# API SETTINGS (FastAPI)
# ------------------------------------------------------------------------------
AE_API_ENV=development
# Number of API container instances to run (Docker Compose Scaling)
AE_API_REPLICAS=3
# Gunicorn / Uvicorn Tuning
# AE_API_GUNICORN_TIMEOUT: worker timeout in seconds. Default in gunicorn_conf.py
# is 120s. Raise for endpoints that run long ffmpeg operations (clip_video, etc.)
# The dev .env typically sets this to 900 to accommodate 5-15 min video jobs.
AE_API_GUNICORN_PORT=5065
AE_API_GUNICORN_TIMEOUT=900
AE_API_GUNICORN_WORKERS=2
AE_API_GUNICORN_THREADS=1
# Security & CORS
# JWT_KEY should be a 22+ character secret string
AE_API_JWT_KEY=XXXX
# Regex for allowed CORS origins
AE_API_ORIGINS_REGEX="(https://.*\.oneskyit\.com)|(http://.*\.oneskyit\.com)|(http://.*.localhost)|(http://.*.localhost:5173)"
# ------------------------------------------------------------------------------
# SMTP SETTINGS (Email)
# ------------------------------------------------------------------------------
# Core SMTP configuration for system notifications and user emails
AE_SMTP_SERVER=linode.oneskyit.com
AE_SMTP_PORT=465
AE_SMTP_USERNAME=send_mail
AE_SMTP_PASSWORD=XXXX
# ------------------------------------------------------------------------------
# APP SETTINGS (SvelteKit)
# ------------------------------------------------------------------------------
AE_APP_ENV=development
AE_APP_BUILD_MODE=staging
AE_APP_REPLICAS=2
# AE App (Node SvelteKit) Gateway Port for External Reverse Proxy
AE_APP_GATEWAY_PORT=3001
# ------------------------------------------------------------------------------
# SOURCE PATHS (Absolute paths on Host Machine)
# ------------------------------------------------------------------------------
# IMPORTANT: These paths must exist on the machine running Docker
# They are mounted into containers as volumes for real-time development
# Project Source Code
AE_API_SRC=/home/scott/OSIT_dev/aether_api_fastapi
AE_APP_SRC=/home/scott/OSIT_dev/aether_app_sveltekit
AE_FLASK_APP_SRC=/home/scott/OSIT_dev/aether_app_flask
# Physical File Storage (Images, Documents, etc.)
# NOTE: Shared between environments to ensure binary availability
HOSTED_FILES_SRC=/home/scott/OSIT/hosted_files
HOSTED_TMP_SRC=/home/scott/OSIT/hosted_tmp
# ------------------------------------------------------------------------------
# SERVICE TUNING & PERFORMANCE
# ------------------------------------------------------------------------------
# phpMyAdmin Host Port
AE_PMA_PORT=8081
# MariaDB Performance (Injected via Docker Compose command flags)
MARIADB_MAX_CONNECTIONS=500
MARIADB_INNODB_BUFFER_POOL_SIZE=512M
MARIADB_QUERY_CACHE_SIZE=32M
MARIADB_TMP_TABLE_SIZE=384M
MARIADB_TABLE_OPEN_CACHE=4000
# ------------------------------------------------------------------------------
# AETHER SHARED CONFIG (DB Driven)
# ------------------------------------------------------------------------------
# Specifies which record from the 'cfg' table to use for shared settings
# (SMTP, API routes, and external service keys)
# common options: 1=Default, 5=Home Dev, 7=Live Test
AE_CFG_ID=5

1
.gitignore vendored
View File

@@ -57,6 +57,7 @@ Thumbs.db
.env
.venv
*.env
!.env.default
env/
venv/
ENV/

View File

@@ -16,7 +16,7 @@ chdir = "/srv/aether_api"
wsgi_app = "app.main:app"
# Numeric variables must be integers
timeout = int(os.getenv('AE_API_GUNICORN_TIMEOUT', 30))
timeout = int(os.getenv('AE_API_GUNICORN_TIMEOUT', 120))
graceful_timeout = int(os.getenv('AE_API_GUNICORN_GRACEFUL_TIMEOUT', 30))
keepalive = int(os.getenv('AE_API_GUNICORN_KEEPALIVE', 4))

View File

@@ -50,6 +50,10 @@ server {
# proxy read timeout being too low will cause 504 Gateway Time-out on the client browser
proxy_read_timeout 2100s;
# proxy_send_timeout and send_timeout default to 60s. For long-running endpoints
# (clip_video, ffmpeg operations that take 5-40 min), raise to match proxy_read_timeout.
proxy_send_timeout 2100s;
send_timeout 2100s;
proxy_pass http://fastapi_backend;
}