Skip to content

Commit 439280a

Browse files
create prod-specific docker compose and add nginx/certbot for HTTPS/TLS termination
1 parent 0e98b91 commit 439280a

10 files changed

Lines changed: 284 additions & 41 deletions

File tree

.env.template

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,26 @@
11
# === Environment ===
22
# The environment to run the application in: development, staging, or production
33
ENVIRONMENT=
4+
DOMAIN=
5+
EMAIL=
46
# ====================
57

68
# === PostgreSQL ===
9+
POSTGRES_DB=
10+
POSTGRES_USER=
11+
POSTGRES_PASSWORD=
712
DB_CONNECTION_STRING=
813
# ===============
914

1015
# === Celery ===
1116
CELERY_BROKER_URL=
1217
CELERY_RESULT_BACKEND=
13-
# =============
18+
# ===============
19+
20+
# === RabbitMQ ===
21+
RABBITMQ_DEFAULT_USER=
22+
RABBITMQ_DEFAULT_PASS=
23+
# ===============
1424

1525
# === Redis ===
1626
REDIS_URL=

Dockerfile

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,19 @@ RUN pip install --no-cache-dir poetry
1515
# Copy only requirements to cache them in docker layer
1616
COPY pyproject.toml poetry.lock* ./
1717

18+
# Add build argument with default value
19+
ARG ENVIRONMENT=development
20+
21+
# Set environment variable from build arg
22+
ENV ENVIRONMENT=${ENVIRONMENT}
23+
1824
# Project initialization
1925
RUN poetry config virtualenvs.create false \
20-
&& poetry install --only main --no-interaction --no-ansi --no-root
26+
&& if [ "$ENVIRONMENT" = "development" ]; then \
27+
poetry install --with dev --no-interaction --no-ansi --no-root; \
28+
else \
29+
poetry install --only main --no-interaction --no-ansi --no-root; \
30+
fi
2131

2232
# Copy the project
2333
COPY .env ./
@@ -30,4 +40,8 @@ ENV PYTHONPATH=/app/src:$PYTHONPATH
3040
EXPOSE 8000
3141

3242
# Command to run the application
33-
CMD ["poetry", "run", "debugpy", "--listen", "0.0.0.0:5678", "-m", "uvicorn", "--reload", "src.solesearch_api.main:app", "--host", "0.0.0.0", "--port", "8000"]
43+
CMD if [ "$ENVIRONMENT" = "development" ]; then \
44+
poetry run debugpy --listen 0.0.0.0:5678 -m uvicorn --reload src.solesearch_api.main:app --host 0.0.0.0 --port 8000; \
45+
else \
46+
poetry run uvicorn src.solesearch_api.main:app --host 0.0.0.0 --port 8000; \
47+
fi

docker-compose.prod.init.yaml

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
services:
2+
nginx:
3+
image: nginx:alpine
4+
container_name: solesearch_nginx
5+
ports:
6+
- "80:80"
7+
volumes:
8+
- ./nginx/templates-init:/etc/nginx/templates
9+
- ./nginx/certbot/etc/letsencrypt:/etc/letsencrypt
10+
- ./nginx/certbot/var/www/certbot:/var/www/certbot
11+
env_file:
12+
- ".env"
13+
14+
certbot:
15+
image: certbot/certbot:latest
16+
container_name: solesearch_certbot
17+
command: certonly --reinstall --webroot --webroot-path=/var/www/certbot --email ${EMAIL} --agree-tos --no-eff-email -d ${DOMAIN}
18+
depends_on:
19+
- nginx
20+
volumes:
21+
- ./nginx/certbot/etc/letsencrypt:/etc/letsencrypt
22+
- ./nginx/certbot/var/www/certbot:/var/www/certbot
23+
env_file:
24+
- ".env"

