10 KiB
Qlockify Deployment
Main deployment and operations repository for Qlockify.
This repo is the entrypoint for running the full product stack in production.
Related Repositories
- 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
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:
nginxfrontendbackendcelerycelery-beatredisdb
Traffic pattern:
qlockify.irserves the frontend- backend traffic is served from
qlockify.irunder/apiand/admin - 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:
qlockify-deployment/
backend/
Dockerfile
.env.sample
qlockify-backend-deployment/
frontend/
Dockerfile
.env.sample
qlockify-frontend-deployment/
nginx/
postgres/
docker-compose.yml
Deployment Flow
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
docker compose up -d --build
The backend container runs:
- database migrations
collectstatic- Gunicorn startup
Domain and Routing
Configured domains:
qlockify.irwww.qlockify.ir
Behavior:
www.qlockify.irredirects toqlockify.irhttpredirects tohttps- frontend is served from
qlockify.ir - backend traffic is proxied from
qlockify.ir/apiandqlockify.ir/admin
Before production startup:
- Point DNS records for
qlockify.irandwww.qlockify.irto the server. - Make sure
80and443are open on the server firewall. - Make sure the TLS certificate covers all required names.
SSL Certificates
Place certificate files here:
./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:
./backend/qlockify-backend-deployment/.env
Core production values:
DJANGO_ALLOWED_HOSTS=qlockify.ir,www.qlockify.irCORS_ALLOWED_ORIGINS=https://qlockify.ir,https://www.qlockify.irCSRF_TRUSTED_ORIGINS=https://qlockify.ir,https://www.qlockify.irBASE_URL=https://qlockify.irPOSTGRES_HOST=dbREDIS_HOST=redisREDIS_URL=redis://redis:6379/0CELERY_BROKER_URL=redis://redis:6379/0CELERY_RESULT_BACKEND=redis://redis:6379/1
Google OAuth values:
GOOGLE_OAUTH_CLIENT_ID=...GOOGLE_OAUTH_CLIENT_SECRET=...GOOGLE_OAUTH_REDIRECT_URI=https://qlockify.ir/api/users/oauth/google/callback/GOOGLE_OAUTH_FRONTEND_CALLBACK_URL=https://qlockify.ir/auth/google/callback
Required Frontend Environment
Set this in:
./frontend/qlockify-frontend-deployment/.env
VITE_API_BASE_URL=/api
Background Workers
This stack includes:
celeryfor async jobscelery-beatfor scheduled jobs
If background scheduling stops working, inspect:
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:
docker compose up -d --build
Restart a subset:
docker compose up -d --build nginx backend frontend
Inspect running services:
docker compose ps
Follow logs:
docker compose logs -f nginx
docker compose logs -f backend
docker compose logs -f celery
docker compose logs -f celery-beat
Stop everything:
docker compose down
Backup the deployed data:
chmod +x ./scripts/backup.sh
./scripts/backup.sh
By default, backup archives are written to ./backups/. Each archive contains:
- PostgreSQL data from the
dbservice - media files from the Docker media volume
.envfiles from the deployment, backend, and frontend projects
Restore a backup archive on another machine:
chmod +x ./scripts/restore.sh
./scripts/restore.sh ./backups/qlockify-backup-YYYYMMDD-HHMMSS.tar.gz
docker compose up -d --build
Restore is destructive for the database by default. To restore only part of an archive, use:
RESTORE_SKIP_DB=1 ./scripts/restore.sh ./backups/qlockify-backup-YYYYMMDD-HHMMSS.tar.gz
RESTORE_SKIP_MEDIA=1 ./scripts/restore.sh ./backups/qlockify-backup-YYYYMMDD-HHMMSS.tar.gz
RESTORE_SKIP_ENV=1 ./scripts/restore.sh ./backups/qlockify-backup-YYYYMMDD-HHMMSS.tar.gz
CI/CD with Gitea Actions
This repository now ships with a Gitea Actions deployment workflow in:
.gitea/workflows/deploy.yml
The backend and frontend repositories each ship with their own workflow files:
- backend:
.gitea/workflows/backend.yml - frontend:
.gitea/workflows/frontend.yml
Deployment behavior:
- backend repo push to
main: runs backend CI, then updates the backend checkout on the server and rebuildsbackend,celery, andcelery-beat - frontend repo push to
main: runs frontend lint/build, then updates the frontend checkout on the server and rebuildsfrontend - deployment repo push to
main: validates deployment files, then updates the deployment checkout on the server and rebuildsnginxplus the app services
The remote deploy entrypoint is:
./scripts/deploy.sh
One-Time Server Bootstrap
Before Actions can deploy automatically, make sure the server is prepared once.
- Clone all three repositories on the server into the expected layout:
~/qlockify-deployment
~/qlockify-deployment/backend/qlockify-backend-deployment
~/qlockify-deployment/frontend/qlockify-frontend-deployment
- Make sure the server can
git fetchall three repositories non-interactively.
Recommended approach:
- add a deploy SSH key on the server
- add the public key to Gitea as a deploy key or a machine-user SSH key
- switch the server-side git remotes to SSH URLs
-
Pull the latest deployment repo once so the server has
scripts/deploy.sh. -
Make the deploy script executable:
chmod +x ~/qlockify-deployment/scripts/deploy.sh
- Make sure the deploy user can run Docker Compose on the server.
Gitea Runner Setup
Gitea Actions requires a trusted runner. Gitea's official docs describe the runner and label model here:
- Actions overview:
https://docs.gitea.com/usage/actions/overview - Act Runner:
https://docs.gitea.com/usage/actions/act-runner
Recommended label setup for this project:
qlockify-python:docker://python:3.14-bookworm
qlockify-node:docker://node:22-bookworm
qlockify-deploy:docker://ubuntu:24.04
Example non-interactive runner registration:
./act_runner register \
--no-interactive \
--instance https://git.amiirkhl.ir \
--token <runner_registration_token> \
--name qlockify-runner \
--labels "qlockify-python:docker://python:3.14-bookworm,qlockify-node:docker://node:22-bookworm,qlockify-deploy:docker://ubuntu:24.04"
Then start the runner daemon:
./act_runner daemon
Gitea Secrets
Create these Actions secrets either at the Qlockify organization level or per repository.
SSH_PRIVATE_KEY- private key used by the workflow to SSH into the deployment server
SSH_KNOWN_HOSTS- output of:
ssh-keyscan -H <your-server-hostname-or-ip>
Do not create GITEA_TOKEN manually. Gitea provides a built-in job token and exposes it as ${{ secrets.GITEA_TOKEN }}. See:
https://docs.gitea.com/usage/actions/token-permissions
Gitea Variables
Create these Actions variables in the Gitea UI:
DEPLOY_HOSTDEPLOY_PORTDEPLOY_USERDEPLOY_PATHDEPLOY_BRANCHBACKEND_BRANCHFRONTEND_BRANCH
Suggested values for your current server layout:
DEPLOY_HOST=h9arjloaye
DEPLOY_PORT=22
DEPLOY_USER=ubuntu
DEPLOY_PATH=/home/ubuntu/qlockify-deployment
DEPLOY_BRANCH=main
BACKEND_BRANCH=main
FRONTEND_BRANCH=main
Gitea variables are available in workflows through ${{ vars.NAME }}. Gitea documents that here:
https://docs.gitea.com/usage/actions/actions-variables
Recommended UI Setup
If all three repositories live under the same Qlockify organization, the cleanest setup is:
- Add one organization-level runner to
Qlockify - Add organization-level variables for the shared deploy target
- Add organization-level secrets for the SSH key and known hosts
This keeps the three repositories consistent and avoids copying the same values three times.
First Deploy Check
After creating the runner, variables, and secrets:
- push the deployment repository first
- confirm the deployment workflow succeeds
- then push backend or frontend changes and confirm their repo-specific workflows deploy only the affected services
If a workflow fails on the server step, first check:
- runner logs
- repository Actions logs
docker compose logs -f backenddocker compose logs -f frontenddocker compose logs -f celerydocker compose logs -f celery-beat
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.