initial docker setup

This commit is contained in:
2026-03-16 11:05:44 +05:30
parent 8bea06be5e
commit 3a096bbc37
8 changed files with 355 additions and 0 deletions

12
.dockerignore Normal file
View File

@@ -0,0 +1,12 @@
node_modules
dist
dist-ssr
.git
.gitignore
Dockerfile
docker-compose.yml
backend
*.log
.env
.env.*
coverage

34
Dockerfile Normal file
View File

@@ -0,0 +1,34 @@
FROM node:20-alpine AS build
WORKDIR /app
ARG VITE_FIREBASE_API_KEY
ARG VITE_FIREBASE_AUTH_DOMAIN
ARG VITE_FIREBASE_PROJECT_ID
ARG VITE_FIREBASE_STORAGE_BUCKET
ARG VITE_FIREBASE_MESSAGING_SENDER_ID
ARG VITE_FIREBASE_APP_ID
ARG VITE_API_URL=/api
ENV VITE_FIREBASE_API_KEY=${VITE_FIREBASE_API_KEY}
ENV VITE_FIREBASE_AUTH_DOMAIN=${VITE_FIREBASE_AUTH_DOMAIN}
ENV VITE_FIREBASE_PROJECT_ID=${VITE_FIREBASE_PROJECT_ID}
ENV VITE_FIREBASE_STORAGE_BUCKET=${VITE_FIREBASE_STORAGE_BUCKET}
ENV VITE_FIREBASE_MESSAGING_SENDER_ID=${VITE_FIREBASE_MESSAGING_SENDER_ID}
ENV VITE_FIREBASE_APP_ID=${VITE_FIREBASE_APP_ID}
ENV VITE_API_URL=${VITE_API_URL}
COPY package.json package-lock.json* ./
RUN npm install
COPY . .
RUN npm run build
FROM nginx:1.27-alpine AS runtime
COPY nginx/default.conf /etc/nginx/conf.d/default.conf
COPY --from=build /app/dist /usr/share/nginx/html
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

12
backend/.dockerignore Normal file
View File

@@ -0,0 +1,12 @@
__pycache__
*.pyc
*.pyo
*.pyd
.Python
.pytest_cache
.mypy_cache
.ruff_cache
.venv
venv
.env
*.log

View File

@@ -4,3 +4,7 @@ API_PORT=8001
ENVIRONMENT=development
FRONTEND_URL=http://localhost:8000
# Docker Compose values:
# MONGODB_URI=mongodb://mongo:27017
# ENVIRONMENT=production

15
backend/Dockerfile Normal file
View File

@@ -0,0 +1,15 @@
FROM python:3.12-slim
WORKDIR /app
ENV PYTHONDONTWRITEBYTECODE=1
ENV PYTHONUNBUFFERED=1
COPY requirements.txt ./
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
EXPOSE 8001
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8001"]

58
docker-compose.yml Normal file
View File

@@ -0,0 +1,58 @@
services:
frontend:
build:
context: .
dockerfile: Dockerfile
args:
VITE_FIREBASE_API_KEY: ${VITE_FIREBASE_API_KEY}
VITE_FIREBASE_AUTH_DOMAIN: ${VITE_FIREBASE_AUTH_DOMAIN}
VITE_FIREBASE_PROJECT_ID: ${VITE_FIREBASE_PROJECT_ID}
VITE_FIREBASE_STORAGE_BUCKET: ${VITE_FIREBASE_STORAGE_BUCKET}
VITE_FIREBASE_MESSAGING_SENDER_ID: ${VITE_FIREBASE_MESSAGING_SENDER_ID}
VITE_FIREBASE_APP_ID: ${VITE_FIREBASE_APP_ID}
VITE_API_URL: ${VITE_API_URL:-/api}
depends_on:
backend:
condition: service_started
ports:
- "127.0.0.1:8000:80"
restart: unless-stopped
networks:
- app_net
backend:
build:
context: ./backend
dockerfile: Dockerfile
env_file:
- ./backend/.env
expose:
- "8001"
depends_on:
mongo:
condition: service_healthy
restart: unless-stopped
networks:
- app_net
mongo:
image: mongo:6
command: ["mongod", "--bind_ip", "0.0.0.0"]
volumes:
- mongo_data:/data/db
healthcheck:
test: ["CMD", "mongosh", "--quiet", "--eval", "db.adminCommand('ping').ok"]
interval: 10s
timeout: 5s
retries: 5
start_period: 10s
restart: unless-stopped
networks:
- app_net
volumes:
mongo_data:
networks:
app_net:
driver: bridge

191
docs/DOCKER_SETUP.md Normal file
View File

