Skip to content

Commit 0dae2e0

Browse files
committed
Added deployment scripts and GitHub Actions
1 parent b50d09e commit 0dae2e0

File tree

3 files changed

+379
-0
lines changed

3 files changed

+379
-0
lines changed

.github/workflows/deploy.yml

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
name: Deploy to EC2
2+
3+
on:
4+
push:
5+
branches: [ main, master ]
6+
pull_request:
7+
branches: [ main, master ]
8+
9+
jobs:
10+
test:
11+
runs-on: ubuntu-latest
12+
steps:
13+
- uses: actions/checkout@v4
14+
15+
- name: Set up Python
16+
uses: actions/setup-python@v4
17+
with:
18+
python-version: '3.10'
19+
20+
- name: Install dependencies
21+
run: |
22+
cd backend
23+
pip install -r requirements.txt || pip install -e .
24+
25+
- name: Run tests
26+
run: |
27+
cd backend
28+
python -m pytest tests/ -v
29+
30+
deploy:
31+
needs: test
32+
runs-on: ubuntu-latest
33+
if: github.ref == 'refs/heads/main' || github.ref == 'refs/heads/master'
34+
35+
steps:
36+
- name: Checkout code
37+
uses: actions/checkout@v4
38+
39+
- name: Setup SSH
40+
uses: webfactory/[email protected]
41+
with:
42+
ssh-private-key: ${{ secrets.EC2_SSH_KEY }}
43+
44+
- name: Add EC2 to known hosts
45+
run: |
46+
ssh-keyscan -H ${{ secrets.EC2_HOST }} >> ~/.ssh/known_hosts
47+
48+
- name: Deploy to EC2
49+
run: |
50+
ssh ec2-user@${{ secrets.EC2_HOST }} << 'EOF'
51+
# Navigate to project directory
52+
cd mosaic-project-cs4800 || cd mosaic-project-cs4800-main
53+
54+
# Pull latest changes
55+
git pull origin main || git pull origin master
56+
57+
# Make deployment script executable
58+
chmod +x deploy-ip.sh
59+
60+
# Run deployment script
61+
./deploy-ip.sh ${{ secrets.EC2_HOST }}
62+
63+
# Deploy with Docker Compose
64+
docker compose -f docker-compose.production.yml down
65+
docker compose -f docker-compose.production.yml up -d --build
66+
67+
# Wait for services to be healthy
68+
sleep 30
69+
70+
# Check if services are running
71+
docker compose -f docker-compose.production.yml ps
72+
73+
# Test backend health
74+
curl -f http://localhost:8000/api/v1/utils/health-check/ || echo "Backend health check failed"
75+
EOF
76+
77+
- name: Verify deployment
78+
run: |
79+
# Wait a bit for services to fully start
80+
sleep 10
81+
82+
# Test if the application is accessible
83+
curl -f http://${{ secrets.EC2_HOST }}:8000/api/v1/utils/health-check/ || echo "Backend not accessible"
84+
curl -f http://${{ secrets.EC2_HOST }} || echo "Frontend not accessible"

