diff --git a/.env.example b/.env.example index e69de29..fdf0c5d 100644 --- a/.env.example +++ b/.env.example @@ -0,0 +1,38 @@ +#################### +# Secret key +#################### +SECRET_KEY=key + +#################### +# Debug +#################### +DEBUG=True + +#################### +# Allowed hosts +#################### +ALLOWED_HOSTS=localhost,127.0.0.1 + +################### +# Database +################### +POSTGRES_PASSWORD=password +POSTGRES_USER=postgres +POSTGRES_DB=uyqur_db +POSTGRES_HOST=db +POSTGRES_PORT=5432 + +################### +# Port +################### +PORT=8000 # optional -> default 8001 + +################### +# Command +################### +COMMAND=sh ./resources/entrypoint.sh # optional + +################### +# Redis +################### +REDIS_URL=redis://redis:6379/0 \ No newline at end of file diff --git a/config/env.py b/config/env.py index e69de29..9506fb1 100644 --- a/config/env.py +++ b/config/env.py @@ -0,0 +1,8 @@ +import os, environ + + +environ.Env.read_env(os.path.join(".env")) + +env = environ.Env( + +) \ No newline at end of file diff --git a/config/settings/base.py b/config/settings/base.py index b8a8e60..9512226 100644 --- a/config/settings/base.py +++ b/config/settings/base.py @@ -1,17 +1,7 @@ -""" -Django settings for config project. - -Generated by 'django-admin startproject' using Django 5.2.4. - -For more information on this file, see -https://docs.djangoproject.com/en/5.2/topics/settings/ - -For the full list of settings and their values, see -https://docs.djangoproject.com/en/5.2/ref/settings/ -""" - from pathlib import Path +from config.env import env + # Build paths inside the project like this: BASE_DIR / 'subdir'. BASE_DIR = Path(__file__).resolve().parent.parent.parent @@ -20,12 +10,12 @@ BASE_DIR = Path(__file__).resolve().parent.parent.parent # See https://docs.djangoproject.com/en/5.2/howto/deployment/checklist/ # SECURITY WARNING: keep the secret key used in production secret! -SECRET_KEY = 'django-insecure-6%*k%_mx!*x&%$y0n*=d)_y-$@qk9#*5ez0#3_4_7fx6ew7(%x' +SECRET_KEY = env.str('SECRET_KEY') # SECURITY WARNING: don't run with debug turned on in production! -DEBUG = True +DEBUG = env.bool('DEBUG') -ALLOWED_HOSTS = [] +ALLOWED_HOSTS = env.list('ALLOWED_HOSTS') # Application definition @@ -74,8 +64,13 @@ WSGI_APPLICATION = 'config.wsgi.application' DATABASES = { 'default': { - 'ENGINE': 'django.db.backends.sqlite3', - 'NAME': BASE_DIR / 'db.sqlite3', + 'ENGINE': 'django.db.backends.postgresql', + 'NAME': env.str('POSTGRES_DB'), + 'USER': env.str('POSTGRES_USER'), + 'PASSWORD': env.str('POSTGRES_PASSWORD'), + 'HOST': env.str('POSTGRES_HOST'), + 'PORT': env.str('POSTGRES_PORT'), + 'CONN_MAX_AGE': 0 } } @@ -102,19 +97,22 @@ AUTH_PASSWORD_VALIDATORS = [ # Internationalization # https://docs.djangoproject.com/en/5.2/topics/i18n/ -LANGUAGE_CODE = 'en-us' +LANGUAGE_CODE = 'uz' -TIME_ZONE = 'UTC' +TIME_ZONE = 'Asia/Tashkent' USE_I18N = True -USE_TZ = True +USE_TZ = False # Static files (CSS, JavaScript, Images) # https://docs.djangoproject.com/en/5.2/howto/static-files/ STATIC_URL = 'static/' +STATIC_ROOT = BASE_DIR / 'resources/static' +MEDIA_URL = 'media/' +MEDIA_ROOT = BASE_DIR / 'resources/media' # Default primary key field type # https://docs.djangoproject.com/en/5.2/ref/settings/#default-auto-field diff --git a/docker-compose.yaml b/docker-compose.yaml index e69de29..3b670f6 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -0,0 +1,56 @@ +networks: + uyqur: + driver: bridge + +volumes: + pg_data: null + +services: + nginx: + networks: + - uyqur + ports: + - ${PORT:-8001}:80 + volumes: + - ./resources/layout/nginx.conf:/etc/nginx/nginx.conf + - ./resources/:/usr/share/nginx/html/resources/ + build: + context: . + dockerfile: ./docker/Dockerfile.nginx + depends_on: + - web + + web: + networks: + - uyqur + build: + context: . + dockerfile: ./docker/Dockerfile.web + restart: always + command: ${COMMAND:-sh ./resources/scripts/entrypoint.sh} + environment: + - PYTHONPYCACHEPREFIX=/var/cache/pycache + volumes: + - './:/code' + depends_on: + - db + - redis + + db: + image: postgres:17 + networks: + - uyqur + restart: always + environment: + POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} + POSTGRES_USER: ${POSTGRES_USER} + POSTGRES_DB: ${POSTGRES_DB} + volumes: + - pg_data:/var/lib/postgresql/data + + redis: + networks: + - uyqur + restart: always + image: redis + diff --git a/docker/Dockerfile.nginx b/docker/Dockerfile.nginx index e69de29..42738e3 100644 --- a/docker/Dockerfile.nginx +++ b/docker/Dockerfile.nginx @@ -0,0 +1,3 @@ +FROM nginx:alpine + +COPY ./resources/layout/nginx.conf /etc/nginx/nginx.conf \ No newline at end of file diff --git a/docker/Dockerfile.web b/docker/Dockerfile.web index e69de29..38e6222 100644 --- a/docker/Dockerfile.web +++ b/docker/Dockerfile.web @@ -0,0 +1,23 @@ +FROM python:3.12 + +WORKDIR /code + +RUN apt-get update && \ + apt-get install -y \ + gdal-bin \ + libgdal-dev \ + python3-gdal \ + libgeos-dev \ + libproj-dev \ + g++ \ + make \ + wkhtmltopdf && \ + apt-get clean && \ + rm -rf /var/lib/apt/lists/* + +RUN gdalinfo --version + +COPY ./ /code +RUN --mount=type=cache,target=/root/.cache/pip python3 -m pip install -r requirements.txt + +CMD ["sh", "./resources/scripts/entrypoint.sh"] \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index e69de29..5a78c8b 100644 --- a/requirements.txt +++ b/requirements.txt @@ -0,0 +1,10 @@ +asgiref==3.9.1 +click==8.2.1 +Django==5.2.4 +django-environ==0.12.0 +gunicorn==23.0.0 +h11==0.16.0 +packaging==25.0 +psycopg2-binary==2.9.10 +sqlparse==0.5.3 +uvicorn==0.35.0 diff --git a/resources/layout/Dockerfile.alpine b/resources/layout/Dockerfile.alpine index e69de29..7d6e714 100644 --- a/resources/layout/Dockerfile.alpine +++ b/resources/layout/Dockerfile.alpine @@ -0,0 +1,13 @@ +FROM python:3.13-alpine + +ENV PYTHONPYCACHEPREFIX=/dev/null + +RUN apk update && apk add git gettext + +WORKDIR /code + +COPY requirements.txt /code/requirements.txt + +RUN --mount=type=cache,target=/root/.cache/pip pip install -r requirements.txt + +CMD ["sh", "./entrypoint.sh"] \ No newline at end of file diff --git a/resources/layout/Dockerfile.nginx b/resources/layout/Dockerfile.nginx index e69de29..42738e3 100644 --- a/resources/layout/Dockerfile.nginx +++ b/resources/layout/Dockerfile.nginx @@ -0,0 +1,3 @@ +FROM nginx:alpine + +COPY ./resources/layout/nginx.conf /etc/nginx/nginx.conf \ No newline at end of file diff --git a/resources/layout/nginx.conf b/resources/layout/nginx.conf index e69de29..86df9f2 100644 --- a/resources/layout/nginx.conf +++ b/resources/layout/nginx.conf @@ -0,0 +1,52 @@ +worker_processes 1; + +events { + worker_connections 1024; +} + +http { + include mime.types; + default_type application/octet-stream; + + log_format main '$remote_addr - $remote_user [$time_local] "$request" ' + '$status $body_bytes_sent "$http_referer" ' + '"$http_user_agent" "$http_x_forwarded_for"'; + access_log /var/log/nginx/access.log main; + + sendfile on; + tcp_nopush on; + tcp_nodelay on; + keepalive_timeout 65; + types_hash_max_size 2048; + client_max_body_size 1024M; + + # Server block for handling requests + server { + listen 80; + + server_name _; + + location / { + proxy_pass http://web:8000; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto https; + proxy_set_header Host $http_host; + } + location /ws/ { + proxy_pass http://web:8000; # Uvicorn serveri ishga tushadigan port + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection 'upgrade'; + proxy_set_header Host $http_host; + } + + location /static/ { + alias /usr/share/nginx/html/resources/staticfiles/; + } + + location /media/ { + alias /usr/share/nginx/html/resources/media/; + } + } +} \ No newline at end of file diff --git a/resources/scripts/backup.sh b/resources/scripts/backup.sh new file mode 100644 index 0000000..5bac180 --- /dev/null +++ b/resources/scripts/backup.sh @@ -0,0 +1,5 @@ +file=/tmp/db-$(/usr/bin/date +\%Y-%m-%d-%H:%M:%S).sql +container=postgres +/usr/bin/docker container exec $container pg_dump -U postgres django > $file +mc cp $file b2/buket-name +rm $file \ No newline at end of file diff --git a/resources/scripts/entrypoint-server.sh b/resources/scripts/entrypoint-server.sh new file mode 100644 index 0000000..b1c9cb5 --- /dev/null +++ b/resources/scripts/entrypoint-server.sh @@ -0,0 +1,8 @@ +#!/bin/bash +python3 manage.py collectstatic --noinput +python3 manage.py migrate --noinput + +gunicorn config.wsgi:application -b 0.0.0.0:8000 --workers $(($(nproc) * 2 + 1)) + + +exit $? \ No newline at end of file diff --git a/resources/scripts/entrypoint.sh b/resources/scripts/entrypoint.sh new file mode 100644 index 0000000..f92abc5 --- /dev/null +++ b/resources/scripts/entrypoint.sh @@ -0,0 +1,7 @@ +#!/bin/bash +python3 manage.py collectstatic --noinput +python3 manage.py migrate --noinput + +uvicorn config.asgi:application --host 0.0.0.0 --port 8000 --reload-dir core --reload-dir config + +exit $? \ No newline at end of file