Fix: Robust API configuration and password handling. Resolved 502 Bad Gateway.

This commit is contained in:
Scott Idem
2026-01-12 18:20:01 -05:00
parent 5044a4fc5b
commit 7bd22d1086
2 changed files with 65 additions and 106 deletions

View File

@@ -1,93 +1,55 @@
# Configuration file for this FastAPI app. # Configuration file for this FastAPI app.
import os import os
from pydantic import AnyHttpUrl, BaseSettings, EmailStr, HttpUrl, PostgresDsn, validator from pydantic import BaseSettings
from typing import Any, Dict, List, Optional, Union from typing import Any, Dict, List, Optional, Union
# ### ### #
class Settings(BaseSettings): class Settings(BaseSettings):
AETHER_CFG = {} AETHER_CFG: Dict[str, Any] = {
AETHER_CFG['id'] = os.getenv('AE_CFG_ID', None) "id": os.getenv('AE_CFG_ID', '0')
# AETHER_CFG['api_id'] = os.getenv('AE_API_CFG_ID', None) # NOT CURRENTLY NEED OR USED }
JWT_KEY = os.getenv('AE_API_JWT_KEY', '22 chars 00xXyYzZ99') # 22 characters; super secret Aether JWT signing key JWT_KEY: str = os.getenv('AE_API_JWT_KEY', 'EHmSXZFKfMEW65E8kxCKmQ')
# APP_NAME: str = "Aether API (FastAPI)"
# SUPER_EMAIL: EmailStr = 'Aether.Super@oneskyit.com'
# Database Connection # Database Connection
DB = {} # We use first-level attributes so BaseSettings can map them automatically if needed,
DB['server'] = os.getenv('AE_DB_SERVER', 'mariadb') # 'linode.oneskyit.com' # linode.oneskyit.com, vpn-linode linode.oneskyit.local # but we keep the DB dictionary structure for compatibility with the rest of the app.
DB['port'] = os.getenv('AE_DB_PORT', '3306') # default = 3306 DB_SERVER: str = os.getenv('AE_DB_SERVER', 'mariadb')
DB['name'] = os.getenv('AE_DB_NAME', None) # 'aether_dev' #onesky_ams_dev DB_PORT: str = os.getenv('AE_DB_PORT', '3306')
DB['username'] = os.getenv('AE_DB_USERNAME', None) # 'osit_aether' # 'onesky_aether' DB_NAME: str = os.getenv('AE_DB_NAME', 'aether_dev')
DB['password'] = os.getenv('AE_DB_PASSWORD', None) # DB_USER: str = os.getenv('AE_DB_USERNAME', 'aether_dev')
SQLALCHEMY_DB_URI = 'mysql://'+DB['username']+':'+DB['password']+'@'+DB['server']+'/'+DB['name'] DB_PASS: str = os.getenv('AE_DB_PASSWORD', '')
# DB['wait_timeout'] = int(os.getenv('AE_DB_WAIT_TIMEOUT', 1800)) # Not used yet! default = 28800; Time (seconds) that the server waits for a connection to become active before closing it.
DB['connect_timeout'] = int(os.getenv('AE_DB_CONNECTION_TIMEOUT', 20)) # default = 10; Time (seconds) that the server waits for a connection to become active before closing it.
DB['pool_recycle'] = int(os.getenv('AE_DB_POOL_RECYCLE', 1800)) # default = ?; Related to SQLAlchemy
@property
def SQLALCHEMY_DB_URI(self) -> str:
# Use a property to ensure the URI is built dynamically and safely
return f"mysql://{self.DB_USER}:{self.DB_PASS}@{self.DB_SERVER}:{self.DB_PORT}/{self.DB_NAME}"
# Aether API log files paths @property
LOG_PATH = {} def DB(self) -> Dict[str, Any]:
LOG_PATH['app'] = os.getenv('AE_API_LOG_PATH', 'admin/log/app.log') # 'admin/log/app.log', '../../logs/aether_api.log' # Compatibility dictionary
# LOG_PATH['app_warning'] = '/logs/aether_api_warning.log' # 'admin/log/app_warning.log' '../../logs/aether_api_warning.log' return {
"server": self.DB_SERVER,
"port": self.DB_PORT,
"name": self.DB_NAME,
"username": self.DB_USER,
"password": self.DB_PASS,
"connect_timeout": int(os.getenv('AE_DB_CONNECTION_TIMEOUT', 20)),
"pool_recycle": int(os.getenv('AE_DB_POOL_RECYCLE', 1800))
}
# Logging
LOG_PATH: Dict[str, str] = {
"app": os.getenv('AE_API_LOG_PATH', '/logs/aether_api.log')
}
# Redis # Redis
REDIS = {} REDIS: Dict[str, str] = {
REDIS['server'] = os.getenv('AE_REDIS_SERVER', 'redis') # 'localhost' 'redis' "server": os.getenv('AE_REDIS_SERVER', 'redis'),
REDIS['port'] = os.getenv('AE_REDIS_PORT', '6379') # '6379' "port": os.getenv('AE_REDIS_PORT', '6379')
}
# CORS
ORIGINS_REGEX: str = os.getenv('AE_API_ORIGINS_REGEX', '(https://.*\.oneskyit\.com)|(https://.*\.oneskyit\.com:4443)')
ORIGINS: List[str] = ['https://oneskyit.com']
# Send SMTP Email settings = Settings()
SMTP = {}
# server
# port
# username
# password
# Server Hosted File Paths
FILES_PATH = {}
# hosted_files_root
# hosted_tmp_root
# CORS Origins
ORIGINS_REGEX = os.getenv('AE_API_ORIGINS_REGEX', '(https://.*\.oneskyit\.com)|(https://.*\.oneskyit\.com:4443)|(https://.*\.oneskyit\.com:8443)') # '(https://.*\.oneskyit\.com)|(http://.*\.oneskyit\.com)|(https://.*\.oneskyit\.com:4443)|(http://.*\.oneskyit\.com:8080)|(http://.*\.oneskyit\.com:8181)|(https://.*\.oneskyit\.com:8443)|(http://.*\.oneskyit\.local)|(http://.*\.oneskyit\.local:5000)|(http://.*.localhost)|(http://.*.localhost:5000)|(http://.*.localhost:8181)'
# A reasonable, but fairly open example regular expression for the CORS origins:
# '(https://.*\.oneskyit\.com)|(http://.*\.oneskyit\.com)|(http://.*\.oneskyit\.com:8181)|(https://.*\.oneskyit\.com:8443)|(http://.*\.oneskyit\.local)|(http://.*\.oneskyit\.local:5000)|(http://.*.localhost)|(http://.*.localhost:5000)|(http://.*.localhost:8181)'
ORIGINS = [
'https://oneskyit.com',
# 'http://app-local.oneskyit.com',
# 'http://192.168.32.20:3000',
# 'http://192.168.32.20:8080',
# 'http://localhost',
# 'http://localhost:3000',
# 'http://localhost:5000',
# 'http://localhost:7800',
# 'http://localhost:8080',
# 'http://localhost:8888',
# 'http://fastapi.localhost',
# 'http://svelte.oneskyit.local:5555',
# 'http://connect.localhost:5000', # Using localhost
# 'http://dev-svelte.oneskyit.local:5555',
# 'http://lci.internal:5000', # Using internal; just in case guess before LCI
# 'http://lci.oneskyit.internal:5000', # Using internal; just in case guess before LCI
# 'http://lci.oneskyit.internal', # Using internal; just in case guess before LCI
]
settings = Settings()

