Skip to content

Commit aa37e29

Browse files
authored
Merge pull request #215 from AAdewunmi/feat/document-deployment-steps
Feat/document deployment steps
2 parents 9085c36 + 6234c0e commit aa37e29

1 file changed

Lines changed: 96 additions & 19 deletions

File tree

docs/deployment.md

Lines changed: 96 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,16 @@
1-
# Production Deployment
1+
# ReturnHub Deployment
22

3-
This repository defaults to `config.settings.dev` when `DJANGO_SETTINGS_MODULE`
4-
is unset. Production deployment should override that explicitly in the
5-
deployment platform, not through ad hoc shell exports.
3+
## Purpose
4+
5+
This document defines the production-like deployment path for ReturnHub using
6+
Docker, Gunicorn, Nginx, and PostgreSQL. The goal is not to support every
7+
hosting platform abstraction. The goal is to make one clear operator path that
8+
can be followed locally, in staging, or in a VM-based deployment with minimal
9+
translation.
10+
11+
This repository defaults to `config.settings.dev` when
12+
`DJANGO_SETTINGS_MODULE` is unset. Production deployment should override that
13+
explicitly in the deployment platform, not through ad hoc shell exports.
614

715
## Required selection
816

@@ -14,37 +22,93 @@ DJANGO_SETTINGS_MODULE=config.settings.production
1422

1523
This is the single explicit switch that enables the production settings module.
1624

17-
## Recommended production env template
25+
## Required environment variables
1826

1927
Use [production.env.example](../production.env.example) as the deployment-facing
20-
template for production configuration.
28+
template and create a real `production.env` file for the Compose-based
29+
production stack.
30+
31+
The current production settings in this repo read `POSTGRES_*` values directly.
32+
They do not currently read `DATABASE_URL`, so `DATABASE_URL` is not part of the
33+
required env contract here.
34+
35+
For the repo's canonical Compose-based production-like stack, `POSTGRES_HOST`
36+
should be `db` so the web container connects to the Compose database service.
37+
38+
Minimum aligned example:
39+
40+
```bash
41+
DJANGO_SETTINGS_MODULE=config.settings.production
42+
DJANGO_SECRET_KEY=replace-with-a-strong-secret
43+
DJANGO_ALLOWED_HOSTS=your-domain.example.com
44+
DJANGO_CSRF_TRUSTED_ORIGINS=https://your-domain.example.com
45+
POSTGRES_DB=returnhub
46+
POSTGRES_USER=returnhub
47+
POSTGRES_PASSWORD=replace-with-a-production-password
48+
POSTGRES_HOST=db
49+
POSTGRES_PORT=5432
50+
RELEASE_VERSION=2026.03.09
51+
```
2152

22-
Key values:
53+
Local or staging production-like verification may also override security flags
54+
when HTTPS termination is not in place yet. For example:
2355

24-
- `DJANGO_SETTINGS_MODULE=config.settings.production`
25-
- `DJANGO_SECRET_KEY=<strong secret>`
26-
- `DJANGO_ALLOWED_HOSTS=<public hostnames>`
27-
- `DJANGO_CSRF_TRUSTED_ORIGINS=<https origins>`
28-
- `POSTGRES_*` database connection values
29-
- `RELEASE_VERSION=<deployment identifier>`
56+
```bash
57+
DJANGO_SECURE_SSL_REDIRECT=0
58+
DJANGO_SESSION_COOKIE_SECURE=0
59+
DJANGO_CSRF_COOKIE_SECURE=0
60+
DJANGO_SECURE_HSTS_SECONDS=0
61+
```
3062

31-
For the repo's Compose-based production stack, create a real `production.env`
32-
from that template and set `POSTGRES_HOST=db` so the web container connects to
33-
the Compose `db` service. The production Compose stack builds `Dockerfile.prod`,
34-
which installs `requirements/prod.txt` instead of the dev dependency set.
63+
The production Compose stack builds `Dockerfile.prod`, which installs
64+
`requirements/prod.txt` instead of the dev dependency set.
65+
66+
## Canonical compose path
3567

3668
```bash
3769
cp production.env.example production.env
3870
docker compose -f docker-compose.prod.yml up --build -d
3971
```
4072

73+
The canonical production-like stack is:
74+
75+
- `db`
76+
- `web`
77+
- `nginx`
78+
79+
## Operator sequence
80+
81+
Use this exact sequence to move from image build to a healthy application:
82+
83+
1. Create and review `production.env` from `production.env.example`.
84+
2. Start the stack:
85+
86+
```bash
87+
docker compose -f docker-compose.prod.yml up --build -d
88+
```
89+
90+
3. Confirm the services are running:
91+
92+
```bash
93+
docker compose -f docker-compose.prod.yml ps
94+
```
95+
96+
4. Verify the app process is using `config.settings.production`.
97+
5. Verify `/api/health/` returns a healthy readiness payload.
98+
6. Verify the landing page responds through Nginx with the expected security headers.
99+
100+
The application should be considered healthy only after the entrypoint has
101+
completed Django checks, migrations, and `collectstatic`, and after Gunicorn and
102+
Nginx are both serving requests successfully.
103+
41104
## Verification
42105

43106
After deployment, verify that the process is using the production settings
44107
module:
45108

46109
```bash
47-
python manage.py shell -c "from django.conf import settings; print(settings.SETTINGS_MODULE)"
110+
docker compose -f docker-compose.prod.yml exec web \
111+
python manage.py shell -c "from django.conf import settings; print(settings.SETTINGS_MODULE)"
48112
```
49113

50114
Expected output:
@@ -56,17 +120,30 @@ config.settings.production
56120
Verify the readiness endpoint exposes the deployed release identifier:
57121

58122
```bash
59-
curl -s https://your-domain.example.com/api/health/ | python -m json.tool
123+
curl -s http://127.0.0.1/api/health/ | python -m json.tool
60124
```
61125

62126
Expected result:
63127

64128
- response contains `"status": "ok"` when the app is healthy
65129
- response contains `"release": "<your deployed RELEASE_VERSION>"`
66130

131+
Verify the landing page headers through the reverse proxy:
132+
133+
```bash
134+
curl -I http://127.0.0.1/
135+
```
136+
137+
Expected result includes:
138+
139+
- `X-Frame-Options: DENY`
140+
- `Referrer-Policy: same-origin`
141+
- `X-Content-Type-Options: nosniff`
142+
67143
## Notes
68144

69145
- Keep `.env.example` for local development only.
146+
- Keep `production.env.example` as the template for the production-like stack.
70147
- Do not rely on one-off `export DJANGO_SETTINGS_MODULE=...` commands during deploy.
71148
- Keep production-only behavior in `config/settings/production.py`.
72149
- Keep `Dockerfile.prod` and `requirements/prod.txt` as the production image path.

0 commit comments

Comments
 (0)