22 KiB
IRT Bank Soal - AaPanel Deployment Guide
Document Version: 1.1 Date: March 21, 2026 Project: IRT-Powered Adaptive Question Bank System v1.2.0 Updated: Clarified PostgreSQL setup using Databases > PgSQL menu
Table of Contents
- Prerequisites
- AaPanel Installation
- Install Required Software via AaPanel
- PostgreSQL Setup
- Python Manager Setup
- Project Deployment
- Environment Configuration
- Database Migration
- Running the Application
- Nginx Reverse Proxy Configuration
- SSL Configuration
- Post-Deployment Verification
- Troubleshooting
1. Prerequisites
Server Requirements
| Requirement | Minimum | Recommended |
|---|---|---|
| OS | Ubuntu 20.04 / CentOS 7+ | Ubuntu 22.04 LTS |
| RAM | 2 GB | 4 GB+ |
| Storage | 20 GB | 50 GB+ |
| CPU | 1 vCPU | 2+ vCPU |
Domain Requirements
- A domain name pointed to your server IP
- Subdomain recommended (e.g.,
api.yourdomain.com)
2. AaPanel Installation
Step 2.1: Install AaPanel
For Ubuntu/Debian:
# Login to your server via SSH
ssh root@your-server-ip
# Install AaPanel
wget -O install.sh http://www.aapanel.com/script/install-ubuntu_6.0_en.sh && bash install.sh
For CentOS:
# Install AaPanel
yum install -y wget && wget -O install.sh http://www.aapanel.com/script/install_6.0_en.sh && sh install.sh
Step 2.2: Access AaPanel
- After installation completes, note the panel URL and credentials
- Access AaPanel via browser:
http://your-server-ip:8888 - Login with provided credentials
- Important: Change default port and password after first login
3. Install Required Software via AaPanel
Step 3.1: Install Nginx
- In AaPanel, go to App Store
- Find Nginx and click Install
- Select version (recommended: 1.24+)
- Click Submit and wait for installation
Step 3.2: Install Python Manager
- Go to App Store
- Search for Python Manager (or PM2 Manager)
- Click Install
Step 3.3: Install Redis (Optional, for Celery)
- Go to App Store
- Find Redis and click Install
- Click Submit
4. PostgreSQL Setup
IMPORTANT: Use Databases > PgSQL menu from AaPanel sidebar.
This menu supports both:
- Local server - PostgreSQL installed on your AaPanel server
- Remote server - External PostgreSQL (Supabase, Neon, AWS RDS, etc.)
Step 4.1: Choose Your Database Type
You have two options:
| Option | Description | Best For |
|---|---|---|
| Remote Database | External PostgreSQL service (Supabase, Neon, etc.) | Easy setup, managed, free tier available |
| Local Database | PostgreSQL on your AaPanel server | Full control, no external dependency |
Option A: Remote PostgreSQL Database (RECOMMENDED)
Use an external PostgreSQL service:
- Supabase - https://supabase.com (free tier: 500MB)
- Neon - https://neon.tech (free tier: 3GB)
- AWS RDS - https://aws.amazon.com/rds/postgresql/
- DigitalOcean - https://www.digitalocean.com/products/managed-databases-postgresql
- Railway - https://railway.app
Step 4.A.1: Create Database on Provider
- Sign up on your chosen provider
- Create a new PostgreSQL project/database
- Note down the connection details from dashboard:
- Host (e.g.,
db.xxxxx.supabase.coorep-xxx.us-east-2.aws.neon.tech) - Port (usually
5432, Supabase uses6543for pooler) - Database name (e.g.,
postgresorneondb) - Username (e.g.,
postgres.xxxxx) - Password
- Host (e.g.,
Step 4.A.2: Add Remote Server to AaPanel PgSQL
- In AaPanel, go to Databases > PgSQL
- Click Remote DB button
- Fill in the form:
- Server Name:
my-remote-db(any name you like) - Server Address:
db.xxxxx.supabase.co(your host) - Port:
5432or6543(check your provider) - Root User:
postgresor your username - Root Password: your password
- Server Name:
- Click Submit
Step 4.A.3: Sync Databases from Remote Server
- After adding remote server, click Get DB from server
- Select your remote server from dropdown
- Click Submit
- Your remote databases will appear in the list
Step 4.A.4: Note Your Connection String
Your connection string format:
postgresql+asyncpg://username:password@host:port/database_name
Example (Supabase):
postgresql+asyncpg://postgres.xxxxx:YourPassword@aws-0-ap-southeast-1.pooler.supabase.com:6543/postgres
Example (Neon):
postgresql+asyncpg://neondb_owner:YourPassword@ep-xxxx.us-east-2.aws.neon.tech/neondb?sslmode=require
Option B: Local PostgreSQL Database
Install PostgreSQL directly on your AaPanel server.
Step 4.B.1: Install PostgreSQL via Terminal
# SSH into your server
ssh root@your-server-ip
# Ubuntu/Debian
apt update
apt install -y postgresql postgresql-contrib
# Start and enable PostgreSQL
systemctl start postgresql
systemctl enable postgresql
# Check status
systemctl status postgresql
Step 4.B.2: Create Database and User via Terminal
# Switch to postgres user
su - postgres
# Enter PostgreSQL CLI
psql
# Run SQL commands:
CREATE DATABASE irt_bank_soal;
CREATE USER irt_user WITH ENCRYPTED PASSWORD 'your_secure_password_here';
GRANT ALL PRIVILEGES ON DATABASE irt_bank_soal TO irt_user;
# Connect to database and grant schema
\c irt_bank_soal
GRANT ALL ON SCHEMA public TO irt_user;
# Exit
\q
exit
Step 4.B.3: Add Local Server to AaPanel PgSQL
- In AaPanel, go to Databases > PgSQL
- Click Root Password to view/change postgres password
- If your local PostgreSQL is not showing, click Get DB from server
- Select Local server
- Click Submit
Step 4.B.4: Create Additional Database via AaPanel (Optional)
- In Databases > PgSQL
- Click Add DB
- Fill in:
- Database name:
irt_bank_soal - Username:
irt_user(or same as DB name) - Password: (click generate or enter custom)
- Add to:
Local server
- Database name:
- Click Submit
Step 4.B.5: Note Your Connection String
postgresql+asyncpg://irt_user:your_password@127.0.0.1:5432/irt_bank_soal
4.1 Test Database Connection
Before proceeding, verify your database connection works.
For Remote Database:
# Install psql client if needed
apt install -y postgresql-client
# Test connection (replace with your details)
psql "postgresql://username:password@host:port/database_name" -c "SELECT version();"
For Local Database:
# Test connection
psql -U irt_user -d irt_bank_soal -h 127.0.0.1 -c "SELECT version();"
# If prompted for password, enter it
4.2 Connection String Quick Reference
| Database Type | Connection String Format |
|---|---|
| Remote (Supabase) | postgresql+asyncpg://postgres.xxxx:password@aws-0-region.pooler.supabase.com:6543/postgres |
| Remote (Neon) | postgresql+asyncpg://user:password@ep-xxxx.region.aws.neon.tech/neondb?sslmode=require |
| Local | postgresql+asyncpg://irt_user:password@127.0.0.1:5432/irt_bank_soal |
Note: We use
postgresql+asyncpg://because our app uses async SQLAlchemy withasyncpgdriver.
5. Python Manager Setup
Step 5.1: Open Python Manager
- In AaPanel, go to App Store
- Find Python Manager and click Settings
Step 5.2: Install Python Version
- Click Version Management
- Select Python 3.11 (or latest stable)
- Click Install
- Wait for installation to complete
6. Project Deployment
Step 6.1: Create Project Directory
# Create project directory
mkdir -p /www/wwwroot/irt-bank-soal
# Navigate to directory
cd /www/wwwroot/irt-bank-soal
Step 6.2: Upload Project Files
Option A: Upload via File Manager
- In AaPanel, go to Files
- Navigate to
/www/wwwroot/irt-bank-soal - Upload your project ZIP file
- Extract the archive
Option B: Clone from Git (if applicable)
cd /www/wwwroot/irt-bank-soal
# If using Git
git clone https://github.com/your-repo/irt-bank-soal.git .
# Or copy from local
# scp -r /Users/dwindown/Applications/tryout-system/* root@your-server-ip:/www/wwwroot/irt-bank-soal/
Step 6.3: Verify Project Structure
# Expected structure:
ls -la /www/wwwroot/irt-bank-soal/
# app/
# app/models/
# app/routers/
# app/services/
# app/core/
# tests/
# requirements.txt
# .env.example
# alembic/
7. Environment Configuration
Step 7.1: Create Virtual Environment via Python Manager
- In AaPanel Python Manager, click Add Project
- Configure:
- Project Name:
irt-bank-soal - Project Path:
/www/wwwroot/irt-bank-soal - Python Version:
Python 3.11 - Framework:
FastAPI - Startup Method:
uvicorn
- Project Name:
- Click Submit
Step 7.2: Create Environment File
# Copy example file
cp /www/wwwroot/irt-bank-soal/.env.example /www/wwwroot/irt-bank-soal/.env
# Edit .env file
nano /www/wwwroot/irt-bank-soal/.env
Step 7.3: Configure .env File
# Database Configuration
# For Remote Database (Supabase example):
# DATABASE_URL=postgresql+asyncpg://postgres.xxxx:password@aws-0-ap-southeast-1.pooler.supabase.com:6543/postgres
# For Remote Database (Neon example):
# DATABASE_URL=postgresql+asyncpg://neondb_owner:password@ep-xxxx.us-east-2.aws.neon.tech/neondb?sslmode=require
# For Local Database:
DATABASE_URL=postgresql+asyncpg://irt_user:your_secure_password_here@127.0.0.1:5432/irt_bank_soal
# Security
SECRET_KEY=your-production-secret-key-min-32-characters-random-string
# Environment
ENVIRONMENT=production
DEBUG=false
# API Configuration
API_V1_STR=/api/v1
PROJECT_NAME=IRT Bank Soal
PROJECT_VERSION=1.2.0
# CORS - Add your WordPress domains
ALLOWED_ORIGINS=https://yourdomain.com,https://www.yourdomain.com
# OpenRouter API (for AI Generation)
OPENROUTER_API_KEY=your-openrouter-api-key-here
OPENROUTER_API_URL=https://openrouter.ai/api/v1
OPENROUTER_MODEL_QWEN=qwen/qwen-2.5-coder-32b-instruct
OPENROUTER_MODEL_LLAMA=meta-llama/llama-3.3-70b-instruct
OPENROUTER_TIMEOUT=60
# WordPress Integration
WORDPRESS_API_URL=https://yourdomain.com/wp-json
WORDPRESS_AUTH_TOKEN=your-wordpress-jwt-token
# Redis (for Celery task queue)
REDIS_URL=redis://127.0.0.1:6379/0
# Admin Panel
ADMIN_USER=admin
ADMIN_PASSWORD=your-secure-admin-password
# Normalization Defaults
DEFAULT_RATAAN=500
DEFAULT_SB=100
MIN_SAMPLE_FOR_DYNAMIC=100
Step 7.4: Generate Secret Key
# Generate a secure secret key
python3 -c "import secrets; print(secrets.token_urlsafe(32))"
# Copy the output and paste into SECRET_KEY in .env
8. Database Migration
Step 8.1: Activate Virtual Environment
# Via Python Manager, the venv is usually at:
source /www/wwwroot/irt-bank-soal/venv/bin/activate
# Or check Python Manager for exact venv path
Step 8.2: Install Dependencies
# Ensure you're in project directory
cd /www/wwwroot/irt-bank-soal
# Install dependencies
pip install -r requirements.txt
# Verify installation
pip list | grep -E "fastapi|sqlalchemy|numpy|scipy|httpx|openpyxl"
Step 8.3: Initialize Alembic (First Time Setup)
# Initialize Alembic if not already done
alembic init alembic
# Generate initial migration
alembic revision --autogenerate -m "Initial migration"
# Apply migration
alembic upgrade head
Step 8.4: Verify Database Tables
# Check tables were created
psql -U irt_user -d irt_bank_soal -h 127.0.0.1 -c "\dt"
# Expected output: websites, users, tryouts, items, sessions, user_answers, tryout_stats
9. Running the Application
Step 9.1: Configure Python Project in AaPanel
- In Python Manager, find your project
irt-bank-soal - Click Settings
- Configure startup:
- Startup File:
app/main.py - Startup Method:
uvicorn - Port:
8000 - Modules:
uvicorn[standard]
- Startup File:
Step 9.2: Set Startup Command
In Python Manager settings, set the startup command:
# Startup command
uvicorn app.main:app --host 127.0.0.1 --port 8000 --workers 4
# Or for development:
uvicorn app.main:app --host 0.0.0.0 --port 8000 --reload
Step 9.3: Start the Application
- In Python Manager, click Start on your project
- Check logs for any errors
- Verify the application is running:
# Test health endpoint
curl http://127.0.0.1:8000/
# Expected response:
# {"status": "healthy", "project_name": "IRT Bank Soal", "version": "1.2.0"}
Step 9.4: Configure Auto-Start on Boot
- In Python Manager, enable Auto-start on boot
- Or manually via terminal:
# Using systemd (create service file)
nano /etc/systemd/system/irt-bank-soal.service
[Unit]
Description=IRT Bank Soal FastAPI Application
After=network.target
# Uncomment below if using LOCAL PostgreSQL:
# After=network.target postgresql.service
[Service]
Type=simple
User=www
Group=www
WorkingDirectory=/www/wwwroot/irt-bank-soal
Environment="PATH=/www/wwwroot/irt-bank-soal/venv/bin"
ExecStart=/www/wwwroot/irt-bank-soal/venv/bin/uvicorn app.main:app --host 127.0.0.1 --port 8000 --workers 4
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
# Enable and start service
systemctl daemon-reload
systemctl enable irt-bank-soal
systemctl start irt-bank-soal
systemctl status irt-bank-soal
10. Nginx Reverse Proxy Configuration
Step 10.1: Create Website in AaPanel
- In AaPanel, go to Website
- Click Add Site
- Configure:
- Domain:
api.yourdomain.com(or your subdomain) - PHP Version: Pure Static (not needed)
- Database: None (already created)
- Domain:
- Click Submit
Step 10.2: Configure Reverse Proxy
- Click Settings on the newly created website
- Go to Reverse Proxy
- Click Add Reverse Proxy
- Configure:
- Proxy Name:
irt-api - Target URL:
http://127.0.0.1:8000
- Proxy Name:
- Click Submit
Step 10.3: Manual Nginx Configuration (Alternative)
# Edit Nginx config
nano /www/server/panel/vhost/nginx/api.yourdomain.com.conf
server {
listen 80;
server_name api.yourdomain.com;
# Access and error logs
access_log /www/wwwlogs/api.yourdomain.com.log;
error_log /www/wwwlogs/api.yourdomain.com.error.log;
# Client body size (for Excel uploads)
client_max_body_size 50M;
# Proxy to FastAPI
location / {
proxy_pass http://127.0.0.1:8000;
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_connect_timeout 60s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
}
# Static files (if any)
location /static/ {
alias /www/wwwroot/irt-bank-soal/static/;
expires 30d;
}
}
Step 10.4: Test and Reload Nginx
# Test Nginx configuration
nginx -t
# Reload Nginx
nginx -s reload
# Or via AaPanel: Website > Settings > Config > Save
11. SSL Configuration
Step 11.1: Install SSL Certificate
- In AaPanel, go to Website
- Click Settings on your site
- Go to SSL
- Choose method:
- Let's Encrypt: Free, auto-renewal
- Own Certificate: Upload your own
- Buy: Purchase through AaPanel
Step 11.2: Configure Let's Encrypt
- Click Let's Encrypt
- Enter your email
- Select domain
api.yourdomain.com - Click Apply
- Enable Force HTTPS
Step 11.3: Update .env for HTTPS
# Edit .env
nano /www/wwwroot/irt-bank-soal/.env
# Update CORS to use HTTPS
ALLOWED_ORIGINS=https://yourdomain.com,https://www.yourdomain.com
12. Post-Deployment Verification
Step 12.1: Test API Endpoints
# Test health endpoint
curl https://api.yourdomain.com/
# Test detailed health
curl https://api.yourdomain.com/health
# Test API documentation
# Open in browser: https://api.yourdomain.com/docs
Step 12.2: Test Database Connection
# Via API
curl https://api.yourdomain.com/health
# Expected response includes database status:
# {"status": "healthy", "database": "connected", "api_version": "v1"}
Step 12.3: Test Admin Panel
# Access admin panel
# Open in browser: https://api.yourdomain.com/admin
# Login with credentials from .env
Step 12.4: Load Test Data (Optional)
# SSH into server
ssh root@your-server-ip
# Navigate to project
cd /www/wwwroot/irt-bank-soal
# Activate venv
source venv/bin/activate
# Run test data script
python3 -c "
import asyncio
from app.database import init_db
asyncio.run(init_db())
print('Database initialized successfully')
"
13. Troubleshooting
Issue: Python Manager Not Starting Application
Solution:
# Check logs
tail -f /www/wwwroot/irt-bank-soal/logs/error.log
# Check if port is in use
lsof -i :8000
# Manually test startup
cd /www/wwwroot/irt-bank-soal
source venv/bin/activate
uvicorn app.main:app --host 127.0.0.1 --port 8000
Issue: Database Connection Failed
For Remote Database:
# Test connection from server
apt install -y postgresql-client
psql "postgresql://username:password@remote-host:port/database" -c "SELECT 1;"
# Check if firewall allows outbound connection
# Most remote DBs use port 5432 or 6543
# Verify DATABASE_URL in .env
cat /www/wwwroot/irt-bank-soal/.env | grep DATABASE_URL
# Common issues:
# - Wrong port (Supabase pooler uses 6543, direct uses 5432)
# - Missing sslmode=require (Neon requires this)
# - IP not whitelisted (check provider dashboard)
For Local Database:
# Check PostgreSQL status
systemctl status postgresql
# Test connection manually
psql -U irt_user -d irt_bank_soal -h 127.0.0.1 -W
# Check pg_hba.conf allows connections
cat /etc/postgresql/*/main/pg_hba.conf | grep -v "^#" | grep -v "^$"
# Verify DATABASE_URL in .env
cat /www/wwwroot/irt-bank-soal/.env | grep DATABASE_URL
Issue: 502 Bad Gateway
Solution:
# Check if FastAPI is running
ps aux | grep uvicorn
# Check Nginx error logs
tail -f /www/wwwlogs/api.yourdomain.com.error.log
# Verify proxy configuration
cat /www/server/panel/vhost/nginx/api.yourdomain.com.conf | grep proxy_pass
Issue: CORS Errors
Solution:
# Check ALLOWED_ORIGINS in .env
cat /www/wwwroot/irt-bank-soal/.env | grep ALLOWED_ORIGINS
# Ensure WordPress domain is included
# Example: ALLOWED_ORIGINS=https://site1.com,https://site2.com
# Restart application after changes
# Via Python Manager: Stop > Start
Issue: SSL Certificate Not Working
Solution:
# Check certificate
openssl s_client -connect api.yourdomain.com:443
# Force HTTPS in Nginx config
# Add to server block:
# return 301 https://$host$request_uri;
# Reload Nginx
nginx -s reload
Issue: Large File Upload Failed
Solution:
# Increase Nginx client body size
nano /www/server/panel/vhost/nginx/api.yourdomain.com.conf
# Add/modify:
# client_max_body_size 100M;
# Also check PHP settings if using PHP
# In AaPanel: PHP > Settings > Upload Max Filesize
Quick Reference Commands
# Application Management
systemctl start irt-bank-soal
systemctl stop irt-bank-soal
systemctl restart irt-bank-soal
systemctl status irt-bank-soal
# Local Database Management (if using local PostgreSQL)
systemctl start postgresql
systemctl stop postgresql
systemctl restart postgresql
systemctl status postgresql
# Nginx Management
nginx -t # Test config
nginx -s reload # Reload config
systemctl restart nginx # Restart Nginx
# View Logs
tail -f /www/wwwlogs/api.yourdomain.com.log
tail -f /www/wwwlogs/api.yourdomain.com.error.log
# Application Logs (if configured)
tail -f /www/wwwroot/irt-bank-soal/logs/app.log
# Test Database Connection
# Local:
psql -U irt_user -d irt_bank_soal -h 127.0.0.1 -c "SELECT version();"
# Remote:
psql "postgresql://user:pass@host:port/db" -c "SELECT version();"
Security Checklist
- Changed AaPanel default port and password
- Database user has strong password
- SECRET_KEY is unique and 32+ characters
- SSL certificate installed and forced HTTPS
- CORS restricted to production domains only
- Firewall configured (only 80, 443, 22, 8888 open)
- Admin password is strong
- For local DB: PostgreSQL not exposed to internet
- For remote DB: IP whitelist configured (if supported)
- Regular backups configured
Backup Configuration
Database Backup
For Local Database:
# Create backup directory
mkdir -p /www/backup
# Manual backup
pg_dump -U irt_user -h 127.0.0.1 irt_bank_soal > /www/backup/irt_bank_soal_$(date +%Y%m%d).sql
# Automated backup (cron)
crontab -e
# Add: 0 2 * * * pg_dump -U irt_user -h 127.0.0.1 irt_bank_soal > /www/backup/irt_bank_soal_$(date +\%Y\%m\%d).sql
For Remote Database:
Most managed PostgreSQL providers have built-in backup features:
- Supabase: Dashboard > Database > Backups (daily automatic)
- Neon: Automatic point-in-time recovery
- AWS RDS: Automated backups with retention period
You can also backup manually:
# Manual backup from remote (requires postgresql-client)
pg_dump "postgresql://username:password@host:port/database" > /www/backup/irt_bank_soal_$(date +%Y%m%d).sql
# Or with SSL for providers like Neon
pg_dump "postgresql://username:password@host:port/database?sslmode=require" > /www/backup/irt_bank_soal_$(date +%Y%m%d).sql
Project Backup
# Backup project files
tar -czvf /www/backup/irt_project_$(date +%Y%m%d).tar.gz /www/wwwroot/irt-bank-soal
# Exclude venv to save space
tar -czvf /www/backup/irt_project_$(date +%Y%m%d).tar.gz --exclude='venv' /www/wwwroot/irt-bank-soal
Document End
Status: Ready for Deployment
Support: Refer to TEST.md for testing procedures and PRD.md for requirements.