Clean up tunnel infrastructure and migrate to Gitea
Some checks failed
Deploy to Production Server / Deploy to 178.63.127.19 (push) Has been cancelled
Some checks failed
Deploy to Production Server / Deploy to 178.63.127.19 (push) Has been cancelled
This commit is contained in:
138
.github/workflows/deploy.yml
vendored
Normal file
138
.github/workflows/deploy.yml
vendored
Normal file
@@ -0,0 +1,138 @@
|
|||||||
|
name: Deploy to Production Server
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
workflow_dispatch: # Allow manual trigger
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
deploy:
|
||||||
|
name: Deploy to 178.63.127.19
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Setup Node.js
|
||||||
|
uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: "20"
|
||||||
|
cache: "npm"
|
||||||
|
|
||||||
|
- name: Install dependencies (Backend)
|
||||||
|
run: |
|
||||||
|
npm ci
|
||||||
|
|
||||||
|
- name: Install dependencies (Frontend)
|
||||||
|
run: |
|
||||||
|
cd frontend
|
||||||
|
npm ci
|
||||||
|
|
||||||
|
- name: Build Frontend
|
||||||
|
run: |
|
||||||
|
cd frontend
|
||||||
|
npm run build
|
||||||
|
env:
|
||||||
|
NODE_ENV: production
|
||||||
|
VITE_API_URL: http://178.63.127.19:3000
|
||||||
|
|
||||||
|
- name: Run Tests (if any)
|
||||||
|
run: |
|
||||||
|
npm test || echo "No tests configured"
|
||||||
|
continue-on-error: true
|
||||||
|
|
||||||
|
- name: Deploy to Production Server
|
||||||
|
uses: appleboy/ssh-action@v1.0.0
|
||||||
|
with:
|
||||||
|
host: ${{ secrets.SERVER_HOST }}
|
||||||
|
username: ${{ secrets.SERVER_USER }}
|
||||||
|
key: ${{ secrets.SSH_PRIVATE_KEY }}
|
||||||
|
port: ${{ secrets.SERVER_PORT || 22 }}
|
||||||
|
script: |
|
||||||
|
echo "🚀 Starting deployment..."
|
||||||
|
|
||||||
|
# Navigate to project directory
|
||||||
|
cd ${{ secrets.DEPLOY_PATH || '/var/www/turbotrades' }}
|
||||||
|
|
||||||
|
# Stop the application
|
||||||
|
echo "⏸️ Stopping application..."
|
||||||
|
pm2 stop turbotrades || echo "App not running"
|
||||||
|
|
||||||
|
# Backup current version
|
||||||
|
echo "💾 Creating backup..."
|
||||||
|
cp -r . ../turbotrades-backup-$(date +%Y%m%d-%H%M%S) || true
|
||||||
|
|
||||||
|
# Pull latest code
|
||||||
|
echo "📥 Pulling latest code..."
|
||||||
|
git fetch origin
|
||||||
|
git reset --hard origin/main
|
||||||
|
|
||||||
|
# Install backend dependencies
|
||||||
|
echo "📦 Installing backend dependencies..."
|
||||||
|
npm ci --production
|
||||||
|
|
||||||
|
# Build and install frontend
|
||||||
|
echo "🎨 Building frontend..."
|
||||||
|
cd frontend
|
||||||
|
npm ci
|
||||||
|
npm run build
|
||||||
|
cd ..
|
||||||
|
|
||||||
|
# Run database migrations (if any)
|
||||||
|
echo "🗄️ Running migrations..."
|
||||||
|
npm run migrate || echo "No migrations to run"
|
||||||
|
|
||||||
|
# Start the application
|
||||||
|
echo "▶️ Starting application..."
|
||||||
|
pm2 start ecosystem.config.js || pm2 start index.js --name turbotrades
|
||||||
|
pm2 save
|
||||||
|
|
||||||
|
# Verify deployment
|
||||||
|
echo "✅ Deployment complete!"
|
||||||
|
pm2 list
|
||||||
|
|
||||||
|
- name: Health Check
|
||||||
|
run: |
|
||||||
|
sleep 10
|
||||||
|
curl -f http://178.63.127.19:3000/api/health || echo "⚠️ Health check failed"
|
||||||
|
|
||||||
|
- name: Notify Success
|
||||||
|
if: success()
|
||||||
|
run: |
|
||||||
|
echo "✅ Deployment successful!"
|
||||||
|
echo "🌐 Server: 178.63.127.19"
|
||||||
|
echo "👤 Repository: git.turbotrades.dev/iDefineHD/TurboTrades"
|
||||||
|
echo "📅 Time: $(date)"
|
||||||
|
|
||||||
|
- name: Notify Failure
|
||||||
|
if: failure()
|
||||||
|
run: |
|
||||||
|
echo "❌ Deployment failed!"
|
||||||
|
echo "Check the logs above for details"
|
||||||
|
|
||||||
|
- name: Rollback on Failure
|
||||||
|
if: failure()
|
||||||
|
uses: appleboy/ssh-action@v1.0.0
|
||||||
|
with:
|
||||||
|
host: ${{ secrets.SERVER_HOST }}
|
||||||
|
username: ${{ secrets.SERVER_USER }}
|
||||||
|
key: ${{ secrets.SSH_PRIVATE_KEY }}
|
||||||
|
port: ${{ secrets.SERVER_PORT || 22 }}
|
||||||
|
script: |
|
||||||
|
echo "🔄 Rolling back to previous version..."
|
||||||
|
cd ${{ secrets.DEPLOY_PATH || '/var/www/turbotrades' }}
|
||||||
|
|
||||||
|
# Find latest backup
|
||||||
|
BACKUP=$(ls -t ../turbotrades-backup-* | head -1)
|
||||||
|
|
||||||
|
if [ -n "$BACKUP" ]; then
|
||||||
|
echo "Found backup: $BACKUP"
|
||||||
|
rm -rf ./*
|
||||||
|
cp -r $BACKUP/* .
|
||||||
|
pm2 restart turbotrades
|
||||||
|
echo "✅ Rollback complete"
|
||||||
|
else
|
||||||
|
echo "❌ No backup found!"
|
||||||
|
fi
|
||||||
5
.gitignore
vendored
5
.gitignore
vendored
@@ -9,6 +9,7 @@ pnpm-lock.yaml
|
|||||||
.env.local
|
.env.local
|
||||||
.env.production
|
.env.production
|
||||||
.env.development
|
.env.development
|
||||||
|
.env.tunnel
|
||||||
|
|
||||||
# Logs
|
# Logs
|
||||||
logs/
|
logs/
|
||||||
@@ -79,3 +80,7 @@ uploads/
|
|||||||
*.backup
|
*.backup
|
||||||
*.bak
|
*.bak
|
||||||
*.old
|
*.old
|
||||||
|
|
||||||
|
# Cloudflare Tunnel
|
||||||
|
.cloudflared/
|
||||||
|
.tunnel-urls.json
|
||||||
|
|||||||
271
CLEANUP_SUMMARY.md
Normal file
271
CLEANUP_SUMMARY.md
Normal file
@@ -0,0 +1,271 @@
|
|||||||
|
# 🧹 TurboTrades Cleanup Summary
|
||||||
|
|
||||||
|
**Date:** January 10, 2026
|
||||||
|
**Action:** Removed tunnel infrastructure and updated repository to Gitea
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ✅ Actions Completed
|
||||||
|
|
||||||
|
### 1. Removed Tunnel Files
|
||||||
|
|
||||||
|
**Deleted Scripts:**
|
||||||
|
- ❌ `scripts/dev-tunnel.js`
|
||||||
|
- ❌ `scripts/tunnel.js`
|
||||||
|
- ❌ `scripts/quick-tunnel.js`
|
||||||
|
- ❌ `scripts/cloudflare-tunnel.js`
|
||||||
|
- ❌ `scripts/setup-cloudflare-tunnel.js`
|
||||||
|
- ❌ `scripts/vscode-tunnel-config.js`
|
||||||
|
|
||||||
|
**Deleted Documentation:**
|
||||||
|
- ❌ `TUNNEL.md`
|
||||||
|
- ❌ `TUNNEL_QUICKSTART.md`
|
||||||
|
- ❌ `TUNNEL_CONFIG.md`
|
||||||
|
- ❌ `.cloudflared/` directory
|
||||||
|
|
||||||
|
**Removed from package.json:**
|
||||||
|
```json
|
||||||
|
- "tunnel": "node scripts/quick-tunnel.js"
|
||||||
|
- "tunnel:setup": "node scripts/setup-cloudflare-tunnel.js"
|
||||||
|
- "tunnel:stable": "node scripts/cloudflare-tunnel.js"
|
||||||
|
- "tunnel:vscode": "node scripts/vscode-tunnel-config.js"
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Updated Repository to Gitea
|
||||||
|
|
||||||
|
**Old Repository:**
|
||||||
|
```
|
||||||
|
https://github.com/iDefineHD/TurboTrades.git
|
||||||
|
```
|
||||||
|
|
||||||
|
**New Repository:**
|
||||||
|
```
|
||||||
|
https://git.turbotrades.dev/iDefineHD/TurboTrades.git
|
||||||
|
```
|
||||||
|
|
||||||
|
**Files Updated:**
|
||||||
|
|
||||||
|
#### `ecosystem.config.js`
|
||||||
|
```javascript
|
||||||
|
// Changed from:
|
||||||
|
repo: "https://github.com/iDefineHD/TurboTrades.git"
|
||||||
|
|
||||||
|
// To:
|
||||||
|
repo: "https://git.turbotrades.dev/iDefineHD/TurboTrades.git"
|
||||||
|
```
|
||||||
|
|
||||||
|
#### `.github/workflows/deploy.yml`
|
||||||
|
```yaml
|
||||||
|
# Updated repository reference in notification:
|
||||||
|
echo "👤 Repository: git.turbotrades.dev/iDefineHD/TurboTrades"
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Git Remote Configuration
|
||||||
|
```bash
|
||||||
|
# Updated local git remote:
|
||||||
|
git remote set-url origin https://git.turbotrades.dev/iDefineHD/TurboTrades.git
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Documentation Updates:
|
||||||
|
- ✅ `DEPLOY_NOW.md` - Updated all GitHub URLs to Gitea
|
||||||
|
- ✅ `DEPLOYMENT_GUIDE.md` - Updated references and placeholder URLs
|
||||||
|
- ✅ `scripts/setup-server.sh` - Updated instructions and clone URLs
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📝 Current Configuration
|
||||||
|
|
||||||
|
### Repository Details
|
||||||
|
- **Platform:** Gitea (self-hosted)
|
||||||
|
- **URL:** https://git.turbotrades.dev/iDefineHD/TurboTrades.git
|
||||||
|
- **Owner:** iDefineHD
|
||||||
|
- **Branch:** main
|
||||||
|
|
||||||
|
### Deployment
|
||||||
|
- **Server:** 178.63.127.19
|
||||||
|
- **User:** root
|
||||||
|
- **Path:** /var/www/turbotrades
|
||||||
|
- **Process Manager:** PM2
|
||||||
|
|
||||||
|
### CI/CD
|
||||||
|
- **Workflow:** `.github/workflows/deploy.yml`
|
||||||
|
- **Trigger:** Push to main branch or manual dispatch
|
||||||
|
- **Actions:** Build, test, deploy, health check, rollback on failure
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔄 What Was Kept
|
||||||
|
|
||||||
|
### Development Tools
|
||||||
|
- ✅ Vite dev server with proxy configuration
|
||||||
|
- ✅ WebSocket proxy support
|
||||||
|
- ✅ Hot module replacement
|
||||||
|
- ✅ VS Code dev tunnels compatibility
|
||||||
|
|
||||||
|
### Deployment Infrastructure
|
||||||
|
- ✅ GitHub Actions workflow (compatible with Gitea Actions)
|
||||||
|
- ✅ PM2 ecosystem configuration
|
||||||
|
- ✅ Server setup scripts
|
||||||
|
- ✅ Deployment documentation
|
||||||
|
- ✅ Health check endpoints
|
||||||
|
|
||||||
|
### Frontend Configuration
|
||||||
|
**Vite proxy configuration retained:**
|
||||||
|
```javascript
|
||||||
|
proxy: {
|
||||||
|
"/api": {
|
||||||
|
target: "http://localhost:3000",
|
||||||
|
changeOrigin: true,
|
||||||
|
},
|
||||||
|
"/ws": {
|
||||||
|
target: "http://localhost:3000",
|
||||||
|
ws: true,
|
||||||
|
changeOrigin: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Allowed hosts include:**
|
||||||
|
- `.devtunnels.ms` - VS Code Dev Tunnels
|
||||||
|
- `localhost`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🚀 Next Steps
|
||||||
|
|
||||||
|
### For Development
|
||||||
|
1. Use VS Code port forwarding for sharing:
|
||||||
|
- Open Ports panel
|
||||||
|
- Forward port 5173 (frontend)
|
||||||
|
- Set visibility to Public
|
||||||
|
- Share the URL
|
||||||
|
|
||||||
|
2. WebSocket connects automatically through proxy
|
||||||
|
|
||||||
|
3. No environment variables needed for local dev
|
||||||
|
|
||||||
|
### For Deployment
|
||||||
|
|
||||||
|
1. **Ensure Gitea repository is accessible:**
|
||||||
|
```bash
|
||||||
|
git remote -v
|
||||||
|
# Should show: https://git.turbotrades.dev/iDefineHD/TurboTrades.git
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Push changes:**
|
||||||
|
```bash
|
||||||
|
git add .
|
||||||
|
git commit -m "Cleanup: Remove tunnel infrastructure, update to Gitea"
|
||||||
|
git push origin main
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **Configure Gitea CI/CD** (if using Gitea Actions):
|
||||||
|
- Add secrets in repository settings
|
||||||
|
- Ensure workflow is enabled
|
||||||
|
- Test deployment pipeline
|
||||||
|
|
||||||
|
4. **Manual deployment option:**
|
||||||
|
```bash
|
||||||
|
ssh root@178.63.127.19
|
||||||
|
cd /var/www/turbotrades
|
||||||
|
git pull origin main
|
||||||
|
npm ci --production
|
||||||
|
cd frontend && npm ci && npm run build && cd ..
|
||||||
|
pm2 restart turbotrades
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ⚠️ Breaking Changes
|
||||||
|
|
||||||
|
### Removed Features
|
||||||
|
- ❌ Cloudflare Tunnel integration
|
||||||
|
- ❌ Localtunnel support
|
||||||
|
- ❌ Ngrok integration
|
||||||
|
- ❌ Automatic tunnel configuration scripts
|
||||||
|
|
||||||
|
### Migration Notes
|
||||||
|
If you were using the tunnel scripts:
|
||||||
|
- Use VS Code built-in port forwarding instead
|
||||||
|
- Or set up Cloudflare Tunnel manually
|
||||||
|
- Or use ngrok directly: `ngrok http 5173`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📚 Documentation Updates
|
||||||
|
|
||||||
|
### Updated Files
|
||||||
|
- `DEPLOY_NOW.md` - All references updated
|
||||||
|
- `DEPLOYMENT_GUIDE.md` - GitHub → Gitea references
|
||||||
|
- `scripts/setup-server.sh` - Repository URLs updated
|
||||||
|
- `.github/workflows/deploy.yml` - Notification text updated
|
||||||
|
|
||||||
|
### Removed Files
|
||||||
|
- All tunnel-related documentation removed
|
||||||
|
- Cloudflare tunnel configuration removed
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ✅ Verification Checklist
|
||||||
|
|
||||||
|
- [x] All tunnel scripts removed
|
||||||
|
- [x] Tunnel documentation removed
|
||||||
|
- [x] package.json scripts cleaned up
|
||||||
|
- [x] Git remote updated to Gitea
|
||||||
|
- [x] ecosystem.config.js updated
|
||||||
|
- [x] GitHub Actions workflow updated
|
||||||
|
- [x] Deployment documentation updated
|
||||||
|
- [x] Setup scripts updated
|
||||||
|
- [x] .gitignore includes tunnel artifacts
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔍 Files to Review Before Pushing
|
||||||
|
|
||||||
|
1. `.env` - Ensure no tunnel URLs are hardcoded
|
||||||
|
2. `frontend/.env` - Check API URL configuration
|
||||||
|
3. `ecosystem.config.js` - Verify Gitea repo URL
|
||||||
|
4. `.github/workflows/deploy.yml` - Test workflow syntax
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 💡 Tips
|
||||||
|
|
||||||
|
### For Local Development
|
||||||
|
- Use VS Code port forwarding for quick sharing
|
||||||
|
- WebSocket connections work through Vite proxy
|
||||||
|
- No configuration changes needed
|
||||||
|
|
||||||
|
### For Production
|
||||||
|
- Push to Gitea triggers deployment
|
||||||
|
- Monitor CI/CD pipeline in Gitea
|
||||||
|
- PM2 handles process management
|
||||||
|
- Automatic rollback on failure
|
||||||
|
|
||||||
|
### For Sharing Work
|
||||||
|
**Quick option:**
|
||||||
|
1. Open VS Code Ports panel
|
||||||
|
2. Forward port 5173
|
||||||
|
3. Make it Public
|
||||||
|
4. Share the URL
|
||||||
|
|
||||||
|
**No .env changes needed!**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🎯 Summary
|
||||||
|
|
||||||
|
- ✅ Removed 6 tunnel scripts
|
||||||
|
- ✅ Removed 4 tunnel documentation files
|
||||||
|
- ✅ Updated repository to Gitea
|
||||||
|
- ✅ Updated all documentation
|
||||||
|
- ✅ Cleaned package.json
|
||||||
|
- ✅ Updated git remote
|
||||||
|
- ✅ Ready for Gitea deployment
|
||||||
|
|
||||||
|
**Result:** Cleaner codebase, self-hosted repository, maintained functionality.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Last Updated:** January 10, 2026
|
||||||
|
**Status:** ✅ Complete
|
||||||
812
DEPLOYMENT_GUIDE.md
Normal file
812
DEPLOYMENT_GUIDE.md
Normal file
@@ -0,0 +1,812 @@
|
|||||||
|
# TurboTrades Deployment Guide
|
||||||
|
|
||||||
|
Complete guide to deploy TurboTrades to your production server at `178.63.127.19`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📋 Table of Contents
|
||||||
|
|
||||||
|
1. [Prerequisites](#prerequisites)
|
||||||
|
2. [Server Setup](#server-setup)
|
||||||
|
3. [GitHub Secrets Configuration](#github-secrets-configuration)
|
||||||
|
4. [Initial Deployment](#initial-deployment)
|
||||||
|
5. [Automatic Deployments](#automatic-deployments)
|
||||||
|
6. [Manual Deployment](#manual-deployment)
|
||||||
|
7. [Monitoring & Maintenance](#monitoring--maintenance)
|
||||||
|
8. [Troubleshooting](#troubleshooting)
|
||||||
|
9. [Rollback Procedures](#rollback-procedures)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔧 Prerequisites
|
||||||
|
|
||||||
|
### On Your Local Machine:
|
||||||
|
- [x] Git installed
|
||||||
|
- [x] GitHub account with repository access
|
||||||
|
- [x] SSH access to server (178.63.127.19)
|
||||||
|
|
||||||
|
### On Your Server (178.63.127.19):
|
||||||
|
- [ ] Ubuntu/Debian Linux
|
||||||
|
- [ ] Node.js 18+ installed
|
||||||
|
- [ ] MongoDB installed and running
|
||||||
|
- [ ] PM2 process manager
|
||||||
|
- [ ] Nginx (optional, for reverse proxy)
|
||||||
|
- [ ] Git installed
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🖥️ Server Setup
|
||||||
|
|
||||||
|
### Step 1: SSH into Your Server
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ssh root@178.63.127.19
|
||||||
|
# Or with specific user:
|
||||||
|
ssh yourusername@178.63.127.19
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 2: Install Required Software
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Update system
|
||||||
|
sudo apt update && sudo apt upgrade -y
|
||||||
|
|
||||||
|
# Install Node.js 20.x
|
||||||
|
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
|
||||||
|
sudo apt-get install -y nodejs
|
||||||
|
|
||||||
|
# Install MongoDB
|
||||||
|
wget -qO - https://www.mongodb.org/static/pgp/server-7.0.asc | sudo apt-key add -
|
||||||
|
echo "deb [ arch=amd64,arm64 ] https://repo.mongodb.org/apt/ubuntu $(lsb_release -cs)/mongodb-org/7.0 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-7.0.list
|
||||||
|
sudo apt update
|
||||||
|
sudo apt install -y mongodb-org
|
||||||
|
|
||||||
|
# Start MongoDB
|
||||||
|
sudo systemctl start mongod
|
||||||
|
sudo systemctl enable mongod
|
||||||
|
|
||||||
|
# Install PM2 globally
|
||||||
|
sudo npm install -g pm2
|
||||||
|
|
||||||
|
# Install Git
|
||||||
|
sudo apt install -y git
|
||||||
|
|
||||||
|
# Install Nginx (optional)
|
||||||
|
sudo apt install -y nginx
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 3: Create Deployment Directory
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Create directory
|
||||||
|
sudo mkdir -p /var/www/turbotrades
|
||||||
|
sudo chown -R $USER:$USER /var/www/turbotrades
|
||||||
|
|
||||||
|
# Navigate to directory
|
||||||
|
cd /var/www/turbotrades
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 4: Generate SSH Deploy Key (Optional but Recommended)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Generate SSH key for deployment
|
||||||
|
ssh-keygen -t ed25519 -C "deploy@turbotrades" -f ~/.ssh/turbotrades_deploy_key
|
||||||
|
|
||||||
|
# Display public key (add to GitHub Deploy Keys)
|
||||||
|
cat ~/.ssh/turbotrades_deploy_key.pub
|
||||||
|
|
||||||
|
# Display private key (add to GitHub Secrets)
|
||||||
|
cat ~/.ssh/turbotrades_deploy_key
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 5: Clone Repository
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd /var/www/turbotrades
|
||||||
|
git clone https://git.turbotrades.dev/iDefineHD/TurboTrades.git .
|
||||||
|
|
||||||
|
# Or with SSH key:
|
||||||
|
git clone git@git.turbotrades.dev:iDefineHD/TurboTrades.git .
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 6: Create Environment File
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd /var/www/turbotrades
|
||||||
|
nano .env
|
||||||
|
```
|
||||||
|
|
||||||
|
Add the following configuration:
|
||||||
|
|
||||||
|
```env
|
||||||
|
# Server Configuration
|
||||||
|
NODE_ENV=production
|
||||||
|
PORT=3000
|
||||||
|
HOST=0.0.0.0
|
||||||
|
|
||||||
|
# Database
|
||||||
|
MONGODB_URI=mongodb://localhost:27017/turbotrades
|
||||||
|
|
||||||
|
# Session Secret (Generate a secure random string)
|
||||||
|
SESSION_SECRET=your-super-secret-session-key-change-this
|
||||||
|
|
||||||
|
# Steam API
|
||||||
|
STEAM_API_KEY=your-steam-api-key-here
|
||||||
|
STEAM_RETURN_URL=http://178.63.127.19:3000/auth/steam/return
|
||||||
|
|
||||||
|
# JWT Secret (Generate a secure random string)
|
||||||
|
JWT_SECRET=your-super-secret-jwt-key-change-this
|
||||||
|
JWT_ACCESS_EXPIRY=15m
|
||||||
|
JWT_REFRESH_EXPIRY=7d
|
||||||
|
|
||||||
|
# CORS
|
||||||
|
CORS_ORIGIN=http://178.63.127.19
|
||||||
|
|
||||||
|
# Redis (if using)
|
||||||
|
REDIS_URL=redis://localhost:6379
|
||||||
|
|
||||||
|
# Admin Steam IDs (comma-separated)
|
||||||
|
ADMIN_STEAM_IDS=76561198000000000,76561198111111111
|
||||||
|
|
||||||
|
# Bot Configuration
|
||||||
|
STEAM_BOT_USERNAME=your-bot-username
|
||||||
|
STEAM_BOT_PASSWORD=your-bot-password
|
||||||
|
STEAM_BOT_SHARED_SECRET=your-bot-shared-secret
|
||||||
|
STEAM_BOT_IDENTITY_SECRET=your-bot-identity-secret
|
||||||
|
|
||||||
|
# CSGOFloat API (optional)
|
||||||
|
CSGOFLOAT_API_KEY=your-csgofloat-api-key
|
||||||
|
|
||||||
|
# Pricing API (optional)
|
||||||
|
PRICING_API_KEY=your-pricing-api-key
|
||||||
|
```
|
||||||
|
|
||||||
|
Save and exit (Ctrl+X, Y, Enter)
|
||||||
|
|
||||||
|
### Step 7: Install Dependencies
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Backend dependencies
|
||||||
|
npm ci --production
|
||||||
|
|
||||||
|
# Frontend dependencies and build
|
||||||
|
cd frontend
|
||||||
|
npm ci
|
||||||
|
npm run build
|
||||||
|
cd ..
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 8: Setup PM2
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Start application with PM2
|
||||||
|
pm2 start ecosystem.config.js --env production
|
||||||
|
|
||||||
|
# Save PM2 configuration
|
||||||
|
pm2 save
|
||||||
|
|
||||||
|
# Setup PM2 to start on boot
|
||||||
|
pm2 startup
|
||||||
|
# Follow the instructions provided by the command above
|
||||||
|
|
||||||
|
# Check status
|
||||||
|
pm2 status
|
||||||
|
pm2 logs turbotrades
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 9: Configure Nginx (Optional but Recommended)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo nano /etc/nginx/sites-available/turbotrades
|
||||||
|
```
|
||||||
|
|
||||||
|
Add the following configuration:
|
||||||
|
|
||||||
|
```nginx
|
||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
server_name 178.63.127.19 yourdomain.com;
|
||||||
|
|
||||||
|
# Frontend (Vite build)
|
||||||
|
location / {
|
||||||
|
root /var/www/turbotrades/frontend/dist;
|
||||||
|
try_files $uri $uri/ /index.html;
|
||||||
|
|
||||||
|
# Cache static assets
|
||||||
|
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
|
||||||
|
expires 1y;
|
||||||
|
add_header Cache-Control "public, immutable";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Backend API
|
||||||
|
location /api {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
# WebSocket support
|
||||||
|
location /ws {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Auth routes
|
||||||
|
location /auth {
|
||||||
|
proxy_pass http://localhost:3000;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Enable the site:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo ln -s /etc/nginx/sites-available/turbotrades /etc/nginx/sites-enabled/
|
||||||
|
sudo nginx -t
|
||||||
|
sudo systemctl restart nginx
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 10: Configure Firewall
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Allow SSH, HTTP, and HTTPS
|
||||||
|
sudo ufw allow 22/tcp
|
||||||
|
sudo ufw allow 80/tcp
|
||||||
|
sudo ufw allow 443/tcp
|
||||||
|
sudo ufw enable
|
||||||
|
sudo ufw status
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔐 GitHub Secrets Configuration
|
||||||
|
|
||||||
|
### Step 1: Go to GitHub Repository Settings
|
||||||
|
|
||||||
|
1. Go to your repository: `https://git.turbotrades.dev/iDefineHD/TurboTrades`
|
||||||
|
2. Click **Settings** → **Secrets** (or CI/CD settings depending on Gitea version)
|
||||||
|
3. Click **New repository secret**
|
||||||
|
|
||||||
|
### Step 2: Add Required Secrets
|
||||||
|
|
||||||
|
Add each of these secrets:
|
||||||
|
|
||||||
|
#### `SERVER_HOST`
|
||||||
|
```
|
||||||
|
178.63.127.19
|
||||||
|
```
|
||||||
|
|
||||||
|
#### `SERVER_USER`
|
||||||
|
```
|
||||||
|
root
|
||||||
|
```
|
||||||
|
(or your SSH username)
|
||||||
|
|
||||||
|
#### `SERVER_PORT`
|
||||||
|
```
|
||||||
|
22
|
||||||
|
```
|
||||||
|
|
||||||
|
#### `SSH_PRIVATE_KEY`
|
||||||
|
```
|
||||||
|
-----BEGIN OPENSSH PRIVATE KEY-----
|
||||||
|
[Your private key content from ~/.ssh/turbotrades_deploy_key]
|
||||||
|
-----END OPENSSH PRIVATE KEY-----
|
||||||
|
```
|
||||||
|
|
||||||
|
#### `DEPLOY_PATH`
|
||||||
|
```
|
||||||
|
/var/www/turbotrades
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 3: Add Deploy Key to GitHub (If Using SSH)
|
||||||
|
|
||||||
|
1. Go to **Settings** → **Deploy keys**
|
||||||
|
2. Click **Add deploy key**
|
||||||
|
3. Title: `Production Server 178.63.127.19`
|
||||||
|
4. Key: Paste your public key from `~/.ssh/turbotrades_deploy_key.pub`
|
||||||
|
5. ✅ Check **Allow write access** (if needed)
|
||||||
|
6. Click **Add key**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🚀 Initial Deployment
|
||||||
|
|
||||||
|
### Method 1: Manual Initial Setup (Recommended)
|
||||||
|
|
||||||
|
Already completed in [Server Setup](#server-setup) above!
|
||||||
|
|
||||||
|
### Method 2: Using PM2 Deploy
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# From your local machine
|
||||||
|
pm2 deploy ecosystem.config.js production setup
|
||||||
|
pm2 deploy ecosystem.config.js production
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔄 Automatic Deployments
|
||||||
|
|
||||||
|
### How It Works
|
||||||
|
|
||||||
|
The CI/CD workflow (`.github/workflows/deploy.yml`) automatically deploys when:
|
||||||
|
1. You push to the `main` branch
|
||||||
|
2. You manually trigger the workflow
|
||||||
|
|
||||||
|
### Deployment Process
|
||||||
|
|
||||||
|
1. **Trigger**: Push to `main` branch
|
||||||
|
```bash
|
||||||
|
git add .
|
||||||
|
git commit -m "feat: Add new feature"
|
||||||
|
git push origin main
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **CI/CD Pipeline**: Automatically runs
|
||||||
|
- ✅ Checks out code
|
||||||
|
- ✅ Builds frontend
|
||||||
|
- ✅ Runs tests
|
||||||
|
- ✅ Deploys to server via SSH
|
||||||
|
- ✅ Restarts PM2
|
||||||
|
- ✅ Runs health check
|
||||||
|
- ✅ Rolls back if failed
|
||||||
|
|
||||||
|
3. **Monitor**: Check repository Actions tab for progress
|
||||||
|
|
||||||
|
### Manual Trigger
|
||||||
|
|
||||||
|
1. Go to **Actions** tab on GitHub
|
||||||
|
2. Select **Deploy to Production Server**
|
||||||
|
3. Click **Run workflow**
|
||||||
|
4. Select branch (usually `main`)
|
||||||
|
5. Click **Run workflow**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🛠️ Manual Deployment
|
||||||
|
|
||||||
|
### Quick Deploy (SSH to Server)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# SSH into server
|
||||||
|
ssh root@178.63.127.19
|
||||||
|
|
||||||
|
# Navigate to project
|
||||||
|
cd /var/www/turbotrades
|
||||||
|
|
||||||
|
# Pull latest changes
|
||||||
|
git pull origin main
|
||||||
|
|
||||||
|
# Install dependencies
|
||||||
|
npm ci --production
|
||||||
|
cd frontend && npm ci && npm run build && cd ..
|
||||||
|
|
||||||
|
# Restart application
|
||||||
|
pm2 restart turbotrades
|
||||||
|
|
||||||
|
# Check status
|
||||||
|
pm2 status
|
||||||
|
pm2 logs turbotrades --lines 50
|
||||||
|
```
|
||||||
|
|
||||||
|
### Using PM2 Deploy Command
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# From your local machine
|
||||||
|
pm2 deploy ecosystem.config.js production update
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📊 Monitoring & Maintenance
|
||||||
|
|
||||||
|
### Check Application Status
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# SSH into server
|
||||||
|
ssh root@178.63.127.19
|
||||||
|
|
||||||
|
# Check PM2 status
|
||||||
|
pm2 status
|
||||||
|
|
||||||
|
# View logs
|
||||||
|
pm2 logs turbotrades
|
||||||
|
|
||||||
|
# View last 100 lines
|
||||||
|
pm2 logs turbotrades --lines 100
|
||||||
|
|
||||||
|
# View only errors
|
||||||
|
pm2 logs turbotrades --err
|
||||||
|
|
||||||
|
# Monitor in real-time
|
||||||
|
pm2 monit
|
||||||
|
```
|
||||||
|
|
||||||
|
### Check Server Resources
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# CPU and Memory usage
|
||||||
|
htop
|
||||||
|
|
||||||
|
# Disk usage
|
||||||
|
df -h
|
||||||
|
|
||||||
|
# Check MongoDB status
|
||||||
|
sudo systemctl status mongod
|
||||||
|
|
||||||
|
# Check Nginx status
|
||||||
|
sudo systemctl status nginx
|
||||||
|
```
|
||||||
|
|
||||||
|
### Database Backup
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Create backup directory
|
||||||
|
mkdir -p /var/backups/turbotrades
|
||||||
|
|
||||||
|
# Backup MongoDB
|
||||||
|
mongodump --out /var/backups/turbotrades/backup-$(date +%Y%m%d-%H%M%S)
|
||||||
|
|
||||||
|
# Automated daily backup (add to crontab)
|
||||||
|
crontab -e
|
||||||
|
# Add this line:
|
||||||
|
0 2 * * * mongodump --out /var/backups/turbotrades/backup-$(date +\%Y\%m\%d)
|
||||||
|
```
|
||||||
|
|
||||||
|
### View Application Logs
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# PM2 logs
|
||||||
|
pm2 logs turbotrades
|
||||||
|
|
||||||
|
# Application logs (if file-based)
|
||||||
|
tail -f /var/www/turbotrades/logs/app.log
|
||||||
|
|
||||||
|
# Nginx access logs
|
||||||
|
tail -f /var/log/nginx/access.log
|
||||||
|
|
||||||
|
# Nginx error logs
|
||||||
|
tail -f /var/log/nginx/error.log
|
||||||
|
```
|
||||||
|
|
||||||
|
### Restart Services
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Restart application
|
||||||
|
pm2 restart turbotrades
|
||||||
|
|
||||||
|
# Restart all PM2 apps
|
||||||
|
pm2 restart all
|
||||||
|
|
||||||
|
# Restart MongoDB
|
||||||
|
sudo systemctl restart mongod
|
||||||
|
|
||||||
|
# Restart Nginx
|
||||||
|
sudo systemctl restart nginx
|
||||||
|
|
||||||
|
# Reload Nginx (without downtime)
|
||||||
|
sudo systemctl reload nginx
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🐛 Troubleshooting
|
||||||
|
|
||||||
|
### Issue: Application Won't Start
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Check PM2 logs
|
||||||
|
pm2 logs turbotrades --err
|
||||||
|
|
||||||
|
# Check if port is already in use
|
||||||
|
sudo lsof -i :3000
|
||||||
|
|
||||||
|
# Check environment variables
|
||||||
|
pm2 show turbotrades
|
||||||
|
|
||||||
|
# Restart with fresh environment
|
||||||
|
pm2 delete turbotrades
|
||||||
|
pm2 start ecosystem.config.js --env production
|
||||||
|
```
|
||||||
|
|
||||||
|
### Issue: Cannot Connect to Database
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Check MongoDB status
|
||||||
|
sudo systemctl status mongod
|
||||||
|
|
||||||
|
# Start MongoDB
|
||||||
|
sudo systemctl start mongod
|
||||||
|
|
||||||
|
# Check MongoDB logs
|
||||||
|
sudo tail -f /var/log/mongodb/mongod.log
|
||||||
|
|
||||||
|
# Test MongoDB connection
|
||||||
|
mongosh
|
||||||
|
```
|
||||||
|
|
||||||
|
### Issue: "Permission Denied" Errors
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Fix ownership
|
||||||
|
sudo chown -R $USER:$USER /var/www/turbotrades
|
||||||
|
|
||||||
|
# Fix permissions
|
||||||
|
chmod -R 755 /var/www/turbotrades
|
||||||
|
```
|
||||||
|
|
||||||
|
### Issue: CI/CD Deployment Fails
|
||||||
|
|
||||||
|
1. **Check CI/CD logs**
|
||||||
|
- Go to repository Actions tab
|
||||||
|
- Click on failed workflow
|
||||||
|
- Review error messages
|
||||||
|
|
||||||
|
2. **Verify Secrets**
|
||||||
|
- Settings → Secrets and variables → Actions
|
||||||
|
- Ensure all secrets are set correctly
|
||||||
|
|
||||||
|
3. **Test SSH Connection Manually**
|
||||||
|
```bash
|
||||||
|
ssh root@178.63.127.19
|
||||||
|
```
|
||||||
|
|
||||||
|
4. **Check Deployment Path**
|
||||||
|
```bash
|
||||||
|
ssh root@178.63.127.19 "ls -la /var/www/turbotrades"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Issue: 502 Bad Gateway (Nginx)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Check if app is running
|
||||||
|
pm2 status
|
||||||
|
|
||||||
|
# Restart application
|
||||||
|
pm2 restart turbotrades
|
||||||
|
|
||||||
|
# Check Nginx configuration
|
||||||
|
sudo nginx -t
|
||||||
|
|
||||||
|
# View Nginx error logs
|
||||||
|
sudo tail -f /var/log/nginx/error.log
|
||||||
|
```
|
||||||
|
|
||||||
|
### Issue: Out of Memory
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Check memory usage
|
||||||
|
free -h
|
||||||
|
|
||||||
|
# Increase PM2 memory limit
|
||||||
|
pm2 stop turbotrades
|
||||||
|
# Edit ecosystem.config.js and increase max_memory_restart
|
||||||
|
pm2 start ecosystem.config.js
|
||||||
|
|
||||||
|
# Add swap space (if needed)
|
||||||
|
sudo fallocate -l 2G /swapfile
|
||||||
|
sudo chmod 600 /swapfile
|
||||||
|
sudo mkswap /swapfile
|
||||||
|
sudo swapon /swapfile
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ⏮️ Rollback Procedures
|
||||||
|
|
||||||
|
### Automatic Rollback
|
||||||
|
|
||||||
|
The CI/CD workflow automatically rolls back if deployment fails.
|
||||||
|
|
||||||
|
### Manual Rollback
|
||||||
|
|
||||||
|
#### Method 1: Using Backups
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# SSH into server
|
||||||
|
ssh root@178.63.127.19
|
||||||
|
|
||||||
|
# List backups
|
||||||
|
ls -lt /var/www/ | grep turbotrades-backup
|
||||||
|
|
||||||
|
# Restore from backup
|
||||||
|
cd /var/www
|
||||||
|
rm -rf turbotrades/*
|
||||||
|
cp -r turbotrades-backup-YYYYMMDD-HHMMSS/* turbotrades/
|
||||||
|
|
||||||
|
# Restart application
|
||||||
|
cd turbotrades
|
||||||
|
pm2 restart turbotrades
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Method 2: Using Git
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# SSH into server
|
||||||
|
ssh root@178.63.127.19
|
||||||
|
cd /var/www/turbotrades
|
||||||
|
|
||||||
|
# View commit history
|
||||||
|
git log --oneline
|
||||||
|
|
||||||
|
# Rollback to specific commit
|
||||||
|
git reset --hard COMMIT_HASH
|
||||||
|
|
||||||
|
# Reinstall dependencies
|
||||||
|
npm ci --production
|
||||||
|
cd frontend && npm ci && npm run build && cd ..
|
||||||
|
|
||||||
|
# Restart
|
||||||
|
pm2 restart turbotrades
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Method 3: Rollback to Previous Tag
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# SSH into server
|
||||||
|
cd /var/www/turbotrades
|
||||||
|
|
||||||
|
# List tags
|
||||||
|
git tag -l
|
||||||
|
|
||||||
|
# Checkout specific tag
|
||||||
|
git checkout v1.0.0
|
||||||
|
|
||||||
|
# Rebuild and restart
|
||||||
|
npm ci --production
|
||||||
|
cd frontend && npm ci && npm run build && cd ..
|
||||||
|
pm2 restart turbotrades
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📝 Deployment Checklist
|
||||||
|
|
||||||
|
### Before Deployment
|
||||||
|
- [ ] All tests pass locally
|
||||||
|
- [ ] Environment variables configured
|
||||||
|
- [ ] Database migrations ready (if any)
|
||||||
|
- [ ] Backup current production data
|
||||||
|
- [ ] Notify team about deployment
|
||||||
|
|
||||||
|
### During Deployment
|
||||||
|
- [ ] Monitor CI/CD workflow
|
||||||
|
- [ ] Watch server logs
|
||||||
|
- [ ] Check PM2 status
|
||||||
|
- [ ] Verify health endpoint
|
||||||
|
|
||||||
|
### After Deployment
|
||||||
|
- [ ] Test critical features
|
||||||
|
- [ ] Check error logs
|
||||||
|
- [ ] Verify database connectivity
|
||||||
|
- [ ] Test admin panel
|
||||||
|
- [ ] Test user authentication
|
||||||
|
- [ ] Monitor performance metrics
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔒 Security Best Practices
|
||||||
|
|
||||||
|
1. **Keep Secrets Safe**
|
||||||
|
- Never commit `.env` file
|
||||||
|
- Use GitHub Secrets for sensitive data
|
||||||
|
- Rotate secrets regularly
|
||||||
|
|
||||||
|
2. **Keep Software Updated**
|
||||||
|
```bash
|
||||||
|
sudo apt update && sudo apt upgrade
|
||||||
|
npm update
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **Enable Firewall**
|
||||||
|
```bash
|
||||||
|
sudo ufw enable
|
||||||
|
sudo ufw status
|
||||||
|
```
|
||||||
|
|
||||||
|
4. **Use HTTPS** (Recommended)
|
||||||
|
```bash
|
||||||
|
sudo apt install certbot python3-certbot-nginx
|
||||||
|
sudo certbot --nginx -d yourdomain.com
|
||||||
|
```
|
||||||
|
|
||||||
|
5. **Regular Backups**
|
||||||
|
- Database backups daily
|
||||||
|
- Code backups before deployment
|
||||||
|
- Test restore procedures
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📞 Support & Resources
|
||||||
|
|
||||||
|
### Useful Commands
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Full deployment script
|
||||||
|
cd /var/www/turbotrades && \
|
||||||
|
git pull origin main && \
|
||||||
|
npm ci --production && \
|
||||||
|
cd frontend && npm ci && npm run build && cd .. && \
|
||||||
|
pm2 restart turbotrades && \
|
||||||
|
pm2 logs turbotrades --lines 20
|
||||||
|
|
||||||
|
# Quick restart
|
||||||
|
pm2 restart turbotrades && pm2 logs turbotrades
|
||||||
|
|
||||||
|
# Check everything
|
||||||
|
pm2 status && \
|
||||||
|
sudo systemctl status mongod && \
|
||||||
|
sudo systemctl status nginx
|
||||||
|
```
|
||||||
|
|
||||||
|
### Logs Locations
|
||||||
|
|
||||||
|
- PM2 Logs: `~/.pm2/logs/`
|
||||||
|
- Application Logs: `/var/www/turbotrades/logs/`
|
||||||
|
- Nginx Access: `/var/log/nginx/access.log`
|
||||||
|
- Nginx Error: `/var/log/nginx/error.log`
|
||||||
|
- MongoDB: `/var/log/mongodb/mongod.log`
|
||||||
|
|
||||||
|
### Performance Monitoring
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Install monitoring tools
|
||||||
|
sudo npm install -g pm2-logrotate
|
||||||
|
pm2 install pm2-logrotate
|
||||||
|
|
||||||
|
# Monitor resources
|
||||||
|
pm2 monit
|
||||||
|
htop
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🎯 Quick Reference
|
||||||
|
|
||||||
|
### Deploy from Local Machine
|
||||||
|
```bash
|
||||||
|
git add .
|
||||||
|
git commit -m "Your message"
|
||||||
|
git push origin main
|
||||||
|
# CI/CD pipeline handles the rest!
|
||||||
|
```
|
||||||
|
|
||||||
|
### Manual Deploy on Server
|
||||||
|
```bash
|
||||||
|
ssh root@178.63.127.19
|
||||||
|
cd /var/www/turbotrades
|
||||||
|
git pull && npm ci --production && cd frontend && npm ci && npm run build && cd .. && pm2 restart turbotrades
|
||||||
|
```
|
||||||
|
|
||||||
|
### Check Status
|
||||||
|
```bash
|
||||||
|
ssh root@178.63.127.19 "pm2 status && pm2 logs turbotrades --lines 20"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Emergency Restart
|
||||||
|
```bash
|
||||||
|
ssh root@178.63.127.19 "pm2 restart turbotrades"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**🎉 Your deployment is now automated and production-ready!**
|
||||||
|
|
||||||
|
For issues or questions, check the troubleshooting section or review the logs.
|
||||||
351
DEPLOY_NOW.md
Normal file
351
DEPLOY_NOW.md
Normal file
@@ -0,0 +1,351 @@
|
|||||||
|
# 🚀 Quick Deployment Guide for TurboTrades
|
||||||
|
|
||||||
|
**Server:** 178.63.127.19
|
||||||
|
**Repository:** git.turbotrades.dev/iDefineHD/TurboTrades
|
||||||
|
**User:** root (or your SSH user)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ⚡ Super Quick Deploy (5 Minutes)
|
||||||
|
|
||||||
|
### 1️⃣ **Push Your Code**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd C:\Users\dg-ho\Documents\projects\TurboTrades
|
||||||
|
|
||||||
|
git add .
|
||||||
|
git commit -m "feat: Complete admin panel with deployment setup"
|
||||||
|
git push origin main
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2️⃣ **Setup Server (One-Time)**
|
||||||
|
|
||||||
|
SSH into your server:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ssh root@178.63.127.19
|
||||||
|
```
|
||||||
|
|
||||||
|
Run the automated setup script:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Download and run setup script
|
||||||
|
curl -o setup.sh https://git.turbotrades.dev/iDefineHD/TurboTrades/raw/branch/main/scripts/setup-server.sh
|
||||||
|
chmod +x setup.sh
|
||||||
|
sudo ./setup.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
**OR** manually setup:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Update system
|
||||||
|
apt update && apt upgrade -y
|
||||||
|
|
||||||
|
# Install Node.js 20
|
||||||
|
curl -fsSL https://deb.nodesource.com/setup_20.x | bash -
|
||||||
|
apt-get install -y nodejs
|
||||||
|
|
||||||
|
# Install MongoDB
|
||||||
|
curl -fsSL https://www.mongodb.org/static/pgp/server-7.0.asc | gpg --dearmor -o /usr/share/keyrings/mongodb-server-7.0.gpg
|
||||||
|
echo "deb [ arch=amd64,arm64 signed-by=/usr/share/keyrings/mongodb-server-7.0.gpg ] https://repo.mongodb.org/apt/ubuntu $(lsb_release -cs)/mongodb-org/7.0 multiverse" | tee /etc/apt/sources.list.d/mongodb-org-7.0.list
|
||||||
|
apt update && apt install -y mongodb-org
|
||||||
|
systemctl start mongod && systemctl enable mongod
|
||||||
|
|
||||||
|
# Install PM2
|
||||||
|
npm install -g pm2
|
||||||
|
|
||||||
|
# Install Nginx
|
||||||
|
apt install -y nginx
|
||||||
|
systemctl start nginx && systemctl enable nginx
|
||||||
|
|
||||||
|
# Create directory
|
||||||
|
mkdir -p /var/www/turbotrades
|
||||||
|
cd /var/www/turbotrades
|
||||||
|
|
||||||
|
# Clone repository
|
||||||
|
git clone https://git.turbotrades.dev/iDefineHD/TurboTrades.git .
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3️⃣ **Configure Environment**
|
||||||
|
|
||||||
|
Create `.env` file on server:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
nano /var/www/turbotrades/.env
|
||||||
|
```
|
||||||
|
|
||||||
|
Add this configuration:
|
||||||
|
|
||||||
|
```env
|
||||||
|
# Server
|
||||||
|
NODE_ENV=production
|
||||||
|
PORT=3000
|
||||||
|
HOST=0.0.0.0
|
||||||
|
|
||||||
|
# Database
|
||||||
|
MONGODB_URI=mongodb://localhost:27017/turbotrades
|
||||||
|
|
||||||
|
# Secrets (CHANGE THESE!)
|
||||||
|
SESSION_SECRET=your-random-secret-here-change-this-123456789
|
||||||
|
JWT_SECRET=your-jwt-secret-here-change-this-987654321
|
||||||
|
JWT_ACCESS_EXPIRY=15m
|
||||||
|
JWT_REFRESH_EXPIRY=7d
|
||||||
|
|
||||||
|
# Steam API
|
||||||
|
STEAM_API_KEY=your-steam-api-key
|
||||||
|
STEAM_RETURN_URL=http://178.63.127.19:3000/auth/steam/return
|
||||||
|
|
||||||
|
# CORS
|
||||||
|
CORS_ORIGIN=http://178.63.127.19
|
||||||
|
|
||||||
|
# Admin Steam IDs (Your Steam ID)
|
||||||
|
ADMIN_STEAM_IDS=76561198000000000
|
||||||
|
|
||||||
|
# Optional: Steam Bot
|
||||||
|
STEAM_BOT_USERNAME=
|
||||||
|
STEAM_BOT_PASSWORD=
|
||||||
|
STEAM_BOT_SHARED_SECRET=
|
||||||
|
STEAM_BOT_IDENTITY_SECRET=
|
||||||
|
```
|
||||||
|
|
||||||
|
Save with `Ctrl+X`, then `Y`, then `Enter`
|
||||||
|
|
||||||
|
### 4️⃣ **Deploy Application**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd /var/www/turbotrades
|
||||||
|
|
||||||
|
# Install dependencies
|
||||||
|
npm ci --production
|
||||||
|
|
||||||
|
# Build frontend
|
||||||
|
cd frontend
|
||||||
|
npm ci
|
||||||
|
npm run build
|
||||||
|
cd ..
|
||||||
|
|
||||||
|
# Start with PM2
|
||||||
|
pm2 start ecosystem.config.js --env production
|
||||||
|
pm2 save
|
||||||
|
pm2 startup
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5️⃣ **Configure Nginx (Optional but Recommended)**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
nano /etc/nginx/sites-available/turbotrades
|
||||||
|
```
|
||||||
|
|
||||||
|
Paste this:
|
||||||
|
|
||||||
|
```nginx
|
||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
server_name 178.63.127.19;
|
||||||
|
|
||||||
|
location / {
|
||||||
|
root /var/www/turbotrades/frontend/dist;
|
||||||
|
try_files $uri $uri/ /index.html;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /api {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /ws {
|
||||||
|
proxy_pass http://localhost:3000;
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
|
proxy_set_header Connection "upgrade";
|
||||||
|
}
|
||||||
|
|
||||||
|
location /auth {
|
||||||
|
proxy_pass http://localhost:3000;
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Enable and restart:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ln -s /etc/nginx/sites-available/turbotrades /etc/nginx/sites-enabled/
|
||||||
|
nginx -t
|
||||||
|
systemctl restart nginx
|
||||||
|
```
|
||||||
|
|
||||||
|
### 6️⃣ **Configure GitHub Actions (Automatic Deployments)**
|
||||||
|
|
||||||
|
1. Go to your repository settings/secrets (Gitea CI/CD settings)
|
||||||
|
2. Click **"New repository secret"** or equivalent
|
||||||
|
3. Add these secrets:
|
||||||
|
|
||||||
|
| Name | Value |
|
||||||
|
|------|-------|
|
||||||
|
| `SERVER_HOST` | `178.63.127.19` |
|
||||||
|
| `SERVER_USER` | `root` (or your SSH username) |
|
||||||
|
| `SERVER_PORT` | `22` |
|
||||||
|
| `SSH_PRIVATE_KEY` | Your SSH private key (see below) |
|
||||||
|
| `DEPLOY_PATH` | `/var/www/turbotrades` |
|
||||||
|
|
||||||
|
#### Generate SSH Key for Deployment:
|
||||||
|
|
||||||
|
On your server:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ssh-keygen -t ed25519 -C "deploy@turbotrades" -f ~/.ssh/turbotrades_deploy
|
||||||
|
cat ~/.ssh/turbotrades_deploy.pub >> ~/.ssh/authorized_keys
|
||||||
|
cat ~/.ssh/turbotrades_deploy # Copy this for GitHub Secret
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🎯 After Setup - How to Deploy
|
||||||
|
|
||||||
|
### Automatic Deployment (Recommended):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Just push to main branch
|
||||||
|
git add .
|
||||||
|
git commit -m "Your changes"
|
||||||
|
git push origin main
|
||||||
|
```
|
||||||
|
|
||||||
|
GitHub Actions will automatically:
|
||||||
|
✅ Build frontend
|
||||||
|
✅ Deploy to server
|
||||||
|
✅ Restart PM2
|
||||||
|
✅ Health check
|
||||||
|
|
||||||
|
Watch progress in your Gitea repository's Actions tab
|
||||||
|
|
||||||
|
### Manual Deployment:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ssh root@178.63.127.19
|
||||||
|
cd /var/www/turbotrades
|
||||||
|
git pull origin main
|
||||||
|
npm ci --production
|
||||||
|
cd frontend && npm ci && npm run build && cd ..
|
||||||
|
pm2 restart turbotrades
|
||||||
|
pm2 logs turbotrades
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔍 Check Status
|
||||||
|
|
||||||
|
### From Your Computer:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Check if site is running
|
||||||
|
curl http://178.63.127.19:3000/api/health
|
||||||
|
|
||||||
|
# Check PM2 status via SSH
|
||||||
|
ssh root@178.63.127.19 "pm2 status"
|
||||||
|
|
||||||
|
# Check logs via SSH
|
||||||
|
ssh root@178.63.127.19 "pm2 logs turbotrades --lines 50"
|
||||||
|
```
|
||||||
|
|
||||||
|
### On Server:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ssh root@178.63.127.19
|
||||||
|
|
||||||
|
# Check PM2
|
||||||
|
pm2 status
|
||||||
|
pm2 logs turbotrades
|
||||||
|
|
||||||
|
# Check MongoDB
|
||||||
|
systemctl status mongod
|
||||||
|
|
||||||
|
# Check Nginx
|
||||||
|
systemctl status nginx
|
||||||
|
|
||||||
|
# Check application logs
|
||||||
|
tail -f /var/www/turbotrades/logs/pm2-combined.log
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🚨 Quick Fixes
|
||||||
|
|
||||||
|
### App Not Starting:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ssh root@178.63.127.19
|
||||||
|
cd /var/www/turbotrades
|
||||||
|
pm2 logs turbotrades --err
|
||||||
|
pm2 restart turbotrades
|
||||||
|
```
|
||||||
|
|
||||||
|
### MongoDB Not Running:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ssh root@178.63.127.19
|
||||||
|
systemctl start mongod
|
||||||
|
systemctl status mongod
|
||||||
|
```
|
||||||
|
|
||||||
|
### Need to Restart Everything:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ssh root@178.63.127.19
|
||||||
|
pm2 restart all
|
||||||
|
systemctl restart mongod
|
||||||
|
systemctl restart nginx
|
||||||
|
```
|
||||||
|
|
||||||
|
### Port 3000 Already in Use:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ssh root@178.63.127.19
|
||||||
|
lsof -i :3000
|
||||||
|
pm2 delete turbotrades
|
||||||
|
pm2 start ecosystem.config.js --env production
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📝 Important URLs
|
||||||
|
|
||||||
|
- **Gitea Repo:** https://git.turbotrades.dev/iDefineHD/TurboTrades
|
||||||
|
- **CI/CD Actions:** Check your Gitea repository's Actions tab
|
||||||
|
- **Repository Secrets:** https://git.turbotrades.dev/iDefineHD/TurboTrades/settings
|
||||||
|
- **Your Server:** http://178.63.127.19
|
||||||
|
- **API Health:** http://178.63.127.19:3000/api/health
|
||||||
|
- **Admin Panel:** http://178.63.127.19/admin
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🎉 You're Done!
|
||||||
|
|
||||||
|
Visit: **http://178.63.127.19**
|
||||||
|
|
||||||
|
Your admin panel is fully functional with:
|
||||||
|
- ✅ User Management
|
||||||
|
- ✅ Promotion Analytics
|
||||||
|
- ✅ Trading & Market Settings
|
||||||
|
- ✅ Announcements
|
||||||
|
- ✅ Maintenance Mode
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📞 Need Help?
|
||||||
|
|
||||||
|
1. Check server logs: `ssh root@178.63.127.19 "pm2 logs"`
|
||||||
|
2. Check Gitea Actions in your repository
|
||||||
|
3. Review full guide: `DEPLOYMENT_GUIDE.md`
|
||||||
|
|
||||||
|
**Happy deploying! 🚀**
|
||||||
@@ -1,318 +1,322 @@
|
|||||||
import { defineStore } from 'pinia'
|
import { defineStore } from "pinia";
|
||||||
import { ref, computed } from 'vue'
|
import { ref, computed } from "vue";
|
||||||
import { useAuthStore } from './auth'
|
import { useAuthStore } from "./auth";
|
||||||
import { useToast } from 'vue-toastification'
|
import { useToast } from "vue-toastification";
|
||||||
|
|
||||||
const toast = useToast()
|
const toast = useToast();
|
||||||
|
|
||||||
export const useWebSocketStore = defineStore('websocket', () => {
|
export const useWebSocketStore = defineStore("websocket", () => {
|
||||||
// State
|
// State
|
||||||
const ws = ref(null)
|
const ws = ref(null);
|
||||||
const isConnected = ref(false)
|
const isConnected = ref(false);
|
||||||
const isConnecting = ref(false)
|
const isConnecting = ref(false);
|
||||||
const reconnectAttempts = ref(0)
|
const reconnectAttempts = ref(0);
|
||||||
const maxReconnectAttempts = ref(5)
|
const maxReconnectAttempts = ref(5);
|
||||||
const reconnectDelay = ref(1000)
|
const reconnectDelay = ref(1000);
|
||||||
const heartbeatInterval = ref(null)
|
const heartbeatInterval = ref(null);
|
||||||
const reconnectTimeout = ref(null)
|
const reconnectTimeout = ref(null);
|
||||||
const messageQueue = ref([])
|
const messageQueue = ref([]);
|
||||||
const listeners = ref(new Map())
|
const listeners = ref(new Map());
|
||||||
|
|
||||||
// Computed
|
// Computed
|
||||||
const connectionStatus = computed(() => {
|
const connectionStatus = computed(() => {
|
||||||
if (isConnected.value) return 'connected'
|
if (isConnected.value) return "connected";
|
||||||
if (isConnecting.value) return 'connecting'
|
if (isConnecting.value) return "connecting";
|
||||||
return 'disconnected'
|
return "disconnected";
|
||||||
})
|
});
|
||||||
|
|
||||||
const canReconnect = computed(() => {
|
const canReconnect = computed(() => {
|
||||||
return reconnectAttempts.value < maxReconnectAttempts.value
|
return reconnectAttempts.value < maxReconnectAttempts.value;
|
||||||
})
|
});
|
||||||
|
|
||||||
// Helper functions
|
// Helper functions
|
||||||
const getWebSocketUrl = () => {
|
const getWebSocketUrl = () => {
|
||||||
const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:'
|
const protocol = window.location.protocol === "https:" ? "wss:" : "ws:";
|
||||||
const host = window.location.host
|
const host = window.location.host;
|
||||||
|
|
||||||
// In development, use the proxy
|
// Always use the current host (works with VS Code tunnels and proxies)
|
||||||
if (import.meta.env.DEV) {
|
return `${protocol}//${host}/ws`;
|
||||||
return `ws://localhost:3000/ws`
|
};
|
||||||
}
|
|
||||||
|
|
||||||
return `${protocol}//${host}/ws`
|
|
||||||
}
|
|
||||||
|
|
||||||
const clearHeartbeat = () => {
|
const clearHeartbeat = () => {
|
||||||
if (heartbeatInterval.value) {
|
if (heartbeatInterval.value) {
|
||||||
clearInterval(heartbeatInterval.value)
|
clearInterval(heartbeatInterval.value);
|
||||||
heartbeatInterval.value = null
|
heartbeatInterval.value = null;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const clearReconnectTimeout = () => {
|
const clearReconnectTimeout = () => {
|
||||||
if (reconnectTimeout.value) {
|
if (reconnectTimeout.value) {
|
||||||
clearTimeout(reconnectTimeout.value)
|
clearTimeout(reconnectTimeout.value);
|
||||||
reconnectTimeout.value = null
|
reconnectTimeout.value = null;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const startHeartbeat = () => {
|
const startHeartbeat = () => {
|
||||||
clearHeartbeat()
|
clearHeartbeat();
|
||||||
|
|
||||||
// Send ping every 30 seconds
|
// Send ping every 30 seconds
|
||||||
heartbeatInterval.value = setInterval(() => {
|
heartbeatInterval.value = setInterval(() => {
|
||||||
if (isConnected.value && ws.value?.readyState === WebSocket.OPEN) {
|
if (isConnected.value && ws.value?.readyState === WebSocket.OPEN) {
|
||||||
send({ type: 'ping' })
|
send({ type: "ping" });
|
||||||
}
|
|
||||||
}, 30000)
|
|
||||||
}
|
}
|
||||||
|
}, 30000);
|
||||||
|
};
|
||||||
|
|
||||||
// Actions
|
// Actions
|
||||||
const connect = () => {
|
const connect = () => {
|
||||||
if (ws.value?.readyState === WebSocket.OPEN || isConnecting.value) {
|
if (ws.value?.readyState === WebSocket.OPEN || isConnecting.value) {
|
||||||
console.log('WebSocket already connected or connecting')
|
console.log("WebSocket already connected or connecting");
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
isConnecting.value = true
|
isConnecting.value = true;
|
||||||
clearReconnectTimeout()
|
clearReconnectTimeout();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const wsUrl = getWebSocketUrl()
|
const wsUrl = getWebSocketUrl();
|
||||||
console.log('Connecting to WebSocket:', wsUrl)
|
console.log("Connecting to WebSocket:", wsUrl);
|
||||||
|
|
||||||
ws.value = new WebSocket(wsUrl)
|
ws.value = new WebSocket(wsUrl);
|
||||||
|
|
||||||
ws.value.onopen = () => {
|
ws.value.onopen = () => {
|
||||||
console.log('WebSocket connected')
|
console.log("WebSocket connected");
|
||||||
isConnected.value = true
|
isConnected.value = true;
|
||||||
isConnecting.value = false
|
isConnecting.value = false;
|
||||||
reconnectAttempts.value = 0
|
reconnectAttempts.value = 0;
|
||||||
|
|
||||||
startHeartbeat()
|
startHeartbeat();
|
||||||
|
|
||||||
// Send queued messages
|
// Send queued messages
|
||||||
while (messageQueue.value.length > 0) {
|
while (messageQueue.value.length > 0) {
|
||||||
const message = messageQueue.value.shift()
|
const message = messageQueue.value.shift();
|
||||||
send(message)
|
send(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Emit connected event
|
// Emit connected event
|
||||||
emit('connected', { timestamp: Date.now() })
|
emit("connected", { timestamp: Date.now() });
|
||||||
}
|
};
|
||||||
|
|
||||||
ws.value.onmessage = (event) => {
|
ws.value.onmessage = (event) => {
|
||||||
try {
|
try {
|
||||||
const data = JSON.parse(event.data)
|
const data = JSON.parse(event.data);
|
||||||
console.log('WebSocket message received:', data)
|
console.log("WebSocket message received:", data);
|
||||||
|
|
||||||
handleMessage(data)
|
handleMessage(data);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Failed to parse WebSocket message:', error)
|
console.error("Failed to parse WebSocket message:", error);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
ws.value.onerror = (error) => {
|
ws.value.onerror = (error) => {
|
||||||
console.error('WebSocket error:', error)
|
console.error("WebSocket error:", error);
|
||||||
isConnecting.value = false
|
isConnecting.value = false;
|
||||||
}
|
};
|
||||||
|
|
||||||
ws.value.onclose = (event) => {
|
ws.value.onclose = (event) => {
|
||||||
console.log('WebSocket closed:', event.code, event.reason)
|
console.log("WebSocket closed:", event.code, event.reason);
|
||||||
isConnected.value = false
|
isConnected.value = false;
|
||||||
isConnecting.value = false
|
isConnecting.value = false;
|
||||||
clearHeartbeat()
|
clearHeartbeat();
|
||||||
|
|
||||||
// Emit disconnected event
|
// Emit disconnected event
|
||||||
emit('disconnected', {
|
emit("disconnected", {
|
||||||
code: event.code,
|
code: event.code,
|
||||||
reason: event.reason,
|
reason: event.reason,
|
||||||
timestamp: Date.now()
|
timestamp: Date.now(),
|
||||||
})
|
});
|
||||||
|
|
||||||
// Attempt to reconnect
|
// Attempt to reconnect
|
||||||
if (!event.wasClean && canReconnect.value) {
|
if (!event.wasClean && canReconnect.value) {
|
||||||
scheduleReconnect()
|
scheduleReconnect();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
};
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Failed to create WebSocket connection:', error)
|
console.error("Failed to create WebSocket connection:", error);
|
||||||
isConnecting.value = false
|
isConnecting.value = false;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const disconnect = () => {
|
const disconnect = () => {
|
||||||
clearHeartbeat()
|
clearHeartbeat();
|
||||||
clearReconnectTimeout()
|
clearReconnectTimeout();
|
||||||
reconnectAttempts.value = maxReconnectAttempts.value // Prevent auto-reconnect
|
reconnectAttempts.value = maxReconnectAttempts.value; // Prevent auto-reconnect
|
||||||
|
|
||||||
if (ws.value) {
|
if (ws.value) {
|
||||||
ws.value.close(1000, 'Client disconnect')
|
ws.value.close(1000, "Client disconnect");
|
||||||
ws.value = null
|
ws.value = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
isConnected.value = false
|
isConnected.value = false;
|
||||||
isConnecting.value = false
|
isConnecting.value = false;
|
||||||
}
|
};
|
||||||
|
|
||||||
const scheduleReconnect = () => {
|
const scheduleReconnect = () => {
|
||||||
if (!canReconnect.value) {
|
if (!canReconnect.value) {
|
||||||
console.log('Max reconnect attempts reached')
|
console.log("Max reconnect attempts reached");
|
||||||
toast.error('Lost connection to server. Please refresh the page.')
|
toast.error("Lost connection to server. Please refresh the page.");
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
reconnectAttempts.value++
|
reconnectAttempts.value++;
|
||||||
const delay = reconnectDelay.value * Math.pow(2, reconnectAttempts.value - 1)
|
const delay =
|
||||||
|
reconnectDelay.value * Math.pow(2, reconnectAttempts.value - 1);
|
||||||
|
|
||||||
console.log(`Reconnecting in ${delay}ms (attempt ${reconnectAttempts.value}/${maxReconnectAttempts.value})`)
|
console.log(
|
||||||
|
`Reconnecting in ${delay}ms (attempt ${reconnectAttempts.value}/${maxReconnectAttempts.value})`
|
||||||
|
);
|
||||||
|
|
||||||
clearReconnectTimeout()
|
clearReconnectTimeout();
|
||||||
reconnectTimeout.value = setTimeout(() => {
|
reconnectTimeout.value = setTimeout(() => {
|
||||||
connect()
|
connect();
|
||||||
}, delay)
|
}, delay);
|
||||||
}
|
};
|
||||||
|
|
||||||
const send = (message) => {
|
const send = (message) => {
|
||||||
if (!ws.value || ws.value.readyState !== WebSocket.OPEN) {
|
if (!ws.value || ws.value.readyState !== WebSocket.OPEN) {
|
||||||
console.warn('WebSocket not connected, queueing message:', message)
|
console.warn("WebSocket not connected, queueing message:", message);
|
||||||
messageQueue.value.push(message)
|
messageQueue.value.push(message);
|
||||||
return false
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const payload = typeof message === 'string' ? message : JSON.stringify(message)
|
const payload =
|
||||||
ws.value.send(payload)
|
typeof message === "string" ? message : JSON.stringify(message);
|
||||||
return true
|
ws.value.send(payload);
|
||||||
|
return true;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Failed to send WebSocket message:', error)
|
console.error("Failed to send WebSocket message:", error);
|
||||||
return false
|
return false;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const handleMessage = (data) => {
|
const handleMessage = (data) => {
|
||||||
const { type, data: payload, timestamp } = data
|
const { type, data: payload, timestamp } = data;
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case 'connected':
|
case "connected":
|
||||||
console.log('Server confirmed connection:', payload)
|
console.log("Server confirmed connection:", payload);
|
||||||
break
|
break;
|
||||||
|
|
||||||
case 'pong':
|
case "pong":
|
||||||
// Heartbeat response
|
// Heartbeat response
|
||||||
break
|
break;
|
||||||
|
|
||||||
case 'notification':
|
case "notification":
|
||||||
if (payload?.message) {
|
if (payload?.message) {
|
||||||
toast.info(payload.message)
|
toast.info(payload.message);
|
||||||
}
|
}
|
||||||
break
|
break;
|
||||||
|
|
||||||
case 'balance_update':
|
case "balance_update":
|
||||||
// Update user balance
|
// Update user balance
|
||||||
const authStore = useAuthStore()
|
const authStore = useAuthStore();
|
||||||
if (payload?.balance !== undefined) {
|
if (payload?.balance !== undefined) {
|
||||||
authStore.updateBalance(payload.balance)
|
authStore.updateBalance(payload.balance);
|
||||||
}
|
}
|
||||||
break
|
break;
|
||||||
|
|
||||||
case 'item_sold':
|
case "item_sold":
|
||||||
toast.success(`Your item "${payload?.itemName || 'item'}" has been sold!`)
|
toast.success(
|
||||||
break
|
`Your item "${payload?.itemName || "item"}" has been sold!`
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
|
||||||
case 'item_purchased':
|
case "item_purchased":
|
||||||
toast.success(`Successfully purchased "${payload?.itemName || 'item'}"!`)
|
toast.success(
|
||||||
break
|
`Successfully purchased "${payload?.itemName || "item"}"!`
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
|
||||||
case 'trade_status':
|
case "trade_status":
|
||||||
if (payload?.status === 'completed') {
|
if (payload?.status === "completed") {
|
||||||
toast.success('Trade completed successfully!')
|
toast.success("Trade completed successfully!");
|
||||||
} else if (payload?.status === 'failed') {
|
} else if (payload?.status === "failed") {
|
||||||
toast.error(`Trade failed: ${payload?.reason || 'Unknown error'}`)
|
toast.error(`Trade failed: ${payload?.reason || "Unknown error"}`);
|
||||||
}
|
}
|
||||||
break
|
break;
|
||||||
|
|
||||||
case 'price_update':
|
case "price_update":
|
||||||
case 'listing_update':
|
case "listing_update":
|
||||||
case 'market_update':
|
case "market_update":
|
||||||
// These will be handled by listeners
|
// These will be handled by listeners
|
||||||
break
|
break;
|
||||||
|
|
||||||
case 'announcement':
|
case "announcement":
|
||||||
if (payload?.message) {
|
if (payload?.message) {
|
||||||
toast.warning(payload.message, { timeout: 10000 })
|
toast.warning(payload.message, { timeout: 10000 });
|
||||||
}
|
}
|
||||||
break
|
break;
|
||||||
|
|
||||||
case 'error':
|
case "error":
|
||||||
console.error('Server error:', payload)
|
console.error("Server error:", payload);
|
||||||
if (payload?.message) {
|
if (payload?.message) {
|
||||||
toast.error(payload.message)
|
toast.error(payload.message);
|
||||||
}
|
}
|
||||||
break
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
console.log('Unhandled message type:', type)
|
console.log("Unhandled message type:", type);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Emit to listeners
|
// Emit to listeners
|
||||||
emit(type, payload)
|
emit(type, payload);
|
||||||
}
|
};
|
||||||
|
|
||||||
const on = (event, callback) => {
|
const on = (event, callback) => {
|
||||||
if (!listeners.value.has(event)) {
|
if (!listeners.value.has(event)) {
|
||||||
listeners.value.set(event, [])
|
listeners.value.set(event, []);
|
||||||
}
|
}
|
||||||
listeners.value.get(event).push(callback)
|
listeners.value.get(event).push(callback);
|
||||||
|
|
||||||
// Return unsubscribe function
|
// Return unsubscribe function
|
||||||
return () => off(event, callback)
|
return () => off(event, callback);
|
||||||
}
|
};
|
||||||
|
|
||||||
const off = (event, callback) => {
|
const off = (event, callback) => {
|
||||||
if (!listeners.value.has(event)) return
|
if (!listeners.value.has(event)) return;
|
||||||
|
|
||||||
const callbacks = listeners.value.get(event)
|
const callbacks = listeners.value.get(event);
|
||||||
const index = callbacks.indexOf(callback)
|
const index = callbacks.indexOf(callback);
|
||||||
|
|
||||||
if (index > -1) {
|
if (index > -1) {
|
||||||
callbacks.splice(index, 1)
|
callbacks.splice(index, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (callbacks.length === 0) {
|
if (callbacks.length === 0) {
|
||||||
listeners.value.delete(event)
|
listeners.value.delete(event);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const emit = (event, data) => {
|
const emit = (event, data) => {
|
||||||
if (!listeners.value.has(event)) return
|
if (!listeners.value.has(event)) return;
|
||||||
|
|
||||||
const callbacks = listeners.value.get(event)
|
const callbacks = listeners.value.get(event);
|
||||||
callbacks.forEach(callback => {
|
callbacks.forEach((callback) => {
|
||||||
try {
|
try {
|
||||||
callback(data)
|
callback(data);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(`Error in event listener for "${event}":`, error)
|
console.error(`Error in event listener for "${event}":`, error);
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
const once = (event, callback) => {
|
const once = (event, callback) => {
|
||||||
const wrappedCallback = (data) => {
|
const wrappedCallback = (data) => {
|
||||||
callback(data)
|
callback(data);
|
||||||
off(event, wrappedCallback)
|
off(event, wrappedCallback);
|
||||||
}
|
};
|
||||||
return on(event, wrappedCallback)
|
return on(event, wrappedCallback);
|
||||||
}
|
};
|
||||||
|
|
||||||
const clearListeners = () => {
|
const clearListeners = () => {
|
||||||
listeners.value.clear()
|
listeners.value.clear();
|
||||||
}
|
};
|
||||||
|
|
||||||
// Ping the server
|
// Ping the server
|
||||||
const ping = () => {
|
const ping = () => {
|
||||||
send({ type: 'ping' })
|
send({ type: "ping" });
|
||||||
}
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
// State
|
// State
|
||||||
@@ -337,5 +341,5 @@ export const useWebSocketStore = defineStore('websocket', () => {
|
|||||||
emit,
|
emit,
|
||||||
clearListeners,
|
clearListeners,
|
||||||
ping,
|
ping,
|
||||||
}
|
};
|
||||||
})
|
});
|
||||||
|
|||||||
@@ -12,6 +12,13 @@ export default defineConfig({
|
|||||||
},
|
},
|
||||||
server: {
|
server: {
|
||||||
port: 5173,
|
port: 5173,
|
||||||
|
host: true, // Listen on all addresses
|
||||||
|
allowedHosts: [
|
||||||
|
".trycloudflare.com", // Cloudflare Quick Tunnels
|
||||||
|
".turbo.local", // Custom tunnel domains
|
||||||
|
".devtunnels.ms", // VS Code Dev Tunnels
|
||||||
|
"localhost",
|
||||||
|
],
|
||||||
proxy: {
|
proxy: {
|
||||||
"/api": {
|
"/api": {
|
||||||
target: "http://localhost:3000",
|
target: "http://localhost:3000",
|
||||||
@@ -19,8 +26,9 @@ export default defineConfig({
|
|||||||
// Don't rewrite - backend expects /api prefix
|
// Don't rewrite - backend expects /api prefix
|
||||||
},
|
},
|
||||||
"/ws": {
|
"/ws": {
|
||||||
target: "ws://localhost:3000",
|
target: "http://localhost:3000",
|
||||||
ws: true,
|
ws: true,
|
||||||
|
changeOrigin: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
459
scripts/setup-server.sh
Normal file
459
scripts/setup-server.sh
Normal file
@@ -0,0 +1,459 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
#######################################################
|
||||||
|
# TurboTrades Server Setup Script
|
||||||
|
# Automated setup for production server 178.63.127.19
|
||||||
|
#######################################################
|
||||||
|
|
||||||
|
set -e # Exit on error
|
||||||
|
|
||||||
|
# Colors for output
|
||||||
|
RED='\033[0;31m'
|
||||||
|
GREEN='\033[0;32m'
|
||||||
|
YELLOW='\033[1;33m'
|
||||||
|
BLUE='\033[0;34m'
|
||||||
|
NC='\033[0m' # No Color
|
||||||
|
|
||||||
|
# Configuration
|
||||||
|
SERVER_IP="178.63.127.19"
|
||||||
|
DEPLOY_PATH="/var/www/turbotrades"
|
||||||
|
APP_NAME="turbotrades"
|
||||||
|
NODE_VERSION="20"
|
||||||
|
|
||||||
|
# Functions
|
||||||
|
print_status() {
|
||||||
|
echo -e "${BLUE}[INFO]${NC} $1"
|
||||||
|
}
|
||||||
|
|
||||||
|
print_success() {
|
||||||
|
echo -e "${GREEN}[SUCCESS]${NC} $1"
|
||||||
|
}
|
||||||
|
|
||||||
|
print_warning() {
|
||||||
|
echo -e "${YELLOW}[WARNING]${NC} $1"
|
||||||
|
}
|
||||||
|
|
||||||
|
print_error() {
|
||||||
|
echo -e "${RED}[ERROR]${NC} $1"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Check if running as root
|
||||||
|
check_root() {
|
||||||
|
if [[ $EUID -ne 0 ]]; then
|
||||||
|
print_warning "This script should be run as root. Some commands may require sudo."
|
||||||
|
read -p "Continue anyway? (y/n) " -n 1 -r
|
||||||
|
echo
|
||||||
|
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Update system
|
||||||
|
update_system() {
|
||||||
|
print_status "Updating system packages..."
|
||||||
|
apt update && apt upgrade -y
|
||||||
|
print_success "System updated"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Install Node.js
|
||||||
|
install_nodejs() {
|
||||||
|
print_status "Installing Node.js ${NODE_VERSION}..."
|
||||||
|
|
||||||
|
if command -v node &> /dev/null; then
|
||||||
|
NODE_CURRENT=$(node -v)
|
||||||
|
print_warning "Node.js is already installed: $NODE_CURRENT"
|
||||||
|
read -p "Reinstall/Update? (y/n) " -n 1 -r
|
||||||
|
echo
|
||||||
|
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
curl -fsSL https://deb.nodesource.com/setup_${NODE_VERSION}.x | bash -
|
||||||
|
apt-get install -y nodejs
|
||||||
|
|
||||||
|
print_success "Node.js installed: $(node -v)"
|
||||||
|
print_success "NPM installed: $(npm -v)"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Install MongoDB
|
||||||
|
install_mongodb() {
|
||||||
|
print_status "Installing MongoDB..."
|
||||||
|
|
||||||
|
if command -v mongod &> /dev/null; then
|
||||||
|
print_warning "MongoDB is already installed"
|
||||||
|
read -p "Reinstall? (y/n) " -n 1 -r
|
||||||
|
echo
|
||||||
|
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Import MongoDB public key
|
||||||
|
curl -fsSL https://www.mongodb.org/static/pgp/server-7.0.asc | \
|
||||||
|
gpg --dearmor -o /usr/share/keyrings/mongodb-server-7.0.gpg
|
||||||
|
|
||||||
|
# Add MongoDB repository
|
||||||
|
echo "deb [ arch=amd64,arm64 signed-by=/usr/share/keyrings/mongodb-server-7.0.gpg ] https://repo.mongodb.org/apt/ubuntu $(lsb_release -cs)/mongodb-org/7.0 multiverse" | \
|
||||||
|
tee /etc/apt/sources.list.d/mongodb-org-7.0.list
|
||||||
|
|
||||||
|
# Install MongoDB
|
||||||
|
apt update
|
||||||
|
apt install -y mongodb-org
|
||||||
|
|
||||||
|
# Start and enable MongoDB
|
||||||
|
systemctl start mongod
|
||||||
|
systemctl enable mongod
|
||||||
|
|
||||||
|
print_success "MongoDB installed and started"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Install PM2
|
||||||
|
install_pm2() {
|
||||||
|
print_status "Installing PM2..."
|
||||||
|
|
||||||
|
if command -v pm2 &> /dev/null; then
|
||||||
|
print_warning "PM2 is already installed: $(pm2 -v)"
|
||||||
|
read -p "Reinstall? (y/n) " -n 1 -r
|
||||||
|
echo
|
||||||
|
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
npm install -g pm2
|
||||||
|
|
||||||
|
# Setup PM2 startup script
|
||||||
|
pm2 startup systemd -u $SUDO_USER --hp /home/$SUDO_USER
|
||||||
|
|
||||||
|
print_success "PM2 installed: $(pm2 -v)"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Install Nginx
|
||||||
|
install_nginx() {
|
||||||
|
print_status "Installing Nginx..."
|
||||||
|
|
||||||
|
if command -v nginx &> /dev/null; then
|
||||||
|
print_warning "Nginx is already installed"
|
||||||
|
read -p "Continue anyway? (y/n) " -n 1 -r
|
||||||
|
echo
|
||||||
|
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
apt install -y nginx
|
||||||
|
systemctl start nginx
|
||||||
|
systemctl enable nginx
|
||||||
|
|
||||||
|
print_success "Nginx installed and started"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Install Git
|
||||||
|
install_git() {
|
||||||
|
print_status "Installing Git..."
|
||||||
|
|
||||||
|
if command -v git &> /dev/null; then
|
||||||
|
print_success "Git is already installed: $(git --version)"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
apt install -y git
|
||||||
|
print_success "Git installed: $(git --version)"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Create deployment directory
|
||||||
|
create_deploy_directory() {
|
||||||
|
print_status "Creating deployment directory: ${DEPLOY_PATH}"
|
||||||
|
|
||||||
|
mkdir -p ${DEPLOY_PATH}
|
||||||
|
|
||||||
|
# Set ownership to current user
|
||||||
|
if [ -n "$SUDO_USER" ]; then
|
||||||
|
chown -R $SUDO_USER:$SUDO_USER ${DEPLOY_PATH}
|
||||||
|
fi
|
||||||
|
|
||||||
|
print_success "Deployment directory created"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Setup firewall
|
||||||
|
setup_firewall() {
|
||||||
|
print_status "Configuring firewall..."
|
||||||
|
|
||||||
|
if ! command -v ufw &> /dev/null; then
|
||||||
|
apt install -y ufw
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Allow SSH, HTTP, HTTPS
|
||||||
|
ufw allow 22/tcp
|
||||||
|
ufw allow 80/tcp
|
||||||
|
ufw allow 443/tcp
|
||||||
|
|
||||||
|
# Enable firewall
|
||||||
|
ufw --force enable
|
||||||
|
|
||||||
|
print_success "Firewall configured"
|
||||||
|
ufw status
|
||||||
|
}
|
||||||
|
|
||||||
|
# Generate SSH deploy key
|
||||||
|
generate_deploy_key() {
|
||||||
|
print_status "Generating SSH deploy key..."
|
||||||
|
|
||||||
|
SSH_DIR="/home/$SUDO_USER/.ssh"
|
||||||
|
DEPLOY_KEY="$SSH_DIR/turbotrades_deploy_key"
|
||||||
|
|
||||||
|
if [ -f "$DEPLOY_KEY" ]; then
|
||||||
|
print_warning "Deploy key already exists at $DEPLOY_KEY"
|
||||||
|
read -p "Generate new key? (y/n) " -n 1 -r
|
||||||
|
echo
|
||||||
|
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
mkdir -p $SSH_DIR
|
||||||
|
ssh-keygen -t ed25519 -C "deploy@turbotrades" -f $DEPLOY_KEY -N ""
|
||||||
|
|
||||||
|
chown -R $SUDO_USER:$SUDO_USER $SSH_DIR
|
||||||
|
chmod 700 $SSH_DIR
|
||||||
|
chmod 600 $DEPLOY_KEY
|
||||||
|
chmod 644 $DEPLOY_KEY.pub
|
||||||
|
|
||||||
|
print_success "Deploy key generated!"
|
||||||
|
echo ""
|
||||||
|
print_status "=== PUBLIC KEY (Add to GitHub Deploy Keys) ==="
|
||||||
|
cat $DEPLOY_KEY.pub
|
||||||
|
echo ""
|
||||||
|
print_status "=== PRIVATE KEY (Add to GitHub Secrets as SSH_PRIVATE_KEY) ==="
|
||||||
|
cat $DEPLOY_KEY
|
||||||
|
echo ""
|
||||||
|
print_warning "Save these keys securely!"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Create .env template
|
||||||
|
create_env_template() {
|
||||||
|
print_status "Creating .env template..."
|
||||||
|
|
||||||
|
ENV_FILE="${DEPLOY_PATH}/.env.example"
|
||||||
|
|
||||||
|
cat > $ENV_FILE << 'EOF'
|
||||||
|
# Server Configuration
|
||||||
|
NODE_ENV=production
|
||||||
|
PORT=3000
|
||||||
|
HOST=0.0.0.0
|
||||||
|
|
||||||
|
# Database
|
||||||
|
MONGODB_URI=mongodb://localhost:27017/turbotrades
|
||||||
|
|
||||||
|
# Session Secret (Generate a secure random string)
|
||||||
|
SESSION_SECRET=change-this-to-a-random-string
|
||||||
|
|
||||||
|
# Steam API
|
||||||
|
STEAM_API_KEY=your-steam-api-key-here
|
||||||
|
STEAM_RETURN_URL=http://178.63.127.19:3000/auth/steam/return
|
||||||
|
|
||||||
|
# JWT Secret (Generate a secure random string)
|
||||||
|
JWT_SECRET=change-this-to-a-random-string
|
||||||
|
JWT_ACCESS_EXPIRY=15m
|
||||||
|
JWT_REFRESH_EXPIRY=7d
|
||||||
|
|
||||||
|
# CORS
|
||||||
|
CORS_ORIGIN=http://178.63.127.19
|
||||||
|
|
||||||
|
# Redis (if using)
|
||||||
|
REDIS_URL=redis://localhost:6379
|
||||||
|
|
||||||
|
# Admin Steam IDs (comma-separated)
|
||||||
|
ADMIN_STEAM_IDS=76561198000000000
|
||||||
|
|
||||||
|
# Bot Configuration
|
||||||
|
STEAM_BOT_USERNAME=your-bot-username
|
||||||
|
STEAM_BOT_PASSWORD=your-bot-password
|
||||||
|
STEAM_BOT_SHARED_SECRET=your-bot-shared-secret
|
||||||
|
STEAM_BOT_IDENTITY_SECRET=your-bot-identity-secret
|
||||||
|
|
||||||
|
# CSGOFloat API (optional)
|
||||||
|
CSGOFLOAT_API_KEY=your-csgofloat-api-key
|
||||||
|
|
||||||
|
# Pricing API (optional)
|
||||||
|
PRICING_API_KEY=your-pricing-api-key
|
||||||
|
EOF
|
||||||
|
|
||||||
|
print_success ".env template created at $ENV_FILE"
|
||||||
|
print_warning "Remember to create ${DEPLOY_PATH}/.env with actual values!"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Create Nginx configuration
|
||||||
|
create_nginx_config() {
|
||||||
|
print_status "Creating Nginx configuration..."
|
||||||
|
|
||||||
|
NGINX_CONFIG="/etc/nginx/sites-available/turbotrades"
|
||||||
|
|
||||||
|
cat > $NGINX_CONFIG << 'EOF'
|
||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
server_name 178.63.127.19;
|
||||||
|
|
||||||
|
client_max_body_size 10M;
|
||||||
|
|
||||||
|
# Frontend (Vite build)
|
||||||
|
location / {
|
||||||
|
root /var/www/turbotrades/frontend/dist;
|
||||||
|
try_files $uri $uri/ /index.html;
|
||||||
|
|
||||||
|
# Cache static assets
|
||||||
|
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
|
||||||
|
expires 1y;
|
||||||
|
add_header Cache-Control "public, immutable";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Backend API
|
||||||
|
location /api {
|
||||||
|
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;
|
||||||
|
proxy_read_timeout 300s;
|
||||||
|
proxy_connect_timeout 75s;
|
||||||
|
}
|
||||||
|
|
||||||
|
# WebSocket support
|
||||||
|
location /ws {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Auth routes
|
||||||
|
location /auth {
|
||||||
|
proxy_pass http://localhost:3000;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Security headers
|
||||||
|
add_header X-Frame-Options "SAMEORIGIN" always;
|
||||||
|
add_header X-Content-Type-Options "nosniff" always;
|
||||||
|
add_header X-XSS-Protection "1; mode=block" always;
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# Enable the site
|
||||||
|
ln -sf $NGINX_CONFIG /etc/nginx/sites-enabled/turbotrades
|
||||||
|
|
||||||
|
# Test Nginx configuration
|
||||||
|
nginx -t
|
||||||
|
|
||||||
|
# Restart Nginx
|
||||||
|
systemctl restart nginx
|
||||||
|
|
||||||
|
print_success "Nginx configuration created and enabled"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Create logs directory
|
||||||
|
create_logs_directory() {
|
||||||
|
print_status "Creating logs directory..."
|
||||||
|
|
||||||
|
LOG_DIR="${DEPLOY_PATH}/logs"
|
||||||
|
mkdir -p $LOG_DIR
|
||||||
|
|
||||||
|
if [ -n "$SUDO_USER" ]; then
|
||||||
|
chown -R $SUDO_USER:$SUDO_USER $LOG_DIR
|
||||||
|
fi
|
||||||
|
|
||||||
|
print_success "Logs directory created at $LOG_DIR"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Print next steps
|
||||||
|
print_next_steps() {
|
||||||
|
echo ""
|
||||||
|
echo "=========================================="
|
||||||
|
print_success "Server setup complete!"
|
||||||
|
echo "=========================================="
|
||||||
|
echo ""
|
||||||
|
print_status "Next steps:"
|
||||||
|
echo ""
|
||||||
|
echo "1. Add the deploy key to Gitea:"
|
||||||
|
echo " - Go to: https://git.turbotrades.dev/iDefineHD/TurboTrades/settings/keys"
|
||||||
|
echo " - Add the PUBLIC key shown above"
|
||||||
|
echo ""
|
||||||
|
echo "2. Add Repository Secrets:"
|
||||||
|
echo " - Go to: https://git.turbotrades.dev/iDefineHD/TurboTrades/settings"
|
||||||
|
echo " - Add these secrets:"
|
||||||
|
echo " - SERVER_HOST: ${SERVER_IP}"
|
||||||
|
echo " - SERVER_USER: $(whoami)"
|
||||||
|
echo " - SERVER_PORT: 22"
|
||||||
|
echo " - SSH_PRIVATE_KEY: (the private key shown above)"
|
||||||
|
echo " - DEPLOY_PATH: ${DEPLOY_PATH}"
|
||||||
|
echo ""
|
||||||
|
echo "3. Clone your repository:"
|
||||||
|
echo " cd ${DEPLOY_PATH}"
|
||||||
|
echo " git clone https://git.turbotrades.dev/iDefineHD/TurboTrades.git ."
|
||||||
|
echo ""
|
||||||
|
echo "4. Create .env file:"
|
||||||
|
echo " cp ${DEPLOY_PATH}/.env.example ${DEPLOY_PATH}/.env"
|
||||||
|
echo " nano ${DEPLOY_PATH}/.env"
|
||||||
|
echo " (Fill in your actual configuration)"
|
||||||
|
echo ""
|
||||||
|
echo "5. Install dependencies and build:"
|
||||||
|
echo " cd ${DEPLOY_PATH}"
|
||||||
|
echo " npm ci --production"
|
||||||
|
echo " cd frontend && npm ci && npm run build && cd .."
|
||||||
|
echo ""
|
||||||
|
echo "6. Start the application:"
|
||||||
|
echo " pm2 start ecosystem.config.js --env production"
|
||||||
|
echo " pm2 save"
|
||||||
|
echo ""
|
||||||
|
echo "7. Visit your application:"
|
||||||
|
echo " http://${SERVER_IP}"
|
||||||
|
echo ""
|
||||||
|
print_success "Setup complete! 🎉"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Main script
|
||||||
|
main() {
|
||||||
|
echo "=========================================="
|
||||||
|
echo " TurboTrades Server Setup"
|
||||||
|
echo " Server: ${SERVER_IP}"
|
||||||
|
echo "=========================================="
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
check_root
|
||||||
|
|
||||||
|
print_status "Starting server setup..."
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Run all setup functions
|
||||||
|
update_system
|
||||||
|
install_nodejs
|
||||||
|
install_mongodb
|
||||||
|
install_pm2
|
||||||
|
install_nginx
|
||||||
|
install_git
|
||||||
|
create_deploy_directory
|
||||||
|
setup_firewall
|
||||||
|
generate_deploy_key
|
||||||
|
create_env_template
|
||||||
|
create_nginx_config
|
||||||
|
create_logs_directory
|
||||||
|
|
||||||
|
# Print next steps
|
||||||
|
print_next_steps
|
||||||
|
}
|
||||||
|
|
||||||
|
# Run main function
|
||||||
|
main
|
||||||
Reference in New Issue
Block a user