@@ -0,0 +1,191 @@
# Docker Setup Guide for Grateful Journal
## Goal
This Docker setup runs the full app locally with three containers:
- Frontend (React app served by nginx)
- Backend (FastAPI)
- MongoDB
The setup is intentionally private to the local machine:
- Frontend is available only at `http://127.0.0.1:8000`
- Backend is not published to the host
- MongoDB is not published to the host
- Backend and MongoDB are reachable only from other containers in the same Docker Compose network
This means other devices on the same network cannot access the UI, backend, or database.
## Files Added for Docker
- Root `Dockerfile` for the frontend build and nginx runtime
- `backend/Dockerfile` for FastAPI
- `docker-compose.yml` for orchestration
- `nginx/default.conf` for SPA serving and API proxying
- Root `.env` for frontend build variables
- `backend/.env` for backend runtime variables
## Prerequisites
- Docker Desktop installed and running
- Docker Compose available via `docker compose`
## Environment Files
### Frontend
The root `.env` file is used during the frontend image build.
Current values:
```env
VITE_FIREBASE_API_KEY=...
VITE_FIREBASE_AUTH_DOMAIN=react-test-8cb04.firebaseapp.com
VITE_FIREBASE_PROJECT_ID=react-test-8cb04
VITE_FIREBASE_STORAGE_BUCKET=react-test-8cb04.firebasestorage.app
VITE_FIREBASE_MESSAGING_SENDER_ID=1036594341832
VITE_FIREBASE_APP_ID=1:1036594341832:web:9db6fa337e9cd2e953c2fd
VITE_API_URL=/api
```
`VITE_API_URL=/api` is important because nginx proxies `/api` requests to the backend container internally.
### Backend
The `backend/.env` file is loaded by the backend container at runtime.
Current values:
```env
MONGODB_URI=mongodb://mongo:27017
MONGODB_DB_NAME=grateful_journal
API_PORT=8001
ENVIRONMENT=production
FRONTEND_URL=http://localhost:8000
```
`MONGODB_URI=mongodb://mongo:27017` works because Docker Compose gives the MongoDB service the hostname `mongo` on the internal network.
## Network Model
### Frontend
The frontend service is published with:
```yaml
ports:
- "127.0.0.1:8000:80"
```
This binds the container to localhost only. The app is reachable from your machine, but not from another device on your LAN.
### Backend
The backend uses:
```yaml
expose:
- "8001"
```
`expose` makes port 8001 available to other containers, but not to your host machine or network.
### MongoDB
MongoDB has no `ports` section, so it is not reachable from outside Docker. Only the backend can talk to it over the Compose network.
## Start the Stack
From the project root:
```bash
docker compose up --build
```
Then open:
- Frontend: `http://127.0.0.1:8000`
The backend API and MongoDB stay internal.
## Stop the Stack
```bash
docker compose down
```
To also remove the database volume:
```bash
docker compose down -v
```
## Rebuild After Changes
If you change frontend code, backend code, or environment variables:
```bash
docker compose up --build
```
If you want a full rebuild without cache:
```bash
docker compose build --no-cache
docker compose up
```
## Data Persistence
MongoDB data is stored in the named Docker volume `mongo_data`.
That means:
- Restarting containers keeps the data
- Removing the containers keeps the data
- Running `docker compose down -v` removes the data
## API Flow
Browser requests follow this path:
1. Browser loads the frontend from nginx on `127.0.0.1:8000`
2. Frontend sends API requests to `/api`
3. nginx forwards `/api` to `http://backend:8001/api/`
4. Backend connects to MongoDB at `mongodb://mongo:27017`
This avoids exposing the backend directly to the host.
## Firebase Note
The frontend still requires the Firebase JavaScript SDK because login happens in the browser.
The backend does not currently verify Firebase ID tokens, so `firebase-admin` is not part of this Docker setup.
If backend token verification is added later, that would be a separate change.
## Troubleshooting
### Docker command not found
Install Docker Desktop and confirm this works:
```bash
docker --version
docker compose version
```
### Frontend loads but API calls fail
Check that:
- `backend/.env` contains `MONGODB_URI=mongodb://mongo:27017`
- Root `.env` contains `VITE_API_URL=/api`
- All containers are healthy with `docker compose ps`
### Want to inspect MongoDB from the host
This setup does not expose MongoDB intentionally.
If you want host access temporarily for debugging, add a port mapping to the MongoDB service, but that weakens the local-only isolation model.

29
nginx/default.conf Normal file
View File

@@ -0,0 +1,29 @@
server {
listen 80;
server_name _;
root /usr/share/nginx/html;
index index.html;
location /api/ {
proxy_pass http://backend:8001/api/;
proxy_http_version 1.1;
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 /health {
proxy_pass http://backend:8001/health;
proxy_http_version 1.1;
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 / {
try_files $uri $uri/ /index.html;
}
}