updated api config and url

This commit is contained in:
Deep Koluguri 2025-12-13 00:42:54 -05:00
parent b86bfad73b
commit dbcfc65752
10 changed files with 432 additions and 29 deletions

View File

@ -11,10 +11,11 @@ Complete guide for deploying the Institutional Trader platform on a Proxmox serv
5. [Database Configuration](#5-database-configuration)
6. [Systemd Services](#6-systemd-services)
7. [Nginx Configuration](#7-nginx-configuration)
8. [SSL Certificates](#8-ssl-certificates)
9. [Database Access for Friend](#9-database-access-for-friend)
10. [Monitoring & Maintenance](#10-monitoring--maintenance)
11. [Troubleshooting](#11-troubleshooting)
8. [DNS Configuration](#8-dns-configuration)
9. [SSL Certificates](#9-ssl-certificates)
10. [Database Access for Friend](#10-database-access-for-friend)
11. [Monitoring & Maintenance](#11-monitoring--maintenance)
12. [Troubleshooting](#12-troubleshooting)
---
@ -206,6 +207,8 @@ nano .env.production
```
**Frontend `.env.production` configuration:**
**⚠️ Critical:** The frontend must have a `.env.production` file with the correct API URL, otherwise it will try to connect to `localhost:3010` which won't work in production.
```env
VITE_API_URL=https://api.yourdomain.com
VITE_WS_URL=wss://api.yourdomain.com
@ -333,6 +336,7 @@ Type=simple
User=root
WorkingDirectory=/opt/institutional_trader/backend/python_service
Environment="PATH=/opt/institutional_trader/backend/python_service/venv/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
EnvironmentFile=/opt/institutional_trader/backend/python_service/.env
ExecStart=/opt/institutional_trader/backend/python_service/venv/bin/uvicorn main:app --host 0.0.0.0 --port 8010
Restart=always
RestartSec=10
@ -343,6 +347,8 @@ StandardError=journal
WantedBy=multi-user.target
```
**Note:** The `EnvironmentFile` directive is optional - the service will also load `.env` automatically via `load_dotenv()` in the code. However, adding it explicitly ensures environment variables are available even if the code path changes.
Enable and start:
```bash
sudo systemctl daemon-reload
@ -479,7 +485,96 @@ server {
}
```
### 7.2 Enable Site
### 7.2 Multi-Container Setup (Nginx on Separate Container)
If you're running nginx on a separate container/VM that proxies to your application containers:
**Example configuration for proxying to another Proxmox container:**
```nginx
server {
listen 443 ssl http2;
server_name traderideas.deepteklabs.com;
ssl_certificate /etc/letsencrypt/live/traderideas.deepteklabs.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/traderideas.deepteklabs.com/privkey.pem;
# Security Headers
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header X-Content-Type-Options "nosniff" always;
# Backend API Routes
location /api/ {
proxy_pass http://192.168.8.151:3000/api/;
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_set_header X-Forwarded-Host $host;
proxy_connect_timeout 60s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
proxy_buffering off;
}
# WebSocket Support (if using WebSockets)
location /ws {
proxy_pass http://192.168.8.151: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_read_timeout 86400; # 24 hours for long-lived connections
}
# Health Check
location /health {
proxy_pass http://192.168.8.151:3000/health;
access_log off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
add_header Cache-Control "no-cache, no-store, must-revalidate";
}
# Frontend (served from application container)
location / {
proxy_pass http://192.168.8.151:8080/;
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;
proxy_hide_header Cache-Control;
add_header Cache-Control "no-cache, no-store, must-revalidate" always;
}
# Static assets with caching
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot|otf|map)$ {
proxy_pass http://192.168.8.151:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
expires 1y;
add_header Cache-Control "public, immutable";
access_log off;
}
}
```
**Important notes for multi-container setup:**
- Replace `192.168.8.151` with your application container's IP
- Ensure containers can communicate (same network/bridge)
- Port 3000 = Backend API, Port 8080 = Frontend (adjust as needed)
- Test connectivity: `curl http://192.168.8.151:3000/health` from nginx container
### 7.3 Enable Site
```bash
# Create symlink
@ -494,19 +589,179 @@ sudo systemctl reload nginx
---
## 8. SSL Certificates
## 8. DNS Configuration
### 8.1 Install Certbot
**⚠️ Important:** Before setting up SSL certificates, you must configure DNS records pointing to your server.
### 8.1 Find Your Server's Public IP Address
```bash
# On your server, find the public IP
curl ifconfig.me
# Or
hostname -I
# Or check in Proxmox Web UI: Datacenter → Your Node → Network
```
### 8.2 Configure DNS A Records
Go to your domain registrar's DNS management panel (where you registered `traderideas.deepteklabs.com`) and add these A records:
| Type | Name | Value | TTL |
|------|------|-------|-----|
| A | `@` (or blank) | `<your-server-ip>` | 3600 |
| A | `www` | `<your-server-ip>` | 3600 |
| A | `api` | `<your-server-ip>` | 3600 |
**Example for `traderideas.deepteklabs.com`:**
- `traderideas.deepteklabs.com``<your-server-ip>` (A record with name `@` or blank)
- `www.traderideas.deepteklabs.com``<your-server-ip>` (A record with name `www`)
- `api.traderideas.deepteklabs.com``<your-server-ip>` (A record with name `api`)
### 8.3 Verify DNS Propagation
Wait 5-15 minutes for DNS to propagate, then verify:
```bash
# Check if DNS records are resolving
dig traderideas.deepteklabs.com +short
dig www.traderideas.deepteklabs.com +short
dig api.traderideas.deepteklabs.com +short
# All should return your server's IP address
# Alternative: Use nslookup
nslookup traderideas.deepteklabs.com
nslookup www.traderideas.deepteklabs.com
nslookup api.traderideas.deepteklabs.com
# Or use online tools:
# - https://dnschecker.org
# - https://www.whatsmydns.net
```
**Common DNS Providers:**
- **Cloudflare**: Dashboard → DNS → Records → Add record
- **Namecheap**: Domain List → Manage → Advanced DNS → Add New Record
- **GoDaddy**: DNS Management → Add Record
- **Google Domains**: DNS → Custom Records → Add Record
### 8.4 Test Domain Accessibility
Once DNS is propagated, test that domains are reachable:
```bash
# From your server
curl -I http://traderideas.deepteklabs.com
curl -I http://www.traderideas.deepteklabs.com
curl -I http://api.traderideas.deepteklabs.com
# Should return HTTP responses (even if 502/503, that's OK - means DNS is working)
```
### 8.5 Cloudflare Proxy (Orange Cloud)
**If your domain uses Cloudflare proxy (orange cloud icon):**
When DNS resolves to Cloudflare IPs (like `104.21.x.x` or `172.67.x.x`), your domain is behind Cloudflare proxy. This affects SSL certificate setup:
**Check if using Cloudflare proxy:**
```bash
dig traderideas.deepteklabs.com +short
# If returns Cloudflare IPs (104.x.x.x, 172.x.x.x), proxy is enabled
```
**Options for SSL with Cloudflare:**
1. **Use DNS Challenge (Recommended)** - Works with proxy enabled
2. **Temporarily Disable Proxy** - Get certs, then re-enable proxy
3. **Use Cloudflare SSL** - Let Cloudflare handle SSL (easiest)
See Section 9.2 for detailed instructions.
**⚠️ Only proceed to SSL setup once DNS records are working!**
---
## 9. SSL Certificates
### 9.1 Install Certbot
```bash
sudo apt install -y certbot python3-certbot-nginx
```
### 8.2 Obtain SSL Certificate
### 9.2 Obtain SSL Certificate
**⚠️ Prerequisites:**
- DNS A records must be configured and propagated (see Section 8)
- Domains must resolve to your server's IP (or Cloudflare if using proxy)
- Port 80 must be accessible from the internet (for HTTP challenge) OR DNS API access (for DNS challenge)
**⚠️ Important:** If your nginx config already references SSL certificates that don't exist, you need to fix this first.
**Check if using Cloudflare proxy:**
```bash
dig traderideas.deepteklabs.com +short
# If returns Cloudflare IPs (104.x.x.x, 172.x.x.x), you're using Cloudflare proxy
```
**If using Cloudflare Proxy, use Option D (DNS Challenge) or Option E (Cloudflare SSL)**
**Option A: Use Standalone Mode (Works if NOT using Cloudflare proxy)**
```bash
# Stop nginx temporarily
sudo systemctl stop nginx
# Get certificates using standalone mode
sudo certbot certonly --standalone -d traderideas.deepteklabs.com -d www.traderideas.deepteklabs.com -d api.traderideas.deepteklabs.com
# Start nginx again
sudo systemctl start nginx
# Now certbot can update the nginx config
sudo certbot --nginx -d traderideas.deepteklabs.com -d www.traderideas.deepteklabs.com -d api.traderideas.deepteklabs.com
```
**Option B: Temporarily Comment Out SSL in Nginx Config**
```bash
# Edit nginx config
sudo nano /etc/nginx/sites-available/institutional-trader
# Temporarily comment out SSL lines:
# - Comment out: listen 443 ssl http2;
# - Comment out: ssl_certificate and ssl_certificate_key lines
# - Change: listen 443 ssl http2; to: listen 80;
# Example temporary config (HTTP only):
# server {
# listen 80;
# server_name traderideas.deepteklabs.com;
# # ssl_certificate /etc/letsencrypt/live/traderideas.deepteklabs.com/fullchain.pem;
# # ssl_certificate_key /etc/letsencrypt/live/traderideas.deepteklabs.com/privkey.pem;
# ...
# }
# Test and reload
sudo nginx -t
sudo systemctl reload nginx
# Now get certificates (certbot will automatically update the config)
sudo certbot --nginx -d traderideas.deepteklabs.com -d www.traderideas.deepteklabs.com -d api.traderideas.deepteklabs.com
# Certbot will automatically:
# - Get the certificates
# - Update your nginx config to use them
# - Add SSL redirects
```
**Option C: Use Certbot with Nginx Plugin (If config is clean and NOT using Cloudflare proxy)**
```bash
# Replace with your actual domain
sudo certbot --nginx -d yourdomain.com -d www.yourdomain.com -d api.yourdomain.com
sudo certbot --nginx -d traderideas.deepteklabs.com -d www.traderideas.deepteklabs.com -d api.traderideas.deepteklabs.com
```
Follow the prompts:
@ -514,7 +769,85 @@ Follow the prompts:
- Agree to terms
- Choose whether to redirect HTTP to HTTPS (recommended: Yes)
### 8.3 Auto-Renewal
**Option D: DNS Challenge (Recommended for Cloudflare proxy)**
If your domain is behind Cloudflare proxy, use DNS challenge:
```bash
# Install Cloudflare plugin for certbot
sudo apt install -y python3-pip
sudo pip3 install certbot-dns-cloudflare
# Create Cloudflare API token directory
sudo mkdir -p /etc/letsencrypt
sudo chmod 700 /etc/letsencrypt
# Create Cloudflare credentials file
sudo nano /etc/letsencrypt/cloudflare.ini
```
Add your Cloudflare API token:
```ini
# Cloudflare API token (get from: Cloudflare Dashboard → My Profile → API Tokens → Create Token)
# Permissions needed: Zone:Zone:Read, Zone:DNS:Edit
dns_cloudflare_api_token = YOUR_CLOUDFLARE_API_TOKEN
```
```bash
# Secure the credentials file
sudo chmod 600 /etc/letsencrypt/cloudflare.ini
# Get certificates using DNS challenge
sudo certbot certonly \
--dns-cloudflare \
--dns-cloudflare-credentials /etc/letsencrypt/cloudflare.ini \
-d traderideas.deepteklabs.com \
-d www.traderideas.deepteklabs.com \
-d api.traderideas.deepteklabs.com
# Update nginx config manually (certbot won't auto-update with DNS challenge)
sudo nano /etc/nginx/sites-available/institutional-trader
# Update ssl_certificate paths to:
# ssl_certificate /etc/letsencrypt/live/traderideas.deepteklabs.com/fullchain.pem;
# ssl_certificate_key /etc/letsencrypt/live/traderideas.deepteklabs.com/privkey.pem;
sudo nginx -t
sudo systemctl reload nginx
```
**Option E: Use Cloudflare SSL (Easiest with Cloudflare proxy)**
If using Cloudflare proxy, you can let Cloudflare handle SSL:
1. **In Cloudflare Dashboard:**
- Go to SSL/TLS → Overview
- Set encryption mode to **"Full"** or **"Full (strict)"**
- Cloudflare will automatically provide SSL certificates
2. **On your server, use self-signed or Cloudflare Origin Certificate:**
```bash
# Generate self-signed certificate (Cloudflare will accept it)
sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
-keyout /etc/ssl/private/nginx-selfsigned.key \
-out /etc/ssl/certs/nginx-selfsigned.crt
# Update nginx config to use self-signed cert
sudo nano /etc/nginx/sites-available/institutional-trader
# Change to:
# ssl_certificate /etc/ssl/certs/nginx-selfsigned.crt;
# ssl_certificate_key /etc/ssl/private/nginx-selfsigned.key;
sudo nginx -t
sudo systemctl reload nginx
```
3. **Or get Cloudflare Origin Certificate:**
- Cloudflare Dashboard → SSL/TLS → Origin Server → Create Certificate
- Copy certificate and key
- Save to `/etc/ssl/certs/cloudflare-origin.crt` and `/etc/ssl/private/cloudflare-origin.key`
- Update nginx config to use these files
### 9.3 Auto-Renewal
Certbot sets up auto-renewal automatically. Test it:
@ -524,7 +857,7 @@ sudo certbot renew --dry-run
---
## 9. Database Access for Friend
## 10. Database Access for Friend
### Option A: Supabase (Recommended)
@ -634,7 +967,7 @@ ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT ON TABLES TO friend_reado
---
## 10. Monitoring & Maintenance
## 11. Monitoring & Maintenance
### 10.1 Health Checks
@ -707,7 +1040,7 @@ sudo -u postgres psql institutional_trader < backup_20240101.sql
---
## 11. Troubleshooting
## 12. Troubleshooting
### Backend Won't Start
@ -725,16 +1058,80 @@ node -e "import('./src/db.js').then(m => m.testConnection())"
### Python Service Won't Start
**Step 1: Check detailed error logs**
```bash
# Check logs
sudo journalctl -u institutional-trader-python -n 50
# View recent logs with full error messages
sudo journalctl -u institutional-trader-python -n 100 --no-pager
# Test manually
# Follow logs in real-time
sudo journalctl -u institutional-trader-python -f
```
**Step 2: Verify systemd service file has correct port**
```bash
# Check current service file
sudo cat /etc/systemd/system/institutional-trader-python.service
# If port is 8000, update it to 8010:
sudo nano /etc/systemd/system/institutional-trader-python.service
# Change: --port 8000 to --port 8010
# Then reload and restart:
sudo systemctl daemon-reload
sudo systemctl restart institutional-trader-python
```
**Step 3: Test manually to see actual error**
```bash
cd /opt/institutional_trader/backend/python_service
source venv/bin/activate
# Check if .env file exists and has correct DB config
cat .env
# Test startup manually
uvicorn main:app --host 0.0.0.0 --port 8010
```
**Step 4: Common issues and fixes**
**Database connection timeout:**
- The service now has a 10-second timeout and will start even if DB is temporarily unavailable
- Check database is reachable: `psql -h <DB_HOST> -U <DB_USER> -d institutional_trader`
- Verify `.env` file in `backend/python_service/` has correct database credentials
**Port already in use:**
```bash
# Check if port 8010 is in use
sudo netstat -tlnp | grep 8010
# Or
sudo lsof -i :8010
# Kill process if needed
sudo kill -9 <PID>
```
**Missing dependencies:**
```bash
cd /opt/institutional_trader/backend/python_service
source venv/bin/activate
pip install -r requirements.txt
```
**Step 5: Verify backend .env has correct Python service URL**
```bash
# Check backend .env
cat /opt/institutional_trader/backend/.env | grep PYTHON_SERVICE_URL
# Should be:
# PYTHON_SERVICE_URL=http://localhost:8010
# If not, update it:
nano /opt/institutional_trader/backend/.env
# Add or update: PYTHON_SERVICE_URL=http://localhost:8010
# Then restart backend:
sudo systemctl restart institutional-trader-backend
```
### Nginx Errors
```bash

View File

@ -1,5 +1,6 @@
import { useEffect, useRef, useState } from 'react';
import { createChart } from 'lightweight-charts';
import { getApiUrl } from '@/config/api';
export default function PriceChart({ symbol, flowData }) {
const chartContainerRef = useRef();
@ -175,7 +176,7 @@ export default function PriceChart({ symbol, flowData }) {
async function fetchPriceData(symbol, timeframe) {
try {
const response = await fetch(
`http://localhost:3010/api/prices/${symbol}?timeframe=${timeframe}`
`${getApiUrl(`/api/prices/${symbol}`)}?timeframe=${timeframe}`
);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);

View File

@ -26,7 +26,7 @@ export default function AlertsFeed() {
}
// WebSocket connection for real-time alerts
// Vite proxy handles /ws -> ws://localhost:3010
// Uses relative URL which will be proxied by nginx or use configured WS URL
const wsProtocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
const wsUrl = `${wsProtocol}//${window.location.host}/ws/alerts`;
@ -75,7 +75,7 @@ export default function AlertsFeed() {
const fetchAlerts = async () => {
try {
let url = '/api/alerts/recent';
let url = getApiUrl('/api/alerts/recent');
if (useHistorical && historicalDate) {
const params = new URLSearchParams({
date: historicalDate,

View File

@ -1,6 +1,7 @@
import { useState, useEffect } from 'react';
import { Badge } from '../ui/Badge';
import { TrendingUp, TrendingDown, Target, BarChart3 } from 'lucide-react';
import { getApiUrl } from '@/config/api';
export default function PerformanceTrackingPanel() {
const [stats, setStats] = useState({
@ -24,7 +25,7 @@ export default function PerformanceTrackingPanel() {
useEffect(() => {
const fetchStats = async () => {
try {
const response = await fetch('http://localhost:3010/api/performance/stats');
const response = await fetch(getApiUrl('/api/performance/stats'));
// Check if response is ok
if (!response.ok) {

View File

@ -2,8 +2,7 @@ import { useEffect, useState } from 'react';
import { DataTable } from '@/components/ui/data-table';
import { Badge } from '@/components/ui/Badge';
import { Button } from '@/components/ui/button';
const API_BASE_URL = import.meta.env.VITE_API_URL || 'http://localhost:3010';
import { getApiUrl } from '@/config/api';
export default function PhaseClassifierPanel() {
const [data, setData] = useState([]);
@ -16,7 +15,7 @@ export default function PhaseClassifierPanel() {
const fetchData = async () => {
try {
setLoading(true);
const response = await fetch(`${API_BASE_URL}/api/options/phase-classifier`);
const response = await fetch(getApiUrl('/api/options/phase-classifier'));
const result = await response.json();
if (result.success) {

View File

@ -4,6 +4,7 @@ import { Badge } from '@/components/ui/Badge';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Star, TrendingUp, TrendingDown, Calendar, Clock } from 'lucide-react';
import { getApiUrl } from '@/config/api';
export default function ScannerPanel() {
const [scanResults, setScanResults] = useState([]);
@ -34,7 +35,7 @@ export default function ScannerPanel() {
const runScan = async () => {
setLoading(true);
try {
let url = 'http://localhost:3010/api/scanner/multi-signal';
let url = getApiUrl('/api/scanner/multi-signal');
if (useHistorical && historicalDate) {
const params = new URLSearchParams({ date: historicalDate });
if (historicalTime) {

View File

@ -1,5 +1,6 @@
import { useState, useEffect } from 'react';
import { X } from 'lucide-react';
import { getApiUrl } from '@/config/api';
export default function Watchlist() {
const [watchlist, setWatchlist] = useState([]);
@ -24,7 +25,7 @@ export default function Watchlist() {
try {
// Fetch prices for all watchlist symbols
const symbols = watchlist.join(',');
const response = await fetch(`http://localhost:3010/api/prices?symbols=${symbols}`);
const response = await fetch(`${getApiUrl('/api/prices')}?symbols=${symbols}`);
const data = await response.json();
if (data.success && data.data) {

View File

@ -1,4 +1,5 @@
import { useState, useCallback } from 'react';
import { getApiUrl } from '@/config/api';
export function useAIAnalysis() {
const [loading, setLoading] = useState(false);
@ -10,7 +11,7 @@ export function useAIAnalysis() {
setError(null);
try {
const response = await fetch('http://localhost:3010/api/options/ai-analysis', {
const response = await fetch(getApiUrl('/api/options/ai-analysis'), {
method: 'POST',
headers: {
'Content-Type': 'application/json',

View File

@ -1,4 +1,5 @@
import { useState, useEffect, useCallback, useRef } from 'react';
import { getApiUrl } from '@/config/api';
export function useOptionsFlow({ autoRefresh = false, interval = 30000, ...filters }) {
const [data, setData] = useState(null);
@ -32,7 +33,7 @@ export function useOptionsFlow({ autoRefresh = false, interval = 30000, ...filte
)
});
const response = await fetch(`http://localhost:3010/api/options/flow?${params}`);
const response = await fetch(`${getApiUrl('/api/options/flow')}?${params}`);
const result = await response.json();
if (result.success) {

View File

@ -1,5 +1,6 @@
import { useEffect, useRef, useState } from "react";
import { useAppStore } from "../store/useAppStore";
import { getWsUrl } from "@/config/api";
export function useWebSocket(url = "/ws/flow") {
const [messages, setMessages] = useState([]);
@ -9,8 +10,8 @@ export function useWebSocket(url = "/ws/flow") {
const addAlert = useAppStore((state) => state.addAlert);
useEffect(() => {
// Create WebSocket connection (use proxy through Vite dev server)
const ws = new WebSocket(`ws://localhost:5010${url}`);
// Create WebSocket connection using configured WS URL
const ws = new WebSocket(getWsUrl(url));
wsRef.current = ws;
ws.onopen = () => {