Add S3/MinIO (RustFS) support and compose updates
Introduce S3-compatible storage support and update local/dev configuration. - .claude: add "WebSearch" to local settings - backend/.env.example: add USE_S3 flag and detailed S3/MinIO (RustFS) example env vars + comments to explain dev vs production usage - backend/vontor_cz/settings.py: refactor to use USE_S3 boolean; set STATIC_ROOT; configure STORAGES for local filesystem vs S3 backends; add handling for S3 endpoint (MinIO/RustFS) vs real AWS S3 including path-style addressing, URL construction, and sensible AWS defaults - docker-compose.yml: add rustfs to service dependencies, include rustfs in networks, change frontend port mapping to 8001:80, and add rustfs-data volume binding These changes enable using a local S3-compatible backend (RustFS/MinIO) in development while keeping the option to swap to real AWS S3 for production.
This commit is contained in:
@@ -18,7 +18,8 @@
|
|||||||
"Bash(node -e \"const r = require\\('react-icons/si'\\); const celery = Object.keys\\(r\\).filter\\(k => k.toLowerCase\\(\\).includes\\('celery'\\) || k.toLowerCase\\(\\).includes\\('worker'\\) || k.toLowerCase\\(\\).includes\\('task'\\)\\).slice\\(0,10\\); console.log\\(celery\\);\")",
|
"Bash(node -e \"const r = require\\('react-icons/si'\\); const celery = Object.keys\\(r\\).filter\\(k => k.toLowerCase\\(\\).includes\\('celery'\\) || k.toLowerCase\\(\\).includes\\('worker'\\) || k.toLowerCase\\(\\).includes\\('task'\\)\\).slice\\(0,10\\); console.log\\(celery\\);\")",
|
||||||
"Bash(Get-ChildItem -Path \"c:\\\\Users\\\\bruno\\\\Documents\\\\GitHub\\\\vontor-cz\\\\backend\\\\\" -Directory | Select-Object -ExpandProperty Name)",
|
"Bash(Get-ChildItem -Path \"c:\\\\Users\\\\bruno\\\\Documents\\\\GitHub\\\\vontor-cz\\\\backend\\\\\" -Directory | Select-Object -ExpandProperty Name)",
|
||||||
"PowerShell(Get-Command python)",
|
"PowerShell(Get-Command python)",
|
||||||
"PowerShell(python -c \"import django; print\\(django.__version__\\)\")"
|
"PowerShell(python -c \"import django; print\\(django.__version__\\)\")",
|
||||||
|
"WebSearch"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,6 +20,8 @@ POSTGRES_USER=dockerDBuser
|
|||||||
POSTGRES_PASSWORD=AWSJeMocDrahaZalezitost
|
POSTGRES_PASSWORD=AWSJeMocDrahaZalezitost
|
||||||
|
|
||||||
# ------------------ MEDIA / STATIC ------------------
|
# ------------------ MEDIA / STATIC ------------------
|
||||||
|
# USE_S3=True enables S3-compatible storage (MinIO or AWS).
|
||||||
|
# Leave USE_S3=False (default) to use local filesystem in development.
|
||||||
MEDIA_URL=/media/
|
MEDIA_URL=/media/
|
||||||
|
|
||||||
# ------------------ REDIS / CACHING / CHANNELS ------------------
|
# ------------------ REDIS / CACHING / CHANNELS ------------------
|
||||||
@@ -44,12 +46,29 @@ EMAIL_USER=
|
|||||||
EMAIL_USER_PASSWORD=
|
EMAIL_USER_PASSWORD=
|
||||||
DEFAULT_FROM_EMAIL=
|
DEFAULT_FROM_EMAIL=
|
||||||
|
|
||||||
# ------------------ AWS (disabled unless USE_AWS=True) ------------------
|
# ------------------ S3 STORAGE ------------------
|
||||||
USE_AWS=False
|
# Set USE_S3=True to enable. AWS_S3_ENDPOINT_URL selects the backend:
|
||||||
AWS_ACCESS_KEY_ID=
|
# set → MinIO / S3-compatible
|
||||||
AWS_SECRET_ACCESS_KEY=
|
# empty → real AWS S3
|
||||||
AWS_STORAGE_BUCKET_NAME=
|
|
||||||
AWS_S3_REGION_NAME=eu-central-1
|
USE_S3=False
|
||||||
|
|
||||||
|
# RustFS (docker-compose default — S3-compatible MinIO successor)
|
||||||
|
AWS_S3_ENDPOINT_URL=http://rustfs:9000
|
||||||
|
AWS_S3_CUSTOM_DOMAIN=localhost:9000/vontor
|
||||||
|
AWS_STORAGE_BUCKET_NAME=vontor
|
||||||
|
AWS_ACCESS_KEY_ID=rustfsadmin
|
||||||
|
AWS_SECRET_ACCESS_KEY=rustfsadmin
|
||||||
|
RUSTFS_ACCESS_KEY=rustfsadmin
|
||||||
|
RUSTFS_SECRET_KEY=rustfsadmin
|
||||||
|
RUSTFS_BUCKET_NAME=vontor
|
||||||
|
|
||||||
|
# AWS S3 (swap in for production — clear AWS_S3_ENDPOINT_URL)
|
||||||
|
# AWS_STORAGE_BUCKET_NAME=my-bucket
|
||||||
|
# AWS_ACCESS_KEY_ID=
|
||||||
|
# AWS_SECRET_ACCESS_KEY=
|
||||||
|
# AWS_S3_REGION_NAME=eu-central-1
|
||||||
|
# AWS_S3_ENDPOINT_URL=
|
||||||
|
|
||||||
# ------------------ JWT / TOKENS (lifetimes defined in code) ------------------
|
# ------------------ JWT / TOKENS (lifetimes defined in code) ------------------
|
||||||
# (No env vars needed; kept placeholder section)
|
# (No env vars needed; kept placeholder section)
|
||||||
|
|||||||
@@ -626,63 +626,59 @@ STATICFILES_DIRS = [
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
if os.getenv("USE_AWS", "") == "True":
|
USE_S3 = _env_bool("USE_S3")
|
||||||
USE_AWS = True
|
print(f"USE_S3: {USE_S3}")
|
||||||
else:
|
|
||||||
USE_AWS = False
|
|
||||||
|
|
||||||
print(f"\n-------------- USE_AWS: {USE_AWS} --------------")
|
STATIC_ROOT = BASE_DIR / 'collectedstaticfiles'
|
||||||
|
|
||||||
if USE_AWS is False:
|
if not USE_S3:
|
||||||
# Development: Use local file system storage for static files
|
# Local filesystem — development only
|
||||||
STORAGES = {
|
STORAGES = {
|
||||||
"default": {
|
"default": {"BACKEND": "django.core.files.storage.FileSystemStorage"},
|
||||||
"BACKEND": "django.core.files.storage.FileSystemStorage",
|
"staticfiles": {"BACKEND": "django.contrib.staticfiles.storage.StaticFilesStorage"},
|
||||||
},
|
|
||||||
"staticfiles": {
|
|
||||||
"BACKEND": "django.contrib.staticfiles.storage.StaticFilesStorage",
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# Media and Static URL for local dev
|
|
||||||
MEDIA_URL = os.getenv("MEDIA_URL", "/media/")
|
MEDIA_URL = os.getenv("MEDIA_URL", "/media/")
|
||||||
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
|
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
|
||||||
|
|
||||||
STATIC_URL = '/static/'
|
STATIC_URL = '/static/'
|
||||||
STATIC_ROOT = BASE_DIR / 'collectedstaticfiles'
|
|
||||||
elif USE_AWS:
|
|
||||||
# PRODUCTION
|
|
||||||
|
|
||||||
AWS_LOCATION = "static"
|
else:
|
||||||
|
# S3-compatible storage — MinIO (AWS_S3_ENDPOINT_URL set) or real AWS S3 (endpoint empty)
|
||||||
|
S3_BUCKET = os.getenv('AWS_STORAGE_BUCKET_NAME', 'vontor')
|
||||||
|
S3_ENDPOINT = os.getenv('AWS_S3_ENDPOINT_URL', '')
|
||||||
|
S3_CUSTOM_DOMAIN = os.getenv('AWS_S3_CUSTOM_DOMAIN', '')
|
||||||
|
S3_SSL = not S3_ENDPOINT or S3_ENDPOINT.startswith('https')
|
||||||
|
S3_PROTO = 'https' if S3_SSL else 'http'
|
||||||
|
|
||||||
# Production: Use S3 storage
|
|
||||||
STORAGES = {
|
STORAGES = {
|
||||||
"default": {
|
"default": {"BACKEND": "storages.backends.s3boto3.S3Boto3Storage"},
|
||||||
"BACKEND" : "storages.backends.s3boto3.S3StaticStorage",
|
"staticfiles": {"BACKEND": "storages.backends.s3boto3.S3StaticStorage"},
|
||||||
},
|
|
||||||
|
|
||||||
"staticfiles": {
|
|
||||||
"BACKEND" : "storages.backends.s3boto3.S3StaticStorage",
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# Media and Static URL for AWS S3
|
|
||||||
MEDIA_URL = f'https://{os.getenv("AWS_STORAGE_BUCKET_NAME")}.s3.amazonaws.com/media/'
|
|
||||||
STATIC_URL = f'https://{os.getenv("AWS_STORAGE_BUCKET_NAME")}.s3.amazonaws.com/static/'
|
|
||||||
|
|
||||||
CSRF_TRUSTED_ORIGINS.append(STATIC_URL)
|
|
||||||
|
|
||||||
# Static files should be collected to a local directory and then uploaded to S3
|
|
||||||
STATIC_ROOT = BASE_DIR / 'collectedstaticfiles'
|
|
||||||
|
|
||||||
AWS_ACCESS_KEY_ID = os.getenv('AWS_ACCESS_KEY_ID')
|
AWS_ACCESS_KEY_ID = os.getenv('AWS_ACCESS_KEY_ID')
|
||||||
AWS_SECRET_ACCESS_KEY = os.getenv('AWS_SECRET_ACCESS_KEY')
|
AWS_SECRET_ACCESS_KEY = os.getenv('AWS_SECRET_ACCESS_KEY')
|
||||||
AWS_STORAGE_BUCKET_NAME = os.getenv('AWS_STORAGE_BUCKET_NAME')
|
AWS_STORAGE_BUCKET_NAME = S3_BUCKET
|
||||||
AWS_S3_REGION_NAME = os.getenv('AWS_S3_REGION_NAME', 'us-east-1') # Default to 'us-east-1' if not set
|
AWS_S3_SIGNATURE_VERSION = 's3v4'
|
||||||
AWS_S3_SIGNATURE_VERSION = 's3v4' # Use AWS Signature Version 4
|
AWS_S3_FILE_OVERWRITE = False
|
||||||
AWS_S3_USE_SSL = True
|
AWS_DEFAULT_ACL = None
|
||||||
AWS_S3_FILE_OVERWRITE = True
|
AWS_QUERYSTRING_AUTH = False
|
||||||
AWS_DEFAULT_ACL = None # Set to None to avoid setting a default ACL
|
AWS_S3_USE_SSL = S3_SSL
|
||||||
|
|
||||||
|
if S3_ENDPOINT:
|
||||||
|
# MinIO / S3-compatible: needs path-style addressing
|
||||||
|
AWS_S3_ENDPOINT_URL = S3_ENDPOINT
|
||||||
|
AWS_S3_ADDRESSING_STYLE = 'path'
|
||||||
|
if S3_CUSTOM_DOMAIN:
|
||||||
|
AWS_S3_CUSTOM_DOMAIN = S3_CUSTOM_DOMAIN
|
||||||
|
AWS_S3_URL_PROTOCOL = f'{S3_PROTO}:'
|
||||||
|
base_host = S3_CUSTOM_DOMAIN or f'{S3_ENDPOINT.split("://")[1]}/{S3_BUCKET}'
|
||||||
|
MEDIA_URL = f'{S3_PROTO}://{base_host}/'
|
||||||
|
STATIC_URL = f'{S3_PROTO}://{base_host}/static/'
|
||||||
|
else:
|
||||||
|
# AWS S3
|
||||||
|
AWS_S3_REGION_NAME = os.getenv('AWS_S3_REGION_NAME', 'us-east-1')
|
||||||
|
MEDIA_URL = f'https://{S3_BUCKET}.s3.amazonaws.com/media/'
|
||||||
|
STATIC_URL = f'https://{S3_BUCKET}.s3.amazonaws.com/static/'
|
||||||
|
CSRF_TRUSTED_ORIGINS.append(STATIC_URL)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ services:
|
|||||||
depends_on:
|
depends_on:
|
||||||
- db
|
- db
|
||||||
- redis
|
- redis
|
||||||
|
- rustfs
|
||||||
volumes:
|
volumes:
|
||||||
- ./backend:/app
|
- ./backend:/app
|
||||||
- static-data:/app/collectedstaticfiles
|
- static-data:/app/collectedstaticfiles
|
||||||
@@ -66,6 +67,7 @@ services:
|
|||||||
- redis
|
- redis
|
||||||
- db
|
- db
|
||||||
- backend
|
- backend
|
||||||
|
- rustfs
|
||||||
networks:
|
networks:
|
||||||
- app_network
|
- app_network
|
||||||
|
|
||||||
@@ -84,6 +86,7 @@ services:
|
|||||||
- redis
|
- redis
|
||||||
- db
|
- db
|
||||||
- backend
|
- backend
|
||||||
|
- rustfs
|
||||||
networks:
|
networks:
|
||||||
- app_network
|
- app_network
|
||||||
|
|
||||||
@@ -114,8 +117,7 @@ services:
|
|||||||
env_file:
|
env_file:
|
||||||
- ./frontend/.env
|
- ./frontend/.env
|
||||||
ports:
|
ports:
|
||||||
- 80:80
|
- 8001:80
|
||||||
# - 9000:80
|
|
||||||
depends_on:
|
depends_on:
|
||||||
- backend
|
- backend
|
||||||
networks:
|
networks:
|
||||||
@@ -157,4 +159,10 @@ volumes:
|
|||||||
type: none
|
type: none
|
||||||
o: bind
|
o: bind
|
||||||
device: ./volumes/media
|
device: ./volumes/media
|
||||||
|
rustfs-data:
|
||||||
|
driver: local
|
||||||
|
driver_opts:
|
||||||
|
type: none
|
||||||
|
o: bind
|
||||||
|
device: ./volumes/rustfs
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user