DEPLOYMENT_GUIDE.md

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
# AWS EC2 Deployment Guide (IP-based)
2+
3+
This guide will help you deploy your FastAPI project to AWS EC2 using the public IP address.
4+
5+
## Prerequisites
6+
7+
1. AWS EC2 instance running Amazon Linux 2023
8+
2. Security group configured to allow:
9+
- SSH (port 22)
10+
- HTTP (port 80)
11+
- Backend API (port 8000)
12+
- Adminer (port 8080)
13+
- Database (port 5432) - optional for external access
14+
15+
## Step 1: Set up EC2 Instance
16+
17+
Connect to your EC2 instance and run these commands:
18+
19+
```bash
20+
# Update the system
21+
sudo yum update -y
22+
23+
# Install Docker
24+
sudo yum install -y docker
25+
sudo systemctl start docker
26+
sudo systemctl enable docker
27+
sudo usermod -a -G docker ec2-user
28+
29+
# Install Docker Compose
30+
sudo curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
31+
sudo chmod +x /usr/local/bin/docker-compose
32+
33+
# Logout and login again to apply docker group changes
34+
exit
35+
```
36+
37+
## Step 2: Upload Project Files
38+
39+
Upload your project files to the EC2 instance. You can use:
40+
41+
```bash
42+
# From your local machine, upload the project
43+
scp -r -i your-key.pem . ec2-user@YOUR_EC2_IP:/home/ec2-user/mosaic-project/
44+
```
45+
46+
Or clone from Git if your project is in a repository:
47+
48+
```bash
49+
# On the EC2 instance
50+
git clone YOUR_REPOSITORY_URL
51+
cd mosaic-project-cs4800
52+
```
53+
54+
## Step 3: Deploy the Application
55+
56+
1. **Run the deployment script** (replace YOUR_EC2_IP with your actual IP):
57+
58+
```bash
59+
./deploy-ip.sh YOUR_EC2_IP
60+
```
61+
62+
2. **Start the services**:
63+
64+
```bash
65+
docker compose -f docker-compose.production.yml up -d
66+
```
67+
68+
## Step 4: Verify Deployment
69+
70+
Your application will be available at:
71+
72+
- **Frontend**: `http://YOUR_EC2_IP`
73+
- **Backend API**: `http://YOUR_EC2_IP:8000`
74+
- **API Documentation**: `http://YOUR_EC2_IP:8000/docs`
75+
- **Adminer (Database UI)**: `http://YOUR_EC2_IP:8080`
76+
77+
## Step 5: Access the Application
78+
79+
1. **Create your first admin user**:
80+
- Go to `http://YOUR_EC2_IP:8000/docs`
81+
- Use the `/api/v1/users/` endpoint to create a user
82+
- Or use the frontend registration
83+
84+
2. **Login and start using the application**:
85+
- Frontend: `http://YOUR_EC2_IP`
86+
- API docs: `http://YOUR_EC2_IP:8000/docs`
87+
88+
## Troubleshooting
89+
90+
### Check if services are running:
91+
```bash
92+
docker compose -f docker-compose.production.yml ps
93+
```
94+
95+
### View logs:
96+
```bash
97+
# All services
98+
docker compose -f docker-compose.production.yml logs
99+
100+
# Specific service
101+
docker compose -f docker-compose.production.yml logs backend
102+
docker compose -f docker-compose.production.yml logs frontend
103+
```
104+
105+
### Restart services:
106+
```bash
107+
docker compose -f docker-compose.production.yml restart
108+
```
109+
110+
### Stop services:
111+
```bash
112+
docker compose -f docker-compose.production.yml down
113+
```
114+
115+
## Security Notes
116+
117+
- The deployment uses HTTP (not HTTPS) since we're using IP addresses
118+
- Database is accessible on port 5432 - consider restricting this in production
119+
- Adminer is accessible on port 8080 - consider restricting this in production
120+
- All passwords are generated securely using Python's secrets module
121+
122+
## Environment Variables
123+
124+
The deployment script automatically generates:
125+
- `SECRET_KEY`: Secure random key for JWT tokens
126+
- `FIRST_SUPERUSER_PASSWORD`: Secure random password for admin user
127+
- `POSTGRES_PASSWORD`: Secure random password for database
128+
129+
You can modify these in the `.env` file if needed.

