Compare commits
12 Commits
3b052aeca4
...
5ef7f18f77
| Author | SHA1 | Date | |
|---|---|---|---|
| 5ef7f18f77 | |||
| 40f89fc9aa | |||
| 4d82094c0b | |||
| 0a328156fa | |||
| a91606cc32 | |||
| 64be80da12 | |||
| 50eaf00cf2 | |||
| 34af725f41 | |||
| 596e2716ab | |||
| 8ab01bd5b7 | |||
| 8b6f25e068 | |||
| d3f14aeb78 |
5
.gitignore
vendored
5
.gitignore
vendored
@@ -1,3 +1,8 @@
|
||||
.env
|
||||
backend/logs/
|
||||
backend/.pytest_cache/
|
||||
|
||||
backend/qlockify-backend-deployment
|
||||
frontend/qlockify-frontend-deployment
|
||||
nginx/certs/*
|
||||
!nginx/certs/.gitkeep
|
||||
|
||||
253
README.md
253
README.md
@@ -1,33 +1,250 @@
|
||||
# Qlockify Deployment
|
||||
|
||||
This repository is the deployment layer only.
|
||||
Main deployment and operations repository for Qlockify.
|
||||
|
||||
It does not contain application source copies. Docker builds read directly from the sibling repositories:
|
||||
This repo is the entrypoint for running the full product stack in production.
|
||||
|
||||
- `../qlockify-backend`
|
||||
- `../qlockify-frontend`
|
||||
## Related Repositories
|
||||
|
||||
## Local structure
|
||||
- Deployment repository declared by `origin`: `https://git.amiirkhl.ir/Qlockify/qlockify-core-deployment.git`
|
||||
- Backend repository declared by its `origin`: `https://git.amiirkhl.ir/Qlockify/qlockify-backend-deployment.git`
|
||||
- Frontend repository declared by its `origin`: `https://git.amiirkhl.ir/Qlockify/qlockify-frontend-deployment.git`
|
||||
|
||||
The expected directory layout is:
|
||||
Use this repo for:
|
||||
|
||||
- Docker Compose orchestration
|
||||
- Nginx
|
||||
- SSL certificate mounting
|
||||
- domain routing
|
||||
- environment layout
|
||||
- production service startup
|
||||
|
||||
Use the backend and frontend repos for application-level implementation details.
|
||||
|
||||
## What This Repo Contains
|
||||
|
||||
- `docker-compose.yml`
|
||||
- Nginx config
|
||||
- Postgres support files
|
||||
- Dockerfiles for production images
|
||||
- deployment environment samples
|
||||
- container networking and volume wiring
|
||||
|
||||
## Architecture
|
||||
|
||||
Main deployed services:
|
||||
|
||||
- `nginx`
|
||||
- `frontend`
|
||||
- `backend`
|
||||
- `celery`
|
||||
- `celery-beat`
|
||||
- `redis`
|
||||
- `db`
|
||||
|
||||
Traffic pattern:
|
||||
|
||||
- `qlockify.ir` serves the frontend
|
||||
- `api.qlockify.ir` serves the backend API, admin, docs, static, and media
|
||||
- Nginx terminates TLS and proxies requests to the frontend and backend containers
|
||||
|
||||
## Expected Repository Layout
|
||||
|
||||
Docker builds read from nested application directories inside this repository:
|
||||
|
||||
- `./backend/qlockify-backend-deployment`
|
||||
- `./frontend/qlockify-frontend-deployment`
|
||||
|
||||
Expected layout:
|
||||
|
||||
```text
|
||||
Qlockify/
|
||||
qlockify-backend/
|
||||
qlockify-frontend/
|
||||
qlockify-deployment/
|
||||
qlockify-deployment/
|
||||
backend/
|
||||
Dockerfile
|
||||
.env.sample
|
||||
qlockify-backend-deployment/
|
||||
frontend/
|
||||
Dockerfile
|
||||
.env.sample
|
||||
qlockify-frontend-deployment/
|
||||
nginx/
|
||||
postgres/
|
||||
docker-compose.yml
|
||||
```
|
||||
|
||||
## Deployment flow
|
||||
## Deployment Flow
|
||||
|
||||
1. Configure deployment env files:
|
||||
- `./.env`
|
||||
- `./backend/.env`
|
||||
- `./frontend/.env`
|
||||
2. From `qlockify-deployment`, build and start the stack:
|
||||
### 1. Place application source
|
||||
|
||||
Put the app repos into:
|
||||
|
||||
- `./backend/qlockify-backend-deployment`
|
||||
- `./frontend/qlockify-frontend-deployment`
|
||||
|
||||
### 2. Configure env files
|
||||
|
||||
Create and fill:
|
||||
|
||||
- `./.env`
|
||||
- `./backend/qlockify-backend-deployment/.env`
|
||||
- `./frontend/qlockify-frontend-deployment/.env`
|
||||
|
||||
### 3. Build and run
|
||||
|
||||
```powershell
|
||||
docker compose up --build
|
||||
docker compose up -d --build
|
||||
```
|
||||
|
||||
The backend container runs database migrations and `collectstatic` on startup, then serves Django with Gunicorn using `config.wsgi:application`.
|
||||
The backend container runs:
|
||||
|
||||
- database migrations
|
||||
- `collectstatic`
|
||||
- Gunicorn startup
|
||||
|
||||
## Domain and Routing
|
||||
|
||||
Configured domains:
|
||||
|
||||
- `qlockify.ir`
|
||||
- `www.qlockify.ir`
|
||||
- `api.qlockify.ir`
|
||||
|
||||
Behavior:
|
||||
|
||||
- `www.qlockify.ir` redirects to `qlockify.ir`
|
||||
- `http` redirects to `https`
|
||||
- frontend is served from `qlockify.ir`
|
||||
- backend traffic is served from `api.qlockify.ir`
|
||||
|
||||
Before production startup:
|
||||
|
||||
1. Point DNS records for `qlockify.ir`, `www.qlockify.ir`, and `api.qlockify.ir` to the server.
|
||||
2. Make sure `80` and `443` are open on the server firewall.
|
||||
3. Make sure the TLS certificate covers all required names.
|
||||
|
||||
## SSL Certificates
|
||||
|
||||
Place certificate files here:
|
||||
|
||||
```text
|
||||
./nginx/certs/fullchain.pem
|
||||
./nginx/certs/privkey.pem
|
||||
```
|
||||
|
||||
The repository intentionally keeps only:
|
||||
|
||||
- `./nginx/certs/.gitkeep`
|
||||
|
||||
Real certificate files are ignored by git.
|
||||
|
||||
## Required Backend Environment
|
||||
|
||||
Set these in:
|
||||
|
||||
```text
|
||||
./backend/qlockify-backend-deployment/.env
|
||||
```
|
||||
|
||||
Core production values:
|
||||
|
||||
- `DJANGO_ALLOWED_HOSTS=api.qlockify.ir,qlockify.ir,www.qlockify.ir`
|
||||
- `CORS_ALLOWED_ORIGINS=https://qlockify.ir,https://www.qlockify.ir`
|
||||
- `CSRF_TRUSTED_ORIGINS=https://api.qlockify.ir,https://qlockify.ir,https://www.qlockify.ir`
|
||||
- `BASE_URL=https://api.qlockify.ir`
|
||||
- `POSTGRES_HOST=db`
|
||||
- `REDIS_HOST=redis`
|
||||
- `REDIS_URL=redis://redis:6379/0`
|
||||
- `CELERY_BROKER_URL=redis://redis:6379/0`
|
||||
- `CELERY_RESULT_BACKEND=redis://redis:6379/1`
|
||||
|
||||
Google OAuth values:
|
||||
|
||||
- `GOOGLE_OAUTH_CLIENT_ID=...`
|
||||
- `GOOGLE_OAUTH_CLIENT_SECRET=...`
|
||||
- `GOOGLE_OAUTH_REDIRECT_URI=https://api.qlockify.ir/api/users/oauth/google/callback/`
|
||||
- `GOOGLE_OAUTH_FRONTEND_CALLBACK_URL=https://qlockify.ir/auth/google/callback`
|
||||
|
||||
## Required Frontend Environment
|
||||
|
||||
Set this in:
|
||||
|
||||
```text
|
||||
./frontend/qlockify-frontend-deployment/.env
|
||||
```
|
||||
|
||||
```text
|
||||
VITE_API_BASE_URL=https://api.qlockify.ir/api
|
||||
```
|
||||
|
||||
## Background Workers
|
||||
|
||||
This stack includes:
|
||||
|
||||
- `celery` for async jobs
|
||||
- `celery-beat` for scheduled jobs
|
||||
|
||||
If background scheduling stops working, inspect:
|
||||
|
||||
```powershell
|
||||
docker compose logs -f celery
|
||||
docker compose logs -f celery-beat
|
||||
```
|
||||
|
||||
## Notifications and SSE
|
||||
|
||||
Notifications use Server-Sent Events at `/api/notifications/stream/`.
|
||||
|
||||
Current behavior:
|
||||
|
||||
- Nginx disables buffering for the SSE endpoint
|
||||
- Gunicorn is tuned to tolerate connected streams for current traffic
|
||||
- if concurrency grows materially, move SSE to async workers or a dedicated ASGI service
|
||||
|
||||
## Useful Operations
|
||||
|
||||
Build/rebuild:
|
||||
|
||||
```powershell
|
||||
docker compose up -d --build
|
||||
```
|
||||
|
||||
Restart a subset:
|
||||
|
||||
```powershell
|
||||
docker compose up -d --build nginx backend frontend
|
||||
```
|
||||
|
||||
Inspect running services:
|
||||
|
||||
```powershell
|
||||
docker compose ps
|
||||
```
|
||||
|
||||
Follow logs:
|
||||
|
||||
```powershell
|
||||
docker compose logs -f nginx
|
||||
docker compose logs -f backend
|
||||
docker compose logs -f celery
|
||||
docker compose logs -f celery-beat
|
||||
```
|
||||
|
||||
Stop everything:
|
||||
|
||||
```powershell
|
||||
docker compose down
|
||||
```
|
||||
|
||||
## Scope Boundary
|
||||
|
||||
This repo should document:
|
||||
|
||||
- infrastructure
|
||||
- runtime topology
|
||||
- domains
|
||||
- Nginx
|
||||
- Docker Compose
|
||||
- SSL
|
||||
- operational startup and troubleshooting
|
||||
|
||||
It should not duplicate the application-specific implementation details already documented in the backend and frontend repositories.
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
ENVIRONMENT=development
|
||||
DEBUG=True
|
||||
|
||||
# Django Core
|
||||
DJANGO_SETTINGS_MODULE=config.settings
|
||||
DJANGO_SECRET_KEY=
|
||||
DJANGO_ALLOWED_HOSTS=
|
||||
# Django Core
|
||||
DJANGO_SETTINGS_MODULE=config.settings
|
||||
DJANGO_SECRET_KEY=
|
||||
DJANGO_ALLOWED_HOSTS=api.qlockify.ir,qlockify.ir,www.qlockify.ir
|
||||
|
||||
# Database
|
||||
POSTGRES_DB=app_db
|
||||
@@ -14,9 +14,9 @@ POSTGRES_PASSWORD=app_password
|
||||
POSTGRES_HOST=db
|
||||
POSTGRES_PORT=5432
|
||||
|
||||
# CORS / CSRF
|
||||
CORS_ALLOWED_ORIGINS=https://app.example.com
|
||||
CSRF_TRUSTED_ORIGINS=https://app.example.com
|
||||
# CORS / CSRF
|
||||
CORS_ALLOWED_ORIGINS=https://qlockify.ir,https://www.qlockify.ir
|
||||
CSRF_TRUSTED_ORIGINS=https://api.qlockify.ir,https://qlockify.ir,https://www.qlockify.ir
|
||||
|
||||
# JWT
|
||||
ACCESS_TOKEN_LIFETIME=5
|
||||
@@ -40,5 +40,5 @@ CELERY_RESULT_BACKEND=redis://redis:6379/0
|
||||
LANGUAGE_CODE=en-us
|
||||
TIME_ZONE=Asia/Tehran
|
||||
|
||||
SMS_APIKEY=
|
||||
BASE_URL=
|
||||
SMS_APIKEY=
|
||||
BASE_URL=https://api.qlockify.ir
|
||||
|
||||
@@ -1,25 +1,34 @@
|
||||
FROM python:3.14-slim
|
||||
FROM python:3.14
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
ENV PYTHONDONTWRITEBYTECODE=1
|
||||
ENV PYTHONUNBUFFERED=1
|
||||
ENV PIP_INDEX_URL=https://package-mirror.liara.ir/repository/pypi/simple
|
||||
|
||||
# Adapted Runflare mirror for Debian-based official Python image
|
||||
RUN . /etc/os-release && \
|
||||
echo "deb http://mirror-linux.runflare.com/debian $VERSION_CODENAME main" > /etc/apt/sources.list && \
|
||||
echo "deb http://mirror-linux.runflare.com/debian $VERSION_CODENAME-updates main" >> /etc/apt/sources.list && \
|
||||
echo "deb http://mirror-linux.runflare.com/debian-security $VERSION_CODENAME-security main" >> /etc/apt/sources.list
|
||||
# ---- APT Iran-safe configuration ----
|
||||
RUN rm -f /etc/apt/sources.list.d/debian.sources && \
|
||||
printf '%s\n' \
|
||||
'deb http://mirror.arvancloud.ir/debian trixie main contrib non-free non-free-firmware' \
|
||||
'deb http://mirror.arvancloud.ir/debian trixie-updates main contrib non-free non-free-firmware' \
|
||||
'deb http://mirror.arvancloud.ir/debian-security trixie-security main contrib non-free non-free-firmware' \
|
||||
> /etc/apt/sources.list && \
|
||||
echo 'Acquire::Check-Valid-Until "false";' > /etc/apt/apt.conf.d/99no-check-valid
|
||||
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y gcc libpq-dev \
|
||||
&& apt-get install -y --no-install-recommends \
|
||||
gcc \
|
||||
libpq-dev \
|
||||
rustc \
|
||||
cargo \
|
||||
pkg-config \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
COPY qlockify-backend/requirements/ /app/requirements/
|
||||
RUN pip install --no-cache-dir -r requirements/base.txt \
|
||||
&& pip install --no-cache-dir -r requirements/prod.txt
|
||||
|
||||
COPY qlockify-backend/ .
|
||||
|
||||
CMD ["gunicorn", "config.wsgi:application", "--bind", "0.0.0.0:8000"]
|
||||
COPY requirements/ /app/requirements/
|
||||
|
||||
RUN pip install --no-cache-dir --upgrade pip setuptools wheel \
|
||||
&& pip install --no-cache-dir -r requirements/base.txt \
|
||||
&& pip install --no-cache-dir -r requirements/prod.txt
|
||||
|
||||
COPY . .
|
||||
|
||||
CMD ["gunicorn", "config.wsgi:application", "--bind", "0.0.0.0:8000"]
|
||||
@@ -1,15 +1,13 @@
|
||||
services:
|
||||
db:
|
||||
services:
|
||||
db:
|
||||
image: postgres:18-alpine
|
||||
restart: always
|
||||
env_file:
|
||||
- .env
|
||||
- ./backend/qlockify-backend-deployment/.env
|
||||
volumes:
|
||||
- postgres_data:/var/lib/postgresql/data
|
||||
- postgres_data:/var/lib/postgresql
|
||||
- ./postgres/init.sql:/docker-entrypoint-initdb.d/init.sql
|
||||
- ./postgres/custom-postgresql.conf:/etc/postgresql/postgresql.conf:ro
|
||||
- ./postgres/pg_hba.conf:/var/lib/postgresql/data/pg_hba.conf:ro
|
||||
command: postgres -c config_file=/etc/postgresql/postgresql.conf
|
||||
command: postgres
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}"]
|
||||
interval: 10s
|
||||
@@ -25,21 +23,27 @@ services:
|
||||
- "127.0.0.1:6379:6379"
|
||||
|
||||
backend:
|
||||
build:
|
||||
context: ..
|
||||
dockerfile: qlockify-deployment/backend/Dockerfile
|
||||
build:
|
||||
context: ./backend/qlockify-backend-deployment
|
||||
dockerfile: ../Dockerfile
|
||||
restart: always
|
||||
env_file:
|
||||
- ./backend/.env
|
||||
env_file:
|
||||
- ./backend/qlockify-backend-deployment/.env
|
||||
volumes:
|
||||
- static_data:/app/staticfiles
|
||||
- media_data:/app/mediafiles
|
||||
- static_data:/app/static
|
||||
- media_data:/app/media
|
||||
command: >
|
||||
sh -c "python manage.py migrate &&
|
||||
python manage.py collectstatic --noinput &&
|
||||
gunicorn config.wsgi:application --bind 0.0.0.0:8000"
|
||||
expose:
|
||||
- "8000"
|
||||
gunicorn config.wsgi:application
|
||||
--bind 0.0.0.0:8000
|
||||
--worker-class gthread
|
||||
--workers 2
|
||||
--threads 8
|
||||
--timeout 120
|
||||
--keep-alive 75"
|
||||
expose:
|
||||
- "8000"
|
||||
depends_on:
|
||||
db:
|
||||
condition: service_healthy
|
||||
@@ -48,43 +52,62 @@ services:
|
||||
|
||||
celery:
|
||||
build:
|
||||
context: ..
|
||||
dockerfile: qlockify-deployment/backend/Dockerfile
|
||||
context: ./backend/qlockify-backend-deployment
|
||||
dockerfile: ../Dockerfile
|
||||
restart: always
|
||||
env_file:
|
||||
- ./backend/.env
|
||||
volumes:
|
||||
- media_data:/app/mediafiles
|
||||
command: celery -A config worker -l INFO
|
||||
env_file:
|
||||
- ./backend/qlockify-backend-deployment/.env
|
||||
volumes:
|
||||
- media_data:/app/media
|
||||
command: celery -A config worker -l INFO
|
||||
depends_on:
|
||||
db:
|
||||
condition: service_healthy
|
||||
redis:
|
||||
condition: service_started
|
||||
backend:
|
||||
condition: service_started
|
||||
|
||||
redis:
|
||||
condition: service_started
|
||||
backend:
|
||||
condition: service_started
|
||||
|
||||
celery-beat:
|
||||
build:
|
||||
context: ./backend/qlockify-backend-deployment
|
||||
dockerfile: ../Dockerfile
|
||||
restart: always
|
||||
env_file:
|
||||
- ./backend/qlockify-backend-deployment/.env
|
||||
volumes:
|
||||
- celery_beat_data:/app/run
|
||||
command: celery -A config beat -l INFO --schedule /app/run/celerybeat-schedule
|
||||
depends_on:
|
||||
db:
|
||||
condition: service_healthy
|
||||
redis:
|
||||
condition: service_started
|
||||
backend:
|
||||
condition: service_started
|
||||
|
||||
frontend:
|
||||
build:
|
||||
context: ..
|
||||
dockerfile: qlockify-deployment/frontend/Dockerfile
|
||||
context: ./frontend/qlockify-frontend-deployment
|
||||
dockerfile: ../Dockerfile
|
||||
restart: always
|
||||
env_file:
|
||||
- ./frontend/.env
|
||||
- ./frontend/qlockify-frontend-deployment/.env
|
||||
expose:
|
||||
- "80"
|
||||
|
||||
nginx:
|
||||
image: nginx:alpine
|
||||
restart: always
|
||||
ports:
|
||||
- "80:80"
|
||||
# - "443:443" # Uncomment when adding SSL
|
||||
volumes:
|
||||
- ./nginx/nginx.conf:/etc/nginx/conf.d/default.conf:ro
|
||||
- ./nginx/.htpasswd:/etc/nginx/.htpasswd:ro
|
||||
- static_data:/usr/share/nginx/html/staticfiles:ro
|
||||
- media_data:/usr/share/nginx/html/mediafiles:ro
|
||||
nginx:
|
||||
image: nginx:alpine
|
||||
restart: always
|
||||
ports:
|
||||
- "80:80"
|
||||
- "443:443"
|
||||
volumes:
|
||||
- ./nginx/nginx.conf:/etc/nginx/conf.d/default.conf:ro
|
||||
- ./nginx/certs:/etc/nginx/certs:ro
|
||||
- ./nginx/.htpasswd:/etc/nginx/.htpasswd:ro
|
||||
- static_data:/usr/share/nginx/html/static:ro
|
||||
- media_data:/usr/share/nginx/html/media:ro
|
||||
depends_on:
|
||||
- backend
|
||||
- frontend
|
||||
@@ -93,3 +116,4 @@ volumes:
|
||||
postgres_data:
|
||||
static_data:
|
||||
media_data:
|
||||
celery_beat_data:
|
||||
|
||||
@@ -1 +1 @@
|
||||
VITE_API_BASE_URL=http://localhost/api
|
||||
VITE_API_BASE_URL=https://api.qlockify.ir
|
||||
|
||||
@@ -1,18 +1,35 @@
|
||||
FROM node:20-alpine AS builder
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
RUN npm config set registry https://package-mirror.liara.ir/repository/npm/ --global
|
||||
|
||||
COPY qlockify-frontend/package*.json ./
|
||||
FROM node:20-alpine AS builder
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
RUN npm config set registry https://package-mirror.liara.ir/repository/npm/ --global
|
||||
|
||||
COPY package*.json ./
|
||||
RUN npm install
|
||||
|
||||
COPY qlockify-frontend/ .
|
||||
COPY . .
|
||||
RUN npm run build
|
||||
|
||||
FROM nginx:alpine
|
||||
|
||||
COPY --from=builder /app/dist /usr/share/nginx/html
|
||||
# Internal Nginx configuration (Root Nginx acts as reverse proxy to this)
|
||||
EXPOSE 80
|
||||
CMD ["nginx", "-g", "daemon off;"]
|
||||
|
||||
FROM nginx:alpine
|
||||
|
||||
COPY --from=builder /app/dist /usr/share/nginx/html
|
||||
|
||||
RUN cat <<'EOF' > /etc/nginx/conf.d/default.conf
|
||||
server {
|
||||
listen 80;
|
||||
server_name _;
|
||||
root /usr/share/nginx/html;
|
||||
index index.html;
|
||||
location /assets/ {
|
||||
try_files $uri =404;
|
||||
access_log off;
|
||||
expires 30d;
|
||||
}
|
||||
location / {
|
||||
try_files $uri $uri/ /index.html;
|
||||
}
|
||||
}
|
||||
EOF
|
||||
|
||||
EXPOSE 80
|
||||
CMD ["nginx", "-g", "daemon off;"]
|
||||
|
||||
@@ -1 +1 @@
|
||||
admin:$2y$05$gSZ4s3BN8TsEc.pS/vaZi.v/AMrIozncWtFDGkNOglJlv59f7jc7i
|
||||
Admin:$2y$10$YQpMsUAwPos59XKbWQRiSOxBJI4WmMbmTJBVy2ZRz/42FG.dj4W8K
|
||||
|
||||
1
nginx/certs/.gitkeep
Normal file
1
nginx/certs/.gitkeep
Normal file
@@ -0,0 +1 @@
|
||||
|
||||
205
nginx/nginx.conf
205
nginx/nginx.conf
@@ -1,55 +1,150 @@
|
||||
server {
|
||||
listen 80;
|
||||
server_name localhost;
|
||||
|
||||
client_max_body_size 100M;
|
||||
sendfile on;
|
||||
|
||||
# Static and Media files
|
||||
location /static/ {
|
||||
alias /usr/share/nginx/html/staticfiles/;
|
||||
expires 30d;
|
||||
access_log off;
|
||||
}
|
||||
|
||||
location /media/ {
|
||||
alias /usr/share/nginx/html/mediafiles/;
|
||||
expires 30d;
|
||||
access_log off;
|
||||
}
|
||||
|
||||
# Protect API Documentation with Basic Auth (from your old project)
|
||||
location ~ ^/(docs|redoc|openapi.json|api/docs|api/redoc|api/openapi.json|api/v1/docs) {
|
||||
auth_basic "Restricted API Documentation";
|
||||
auth_basic_user_file /etc/nginx/.htpasswd;
|
||||
|
||||
proxy_pass http://backend:8000;
|
||||
proxy_set_header Host $host;
|
||||
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 $scheme;
|
||||
}
|
||||
|
||||
# Standard API Proxy
|
||||
location /api/ {
|
||||
proxy_pass http://backend:8000;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
}
|
||||
|
||||
# Admin Panel Proxy
|
||||
location /admin/ {
|
||||
proxy_pass http://backend:8000;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
}
|
||||
|
||||
# Frontend Proxy
|
||||
location / {
|
||||
proxy_pass http://frontend:80;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
}
|
||||
}
|
||||
server {
|
||||
listen 80;
|
||||
server_name qlockify.ir www.qlockify.ir;
|
||||
|
||||
return 301 https://qlockify.ir$request_uri;
|
||||
}
|
||||
|
||||
server {
|
||||
listen 80;
|
||||
server_name api.qlockify.ir;
|
||||
|
||||
return 301 https://api.qlockify.ir$request_uri;
|
||||
}
|
||||
|
||||
server {
|
||||
listen 443 ssl;
|
||||
http2 on;
|
||||
server_name www.qlockify.ir;
|
||||
|
||||
ssl_certificate /etc/nginx/certs/fullchain.pem;
|
||||
ssl_certificate_key /etc/nginx/certs/privkey.pem;
|
||||
ssl_protocols TLSv1.2 TLSv1.3;
|
||||
ssl_prefer_server_ciphers on;
|
||||
ssl_session_timeout 1d;
|
||||
ssl_session_cache shared:SSL:10m;
|
||||
|
||||
return 301 https://qlockify.ir$request_uri;
|
||||
}
|
||||
|
||||
server {
|
||||
listen 443 ssl;
|
||||
http2 on;
|
||||
server_name qlockify.ir;
|
||||
|
||||
ssl_certificate /etc/nginx/certs/fullchain.pem;
|
||||
ssl_certificate_key /etc/nginx/certs/privkey.pem;
|
||||
ssl_protocols TLSv1.2 TLSv1.3;
|
||||
ssl_prefer_server_ciphers on;
|
||||
ssl_session_timeout 1d;
|
||||
ssl_session_cache shared:SSL:10m;
|
||||
|
||||
client_max_body_size 100M;
|
||||
sendfile on;
|
||||
|
||||
location /api/ {
|
||||
return 301 https://api.qlockify.ir$request_uri;
|
||||
}
|
||||
|
||||
location /admin/ {
|
||||
return 301 https://api.qlockify.ir$request_uri;
|
||||
}
|
||||
|
||||
location /docs {
|
||||
return 301 https://api.qlockify.ir$request_uri;
|
||||
}
|
||||
|
||||
location /redoc {
|
||||
return 301 https://api.qlockify.ir$request_uri;
|
||||
}
|
||||
|
||||
location /openapi.json {
|
||||
return 301 https://api.qlockify.ir$request_uri;
|
||||
}
|
||||
|
||||
location /static/ {
|
||||
return 301 https://api.qlockify.ir$request_uri;
|
||||
}
|
||||
|
||||
location /media/ {
|
||||
return 301 https://api.qlockify.ir$request_uri;
|
||||
}
|
||||
|
||||
location / {
|
||||
proxy_pass http://frontend:80;
|
||||
proxy_set_header Host $host;
|
||||
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 $scheme;
|
||||
}
|
||||
}
|
||||
|
||||
server {
|
||||
listen 443 ssl;
|
||||
http2 on;
|
||||
server_name api.qlockify.ir;
|
||||
|
||||
ssl_certificate /etc/nginx/certs/fullchain.pem;
|
||||
ssl_certificate_key /etc/nginx/certs/privkey.pem;
|
||||
ssl_protocols TLSv1.2 TLSv1.3;
|
||||
ssl_prefer_server_ciphers on;
|
||||
ssl_session_timeout 1d;
|
||||
ssl_session_cache shared:SSL:10m;
|
||||
|
||||
client_max_body_size 100M;
|
||||
sendfile on;
|
||||
|
||||
location /static/ {
|
||||
alias /usr/share/nginx/html/static/;
|
||||
expires 30d;
|
||||
access_log off;
|
||||
}
|
||||
|
||||
location /media/ {
|
||||
alias /usr/share/nginx/html/media/;
|
||||
expires 30d;
|
||||
access_log off;
|
||||
}
|
||||
|
||||
location ~ ^/(docs|redoc|openapi.json|api/docs|api/redoc|api/openapi.json|api/v1/docs) {
|
||||
auth_basic "Restricted API Documentation";
|
||||
auth_basic_user_file /etc/nginx/.htpasswd;
|
||||
|
||||
proxy_pass http://backend:8000;
|
||||
proxy_set_header Host $host;
|
||||
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 $scheme;
|
||||
}
|
||||
|
||||
location /api/notifications/stream/ {
|
||||
proxy_pass http://backend:8000;
|
||||
proxy_http_version 1.1;
|
||||
proxy_buffering off;
|
||||
proxy_cache off;
|
||||
proxy_read_timeout 3600s;
|
||||
proxy_send_timeout 3600s;
|
||||
proxy_set_header Connection "";
|
||||
proxy_set_header Host $host;
|
||||
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 $scheme;
|
||||
add_header X-Accel-Buffering no;
|
||||
}
|
||||
|
||||
location /api/ {
|
||||
proxy_pass http://backend:8000;
|
||||
proxy_set_header Host $host;
|
||||
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 $scheme;
|
||||
}
|
||||
|
||||
location /admin/ {
|
||||
proxy_pass http://backend:8000;
|
||||
proxy_set_header Host $host;
|
||||
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 $scheme;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
# TYPE DATABASE USER ADDRESS METHOD
|
||||
local all all scram-sha-256
|
||||
host all all 127.0.0.1/32 scram-sha-256
|
||||
|
||||
# Allow Docker containers to connect (Standard Docker bridge subnets)
|
||||
host all all 172.16.0.0/12 scram-sha-256
|
||||
host all all 192.168.0.0/16 scram-sha-256
|
||||
|
||||
# Reject everything else
|
||||
host all all 0.0.0.0/0 reject
|
||||
host all all ::/0 reject
|
||||
Reference in New Issue
Block a user