docker-compose.prod.yml

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
services:
2+
nginx:
3+
image: nginx:alpine
4+
container_name: solesearch_nginx
5+
ports:
6+
- "80:80"
7+
- "443:443"
8+
volumes:
9+
- ./nginx/templates:/etc/nginx/templates
10+
- ./nginx/certbot/etc/letsencrypt:/etc/letsencrypt
11+
- ./nginx/certbot/var/www/certbot:/var/www/certbot
12+
depends_on:
13+
- api
14+
networks:
15+
- solesearch_network
16+
restart: always
17+
18+
certbot:
19+
image: certbot/certbot:latest
20+
container_name: solesearch_certbot
21+
command: certonly --reinstall --webroot --webroot-path=/var/www/certbot --email ${EMAIL} --agree-tos --no-eff-email -d ${DOMAIN}
22+
volumes:
23+
- ./nginx/certbot/etc/letsencrypt:/etc/letsencrypt
24+
- ./nginx/certbot/var/www/certbot:/var/www/certbot
25+
depends_on:
26+
- nginx
27+
restart: unless-stopped
28+
env_file:
29+
- ".env"
30+
31+
api:
32+
build:
33+
context: .
34+
args:
35+
- ENVIRONMENT=production
36+
container_name: solesearch_api
37+
depends_on:
38+
- db
39+
- redis
40+
volumes:
41+
- ~/solesearch/api/data:/var/data/solesearch
42+
networks:
43+
- solesearch_network
44+
restart: always
45+
env_file:
46+
- ".env"
47+
48+
celery_worker:
49+
build:
50+
context: .
51+
args:
52+
- ENVIRONMENT=production
53+
container_name: solesearch_worker
54+
command: celery -A solesearch_api.tasks worker --loglevel=info
55+
depends_on:
56+
- api
57+
- redis
58+
- rabbitmq
59+
volumes:
60+
- ~/solesearch/api/data:/var/data/solesearch
61+
networks:
62+
- solesearch_network
63+
restart: always
64+
env_file:
65+
- ".env"
66+
67+
celery_beat:
68+
build:
69+
context: .
70+
args:
71+
- ENVIRONMENT=production
72+
container_name: solesearch_beat
73+
command: celery -A solesearch_api.tasks beat --loglevel=info
74+
depends_on:
75+
- api
76+
- redis
77+
- rabbitmq
78+
volumes:
79+
- ~/solesearch/api/data:/var/data/solesearch
80+
networks:
81+
- solesearch_network
82+
restart: always
83+
env_file:
84+
- ".env"
85+
86+
db:
87+
image: postgres:16-alpine
88+
container_name: solesearch_db
89+
env_file:
90+
- ".env"
91+
volumes:
92+
- postgres_data:/var/lib/postgresql/data
93+
ports:
94+
- "5432:5432"
95+
networks:
96+
- solesearch_network
97+
restart: always
98+
99+
redis:
100+
image: redis:alpine
101+
container_name: solesearch_redis
102+
volumes:
103+
- redis_data:/data
104+
networks:
105+
- solesearch_network
106+
restart: always
107+
108+
rabbitmq:
109+
image: rabbitmq:management-alpine
110+
container_name: solesearch_rabbitmq
111+
ports:
112+
- "15672:15672"
113+
networks:
114+
- solesearch_network
115+
restart: always
116+
env_file:
117+
- ".env"
118+
119+
volumes:
120+
postgres_data:
121+
redis_data:
122+
123+
124+
networks:
125+
solesearch_network:
126+
driver: bridge

docker-compose.yml

Lines changed: 37 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,100 +1,99 @@
11
services:
22
api:
3-
build: .
4-
container_name: sneakers_api
5-
working_dir: /app
3+
build:
4+
context: .
5+
args:
6+
- ENVIRONMENT=development
7+
container_name: solesearch_api
68
depends_on:
79
- db
810
- redis
9-
ports:
10-
- "8000:8000"
11-
- "5678:5678"
1211
volumes:
13-
- ~/data/solesearch:/var/data/solesearch
12+
- ~/solesearch/api/data:/var/data/solesearch
1413
networks:
15-
- sneakers_network
14+
- solesearch_network
1615
restart: always
1716
env_file:
1817
- ".env"
1918

