Server deploy script
This commit is contained in:
parent
9c82c677ce
commit
4c2a2f6aca
|
|
@ -0,0 +1,465 @@
|
||||||
|
# Deployment Guide: Farm Auth Service on AWS Lightsail
|
||||||
|
|
||||||
|
This guide will help you deploy the Farm Auth Service on AWS Lightsail Ubuntu server with the domain `auth.livingai.app`.
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
- AWS Lightsail Ubuntu server (at least 1GB RAM recommended)
|
||||||
|
- Domain name `auth.livingai.app` pointing to your Lightsail server IP
|
||||||
|
- Access to AWS Console (for database if using AWS RDS)
|
||||||
|
- SSH access to your Lightsail server
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Step 1: Set Up AWS Lightsail Instance
|
||||||
|
|
||||||
|
1. **Create Lightsail Instance**
|
||||||
|
- Go to AWS Lightsail Console
|
||||||
|
- Click "Create instance"
|
||||||
|
- Choose:
|
||||||
|
- Platform: Linux/Unix
|
||||||
|
- Blueprint: Ubuntu 22.04 LTS (or latest)
|
||||||
|
- Instance plan: At least $5/month (1GB RAM)
|
||||||
|
- Name: `auth-service-server`
|
||||||
|
- Click "Create instance"
|
||||||
|
|
||||||
|
2. **Configure Static IP**
|
||||||
|
- In Lightsail, go to Networking → Static IPs
|
||||||
|
- Click "Create static IP"
|
||||||
|
- Attach to your instance
|
||||||
|
- **Note the static IP address** - you'll need it for DNS configuration
|
||||||
|
|
||||||
|
3. **Configure Firewall (Security Groups)**
|
||||||
|
- Go to Networking → Firewall
|
||||||
|
- Add rules:
|
||||||
|
- HTTP (port 80) - Allow from Anywhere
|
||||||
|
- HTTPS (port 443) - Allow from Anywhere
|
||||||
|
- SSH (port 22) - Allow from Your IP (for security)
|
||||||
|
- Custom TCP 3000 - Allow from localhost only (for Node.js app)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Step 2: Configure DNS
|
||||||
|
|
||||||
|
1. **Point Domain to Lightsail IP**
|
||||||
|
- Go to your domain registrar (where you manage livingai.app)
|
||||||
|
- Add/Update A record:
|
||||||
|
- Type: A
|
||||||
|
- Name: auth (or @ if using subdomain)
|
||||||
|
- Value: Your Lightsail static IP address
|
||||||
|
- TTL: 300 (5 minutes)
|
||||||
|
- Wait for DNS propagation (can take up to 48 hours, usually faster)
|
||||||
|
|
||||||
|
2. **Verify DNS**
|
||||||
|
```bash
|
||||||
|
# On your local machine
|
||||||
|
nslookup auth.livingai.app
|
||||||
|
# Should return your Lightsail IP
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Step 3: Initial Server Setup (SSH into server)
|
||||||
|
|
||||||
|
1. **Connect to Server**
|
||||||
|
```bash
|
||||||
|
# Download SSH key from Lightsail or use existing key
|
||||||
|
ssh -i /path/to/your-key.pem ubuntu@your-lightsail-ip
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Update System**
|
||||||
|
```bash
|
||||||
|
sudo apt update && sudo apt upgrade -y
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **Install Node.js (v18 or higher)**
|
||||||
|
```bash
|
||||||
|
# Install Node.js using NodeSource repository
|
||||||
|
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
|
||||||
|
sudo apt install -y nodejs
|
||||||
|
|
||||||
|
# Verify installation
|
||||||
|
node --version
|
||||||
|
npm --version
|
||||||
|
```
|
||||||
|
|
||||||
|
4. **Install Nginx**
|
||||||
|
```bash
|
||||||
|
sudo apt install -y nginx
|
||||||
|
sudo systemctl start nginx
|
||||||
|
sudo systemctl enable nginx
|
||||||
|
```
|
||||||
|
|
||||||
|
5. **Install PM2 (Process Manager)**
|
||||||
|
```bash
|
||||||
|
sudo npm install -g pm2
|
||||||
|
```
|
||||||
|
|
||||||
|
6. **Install Git**
|
||||||
|
```bash
|
||||||
|
sudo apt install -y git
|
||||||
|
```
|
||||||
|
|
||||||
|
7. **Install Certbot (for SSL)**
|
||||||
|
```bash
|
||||||
|
sudo apt install -y certbot python3-certbot-nginx
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Step 4: Deploy Application Code
|
||||||
|
|
||||||
|
1. **Clone Repository**
|
||||||
|
```bash
|
||||||
|
# Create application directory
|
||||||
|
cd /home/ubuntu
|
||||||
|
mkdir -p apps
|
||||||
|
cd apps
|
||||||
|
|
||||||
|
# Clone your repository (adjust URL as needed)
|
||||||
|
git clone <your-repository-url> farm-auth-service
|
||||||
|
# OR if you need to upload manually:
|
||||||
|
# scp -r /path/to/farm-auth-service ubuntu@your-ip:/home/ubuntu/apps/
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Navigate to Project Directory**
|
||||||
|
```bash
|
||||||
|
cd farm-auth-service
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **Install Dependencies**
|
||||||
|
```bash
|
||||||
|
npm install --production
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Step 5: Configure Environment Variables
|
||||||
|
|
||||||
|
1. **Create .env File**
|
||||||
|
```bash
|
||||||
|
cp example.env .env
|
||||||
|
nano .env
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Configure .env File** (Update these values)
|
||||||
|
```env
|
||||||
|
# Database Mode
|
||||||
|
DATABASE_MODE=aws
|
||||||
|
|
||||||
|
# AWS Configuration (for SSM Parameter Store)
|
||||||
|
AWS_REGION=ap-south-1
|
||||||
|
AWS_ACCESS_KEY_ID=your_aws_access_key_here
|
||||||
|
AWS_SECRET_ACCESS_KEY=your_aws_secret_key_here
|
||||||
|
DB_USE_READONLY=false
|
||||||
|
|
||||||
|
# Database connection (auto-detected from SSM if not set)
|
||||||
|
# DB_HOST=db.livingai.app
|
||||||
|
# DB_PORT=5432
|
||||||
|
# DB_NAME=livingai_test_db
|
||||||
|
|
||||||
|
# JWT Configuration (IMPORTANT: Generate new secrets for production!)
|
||||||
|
JWT_ACCESS_SECRET=your_strong_random_secret_here_min_32_chars
|
||||||
|
JWT_REFRESH_SECRET=your_strong_random_secret_here_min_32_chars
|
||||||
|
JWT_ACCESS_TTL=15m
|
||||||
|
JWT_REFRESH_TTL=7d
|
||||||
|
|
||||||
|
# Redis Configuration (Optional - for rate limiting)
|
||||||
|
# REDIS_URL=redis://your-redis-host:6379
|
||||||
|
# Or if password protected:
|
||||||
|
# REDIS_URL=redis://:password@your-redis-host:6379
|
||||||
|
|
||||||
|
# Application Configuration
|
||||||
|
NODE_ENV=production
|
||||||
|
PORT=3000
|
||||||
|
TRUST_PROXY=true
|
||||||
|
|
||||||
|
# CORS Configuration (REQUIRED for production)
|
||||||
|
CORS_ALLOWED_ORIGINS=https://your-mobile-app-domain.com,https://app.livingai.app
|
||||||
|
# Add all domains that will access this API
|
||||||
|
|
||||||
|
# Twilio Configuration (if using SMS OTP)
|
||||||
|
# TWILIO_ACCOUNT_SID=your_twilio_account_sid
|
||||||
|
# TWILIO_AUTH_TOKEN=your_twilio_auth_token
|
||||||
|
# TWILIO_PHONE_NUMBER=+1234567890
|
||||||
|
|
||||||
|
# Admin Dashboard (optional)
|
||||||
|
# ENABLE_ADMIN_DASHBOARD=false
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **Generate Strong JWT Secrets** (Do this on your local machine)
|
||||||
|
```bash
|
||||||
|
# Generate random secrets (64 characters each)
|
||||||
|
node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"
|
||||||
|
node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"
|
||||||
|
```
|
||||||
|
Copy the output to `JWT_ACCESS_SECRET` and `JWT_REFRESH_SECRET`
|
||||||
|
|
||||||
|
4. **Secure .env File**
|
||||||
|
```bash
|
||||||
|
chmod 600 .env
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Step 6: Configure Nginx Reverse Proxy
|
||||||
|
|
||||||
|
1. **Create Nginx Configuration**
|
||||||
|
```bash
|
||||||
|
sudo nano /etc/nginx/sites-available/auth.livingai.app
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Add Configuration** (Before SSL)
|
||||||
|
```nginx
|
||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
server_name auth.livingai.app;
|
||||||
|
|
||||||
|
location / {
|
||||||
|
proxy_pass http://localhost:3000;
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
|
proxy_set_header Connection 'upgrade';
|
||||||
|
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;
|
||||||
|
proxy_cache_bypass $http_upgrade;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **Enable Site**
|
||||||
|
```bash
|
||||||
|
sudo ln -s /etc/nginx/sites-available/auth.livingai.app /etc/nginx/sites-enabled/
|
||||||
|
sudo nginx -t # Test configuration
|
||||||
|
sudo systemctl reload nginx
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Step 7: Set Up SSL Certificate (Let's Encrypt)
|
||||||
|
|
||||||
|
1. **Obtain SSL Certificate**
|
||||||
|
```bash
|
||||||
|
sudo certbot --nginx -d auth.livingai.app
|
||||||
|
```
|
||||||
|
- Follow prompts (enter email, agree to terms)
|
||||||
|
- Choose redirect HTTP to HTTPS (option 2)
|
||||||
|
|
||||||
|
2. **Verify Auto-renewal**
|
||||||
|
```bash
|
||||||
|
sudo certbot renew --dry-run
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **Update Nginx Config** (Certbot should have done this automatically)
|
||||||
|
Your config should now include SSL and redirect HTTP to HTTPS.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Step 8: Start Application with PM2
|
||||||
|
|
||||||
|
1. **Start Application**
|
||||||
|
```bash
|
||||||
|
cd /home/ubuntu/apps/farm-auth-service
|
||||||
|
pm2 start src/index.js --name "auth-service"
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Save PM2 Configuration**
|
||||||
|
```bash
|
||||||
|
pm2 save
|
||||||
|
pm2 startup
|
||||||
|
# Copy and run the command it outputs (starts PM2 on boot)
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **PM2 Useful Commands**
|
||||||
|
```bash
|
||||||
|
pm2 list # View running processes
|
||||||
|
pm2 logs auth-service # View logs
|
||||||
|
pm2 restart auth-service # Restart service
|
||||||
|
pm2 stop auth-service # Stop service
|
||||||
|
pm2 monit # Monitor resources
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Step 9: Configure Firewall (UFW)
|
||||||
|
|
||||||
|
1. **Set Up Firewall Rules**
|
||||||
|
```bash
|
||||||
|
sudo ufw allow OpenSSH
|
||||||
|
sudo ufw allow 'Nginx Full'
|
||||||
|
sudo ufw enable
|
||||||
|
sudo ufw status
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Step 10: Test Deployment
|
||||||
|
|
||||||
|
1. **Check Application Status**
|
||||||
|
```bash
|
||||||
|
pm2 status
|
||||||
|
pm2 logs auth-service --lines 50
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Test API Endpoint**
|
||||||
|
```bash
|
||||||
|
# From server
|
||||||
|
curl http://localhost:3000/health
|
||||||
|
|
||||||
|
# From your local machine (should work via domain)
|
||||||
|
curl https://auth.livingai.app/health
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **Check Nginx Logs**
|
||||||
|
```bash
|
||||||
|
sudo tail -f /var/log/nginx/access.log
|
||||||
|
sudo tail -f /var/log/nginx/error.log
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Step 11: Database Setup (if using AWS RDS)
|
||||||
|
|
||||||
|
1. **Ensure Database is Accessible**
|
||||||
|
- Your Lightsail instance should be able to connect to your AWS RDS instance
|
||||||
|
- Check security groups allow connection from Lightsail IP
|
||||||
|
- Verify SSM Parameter Store has correct credentials
|
||||||
|
|
||||||
|
2. **Test Database Connection**
|
||||||
|
```bash
|
||||||
|
cd /home/ubuntu/apps/farm-auth-service
|
||||||
|
node -e "require('./src/db').then(() => console.log('DB Connected')).catch(e => console.error(e))"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Step 12: Optional - Set Up Redis (for Rate Limiting)
|
||||||
|
|
||||||
|
If you want to use Redis for rate limiting:
|
||||||
|
|
||||||
|
1. **Option A: Install Redis on Same Server**
|
||||||
|
```bash
|
||||||
|
sudo apt install -y redis-server
|
||||||
|
sudo systemctl start redis-server
|
||||||
|
sudo systemctl enable redis-server
|
||||||
|
```
|
||||||
|
Then update `.env`:
|
||||||
|
```env
|
||||||
|
REDIS_URL=redis://localhost:6379
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Option B: Use AWS ElastiCache**
|
||||||
|
- Create ElastiCache Redis cluster
|
||||||
|
- Update `.env` with ElastiCache endpoint:
|
||||||
|
```env
|
||||||
|
REDIS_URL=redis://your-elasticache-endpoint:6379
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Monitoring and Maintenance
|
||||||
|
|
||||||
|
### View Logs
|
||||||
|
```bash
|
||||||
|
pm2 logs auth-service
|
||||||
|
pm2 logs auth-service --err # Error logs only
|
||||||
|
pm2 logs auth-service --out # Output logs only
|
||||||
|
```
|
||||||
|
|
||||||
|
### Restart Service
|
||||||
|
```bash
|
||||||
|
pm2 restart auth-service
|
||||||
|
```
|
||||||
|
|
||||||
|
### Update Application
|
||||||
|
```bash
|
||||||
|
cd /home/ubuntu/apps/farm-auth-service
|
||||||
|
git pull # or upload new files
|
||||||
|
npm install --production
|
||||||
|
pm2 restart auth-service
|
||||||
|
```
|
||||||
|
|
||||||
|
### Monitor Resources
|
||||||
|
```bash
|
||||||
|
pm2 monit
|
||||||
|
htop # System resources
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### Application Not Starting
|
||||||
|
1. Check logs: `pm2 logs auth-service`
|
||||||
|
2. Verify .env file exists and has correct values
|
||||||
|
3. Check database connectivity
|
||||||
|
4. Verify all dependencies installed: `npm list`
|
||||||
|
|
||||||
|
### 502 Bad Gateway
|
||||||
|
- Check if app is running: `pm2 status`
|
||||||
|
- Check app logs: `pm2 logs auth-service`
|
||||||
|
- Verify port 3000 is listening: `netstat -tlnp | grep 3000`
|
||||||
|
- Check Nginx error logs: `sudo tail -f /var/log/nginx/error.log`
|
||||||
|
|
||||||
|
### SSL Certificate Issues
|
||||||
|
- Verify DNS points to correct IP: `nslookup auth.livingai.app`
|
||||||
|
- Check certificate: `sudo certbot certificates`
|
||||||
|
- Renew manually: `sudo certbot renew`
|
||||||
|
|
||||||
|
### Database Connection Issues
|
||||||
|
- Verify AWS SSM parameters are correct
|
||||||
|
- Check AWS credentials in .env
|
||||||
|
- Test database connectivity from server
|
||||||
|
- Check security group allows connection
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Security Checklist
|
||||||
|
|
||||||
|
- [ ] Strong JWT secrets generated and stored securely
|
||||||
|
- [ ] .env file has 600 permissions
|
||||||
|
- [ ] Firewall configured (UFW)
|
||||||
|
- [ ] SSL certificate installed and auto-renewal working
|
||||||
|
- [ ] CORS configured with specific allowed origins (not *)
|
||||||
|
- [ ] AWS credentials have minimal required permissions
|
||||||
|
- [ ] Regular security updates: `sudo apt update && sudo apt upgrade`
|
||||||
|
- [ ] PM2 logs are monitored
|
||||||
|
- [ ] Database credentials stored in SSM (not in .env)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Backup Strategy
|
||||||
|
|
||||||
|
1. **Database Backups**
|
||||||
|
- Set up automated RDS snapshots in AWS Console
|
||||||
|
- Or use pg_dump for manual backups
|
||||||
|
|
||||||
|
2. **Application Code**
|
||||||
|
- Code is in Git repository (already backed up)
|
||||||
|
- Keep .env file backed up securely (encrypted)
|
||||||
|
|
||||||
|
3. **Configuration**
|
||||||
|
- Document all configuration changes
|
||||||
|
- Keep .env template versioned (without secrets)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Next Steps
|
||||||
|
|
||||||
|
1. Set up monitoring/alerting (e.g., CloudWatch, PM2 Plus)
|
||||||
|
2. Configure log rotation for PM2
|
||||||
|
3. Set up CI/CD pipeline for automated deployments
|
||||||
|
4. Configure health checks and auto-restart on failure
|
||||||
|
5. Set up database backups schedule
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Support
|
||||||
|
|
||||||
|
For issues, check:
|
||||||
|
- Application logs: `pm2 logs auth-service`
|
||||||
|
- Nginx logs: `/var/log/nginx/`
|
||||||
|
- System logs: `journalctl -xe`
|
||||||
|
|
||||||
|
|
@ -1,159 +0,0 @@
|
||||||
# AWS Database Migration - Implementation Summary
|
|
||||||
|
|
||||||
## ✅ Completed Changes
|
|
||||||
|
|
||||||
All code changes have been implemented to migrate from local Docker PostgreSQL to AWS PostgreSQL using AWS SSM Parameter Store for secure credential management.
|
|
||||||
|
|
||||||
## 📁 Files Modified
|
|
||||||
|
|
||||||
### 1. `src/utils/awsSsm.js`
|
|
||||||
**Changes:**
|
|
||||||
- ✅ Updated to use correct SSM parameter paths:
|
|
||||||
- Read-Write: `/test/livingai/db/app`
|
|
||||||
- Read-Only: `/test/livingai/db/app/readonly`
|
|
||||||
- ✅ Added support for `DB_USE_READONLY` environment variable
|
|
||||||
- ✅ Improved error handling with detailed error messages
|
|
||||||
- ✅ Added `buildDatabaseConfig()` function for SSL support
|
|
||||||
- ✅ Updated credential validation and parsing
|
|
||||||
|
|
||||||
### 2. `src/db.js`
|
|
||||||
**Changes:**
|
|
||||||
- ✅ Added SSL configuration for self-signed certificates
|
|
||||||
- ✅ Updated to use `buildDatabaseConfig()` instead of connection string
|
|
||||||
- ✅ Improved error handling and logging
|
|
||||||
- ✅ Auto-detection of AWS database when `DB_HOST=db.livingai.app`
|
|
||||||
- ✅ Connection pool configuration (max: 20, idleTimeout: 30s)
|
|
||||||
|
|
||||||
### 3. `src/config.js`
|
|
||||||
**Changes:**
|
|
||||||
- ✅ Updated to require AWS credentials when using SSM
|
|
||||||
- ✅ Removed `DATABASE_URL` from required env vars when `USE_AWS_SSM=true`
|
|
||||||
- ✅ Added validation for AWS credentials
|
|
||||||
|
|
||||||
### 4. Documentation
|
|
||||||
**New Files:**
|
|
||||||
- ✅ `docs/getting-started/AWS_DATABASE_MIGRATION.md` - Complete migration guide
|
|
||||||
- ✅ `docs/getting-started/ENV_VARIABLES_REFERENCE.md` - Environment variables reference
|
|
||||||
- ✅ `MIGRATION_SUMMARY.md` - This file
|
|
||||||
|
|
||||||
## 🔒 Security Implementation
|
|
||||||
|
|
||||||
### ✅ Credentials Management
|
|
||||||
- **NO database credentials in `.env` files**
|
|
||||||
- Credentials fetched from AWS SSM Parameter Store at runtime
|
|
||||||
- Only AWS credentials (for SSM access) in `.env`
|
|
||||||
- Supports both read-write and read-only users
|
|
||||||
|
|
||||||
### ✅ SSL Configuration
|
|
||||||
- SSL enabled with `rejectUnauthorized: false` for self-signed certificates
|
|
||||||
- Connection string includes `?sslmode=require`
|
|
||||||
- Proper SSL configuration in connection pool
|
|
||||||
|
|
||||||
## 📋 Required Environment Variables
|
|
||||||
|
|
||||||
### For AWS Database (Production)
|
|
||||||
```env
|
|
||||||
# AWS Configuration (for SSM access)
|
|
||||||
AWS_REGION=ap-south-1
|
|
||||||
AWS_ACCESS_KEY_ID=your_aws_access_key
|
|
||||||
AWS_SECRET_ACCESS_KEY=your_aws_secret_key
|
|
||||||
USE_AWS_SSM=true
|
|
||||||
|
|
||||||
# JWT Configuration
|
|
||||||
JWT_ACCESS_SECRET=your_secret
|
|
||||||
JWT_REFRESH_SECRET=your_secret
|
|
||||||
```
|
|
||||||
|
|
||||||
### Optional
|
|
||||||
```env
|
|
||||||
DB_USE_READONLY=false # false = read_write_user, true = read_only_user
|
|
||||||
DB_HOST=db.livingai.app
|
|
||||||
DB_PORT=5432
|
|
||||||
DB_NAME=livingai_test_db
|
|
||||||
```
|
|
||||||
|
|
||||||
## 🔄 Migration Steps
|
|
||||||
|
|
||||||
1. **Set up AWS SSM Parameters:**
|
|
||||||
- Create `/test/livingai/db/app` with read-write user credentials (JSON format)
|
|
||||||
- Create `/test/livingai/db/app/readonly` with read-only user credentials (optional)
|
|
||||||
|
|
||||||
2. **Update `.env` file:**
|
|
||||||
- Add AWS credentials (AWS_REGION, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY)
|
|
||||||
- Set `USE_AWS_SSM=true`
|
|
||||||
- Remove any database credentials (DB_USER, DB_PASSWORD, DATABASE_URL)
|
|
||||||
|
|
||||||
3. **Verify IAM Permissions:**
|
|
||||||
- Ensure IAM user/role has `ssm:GetParameter` permission for both SSM parameter paths
|
|
||||||
|
|
||||||
4. **Test Connection:**
|
|
||||||
- Start application: `npm start`
|
|
||||||
- Verify logs show successful SSM credential fetch and database connection
|
|
||||||
|
|
||||||
## 🧪 Testing Checklist
|
|
||||||
|
|
||||||
- [ ] AWS SSM parameters created with correct paths and JSON format
|
|
||||||
- [ ] IAM user has SSM read permissions
|
|
||||||
- [ ] `.env` file has AWS credentials (no DB credentials)
|
|
||||||
- [ ] `USE_AWS_SSM=true` in `.env`
|
|
||||||
- [ ] Application starts without errors
|
|
||||||
- [ ] Database connection established successfully
|
|
||||||
- [ ] SSL connection working (no SSL errors)
|
|
||||||
- [ ] API endpoints respond correctly
|
|
||||||
- [ ] Database queries execute successfully
|
|
||||||
- [ ] All business logic works as before
|
|
||||||
|
|
||||||
## 🔍 Verification Commands
|
|
||||||
|
|
||||||
### Check AWS SSM Parameter
|
|
||||||
```bash
|
|
||||||
aws ssm get-parameter --name "/test/livingai/db/app" --with-decryption --region ap-south-1
|
|
||||||
```
|
|
||||||
|
|
||||||
### Test Database Connection
|
|
||||||
```bash
|
|
||||||
npm start
|
|
||||||
# Look for these log messages:
|
|
||||||
# ✅ Successfully fetched DB credentials from SSM: /test/livingai/db/app (read-write user)
|
|
||||||
# ✅ Using database credentials from AWS SSM Parameter Store
|
|
||||||
# ✅ Database connection established successfully
|
|
||||||
```
|
|
||||||
|
|
||||||
## ⚠️ Important Notes
|
|
||||||
|
|
||||||
1. **No Breaking Changes**: All business logic remains unchanged. Only database connection configuration was updated.
|
|
||||||
|
|
||||||
2. **Backward Compatibility**: Local development still works with `DATABASE_URL` when `USE_AWS_SSM=false`.
|
|
||||||
|
|
||||||
3. **Security**: Database credentials are never stored in files. They are fetched from AWS SSM at runtime.
|
|
||||||
|
|
||||||
4. **SSL**: Self-signed certificates are supported via `rejectUnauthorized: false` configuration.
|
|
||||||
|
|
||||||
5. **Connection Pooling**: Configured with sensible defaults (max 20 connections, 30s idle timeout).
|
|
||||||
|
|
||||||
## 📚 Documentation
|
|
||||||
|
|
||||||
For detailed information, see:
|
|
||||||
- `docs/getting-started/AWS_DATABASE_MIGRATION.md` - Complete migration guide
|
|
||||||
- `docs/getting-started/ENV_VARIABLES_REFERENCE.md` - Environment variables reference
|
|
||||||
|
|
||||||
## 🐛 Troubleshooting
|
|
||||||
|
|
||||||
Common issues and solutions are documented in `docs/getting-started/AWS_DATABASE_MIGRATION.md` under the "Troubleshooting" section.
|
|
||||||
|
|
||||||
## ✨ Next Steps
|
|
||||||
|
|
||||||
1. Review the changes in the modified files
|
|
||||||
2. Set up AWS SSM parameters with your database credentials
|
|
||||||
3. Update your `.env` file with AWS credentials
|
|
||||||
4. Test the connection
|
|
||||||
5. Deploy to your AWS environment
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
**Migration Status**: ✅ Complete
|
|
||||||
**All Requirements Met**: ✅ Yes
|
|
||||||
**Security Requirements Met**: ✅ Yes
|
|
||||||
**Backward Compatibility**: ✅ Maintained
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,131 @@
|
||||||
|
# Quick Deployment Reference - auth.livingai.app
|
||||||
|
|
||||||
|
## TL;DR - Quick Steps
|
||||||
|
|
||||||
|
### 1. Lightsail Setup
|
||||||
|
- Create Ubuntu 22.04 instance
|
||||||
|
- Attach static IP
|
||||||
|
- Open ports: 80, 443, 22
|
||||||
|
|
||||||
|
### 2. DNS Configuration
|
||||||
|
- Point `auth.livingai.app` A record to Lightsail static IP
|
||||||
|
|
||||||
|
### 3. Server Setup (SSH into server)
|
||||||
|
```bash
|
||||||
|
# Run setup script
|
||||||
|
cd ~ && wget https://your-repo/setup-server.sh
|
||||||
|
bash setup-server.sh
|
||||||
|
|
||||||
|
# OR manually:
|
||||||
|
sudo apt update && sudo apt upgrade -y
|
||||||
|
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
|
||||||
|
sudo apt install -y nodejs nginx git certbot python3-certbot-nginx
|
||||||
|
sudo npm install -g pm2
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. Deploy Application
|
||||||
|
```bash
|
||||||
|
cd ~/apps
|
||||||
|
git clone <your-repo-url> farm-auth-service
|
||||||
|
cd farm-auth-service
|
||||||
|
npm install --production
|
||||||
|
cp example.env .env
|
||||||
|
nano .env # Configure environment variables
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5. Configure Nginx
|
||||||
|
```bash
|
||||||
|
sudo nano /etc/nginx/sites-available/auth.livingai.app
|
||||||
|
# Add configuration (see DEPLOYMENT_GUIDE.md)
|
||||||
|
sudo ln -s /etc/nginx/sites-available/auth.livingai.app /etc/nginx/sites-enabled/
|
||||||
|
sudo nginx -t
|
||||||
|
sudo systemctl reload nginx
|
||||||
|
```
|
||||||
|
|
||||||
|
### 6. SSL Certificate
|
||||||
|
```bash
|
||||||
|
sudo certbot --nginx -d auth.livingai.app
|
||||||
|
```
|
||||||
|
|
||||||
|
### 7. Start Application
|
||||||
|
```bash
|
||||||
|
cd ~/apps/farm-auth-service
|
||||||
|
pm2 start ecosystem.config.js
|
||||||
|
pm2 save
|
||||||
|
pm2 startup # Follow instructions
|
||||||
|
```
|
||||||
|
|
||||||
|
### 8. Configure Firewall
|
||||||
|
```bash
|
||||||
|
sudo ufw allow OpenSSH
|
||||||
|
sudo ufw allow 'Nginx Full'
|
||||||
|
sudo ufw enable
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Critical Configuration (.env)
|
||||||
|
|
||||||
|
**Required Settings:**
|
||||||
|
```env
|
||||||
|
NODE_ENV=production
|
||||||
|
PORT=3000
|
||||||
|
TRUST_PROXY=true
|
||||||
|
DATABASE_MODE=aws
|
||||||
|
AWS_REGION=ap-south-1
|
||||||
|
AWS_ACCESS_KEY_ID=your_key
|
||||||
|
AWS_SECRET_ACCESS_KEY=your_secret
|
||||||
|
JWT_ACCESS_SECRET=generate_strong_secret_min_32_chars
|
||||||
|
JWT_REFRESH_SECRET=generate_strong_secret_min_32_chars
|
||||||
|
CORS_ALLOWED_ORIGINS=https://your-app-domain.com,https://app.livingai.app
|
||||||
|
```
|
||||||
|
|
||||||
|
**Generate JWT Secrets:**
|
||||||
|
```bash
|
||||||
|
node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Useful Commands
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# View logs
|
||||||
|
pm2 logs auth-service
|
||||||
|
|
||||||
|
# Restart
|
||||||
|
pm2 restart auth-service
|
||||||
|
|
||||||
|
# Status
|
||||||
|
pm2 status
|
||||||
|
|
||||||
|
# Nginx logs
|
||||||
|
sudo tail -f /var/log/nginx/error.log
|
||||||
|
sudo tail -f /var/log/nginx/access.log
|
||||||
|
|
||||||
|
# Test API
|
||||||
|
curl https://auth.livingai.app/health
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
**502 Bad Gateway?**
|
||||||
|
- Check PM2: `pm2 status`
|
||||||
|
- Check logs: `pm2 logs auth-service`
|
||||||
|
- Check Nginx: `sudo nginx -t`
|
||||||
|
|
||||||
|
**Can't connect to database?**
|
||||||
|
- Verify AWS credentials in .env
|
||||||
|
- Check SSM Parameter Store access
|
||||||
|
- Test connection: `node -e "require('./src/db')"`
|
||||||
|
|
||||||
|
**SSL issues?**
|
||||||
|
- Verify DNS: `nslookup auth.livingai.app`
|
||||||
|
- Renew cert: `sudo certbot renew`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
For detailed instructions, see `DEPLOYMENT_GUIDE.md`
|
||||||
|
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
// PM2 Ecosystem Configuration File
|
||||||
|
// Usage: pm2 start ecosystem.config.js
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
apps: [{
|
||||||
|
name: 'auth-service',
|
||||||
|
script: 'src/index.js',
|
||||||
|
instances: 1, // For single instance, use 1. For cluster mode, use 'max' or number
|
||||||
|
exec_mode: 'fork', // 'fork' for single instance, 'cluster' for multiple instances
|
||||||
|
watch: false, // Set to true for development
|
||||||
|
max_memory_restart: '500M', // Restart if memory exceeds 500MB
|
||||||
|
env: {
|
||||||
|
NODE_ENV: 'production',
|
||||||
|
PORT: 3000
|
||||||
|
},
|
||||||
|
error_file: './logs/pm2-error.log',
|
||||||
|
out_file: './logs/pm2-out.log',
|
||||||
|
log_date_format: 'YYYY-MM-DD HH:mm:ss Z',
|
||||||
|
merge_logs: true,
|
||||||
|
autorestart: true,
|
||||||
|
max_restarts: 10,
|
||||||
|
min_uptime: '10s',
|
||||||
|
listen_timeout: 10000,
|
||||||
|
kill_timeout: 5000
|
||||||
|
}]
|
||||||
|
};
|
||||||
|
|
||||||
|
|
@ -1,231 +0,0 @@
|
||||||
# Kotlin OTP Verification Fix
|
|
||||||
|
|
||||||
## Issue Analysis
|
|
||||||
|
|
||||||
The backend `/auth/verify-otp` endpoint expects:
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"phone_number": "+919876543210", // Must be E.164 format with +
|
|
||||||
"code": "123456", // String, not number
|
|
||||||
"device_id": "optional-device-id",
|
|
||||||
"device_info": {
|
|
||||||
"platform": "android",
|
|
||||||
"model": "device-model",
|
|
||||||
"os_version": "Android 13",
|
|
||||||
"app_version": "1.0.0",
|
|
||||||
"language_code": "en",
|
|
||||||
"timezone": "Asia/Kolkata"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Common Issues in Kotlin Implementation
|
|
||||||
|
|
||||||
1. **Phone Number Format**: Must include `+` prefix (E.164 format)
|
|
||||||
2. **OTP Code Type**: Must be sent as string, not integer
|
|
||||||
3. **Request Body**: Must match exact field names (`phone_number`, `code`)
|
|
||||||
4. **Missing Device Info**: Backend accepts but doesn't require device_info
|
|
||||||
|
|
||||||
## Fixed Kotlin Code
|
|
||||||
|
|
||||||
### Option 1: Update AuthManager.login() method
|
|
||||||
|
|
||||||
```kotlin
|
|
||||||
// In AuthManager.kt or AuthApiClient.kt
|
|
||||||
suspend fun login(phoneNumber: String, otpCode: String): Result<LoginResponse> {
|
|
||||||
return try {
|
|
||||||
// Ensure phone number has + prefix (E.164 format)
|
|
||||||
val normalizedPhone = if (phoneNumber.startsWith("+")) {
|
|
||||||
phoneNumber
|
|
||||||
} else if (phoneNumber.length == 10) {
|
|
||||||
"+91$phoneNumber" // Add +91 for 10-digit Indian numbers
|
|
||||||
} else {
|
|
||||||
phoneNumber // Keep as is if already formatted
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ensure OTP is string (not integer)
|
|
||||||
val otpString = otpCode.toString().trim()
|
|
||||||
|
|
||||||
// Get device info
|
|
||||||
val deviceId = getDeviceId() // Your method to get device ID
|
|
||||||
val deviceInfo = getDeviceInfo() // Your method to get device info
|
|
||||||
|
|
||||||
val requestBody = mapOf(
|
|
||||||
"phone_number" to normalizedPhone,
|
|
||||||
"code" to otpString,
|
|
||||||
"device_id" to deviceId,
|
|
||||||
"device_info" to deviceInfo
|
|
||||||
)
|
|
||||||
|
|
||||||
val response = apiClient.post("/auth/verify-otp", requestBody)
|
|
||||||
|
|
||||||
if (response.isSuccessful) {
|
|
||||||
val loginResponse = response.body() // Parse your LoginResponse
|
|
||||||
Result.success(loginResponse)
|
|
||||||
} else {
|
|
||||||
// Handle error response
|
|
||||||
val errorBody = response.errorBody()?.string()
|
|
||||||
Result.failure(Exception("OTP verification failed: $errorBody"))
|
|
||||||
}
|
|
||||||
} catch (e: Exception) {
|
|
||||||
Result.failure(e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Helper function to get device info
|
|
||||||
private fun getDeviceInfo(): Map<String, String?> {
|
|
||||||
return mapOf(
|
|
||||||
"platform" to "android",
|
|
||||||
"model" to android.os.Build.MODEL,
|
|
||||||
"os_version" to android.os.Build.VERSION.RELEASE,
|
|
||||||
"app_version" to getAppVersion(), // Your method
|
|
||||||
"language_code" to Locale.getDefault().language,
|
|
||||||
"timezone" to TimeZone.getDefault().id
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getDeviceId(): String {
|
|
||||||
// Use your existing device ID logic
|
|
||||||
// Could be Android ID, UUID, etc.
|
|
||||||
return Settings.Secure.getString(
|
|
||||||
context.contentResolver,
|
|
||||||
Settings.Secure.ANDROID_ID
|
|
||||||
) ?: UUID.randomUUID().toString()
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Option 2: Quick Fix in OtpScreen.kt
|
|
||||||
|
|
||||||
Update your `OtpScreen.kt` to ensure proper formatting:
|
|
||||||
|
|
||||||
```kotlin
|
|
||||||
@Composable
|
|
||||||
fun OtpScreen(navController: NavController, phoneNumber: String, name: String) {
|
|
||||||
val otp = remember { mutableStateOf("") }
|
|
||||||
val context = LocalContext.current.applicationContext
|
|
||||||
val scope = rememberCoroutineScope()
|
|
||||||
val authManager = remember { AuthManager(context, AuthApiClient(context), TokenManager(context)) }
|
|
||||||
|
|
||||||
val isSignInFlow = name == "existing_user"
|
|
||||||
|
|
||||||
// Normalize phone number to ensure it has + prefix
|
|
||||||
val normalizedPhone = remember(phoneNumber) {
|
|
||||||
if (phoneNumber.startsWith("+")) {
|
|
||||||
phoneNumber
|
|
||||||
} else if (phoneNumber.length == 10) {
|
|
||||||
"+91$phoneNumber"
|
|
||||||
} else {
|
|
||||||
phoneNumber
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Box(
|
|
||||||
modifier = Modifier.fillMaxSize()
|
|
||||||
) {
|
|
||||||
Column(
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxSize()
|
|
||||||
.padding(horizontal = 36.dp),
|
|
||||||
horizontalAlignment = Alignment.CenterHorizontally
|
|
||||||
) {
|
|
||||||
Spacer(modifier = Modifier.height(200.dp))
|
|
||||||
|
|
||||||
Text("Enter OTP", fontSize = 24.sp, fontWeight = FontWeight.Medium, color = Color(0xFF364153))
|
|
||||||
|
|
||||||
Spacer(modifier = Modifier.height(32.dp))
|
|
||||||
|
|
||||||
TextField(
|
|
||||||
value = otp.value,
|
|
||||||
onValueChange = { if (it.length <= 6 && it.all { char -> char.isDigit() }) otp.value = it },
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
.height(60.dp)
|
|
||||||
.shadow(elevation = 1.dp, shape = RoundedCornerShape(16.dp)),
|
|
||||||
shape = RoundedCornerShape(16.dp),
|
|
||||||
colors = TextFieldDefaults.colors(
|
|
||||||
focusedContainerColor = Color.White.copy(alpha = 0.9f),
|
|
||||||
unfocusedContainerColor = Color.White.copy(alpha = 0.9f),
|
|
||||||
disabledContainerColor = Color.White.copy(alpha = 0.9f),
|
|
||||||
focusedIndicatorColor = Color.Transparent,
|
|
||||||
unfocusedIndicatorColor = Color.Transparent,
|
|
||||||
),
|
|
||||||
textStyle = LocalTextStyle.current.copy(textAlign = TextAlign.Center, fontSize = 24.sp),
|
|
||||||
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number)
|
|
||||||
)
|
|
||||||
|
|
||||||
Spacer(modifier = Modifier.height(48.dp))
|
|
||||||
|
|
||||||
Button(
|
|
||||||
onClick = {
|
|
||||||
scope.launch {
|
|
||||||
// Ensure OTP is not empty and is 6 digits
|
|
||||||
if (otp.value.length != 6) {
|
|
||||||
Toast.makeText(context, "Please enter a valid 6-digit OTP", Toast.LENGTH_SHORT).show()
|
|
||||||
return@launch
|
|
||||||
}
|
|
||||||
|
|
||||||
// Use normalized phone number
|
|
||||||
authManager.login(normalizedPhone, otp.value.trim())
|
|
||||||
.onSuccess { response ->
|
|
||||||
if (isSignInFlow) {
|
|
||||||
navController.navigate("success") { popUpTo("login") { inclusive = true } }
|
|
||||||
} else {
|
|
||||||
if (response.needsProfile) {
|
|
||||||
navController.navigate("create_profile/$name")
|
|
||||||
} else {
|
|
||||||
navController.navigate("success") { popUpTo("login") { inclusive = true } }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.onFailure { error ->
|
|
||||||
// More detailed error handling
|
|
||||||
val errorMessage = error.message ?: "Invalid or expired OTP"
|
|
||||||
Toast.makeText(context, errorMessage, Toast.LENGTH_SHORT).show()
|
|
||||||
Log.e("OtpScreen", "OTP verification failed", error)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
shape = RoundedCornerShape(16.dp),
|
|
||||||
colors = ButtonDefaults.buttonColors(containerColor = Color(0xFFFE9A00)),
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
.height(56.dp)
|
|
||||||
.shadow(elevation = 4.dp, shape = RoundedCornerShape(16.dp))
|
|
||||||
) {
|
|
||||||
Text("Continue", color = Color.White, fontSize = 16.sp, fontWeight = FontWeight.Medium)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Key Changes to Check in Your AuthManager/AuthApiClient
|
|
||||||
|
|
||||||
1. **Phone Number Normalization**: Ensure `+` prefix is present
|
|
||||||
2. **OTP as String**: Send OTP as string, not integer
|
|
||||||
3. **Request Body Format**: Use exact field names from backend
|
|
||||||
4. **Error Handling**: Check response status and error body
|
|
||||||
|
|
||||||
## Debugging Steps
|
|
||||||
|
|
||||||
1. **Add Logging**: Log the exact request being sent
|
|
||||||
```kotlin
|
|
||||||
Log.d("AuthManager", "Sending verify-otp: phone=$normalizedPhone, code=$otpString")
|
|
||||||
Log.d("AuthManager", "Request body: $requestBody")
|
|
||||||
```
|
|
||||||
|
|
||||||
2. **Check Response**: Log the response
|
|
||||||
```kotlin
|
|
||||||
Log.d("AuthManager", "Response code: ${response.code()}")
|
|
||||||
Log.d("AuthManager", "Response body: ${response.body()?.string()}")
|
|
||||||
```
|
|
||||||
|
|
||||||
3. **Compare with HTML**: Use the same phone number and OTP in HTML test page to verify backend is working
|
|
||||||
|
|
||||||
## Most Likely Issues
|
|
||||||
|
|
||||||
1. **Phone number missing `+` prefix** - Backend normalizes but expects E.164 format
|
|
||||||
2. **OTP sent as number instead of string** - Backend expects string
|
|
||||||
3. **Wrong field names** - Must be `phone_number` and `code` (with underscores)
|
|
||||||
4. **Request body not properly serialized** - Check your JSON serialization
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,67 @@
|
||||||
|
#!/bin/bash
|
||||||
|
# Quick Setup Script for AWS Lightsail Ubuntu Server
|
||||||
|
# Run this script on your Lightsail server after initial SSH connection
|
||||||
|
# Usage: bash setup-server.sh
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
echo "🚀 Starting Farm Auth Service Server Setup..."
|
||||||
|
|
||||||
|
# Update system
|
||||||
|
echo "📦 Updating system packages..."
|
||||||
|
sudo apt update && sudo apt upgrade -y
|
||||||
|
|
||||||
|
# Install Node.js
|
||||||
|
echo "📦 Installing Node.js..."
|
||||||
|
if ! command -v node &> /dev/null; then
|
||||||
|
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
|
||||||
|
sudo apt install -y nodejs
|
||||||
|
else
|
||||||
|
echo "✅ Node.js already installed: $(node --version)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Install Nginx
|
||||||
|
echo "📦 Installing Nginx..."
|
||||||
|
if ! command -v nginx &> /dev/null; then
|
||||||
|
sudo apt install -y nginx
|
||||||
|
sudo systemctl start nginx
|
||||||
|
sudo systemctl enable nginx
|
||||||
|
else
|
||||||
|
echo "✅ Nginx already installed"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Install PM2
|
||||||
|
echo "📦 Installing PM2..."
|
||||||
|
if ! command -v pm2 &> /dev/null; then
|
||||||
|
sudo npm install -g pm2
|
||||||
|
else
|
||||||
|
echo "✅ PM2 already installed: $(pm2 --version)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Install Git
|
||||||
|
echo "📦 Installing Git..."
|
||||||
|
sudo apt install -y git
|
||||||
|
|
||||||
|
# Install Certbot
|
||||||
|
echo "📦 Installing Certbot..."
|
||||||
|
sudo apt install -y certbot python3-certbot-nginx
|
||||||
|
|
||||||
|
# Create application directory
|
||||||
|
echo "📁 Creating application directory..."
|
||||||
|
mkdir -p ~/apps
|
||||||
|
cd ~/apps
|
||||||
|
|
||||||
|
# Create logs directory
|
||||||
|
echo "📁 Creating logs directory..."
|
||||||
|
mkdir -p ~/apps/farm-auth-service/logs
|
||||||
|
|
||||||
|
echo "✅ Server setup completed!"
|
||||||
|
echo ""
|
||||||
|
echo "Next steps:"
|
||||||
|
echo "1. Clone your repository: cd ~/apps && git clone <your-repo-url> farm-auth-service"
|
||||||
|
echo "2. Install dependencies: cd farm-auth-service && npm install --production"
|
||||||
|
echo "3. Configure .env file: cp example.env .env && nano .env"
|
||||||
|
echo "4. Configure Nginx (see DEPLOYMENT_GUIDE.md)"
|
||||||
|
echo "5. Set up SSL: sudo certbot --nginx -d auth.livingai.app"
|
||||||
|
echo "6. Start application: pm2 start ecosystem.config.js"
|
||||||
|
|
||||||
Loading…
Reference in New Issue