| #!/usr/bin/env bash |
| |
| |
| |
| |
| |
| set -euo pipefail |
|
|
| RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m' |
| BLUE='\033[0;34m'; BOLD='\033[1m'; NC='\033[0m' |
|
|
| log() { echo -e "${BLUE}[$(date +'%H:%M:%S')]${NC} $*"; } |
| ok() { echo -e " ${GREEN}β${NC} $*"; } |
| warn() { echo -e " ${YELLOW}β ${NC} $*"; } |
| err() { echo -e " ${RED}β $*${NC}"; exit 1; } |
|
|
| echo -e "\n${BOLD}${BLUE}ββββββββββββββββββββββββββββββββββββββββββ${NC}" |
| echo -e "${BOLD}${BLUE}β ποΈ KomposIn Setup β${NC}" |
| echo -e "${BOLD}${BLUE}ββββββββββββββββββββββββββββββββββββββββββ${NC}\n" |
|
|
| |
| [ "$EUID" -eq 0 ] || err "Script ini harus dijalankan dengan sudo" |
|
|
| |
| log "Update sistem..." |
| apt-get update && apt-get upgrade -y |
|
|
| |
| log "Menginstall system libraries..." |
| apt-get install -y \ |
| python3.11 python3.11-venv python3-pip \ |
| nodejs npm \ |
| nginx \ |
| git git-lfs \ |
| curl wget \ |
| build-essential libssl-dev |
|
|
| ok "System packages terinstall" |
|
|
| |
| log "Setup user dan direktori..." |
| getent passwd komposin >/dev/null 2>&1 || { |
| useradd -m -s /bin/bash -d /home/komposin komposin |
| ok "User komposin dibuat" |
| } |
|
|
| mkdir -p /opt/komposin /var/log/komposin |
| chown -R komposin:komposin /opt/komposin /var/log/komposin |
| chmod 0755 /opt/komposin /var/log/komposin |
|
|
| |
| log "Setup FastAPI backend..." |
| cd /opt/komposin |
|
|
| |
| if [ -d "fpAI-komposin" ]; then |
| cd fpAI-komposin |
| git pull hf main 2>/dev/null || warn "git pull gagal" |
| else |
| git clone https://huggingface.co/KomposIn-Team/fpAI-komposin fpAI-komposin |
| cd fpAI-komposin |
| fi |
|
|
| git lfs pull |
|
|
| |
| cd /opt/komposin/fpAI-komposin/be |
| [ -d "venv" ] && rm -rf venv |
| python3.11 -m venv venv |
| source venv/bin/activate |
|
|
| |
| pip install --upgrade pip |
| pip install --extra-index-url https://download.pytorch.org/whl/cpu torch torchvision |
| pip install -r requirements.txt |
|
|
| ok "FastAPI backend ready" |
|
|
| |
| log "Setup Next.js frontend..." |
| cd /opt/komposin/fpAI-komposin/fe |
|
|
| |
| if ! grep -q "output.*standalone" next.config.ts 2>/dev/null; then |
| warn "next.config.ts belum punya output: 'standalone'" |
| warn "Tambahkan baris ini ke next.config.ts:" |
| warn " output: 'standalone'," |
| fi |
|
|
| npm install |
| npm run build |
|
|
| ok "Next.js frontend build selesai" |
|
|
| |
| log "Setup Nginx..." |
| cat > /etc/nginx/sites-available/komposin <<'EOF' |
| upstream backend { |
| server 127.0.0.1:8000; |
| keepalive 16; |
| } |
|
|
| upstream frontend { |
| server 127.0.0.1:3000; |
| keepalive 32; |
| } |
|
|
| server { |
| listen 80 default_server; |
| server_name _; |
| client_max_body_size 20M; |
|
|
| |
| limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s; |
| limit_req_zone $binary_remote_addr zone=web:10m rate=30r/s; |
|
|
| |
| location /api/ { |
| limit_req zone=api burst=30 nodelay; |
| rewrite ^/api/(.*) /$1 break; |
|
|
| proxy_pass http://backend; |
| 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_set_header Upgrade $http_upgrade; |
| proxy_set_header Connection "upgrade"; |
|
|
| proxy_read_timeout 180s; |
| proxy_connect_timeout 10s; |
| proxy_send_timeout 60s; |
| } |
|
|
| |
| location / { |
| limit_req zone=web burst=50 nodelay; |
|
|
| proxy_pass http://frontend; |
| 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_set_header Upgrade $http_upgrade; |
| proxy_set_header Connection "upgrade"; |
|
|
| proxy_read_timeout 60s; |
| } |
| } |
| EOF |
|
|
| |
| ln -sf /etc/nginx/sites-available/komposin /etc/nginx/sites-enabled/ |
| rm -f /etc/nginx/sites-enabled/default |
|
|
| |
| nginx -t || err "Nginx config error" |
| systemctl enable nginx |
| systemctl restart nginx |
| ok "Nginx configured dan running" |
|
|
| |
| log "Setup systemd services..." |
|
|
| |
| cat > /etc/systemd/system/komposin-backend.service <<EOF |
| [Unit] |
| Description=KomposIn FastAPI Backend |
| After=network.target |
| Wants=komposin-backend.service |
| |
| [Service] |
| Type=simple |
| User=komposin |
| Group=komposin |
| WorkingDirectory=/opt/komposin/fpAI-komposin/be |
| Environment="PATH=/opt/komposin/fpAI-komposin/be/venv/bin" |
| Environment="PYTHONDONTWRITEBYTECODE=1" |
| Environment="MODEL_PATH=/opt/komposin/fpAI-komposin/model/waste_segmentor_yolo26/waste_yolo26seg_best.pt" |
| ExecStart=/opt/komposin/fpAI-komposin/be/venv/bin/uvicorn main:app \ |
| --host 127.0.0.1 \ |
| --port 8000 \ |
| --workers 1 \ |
| --access-log |
| |
| StandardOutput=journal |
| StandardError=journal |
| Restart=on-failure |
| RestartSec=10s |
| |
| [Install] |
| WantedBy=multi-user.target |
| EOF |
|
|
| |
| cat > /etc/systemd/system/komposin-frontend.service <<EOF |
| [Unit] |
| Description=KomposIn Next.js Frontend |
| After=network.target |
| |
| [Service] |
| Type=simple |
| User=komposin |
| Group=komposin |
| WorkingDirectory=/opt/komposin/fpAI-komposin/fe |
| Environment="NODE_ENV=production" |
| Environment="PORT=3000" |
| Environment="HOSTNAME=127.0.0.1" |
| ExecStart=/usr/bin/node /opt/komposin/fpAI-komposin/fe/.next/standalone/server.js |
| |
| StandardOutput=journal |
| StandardError=journal |
| Restart=on-failure |
| RestartSec=10s |
| |
| [Install] |
| WantedBy=multi-user.target |
| EOF |
|
|
| |
| systemctl daemon-reload |
| systemctl enable komposin-backend.service komposin-frontend.service |
| ok "Systemd units created" |
|
|
| |
| log "Memulai services..." |
| systemctl start komposin-backend.service |
| systemctl start komposin-frontend.service |
| sleep 5 |
|
|
| |
| echo "" |
| log "Status service:" |
| systemctl status komposin-backend.service --no-pager | grep -E "Active|Main PID" |
| systemctl status komposin-frontend.service --no-pager | grep -E "Active|Main PID" |
|
|
| |
| log "Verifying setup..." |
| sleep 3 |
|
|
| BACKEND_OK=false |
| FRONTEND_OK=false |
|
|
| curl -f http://127.0.0.1:8000/health >/dev/null 2>&1 && BACKEND_OK=true || true |
| curl -f http://127.0.0.1:3000 >/dev/null 2>&1 && FRONTEND_OK=true || true |
|
|
| [ "$BACKEND_OK" = true ] && ok "Backend responding" || warn "Backend tidak respond" |
| [ "$FRONTEND_OK" = true ] && ok "Frontend responding" || warn "Frontend tidak respond" |
|
|
| |
| PUBLIC_IP=$(curl -s --max-time 5 ifconfig.me 2>/dev/null || \ |
| curl -s --max-time 5 api.ipify.org 2>/dev/null || \ |
| hostname -I | awk '{print $1}') |
|
|
| echo "" |
| echo -e "\n${GREEN}${BOLD}ββββββββββββββββββββββββββββββββββββββββββββ${NC}" |
| echo -e "${GREEN}${BOLD} β
KomposIn Non-Docker siap!${NC}" |
| echo -e "${GREEN}${BOLD}ββββββββββββββββββββββββββββββββββββββββββββ${NC}\n" |
|
|
| echo -e " π Aplikasi : ${GREEN}http://${PUBLIC_IP}${NC}" |
| echo -e " π‘ API Docs : ${GREEN}http://${PUBLIC_IP}/api/docs${NC}" |
| echo -e " π Project dir : ${GREEN}/opt/komposin/fpAI-komposin${NC}" |
| echo -e " π Backend log : journalctl -u komposin-backend.service -f" |
| echo -e " π Frontend log: journalctl -u komposin-frontend.service -f" |
| echo -e " π Restart : systemctl restart komposin-{backend,frontend}.service" |
| echo -e " π Stop : systemctl stop komposin-{backend,frontend}.service\n" |
|
|
| echo -e "${YELLOW}Pastikan port 80 sudah dibuka di Azure NSG (Network Security Group)!${NC}" |
| echo -e "${YELLOW}Buka: portal.azure.com β VM β Networking β Add inbound rule β Port 80${NC}\n" |
|
|