2019
celery_worker:
21-
build: .
22-
container_name: sneakers_worker
23-
working_dir: /app
24-
command: ["sh", "-c", "pip install debugpy -t /tmp && python /tmp/debugpy --listen 0.0.0.0:6900 -m celery -A solesearch_api.tasks worker --loglevel=info"]
20+
build:
21+
context: .
22+
args:
23+
- ENVIRONMENT=development
24+
container_name: solesearch_worker
25+
command: celery -A solesearch_api.tasks worker --loglevel=info
2526
depends_on:
2627
- api
2728
- redis
2829
- rabbitmq
29-
ports:
30-
- "6900:6900"
3130
volumes:
32-
- ~/data/solesearch:/var/data/solesearch
31+
- ~/solesearch/api/data:/var/data/solesearch
3332
networks:
34-
- sneakers_network
33+
- solesearch_network
3534
restart: always
3635
env_file:
3736
- ".env"
3837

3938
celery_beat:
40-
build: .
41-
container_name: sneakers_beat
39+
build:
40+
context: .
41+
args:
42+
- ENVIRONMENT=development
43+
container_name: solesearch_beat
4244
command: celery -A solesearch_api.tasks beat --loglevel=info
4345
depends_on:
4446
- api
4547
- redis
4648
- rabbitmq
4749
volumes:
48-
- ~/data/solesearch:/var/data/solesearch
50+
- ~/solesearch/api/data:/var/data/solesearch
4951
networks:
50-
- sneakers_network
52+
- solesearch_network
5153
restart: always
5254
env_file:
5355
- ".env"
5456

5557
db:
5658
image: postgres:16-alpine
57-
container_name: sneakers_db
58-
environment:
59-
POSTGRES_DB: Sneakers
60-
POSTGRES_USER: solesearch
61-
POSTGRES_PASSWORD: solesearch
59+
container_name: solesearch_db
60+
env_file:
61+
- ".env"
6262
volumes:
6363
- postgres_data:/var/lib/postgresql/data
6464
ports:
6565
- "5432:5432"
6666
networks:
67-
- sneakers_network
67+
- solesearch_network
6868
restart: always
6969

7070
redis:
7171
image: redis:alpine
72-
container_name: sneakers_redis
73-
ports:
74-
- "6379:6379"
72+
container_name: solesearch_redis
7573
volumes:
7674
- redis_data:/data
75+
ports:
76+
- "6379:6379"
7777
networks:
78-
- sneakers_network
78+
- solesearch_network
7979
restart: always
8080

8181
rabbitmq:
82-
image: rabbitmq:alpine
83-
container_name: sneakers_rabbitmq
82+
image: rabbitmq:management-alpine
83+
container_name: solesearch_rabbitmq
8484
ports:
85-
- "5672:5672"
85+
- "15672:15672"
8686
networks:
87-
- sneakers_network
88-
environment:
89-
- RABBITMQ_DEFAULT_USER=solesearch
90-
- RABBITMQ_DEFAULT_PASS=solesearch
87+
- solesearch_network
9188
restart: always
89+
env_file:
90+
- ".env"
9291

9392
volumes:
9493
postgres_data:
9594
redis_data:
9695

9796

9897
networks:
99-
sneakers_network:
98+
solesearch_network:
10099
driver: bridge

install.sh

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
#!/bin/bash
2+
3+
# Create the certificate for the first time
4+
docker-compose -f ./docker-compose.prod.init.yaml up -d nginx
5+
docker-compose -f ./docker-compose.prod.init.yaml up certbot
6+
docker-compose -f ./docker-compose.prod.init.yaml down
7+
8+
# Copy the configuration files down
9+
curl -L --create-dirs -o nginx/certbot/etc/letsencrypt/options-ssl-nginx.conf https://raw.githubusercontent.com/certbot/certbot/master/certbot-nginx/certbot_nginx/_internal/tls_configs/options-ssl-nginx.conf
10+
openssl dhparam -out nginx/certbot/etc/letsencrypt/ssl-dhparams.pem 2048
11+
12+
# Start the production services
13+
docker-compose -f ./docker-compose.prod.yaml up -d
14+
15+
# Add the cron job
16+
echo "0 5 * * * $(pwd)/renew_cert.sh" | crontab -
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
server {
2+
listen [::]:80;
3+
listen 80;
4+
server_name $DOMAIN www.$DOMAIN;
5+
location ~ /.well-known/acme-challenge/ {
6+
allow all;
7+
root /var/www/certbot;
8+
}
9+
}

0 commit comments

Comments
 (0)