fix(docker): make instance directory configurable and writable

- Add INSTANCE_BASE_PATH config option (defaults to /data/instances)
- Update docker.py to use configured path instead of hardcoded 'data/instances'
- Update Dockerfile to create /data/instances and chown to appuser
- Add instance_data volume to docker-compose.traefik.yml and docker-compose.yml
- Set INSTANCE_BASE_PATH env var in both compose files

This fixes the PermissionError when creating tool instances because
appuser can now write to /data/instances.
This commit is contained in:
Fusion
2026-05-20 10:09:37 +02:00
parent d4e992a9e2
commit 25662e525c
5 changed files with 17 additions and 5 deletions
+2 -2
View File
@@ -35,8 +35,8 @@ ENV PATH=/home/appuser/.local/bin:$PATH
# Copy application code # Copy application code
COPY --chown=appuser:appgroup . . COPY --chown=appuser:appgroup . .
# Create directories for repo storage # Create directories for repo and instance storage
RUN mkdir -p /data/repos && chown -R appuser:appgroup /data/repos RUN mkdir -p /data/repos /data/instances && chown -R appuser:appgroup /data
# Copy wait-for-db script # Copy wait-for-db script
COPY wait-for-db.sh /usr/local/bin/wait-for-db.sh COPY wait-for-db.sh /usr/local/bin/wait-for-db.sh
+3
View File
@@ -49,6 +49,9 @@ class Settings(BaseSettings):
# Repository storage # Repository storage
repo_base_path: str = "/data/repos" repo_base_path: str = "/data/repos"
# Tool instance storage
instance_base_path: str = "/data/instances"
model_config = SettingsConfigDict(env_file=".env", extra="ignore", populate_by_name=True) model_config = SettingsConfigDict(env_file=".env", extra="ignore", populate_by_name=True)
+5 -2
View File
@@ -23,16 +23,19 @@ def render_compose_template(template: str, variables: dict[str, Any]) -> str:
return result return result
def ensure_instance_directory(instance_id: str, base_path: str = "data/instances") -> str: def ensure_instance_directory(instance_id: str, base_path: str | None = None) -> str:
"""Create and return the instance directory path. """Create and return the instance directory path.
Args: Args:
instance_id: Unique instance identifier instance_id: Unique instance identifier
base_path: Base directory for all instances base_path: Base directory for all instances (defaults to Settings.instance_base_path)
Returns: Returns:
Absolute path to instance directory Absolute path to instance directory
""" """
if base_path is None:
from src.config import Settings
base_path = Settings().instance_base_path
instance_dir = Path(base_path) / instance_id instance_dir = Path(base_path) / instance_id
instance_dir.mkdir(parents=True, exist_ok=True) instance_dir.mkdir(parents=True, exist_ok=True)
return str(instance_dir.absolute()) return str(instance_dir.absolute())
+3
View File
@@ -80,6 +80,7 @@ services:
SESSION_SECRET: ${SESSION_SECRET:-change-me-in-production} SESSION_SECRET: ${SESSION_SECRET:-change-me-in-production}
SESSION_TTL_HOURS: ${SESSION_TTL_HOURS:-24} SESSION_TTL_HOURS: ${SESSION_TTL_HOURS:-24}
REPO_BASE_PATH: /data/repos REPO_BASE_PATH: /data/repos
INSTANCE_BASE_PATH: /data/instances
API_DOMAIN: ${API_DOMAIN} API_DOMAIN: ${API_DOMAIN}
WEB_DOMAIN: ${WEB_DOMAIN} WEB_DOMAIN: ${WEB_DOMAIN}
AUTHENTIK_DOMAIN: ${AUTHENTIK_DOMAIN} AUTHENTIK_DOMAIN: ${AUTHENTIK_DOMAIN}
@@ -92,6 +93,7 @@ services:
AUTHENTIK_TOKEN_URL: ${AUTHENTIK_TOKEN_URL:-} AUTHENTIK_TOKEN_URL: ${AUTHENTIK_TOKEN_URL:-}
volumes: volumes:
- repo_data:/data/repos - repo_data:/data/repos
- instance_data:/data/instances
- avatar_uploads:/app/uploads - avatar_uploads:/app/uploads
depends_on: depends_on:
postgres: postgres:
@@ -114,6 +116,7 @@ volumes:
postgres_data: postgres_data:
redis_data: redis_data:
repo_data: repo_data:
instance_data:
avatar_uploads: avatar_uploads:
networks: networks:
+4 -1
View File
@@ -53,10 +53,12 @@ services:
POSTGRES_HOST: postgres POSTGRES_HOST: postgres
POSTGRES_PORT: 5432 POSTGRES_PORT: 5432
REDIS_URL: redis://redis:6379/0 REDIS_URL: redis://redis:6379/0
JWT_SECRET: ${JWT_SECRET:-change-me-in-production} SESSION_SECRET: ${SESSION_SECRET:-change-me-in-production}
REPO_BASE_PATH: /data/repos REPO_BASE_PATH: /data/repos
INSTANCE_BASE_PATH: /data/instances
volumes: volumes:
- repo_data:/data/repos - repo_data:/data/repos
- instance_data:/data/instances
ports: ports:
- "8000:8000" - "8000:8000"
depends_on: depends_on:
@@ -90,6 +92,7 @@ volumes:
postgres_data: postgres_data:
redis_data: redis_data:
repo_data: repo_data:
instance_data:
networks: networks:
backend: backend: