Deploying a FastAPI + React Application with Docker
Deploying a web application using FastAPI (backend) and React (frontend) with Docker is an effective way to ensure consistency across different environments. Below, you'll find a detailed guide outlining the best practices and step-by-step instructions to help you deploy your application to a server using Docker.
Table of Contents
- Prerequisites
- Project Structure
- Setting Up the FastAPI Backend
- Setting Up the React Frontend
- Creating Dockerfiles
- Docker Compose Configuration
- Environment Variables and Configuration
- Building and Running with Docker Compose
- Deploying to a Server
- Additional Best Practices
- Conclusion
Prerequisites
Before proceeding, ensure you have the following installed on your local machine:
- Docker: Install Docker
- Docker Compose: Comes bundled with Docker Desktop for Windows and macOS. For Linux, install Docker Compose.
- Git: For version control. Install Git
- Basic Knowledge: Familiarity with Python, JavaScript, FastAPI, React, and command-line interfaces.
Project Structure
Organizing your project systematically will simplify development and deployment. Here's a recommended structure:
1 |
|
Setting Up the FastAPI Backend
Initialize FastAPI Project
Navigate to the
backend
directory and create a virtual environment:1
2
3cd my-web-app/backend
python -m venv venv
source venv/bin/activate # On Windows: venv\Scripts\activateInstall Dependencies
Install FastAPI and Uvicorn:
1
pip install fastapi uvicorn
Create
main.py
1
2
3
4
5
6
7
8
9# backend/app/main.py
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
def read_root():
return {"message": "Hello from FastAPI"}Freeze Requirements
1
pip freeze > requirements.txt
Setting Up the React Frontend
Initialize React Project
Navigate to the
frontend
directory and create a new React app usingcreate-react-app
:1
2cd ../frontend
npx create-react-app .Modify
App.js
Update the default
App.js
to fetch data from FastAPI:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21// frontend/src/App.js
import React, { useEffect, useState } from 'react';
function App() {
const [message, setMessage] = useState('');
useEffect(() => {
fetch('http://localhost:8000/')
.then(response => response.json())
.then(data => setMessage(data.message));
}, []);
return (
<div className="App">
<h1>{message}</h1>
</div>
);
}
export default App;Install Dependencies
If you plan to use additional libraries, install them using
npm
oryarn
.
Creating Dockerfiles
Backend Dockerfile
Create a Dockerfile
in the backend
directory:
1 |
|
Frontend Dockerfile
Create a Dockerfile
in the frontend
directory:
1 |
|
Docker Compose Configuration
To manage both frontend and backend containers, use Docker Compose.
Create a docker-compose.yml
in the root of your project:
1 |
|
Environment Variables and Configuration
Managing environment variables is crucial for different environments (development, production).
Backend Environment Variables
Create a
.env
file in thebackend
directory:1
2
3
4# backend/.env
DATABASE_URL=sqlite:///./test.db
SECRET_KEY=your-secret-keyUpdate the backend
Dockerfile
to copy the.env
file:1
2
3# backend/Dockerfile (add the following line before CMD)
COPY .env .Frontend Configuration
React uses environment variables prefixed with
REACT_APP_
.Create a
.env
file in thefrontend
directory:1
2
3# frontend/.env
REACT_APP_API_URL=http://localhost:8000/Update API calls in React to use this variable:
1
2
3
4
5
6
7// frontend/src/App.js
useEffect(() => {
fetch(process.env.REACT_APP_API_URL)
.then(response => response.json())
.then(data => setMessage(data.message));
}, []);
Building and Running with Docker Compose
Build the Containers
From the root directory (
my-web-app/
), run:1
docker-compose build
Run the Containers
1
docker-compose up
Access the Application
- Frontend: http://localhost:3000
- Backend API: http://localhost:8000
Stopping the Application
Press
CTRL+C
in the terminal where Docker Compose is running, then:1
docker-compose down
Deploying to a Server
Once your application works locally with Docker, you can deploy it to a production server. Here's how:
Choosing a Hosting Provider
Popular options include:
- AWS EC2
- DigitalOcean Droplets
- Google Cloud Compute Engine
- Azure Virtual Machines
- Heroku (supports Docker deployments)
For this guide, we'll use DigitalOcean Droplets as an example.
Setting Up the Server
Create a Droplet
- Sign up or log in to DigitalOcean.
- Create a new Droplet with your preferred OS (e.g., Ubuntu 22.04).
- Ensure you select Docker when choosing the image or install it manually later.
Access the Server
Use SSH to connect:
1
ssh root@your_server_ip
Install Docker and Docker Compose (if not pre-installed)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16# Update packages
sudo apt-get update
# Install Docker
sudo apt-get install -y docker.io
# Start and enable Docker
sudo systemctl start docker
sudo systemctl enable docker
# Install Docker Compose
sudo curl -L "https://github.com/docker/compose/releases/download/v2.20.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
# Verify installation
docker-compose --version
Transferring Your Application
Clone Your Repository
On the server, install Git and clone your project:
1
2
3sudo apt-get install -y git
git clone https://github.com/yourusername/my-web-app.git
cd my-web-appReplace the URL with your repository's URL.
Set Up Environment Variables
Ensure
.env
files are set up correctly on the server. You might need to create them manually or use secrets management.Build and Run with Docker Compose
1
2sudo docker-compose build
sudo docker-compose up -dConfigure Firewall
Allow necessary ports (e.g., 80, 443):
1
2
3
4sudo ufw allow OpenSSH
sudo ufw allow 80
sudo ufw allow 443
sudo ufw enableSet Up a Reverse Proxy (Optional but Recommended)
Using Nginx as a reverse proxy can help manage traffic and SSL.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33sudo apt-get install -y nginx
# Create Nginx configuration
sudo nano /etc/nginx/sites-available/my-web-app
# Add the following configuration
server {
listen 80;
server_name your_domain.com;
location /api/ {
proxy_pass http://localhost:8000/;
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 / {
proxy_pass http://localhost:3000/;
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;
}
}
# Enable the configuration
sudo ln -s /etc/nginx/sites-available/my-web-app /etc/nginx/sites-enabled/
# Test and reload Nginx
sudo nginx -t
sudo systemctl reload nginxSecure Your Application with SSL
Use Let's Encrypt for free SSL certificates.
1
2sudo apt-get install -y certbot python3-certbot-nginx
sudo certbot --nginx -d your_domain.comFollow the prompts to complete SSL setup.
Additional Best Practices
Security Considerations
Keep Dependencies Updated: Regularly update your dependencies to patch vulnerabilities.
Use Environment Variables: Never hardcode sensitive information. Use environment variables or secret managers.
Limit Access: Use firewalls to restrict access to essential ports only.
Use Non-Root Users in Containers: Modify Dockerfiles to run applications with non-root users.
1
2
3
4
5
6
7
8
9
10# Example addition to Dockerfile
# Add a user
RUN addgroup --system appgroup && adduser --system appuser --ingroup appgroup
# Set ownership
RUN chown -R appuser:appgroup /app
# Switch to the user
USER appuser
Optimizing Docker Images
- Use Multi-Stage Builds: As shown in the frontend Dockerfile, use multi-stage builds to reduce image size.
- Leverage Caching: Order Dockerfile instructions to maximize cache efficiency.
- Minimize Layers: Combine commands where possible to reduce the number of layers.
Logging and Monitoring
- Centralized Logging: Use tools like ELK Stack (Elasticsearch, Logstash, Kibana) or cloud services.
- Monitoring Tools: Implement monitoring with Prometheus, Grafana, or similar tools to track application performance and uptime.
Conclusion
Deploying a FastAPI and React application using Docker ensures a scalable and maintainable setup across different environments. By following the best practices outlined above—such as proper project structuring, using Docker Compose, managing environment variables securely, and implementing security measures—you can efficiently deploy and manage your web application on a server.
Remember to continuously monitor your application's performance and security, and keep your Docker images and dependencies up to date. Happy coding!