feat(deploy): add qlockify.ir domain and ssl config
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -4,3 +4,5 @@ backend/.pytest_cache/
|
|||||||
|
|
||||||
backend/qlockify-backend-deployment
|
backend/qlockify-backend-deployment
|
||||||
frontend/qlockify-frontend-deployment
|
frontend/qlockify-frontend-deployment
|
||||||
|
nginx/certs/*
|
||||||
|
!nginx/certs/.gitkeep
|
||||||
|
|||||||
51
README.md
51
README.md
@@ -2,7 +2,10 @@
|
|||||||
|
|
||||||
This repository is the deployment layer only.
|
This repository is the deployment layer only.
|
||||||
|
|
||||||
Docker builds read from the local `./backend` and `./frontend` directories inside this repository.
|
Docker builds now read from nested application source directories inside this repository:
|
||||||
|
- `./backend/qlockify-backend-deployment`
|
||||||
|
- `./frontend/qlockify-frontend-deployment`
|
||||||
|
|
||||||
Those directories are expected to contain the backend and frontend application source before you build for deployment.
|
Those directories are expected to contain the backend and frontend application source before you build for deployment.
|
||||||
|
|
||||||
## Local structure
|
## Local structure
|
||||||
@@ -12,7 +15,9 @@ The expected deployment layout is:
|
|||||||
```text
|
```text
|
||||||
qlockify-deployment/
|
qlockify-deployment/
|
||||||
backend/
|
backend/
|
||||||
|
qlockify-backend-deployment/
|
||||||
frontend/
|
frontend/
|
||||||
|
qlockify-frontend-deployment/
|
||||||
nginx/
|
nginx/
|
||||||
postgres/
|
postgres/
|
||||||
docker-compose.yml
|
docker-compose.yml
|
||||||
@@ -21,12 +26,12 @@ qlockify-deployment/
|
|||||||
## Deployment flow
|
## Deployment flow
|
||||||
|
|
||||||
1. Put your application source into:
|
1. Put your application source into:
|
||||||
- `./backend`
|
- `./backend/qlockify-backend-deployment`
|
||||||
- `./frontend`
|
- `./frontend/qlockify-frontend-deployment`
|
||||||
2. Configure deployment env files:
|
2. Configure deployment env files:
|
||||||
- `./.env`
|
- `./.env`
|
||||||
- `./backend/.env`
|
- `./backend/qlockify-backend-deployment/.env`
|
||||||
- `./frontend/.env`
|
- `./frontend/qlockify-frontend-deployment/.env`
|
||||||
3. From `qlockify-deployment`, build and start the stack:
|
3. From `qlockify-deployment`, build and start the stack:
|
||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
@@ -35,6 +40,42 @@ docker compose up --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 and `collectstatic` on startup, then serves Django with Gunicorn using `config.wsgi:application`.
|
||||||
|
|
||||||
|
## Domain setup
|
||||||
|
|
||||||
|
The Nginx config is prepared for:
|
||||||
|
- `qlockify.ir`
|
||||||
|
- `www.qlockify.ir`
|
||||||
|
|
||||||
|
Requests to `www.qlockify.ir` are redirected to `qlockify.ir`.
|
||||||
|
|
||||||
|
Before bringing the stack up in production:
|
||||||
|
1. Point the DNS `A` or `AAAA` records for `qlockify.ir` and `www.qlockify.ir` to your server.
|
||||||
|
2. Set the backend env values in `./backend/qlockify-backend-deployment/.env`:
|
||||||
|
- `DJANGO_ALLOWED_HOSTS=qlockify.ir,www.qlockify.ir`
|
||||||
|
- `CORS_ALLOWED_ORIGINS=https://qlockify.ir,https://www.qlockify.ir`
|
||||||
|
- `CSRF_TRUSTED_ORIGINS=https://qlockify.ir,https://www.qlockify.ir`
|
||||||
|
- `BASE_URL=https://qlockify.ir`
|
||||||
|
3. Set the frontend env value in `./frontend/qlockify-frontend-deployment/.env`:
|
||||||
|
- `VITE_API_BASE_URL=https://qlockify.ir/api`
|
||||||
|
|
||||||
|
## SSL certificates
|
||||||
|
|
||||||
|
HTTPS is configured through Nginx if you place these files in:
|
||||||
|
|
||||||
|
```text
|
||||||
|
./nginx/certs/fullchain.pem
|
||||||
|
./nginx/certs/privkey.pem
|
||||||
|
```
|
||||||
|
|
||||||
|
The repo keeps `./nginx/certs/.gitkeep` only. Actual certificate files are ignored by git.
|
||||||
|
|
||||||
|
With the current Nginx config:
|
||||||
|
- `http://qlockify.ir` redirects to `https://qlockify.ir`
|
||||||
|
- `http://www.qlockify.ir` redirects to `https://qlockify.ir`
|
||||||
|
- `https://www.qlockify.ir` redirects to `https://qlockify.ir`
|
||||||
|
|
||||||
|
Make sure port `443` is open on the server firewall before starting the stack.
|
||||||
|
|
||||||
## SSE Notifications
|
## SSE Notifications
|
||||||
|
|
||||||
Notifications now use Server-Sent Events at `/api/notifications/stream/`.
|
Notifications now use Server-Sent Events at `/api/notifications/stream/`.
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ DEBUG=True
|
|||||||
# Django Core
|
# Django Core
|
||||||
DJANGO_SETTINGS_MODULE=config.settings
|
DJANGO_SETTINGS_MODULE=config.settings
|
||||||
DJANGO_SECRET_KEY=
|
DJANGO_SECRET_KEY=
|
||||||
DJANGO_ALLOWED_HOSTS=
|
DJANGO_ALLOWED_HOSTS=qlockify.ir,www.qlockify.ir
|
||||||
|
|
||||||
# Database
|
# Database
|
||||||
POSTGRES_DB=app_db
|
POSTGRES_DB=app_db
|
||||||
@@ -15,8 +15,8 @@ POSTGRES_HOST=db
|
|||||||
POSTGRES_PORT=5432
|
POSTGRES_PORT=5432
|
||||||
|
|
||||||
# CORS / CSRF
|
# CORS / CSRF
|
||||||
CORS_ALLOWED_ORIGINS=https://app.example.com
|
CORS_ALLOWED_ORIGINS=https://qlockify.ir,https://www.qlockify.ir
|
||||||
CSRF_TRUSTED_ORIGINS=https://app.example.com
|
CSRF_TRUSTED_ORIGINS=https://qlockify.ir,https://www.qlockify.ir
|
||||||
|
|
||||||
# JWT
|
# JWT
|
||||||
ACCESS_TOKEN_LIFETIME=5
|
ACCESS_TOKEN_LIFETIME=5
|
||||||
@@ -41,4 +41,4 @@ LANGUAGE_CODE=en-us
|
|||||||
TIME_ZONE=Asia/Tehran
|
TIME_ZONE=Asia/Tehran
|
||||||
|
|
||||||
SMS_APIKEY=
|
SMS_APIKEY=
|
||||||
BASE_URL=
|
BASE_URL=https://qlockify.ir
|
||||||
|
|||||||
@@ -77,9 +77,10 @@ services:
|
|||||||
restart: always
|
restart: always
|
||||||
ports:
|
ports:
|
||||||
- "80:80"
|
- "80:80"
|
||||||
# - "443:443" # Uncomment when adding SSL
|
- "443:443"
|
||||||
volumes:
|
volumes:
|
||||||
- ./nginx/nginx.conf:/etc/nginx/conf.d/default.conf:ro
|
- ./nginx/nginx.conf:/etc/nginx/conf.d/default.conf:ro
|
||||||
|
- ./nginx/certs:/etc/nginx/certs:ro
|
||||||
- ./nginx/.htpasswd:/etc/nginx/.htpasswd:ro
|
- ./nginx/.htpasswd:/etc/nginx/.htpasswd:ro
|
||||||
- static_data:/usr/share/nginx/html/staticfiles:ro
|
- static_data:/usr/share/nginx/html/staticfiles:ro
|
||||||
- media_data:/usr/share/nginx/html/mediafiles:ro
|
- media_data:/usr/share/nginx/html/mediafiles:ro
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
VITE_API_BASE_URL=http://localhost/api
|
VITE_API_BASE_URL=https://qlockify.ir/api
|
||||||
|
|||||||
1
nginx/certs/.gitkeep
Normal file
1
nginx/certs/.gitkeep
Normal file
@@ -0,0 +1 @@
|
|||||||
|
|
||||||
@@ -1,6 +1,36 @@
|
|||||||
server {
|
server {
|
||||||
listen 80;
|
listen 80;
|
||||||
server_name localhost;
|
server_name qlockify.ir www.qlockify.ir;
|
||||||
|
|
||||||
|
return 301 https://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;
|
client_max_body_size 100M;
|
||||||
sendfile on;
|
sendfile on;
|
||||||
@@ -18,7 +48,7 @@ server {
|
|||||||
access_log off;
|
access_log off;
|
||||||
}
|
}
|
||||||
|
|
||||||
# Protect API Documentation with Basic Auth (from your old project)
|
# Protect API Documentation with Basic Auth
|
||||||
location ~ ^/(docs|redoc|openapi.json|api/docs|api/redoc|api/openapi.json|api/v1/docs) {
|
location ~ ^/(docs|redoc|openapi.json|api/docs|api/redoc|api/openapi.json|api/v1/docs) {
|
||||||
auth_basic "Restricted API Documentation";
|
auth_basic "Restricted API Documentation";
|
||||||
auth_basic_user_file /etc/nginx/.htpasswd;
|
auth_basic_user_file /etc/nginx/.htpasswd;
|
||||||
@@ -30,7 +60,6 @@ server {
|
|||||||
proxy_set_header X-Forwarded-Proto $scheme;
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
}
|
}
|
||||||
|
|
||||||
# Standard API Proxy
|
|
||||||
location /api/notifications/stream/ {
|
location /api/notifications/stream/ {
|
||||||
proxy_pass http://backend:8000;
|
proxy_pass http://backend:8000;
|
||||||
proxy_http_version 1.1;
|
proxy_http_version 1.1;
|
||||||
@@ -54,7 +83,6 @@ server {
|
|||||||
proxy_set_header X-Forwarded-Proto $scheme;
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
}
|
}
|
||||||
|
|
||||||
# Admin Panel Proxy
|
|
||||||
location /admin/ {
|
location /admin/ {
|
||||||
proxy_pass http://backend:8000;
|
proxy_pass http://backend:8000;
|
||||||
proxy_set_header Host $host;
|
proxy_set_header Host $host;
|
||||||
@@ -63,10 +91,11 @@ server {
|
|||||||
proxy_set_header X-Forwarded-Proto $scheme;
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
}
|
}
|
||||||
|
|
||||||
# Frontend Proxy
|
|
||||||
location / {
|
location / {
|
||||||
proxy_pass http://frontend:80;
|
proxy_pass http://frontend:80;
|
||||||
proxy_set_header Host $host;
|
proxy_set_header Host $host;
|
||||||
proxy_set_header X-Real-IP $remote_addr;
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user