View File

@@ -30,9 +30,6 @@ services:
- ./conf/certs/oneskyit.com_privkey.pem:/etc/certs/privkey.pem - ./conf/certs/oneskyit.com_privkey.pem:/etc/certs/privkey.pem
- ./conf/certs/ssl-dhparams.pem:/etc/certs/ssl-dhparams.pem - ./conf/certs/ssl-dhparams.pem:/etc/certs/ssl-dhparams.pem
- ./logs/web:/logs - ./logs/web:/logs
networks:
- ae_public
- ae_private
depends_on: depends_on:
- ae_api - ae_api
- aether_app_gunicorn - aether_app_gunicorn
@@ -47,8 +44,6 @@ services:
container_name: ${CONTAINER_REDIS} container_name: ${CONTAINER_REDIS}
image: redis image: redis
command: redis-server --save "" --loglevel warning command: redis-server --save "" --loglevel warning
networks:
- ae_private
logging: logging:
driver: "json-file" driver: "json-file"
options: options:
@@ -76,8 +71,6 @@ services:
volumes: volumes:
- ./srv/mariadb:/var/lib/mysql - ./srv/mariadb:/var/lib/mysql
- ./conf/mariadb/server.cnf:/etc/mysql/conf.d/server.cnf - ./conf/mariadb/server.cnf:/etc/mysql/conf.d/server.cnf
networks:
- ae_private
logging: logging:
driver: "json-file" driver: "json-file"
options: options:
@@ -93,9 +86,6 @@ services:
UPLOAD_LIMIT: 64M UPLOAD_LIMIT: 64M
ports: ports:
- "${AE_PMA_PORT}:80" - "${AE_PMA_PORT}:80"
networks:
- ae_public
- ae_private
depends_on: depends_on:
- mariadb - mariadb
logging: logging:
@@ -110,12 +100,6 @@ services:
context: ./ context: ./
dockerfile: aether_fastapi_gunicorn.Dockerfile dockerfile: aether_fastapi_gunicorn.Dockerfile
scale: ${AE_API_REPLICAS} scale: ${AE_API_REPLICAS}
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:5005/docs"]
interval: 10s
timeout: 5s
retries: 3
start_period: 10s
env_file: env_file:
- ./.env - ./.env
extra_hosts: extra_hosts:
@@ -134,8 +118,6 @@ services:
- ${HOSTED_FILES_SRC}:/srv/hosted_files - ${HOSTED_FILES_SRC}:/srv/hosted_files
- ${HOSTED_TMP_SRC}:/srv/hosted_tmp - ${HOSTED_TMP_SRC}:/srv/hosted_tmp
- ./temp/ae_api:/temp - ./temp/ae_api:/temp
networks:
- ae_private
depends_on: depends_on:
- redis - redis
- mariadb - mariadb
@@ -148,6 +130,7 @@ services:
max-file: "3" max-file: "3"
aether_app_gunicorn: aether_app_gunicorn:
# ... (same as before) ...
restart: always restart: always
container_name: ${CONTAINER_AE_APP} container_name: ${CONTAINER_AE_APP}
build: build:
@@ -170,9 +153,6 @@ services:
- ${HOSTED_FILES_SRC}:/srv/hosted_files - ${HOSTED_FILES_SRC}:/srv/hosted_files
- ${HOSTED_TMP_SRC}:/srv/hosted_tmp - ${HOSTED_TMP_SRC}:/srv/hosted_tmp
- ./tmp/ae_app:/tmp - ./tmp/ae_app:/tmp
networks:
- ae_public
- ae_private
depends_on: depends_on:
- ae_api - ae_api
stdin_open: true stdin_open: true
@@ -190,8 +170,6 @@ services:
- /var/run/docker.sock:/var/run/docker.sock - /var/run/docker.sock:/var/run/docker.sock
ports: ports:
- "8881:8080" - "8881:8080"
networks:
- ae_public
restart: unless-stopped restart: unless-stopped
logging: logging:
driver: "json-file" driver: "json-file"
@@ -199,9 +177,28 @@ services:
max-size: "10m" max-size: "10m"
max-file: "3" max-file: "3"
ae_ops:
# ... (same as before) ...
container_name: ae_ops_dev
image: alpine:latest
restart: always
env_file:
- ./.env
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- ./backups:/backups
- ./scripts:/scripts
- ./logs:/logs
- ./conf/crontab:/etc/crontabs/root
command: sh -c "apk add --no-cache docker-cli bash && crond -f -l 2"
depends_on:
- mariadb
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
networks: networks:
ae_public: default:
name: ae_dev_public name: ae_dev_net
ae_private:
name: ae_dev_private
internal: true