diff --git a/Dockerfile b/Dockerfile index c6c356b9..00cc1b84 100644 --- a/Dockerfile +++ b/Dockerfile @@ -69,7 +69,7 @@ RUN sed -i 's/^user www\-data\;$/user root\;/' /etc/nginx/nginx.conf # copy application into container COPY ./backend /app COPY ./docker_assets/run.sh /app -COPY ./docker_assets/uwsgi.ini /app +COPY ./docker_assets/backend_start.py /app COPY --from=node-builder ./frontend/dist /app/static diff --git a/README.md b/README.md index 4d724072..c123c019 100644 --- a/README.md +++ b/README.md @@ -57,7 +57,7 @@ Take a look at the example [docker-compose.yml](https://github.com/tubearchivist | REDIS_HOST | Hostname for Redis | Required | | TZ | Set your timezone for the scheduler | Required | | TA_PORT | Overwrite Nginx port | Optional | -| TA_UWSGI_PORT | Overwrite container internal uwsgi port | Optional | +| TA_BACKEND_PORT | Overwrite container internal backend server port | Optional | | TA_ENABLE_AUTH_PROXY | Enables support for forwarding auth in reverse proxies | [Read more](https://docs.tubearchivist.com/configuration/forward-auth/) | | TA_AUTH_PROXY_USERNAME_HEADER | Header containing username to log in | Optional | | TA_AUTH_PROXY_LOGOUT_URL | Logout URL for forwarded auth | Optional | diff --git a/backend/common/src/env_settings.py b/backend/common/src/env_settings.py index 1347d410..aff67bcd 100644 --- a/backend/common/src/env_settings.py +++ b/backend/common/src/env_settings.py @@ -27,7 +27,7 @@ class EnvironmentSettings: ENABLE_CAST: bool = bool(environ.get("ENABLE_CAST")) TZ: str = str(environ.get("TZ", "UTC")) TA_PORT: int = int(environ.get("TA_PORT", False)) - TA_UWSGI_PORT: int = int(environ.get("TA_UWSGI_PORT", False)) + TA_BACKEND_PORT: int = int(environ.get("TA_BACKEND_PORT", False)) TA_USERNAME: str = str(environ.get("TA_USERNAME")) TA_PASSWORD: str = str(environ.get("TA_PASSWORD")) @@ -75,7 +75,7 @@ class EnvironmentSettings: TZ: {self.TZ} ENABLE_CAST: {self.ENABLE_CAST} TA_PORT: {self.TA_PORT} - TA_UWSGI_PORT: {self.TA_UWSGI_PORT} + TA_BACKEND_PORT: {self.TA_BACKEND_PORT} TA_USERNAME: {self.TA_USERNAME} TA_PASSWORD: *****""" ) diff --git a/backend/config/management/commands/ta_envcheck.py b/backend/config/management/commands/ta_envcheck.py index 8c3afb4f..8918777f 100644 --- a/backend/config/management/commands/ta_envcheck.py +++ b/backend/config/management/commands/ta_envcheck.py @@ -8,6 +8,7 @@ Functionality: import os import re +from time import sleep from common.src.env_settings import EnvironmentSettings from django.core.management.base import BaseCommand, CommandError @@ -60,9 +61,11 @@ EXPECTED_ENV_VARS = [ "ES_URL", "TA_HOST", ] +UNEXPECTED_ENV_VARS = { + "TA_UWSGI_PORT": "Has been replaced with 'TA_BACKEND_PORT'" +} INST = "https://github.com/tubearchivist/tubearchivist#installing-and-updating" NGINX = "/etc/nginx/sites-available/default" -UWSGI = "/app/uwsgi.ini" class Command(BaseCommand): @@ -76,9 +79,10 @@ class Command(BaseCommand): self.stdout.write(LOGO) self.stdout.write(TOPIC) self._expected_vars() + self._unexpected_vars() self._elastic_user_overwrite() self._ta_port_overwrite() - self._ta_uwsgi_overwrite() + self._ta_backend_port_overwrite() self._enable_cast_overwrite() self._create_superuser() @@ -90,20 +94,41 @@ class Command(BaseCommand): if not env.get(var): message = f" 🗙 expected env var {var} not set\n {INST}" self.stdout.write(self.style.ERROR(message)) + sleep(60) raise CommandError(message) message = " ✓ all expected env vars are set" self.stdout.write(self.style.SUCCESS(message)) + def _unexpected_vars(self): + """check for unexpected env vars""" + self.stdout.write("[2] checking for unexpected env vars") + for var, message in UNEXPECTED_ENV_VARS.items(): + if not os.environ.get(var): + continue + + message = ( + f" 🗙 unexpected env var {var} found\n" + f" {message} \n" + " see release notes for a list of all changes." + ) + + self.stdout.write(self.style.ERROR(message)) + sleep(60) + raise CommandError(message) + + message = " ✓ no unexpected env vars found" + self.stdout.write(self.style.SUCCESS(message)) + def _elastic_user_overwrite(self): """check for ELASTIC_USER overwrite""" - self.stdout.write("[2] check ES user overwrite") + self.stdout.write("[3] check ES user overwrite") env = EnvironmentSettings.ES_USER self.stdout.write(self.style.SUCCESS(f" ✓ ES user is set to {env}")) def _ta_port_overwrite(self): """set TA_PORT overwrite for nginx""" - self.stdout.write("[3] check TA_PORT overwrite") + self.stdout.write("[4] check TA_PORT overwrite") overwrite = EnvironmentSettings.TA_PORT if not overwrite: self.stdout.write(self.style.SUCCESS(" TA_PORT is not set")) @@ -119,35 +144,30 @@ class Command(BaseCommand): self.stdout.write(self.style.SUCCESS(message)) - def _ta_uwsgi_overwrite(self): - """set TA_UWSGI_PORT overwrite""" - self.stdout.write("[4] check TA_UWSGI_PORT overwrite") - overwrite = EnvironmentSettings.TA_UWSGI_PORT + def _ta_backend_port_overwrite(self): + """set TA_BACKEND_PORT overwrite""" + self.stdout.write("[5] check TA_BACKEND_PORT overwrite") + overwrite = EnvironmentSettings.TA_BACKEND_PORT if not overwrite: - message = " TA_UWSGI_PORT is not set" + message = " TA_BACKEND_PORT is not set" self.stdout.write(self.style.SUCCESS(message)) return - # nginx - regex = re.compile(r"uwsgi_pass localhost:[0-9]{1,5}") - to_overwrite = f"uwsgi_pass localhost:{overwrite}" + # modify nginx conf + regex = re.compile(r"proxy_pass http://localhost:[0-9]{1,5}") + to_overwrite = f"proxy_pass http://localhost:{overwrite}" changed = file_overwrite(NGINX, regex, to_overwrite) - # uwsgi - regex = re.compile(r"socket = :[0-9]{1,5}") - to_overwrite = f"socket = :{overwrite}" - changed = file_overwrite(UWSGI, regex, to_overwrite) - if changed: - message = f" ✓ TA_UWSGI_PORT changed to {overwrite}" + message = f" ✓ TA_BACKEND_PORT changed to {overwrite}" else: - message = f" ✓ TA_UWSGI_PORT already set to {overwrite}" + message = f" ✓ TA_BACKEND_PORT already set to {overwrite}" self.stdout.write(self.style.SUCCESS(message)) def _enable_cast_overwrite(self): """cast workaround, remove auth for static files in nginx""" - self.stdout.write("[5] check ENABLE_CAST overwrite") + self.stdout.write("[6] check ENABLE_CAST overwrite") overwrite = EnvironmentSettings.ENABLE_CAST if not overwrite: self.stdout.write(self.style.SUCCESS(" ENABLE_CAST is not set")) @@ -164,7 +184,7 @@ class Command(BaseCommand): def _create_superuser(self): """create superuser if not exist""" - self.stdout.write("[6] create superuser") + self.stdout.write("[7] create superuser") is_created = Account.objects.filter(is_superuser=True) if is_created: message = " superuser already created" diff --git a/backend/requirements.txt b/backend/requirements.txt index b2a3f921..3bfebca1 100644 --- a/backend/requirements.txt +++ b/backend/requirements.txt @@ -9,6 +9,6 @@ Pillow==11.0.0 redis==5.2.1 requests==2.32.3 ryd-client==0.0.6 -uWSGI==2.0.28 +uvicorn==0.34.0 whitenoise==6.8.2 yt-dlp[default]==2024.12.13 diff --git a/docker_assets/backend_start.py b/docker_assets/backend_start.py new file mode 100755 index 00000000..997e2781 --- /dev/null +++ b/docker_assets/backend_start.py @@ -0,0 +1,18 @@ +"""start backend python application, read env var""" + +from os import environ + +import uvicorn + +LOG_LEVEL = "info" if environ.get("DJANGO_DEBUG") else "error" +PORT = int(environ.get("TA_BACKEND_PORT", 8080)) + +if __name__ == "__main__": + uvicorn.run( + "config.asgi:application", + host="0.0.0.0", + port=PORT, + workers=4, + log_level=LOG_LEVEL, + reload=False, + ) diff --git a/docker_assets/nginx.conf b/docker_assets/nginx.conf index 438ca98d..e6dd7e1b 100644 --- a/docker_assets/nginx.conf +++ b/docker_assets/nginx.conf @@ -34,13 +34,13 @@ server { } location /api { - include uwsgi_params; - uwsgi_pass localhost:8080; + include proxy_params; + proxy_pass http://localhost:8080; } location /admin { - include uwsgi_params; - uwsgi_pass localhost:8080; + include proxy_params; + proxy_pass http://localhost:8080; } location /static/ { diff --git a/docker_assets/run.sh b/docker_assets/run.sh index 59fa8edb..9a357a9c 100644 --- a/docker_assets/run.sh +++ b/docker_assets/run.sh @@ -20,4 +20,4 @@ nginx & celery -A task.celery worker --loglevel=INFO --max-tasks-per-child 10 & celery -A task beat --loglevel=INFO \ --scheduler django_celery_beat.schedulers:DatabaseScheduler & -uwsgi --ini uwsgi.ini +python backend_start.py diff --git a/docker_assets/uwsgi.ini b/docker_assets/uwsgi.ini deleted file mode 100644 index 436d398c..00000000 --- a/docker_assets/uwsgi.ini +++ /dev/null @@ -1,11 +0,0 @@ -[uwsgi] -module = config.wsgi:application -master = True -pidfile = /tmp/project-master.pid -vacuum = True -max-requests = 5000 -socket = :8080 -buffer-size = 8192 -log-5xx = true -log-4xx = true -disable-logging = true