deploy-ip.sh

Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
#!/bin/bash
2+
3+
# Deployment script for FastAPI project on EC2 with IP address
4+
# Usage: ./deploy-ip.sh YOUR_EC2_IP
5+
6+
if [ -z "$1" ]; then
7+
echo "Usage: ./deploy-ip.sh YOUR_EC2_IP"
8+
echo "Example: ./deploy-ip.sh 54.123.45.67"
9+
exit 1
10+
fi
11+
12+
EC2_IP=$1
13+
14+
echo "Deploying to EC2 IP: $EC2_IP"
15+
16+
# Create environment file
17+
cat > .env << EOF
18+
# Production Environment Variables for IP-based deployment
19+
ENVIRONMENT=production
20+
DOMAIN=$EC2_IP
21+
PROJECT_NAME=Mosaic Project
22+
STACK_NAME=mosaic-project-production
23+
BACKEND_CORS_ORIGINS=http://$EC2_IP:5173,http://$EC2_IP:80,http://$EC2_IP
24+
FRONTEND_HOST=http://$EC2_IP:5173
25+
SECRET_KEY=$(python3 -c "import secrets; print(secrets.token_urlsafe(32))")
26+
27+
FIRST_SUPERUSER_PASSWORD=$(python3 -c "import secrets; print(secrets.token_urlsafe(16))")
28+
POSTGRES_SERVER=db
29+
POSTGRES_PORT=5432
30+
POSTGRES_USER=postgres
31+
POSTGRES_PASSWORD=$(python3 -c "import secrets; print(secrets.token_urlsafe(16))")
32+
POSTGRES_DB=app
33+
SMTP_HOST=
34+
SMTP_USER=
35+
SMTP_PASSWORD=
36+
EMAILS_FROM_EMAIL=
37+
DOCKER_IMAGE_BACKEND=mosaic-backend
38+
DOCKER_IMAGE_FRONTEND=mosaic-frontend
39+
TAG=latest
40+
EOF
41+
42+
echo "Environment file created with secure random keys"
43+
44+
# Create simplified docker-compose for IP deployment
45+
cat > docker-compose.production.yml << EOF
46+
services:
47+
db:
48+
image: postgres:17
49+
restart: always
50+
healthcheck:
51+
test: ["CMD-SHELL", "pg_isready -U \${POSTGRES_USER} -d \${POSTGRES_DB}"]
52+
interval: 10s
53+
retries: 5
54+
start_period: 30s
55+
timeout: 10s
56+
volumes:
57+
- app-db-data:/var/lib/postgresql/data/pgdata
58+
environment:
59+
- PGDATA=/var/lib/postgresql/data/pgdata
60+
- POSTGRES_PASSWORD=\${POSTGRES_PASSWORD}
61+
- POSTGRES_USER=\${POSTGRES_USER}
62+
- POSTGRES_DB=\${POSTGRES_DB}
63+
ports:
64+
- "5432:5432"
65+
66+
adminer:
67+
image: adminer
68+
restart: always
69+
depends_on:
70+
- db
71+
environment:
72+
- ADMINER_DESIGN=pepa-linha-dark
73+
ports:
74+
- "8080:8080"
75+
76+
prestart:
77+
image: \${DOCKER_IMAGE_BACKEND}:\${TAG}
78+
build:
79+
context: ./backend
80+
depends_on:
81+
db:
82+
condition: service_healthy
83+
restart: true
84+
command: bash scripts/prestart.sh
85+
environment:
86+
- DOMAIN=\${DOMAIN}
87+
- FRONTEND_HOST=\${FRONTEND_HOST}
88+
- ENVIRONMENT=\${ENVIRONMENT}
89+
- BACKEND_CORS_ORIGINS=\${BACKEND_CORS_ORIGINS}
90+
- SECRET_KEY=\${SECRET_KEY}
91+
- FIRST_SUPERUSER=\${FIRST_SUPERUSER}
92+
- FIRST_SUPERUSER_PASSWORD=\${FIRST_SUPERUSER_PASSWORD}
93+
- SMTP_HOST=\${SMTP_HOST}
94+
- SMTP_USER=\${SMTP_USER}
95+
- SMTP_PASSWORD=\${SMTP_PASSWORD}
96+
- EMAILS_FROM_EMAIL=\${EMAILS_FROM_EMAIL}
97+
- POSTGRES_SERVER=db
98+
- POSTGRES_PORT=\${POSTGRES_PORT}
99+
- POSTGRES_DB=\${POSTGRES_DB}
100+
- POSTGRES_USER=\${POSTGRES_USER}
101+
- POSTGRES_PASSWORD=\${POSTGRES_PASSWORD}
102+
103+
backend:
104+
image: \${DOCKER_IMAGE_BACKEND}:\${TAG}
105+
restart: always
106+
depends_on:
107+
db:
108+
condition: service_healthy
109+
restart: true
110+
prestart:
111+
condition: service_completed_successfully
112+
build:
113+
context: ./backend
114+
environment:
115+
- DOMAIN=\${DOMAIN}
116+
- FRONTEND_HOST=\${FRONTEND_HOST}
117+
- ENVIRONMENT=\${ENVIRONMENT}
118+
- BACKEND_CORS_ORIGINS=\${BACKEND_CORS_ORIGINS}
119+
- SECRET_KEY=\${SECRET_KEY}
120+
- FIRST_SUPERUSER=\${FIRST_SUPERUSER}
121+
- FIRST_SUPERUSER_PASSWORD=\${FIRST_SUPERUSER_PASSWORD}
122+
- SMTP_HOST=\${SMTP_HOST}
123+
- SMTP_USER=\${SMTP_USER}
124+
- SMTP_PASSWORD=\${SMTP_PASSWORD}
125+
- EMAILS_FROM_EMAIL=\${EMAILS_FROM_EMAIL}
126+
- POSTGRES_SERVER=db
127+
- POSTGRES_PORT=\${POSTGRES_PORT}
128+
- POSTGRES_DB=\${POSTGRES_DB}
129+
- POSTGRES_USER=\${POSTGRES_USER}
130+
- POSTGRES_PASSWORD=\${POSTGRES_PASSWORD}
131+
healthcheck:
132+
test: ["CMD", "curl", "-f", "http://localhost:8000/api/v1/utils/health-check/"]
133+
interval: 10s
134+
timeout: 5s
135+
retries: 5
136+
ports:
137+
- "8000:8000"
138+
139+
frontend:
140+
image: \${DOCKER_IMAGE_FRONTEND}:\${TAG}
141+
restart: always
142+
build:
143+
context: ./frontend
144+
args:
145+
- VITE_API_URL=http://$EC2_IP:8000
146+
- NODE_ENV=production
147+
ports:
148+
- "80:80"
149+
150+
volumes:
151+
app-db-data:
152+
EOF
153+
154+
echo "Production docker-compose file created"
155+
156+
echo "Deployment files created successfully!"
157+
echo ""
158+
echo "Next steps:"
159+
echo "1. Copy your project files to the EC2 instance"
160+
echo "2. Run: docker compose -f docker-compose.production.yml up -d"
161+
echo ""
162+
echo "Your application will be available at:"
163+
echo "- Frontend: http://$EC2_IP"
164+
echo "- Backend API: http://$EC2_IP:8000"
165+
echo "- API Docs: http://$EC2_IP:8000/docs"
166+
echo "- Adminer: http://$EC2_IP:8080"

0 commit comments

Comments
 (0)