🚀 Salfanet Radius — Install Wizard

Panduan instalasi manual lengkap untuk deploy Salfanet Radius ISP Management di VPS Ubuntu.

📋

Ringkasan Instalasi

Step 1 — System Packages

Install dependencies, kernel module, timezone, NTP

Step 2 — Node.js 20 LTS

Install Node.js via NodeSource PPA

Step 3 — MySQL 8.0

Install MySQL, buat database & user

Step 4 — Deploy Aplikasi

Copy files, .env, npm install, Prisma migrate, seed

Step 5 — FreeRADIUS 3.x

Install & konfigurasi RADIUS server + SQL module

Step 6 — Nginx

Reverse proxy ke Next.js port 3000

Step 7 — PM2 & Build

Install PM2, buat swap, build Next.js, start app

Step 9 — Mobile APK (Opsional)

Build APK customer Android

Estimasi waktu: 25-30 menit tanpa APK, 45-70 menit dengan APK build. Redis hanya +2 menit.
🔧

Instalasi Otomatis (1 Command)

Jika tidak ingin manual, jalankan installer otomatis:

cd /root/salfanet-radius/vps-install
bash vps-installer.sh

Installer otomatis akan menjalankan semua step di bawah secara berurutan dengan UI interaktif.

📦 System Requirements

Minimum Hardware

ResourceMinimumRekomendasi
CPU1 core2 core
RAM2 GB4 GB
Disk15 GB30 GB+
NetworkPublic IP / Cloudflare TunnelStatic Public IP

Supported OS

OSStatus
Ubuntu 24.04 LTSRecommended
Ubuntu 22.04 LTSSupported
Ubuntu 20.04 LTSLegacy
Debian 11/12Experimental

Supported Environment

EnvironmentCatatan
VPS (KVM/Dedicated)Full support, UFW aktif
Proxmox LXCPerlu TUN/TAP device di host, UFW di-skip (pakai host firewall)
VM (VirtualBox/VMware)Full support
Bare MetalFull support
⚠️
Proxmox LXC: Aktifkan TUN device di host: echo "lxc.cgroup2.devices.allow: c 10:200 rwm" >> /etc/pve/lxc/<CTID>.conf dan echo "lxc.mount.entry: /dev/net/tun dev/net/tun none bind,create=file" >> /etc/pve/lxc/<CTID>.conf

Software yang Akan Di-Install

PackageVersiFungsi
Node.js20 LTSJavaScript runtime
MySQL8.0Database server
FreeRADIUS3.xRADIUS authentication server
NginxlatestReverse proxy & static files
PM2latestProcess manager (Node.js)
strongSwanlatestIPSec/L2TP VPN
xl2tpdlatestL2TP daemon
ChronylatestNTP time sync
CertbotlatestSSL/TLS certificates

⚙️ Konfigurasi

Sesuaikan nilai konfigurasi di bawah. Nilai ini akan digunakan di semua command pada step berikutnya.

🌐

Server

🗄️

Database MySQL

🔐

Aplikasi

💡
Semua command di step berikutnya akan otomatis menggunakan nilai konfigurasi di atas.

Step 1 — System Packages

Install semua system dependencies, kernel module, konfigurasi timezone dan NTP.

1.1 Update System & Install Packages

apt-get update && apt-get upgrade -y
apt-get install -y \
  curl wget git build-essential software-properties-common \
  ufw nginx certbot python3-certbot-nginx \
  sudo vim htop chrony ntpdate sshpass \
  xl2tpd strongswan strongswan-pki \
  libcharon-extra-plugins libstrongswan-standard-plugins

1.2 Setup PPP & TUN Device

Diperlukan untuk VPN (L2TP/PPTP) dan PPPoE.

# Buat device /dev/ppp dan /dev/net/tun
[ ! -e /dev/ppp ] && mknod /dev/ppp c 108 0 && chmod 600 /dev/ppp
mkdir -p /dev/net
[ ! -e /dev/net/tun ] && mknod /dev/net/tun c 10 200 && chmod 666 /dev/net/tun

# Auto-load kernel modules
cat > /etc/modules-load.d/ppp.conf << 'EOF'
ppp_generic
ppp_async
ppp_mppe
ppp_deflate
l2tp_core
l2tp_ppp
l2tp_netlink
tun
EOF

# Load modules sekarang
for mod in ppp_generic ppp_async ppp_mppe ppp_deflate tun; do
  modprobe $mod 2>/dev/null || true
done

# xl2tpd runtime directory
mkdir -p /var/run/xl2tpd
cat > /etc/tmpfiles.d/xl2tpd.conf << 'EOF'
d /var/run/xl2tpd 0755 root root -
EOF

1.3 Enable IP Forwarding

# Tambahkan ke sysctl.conf
cat >> /etc/sysctl.conf << 'EOF'

# IP Forwarding - Salfanet Radius
net.ipv4.ip_forward=1
net.ipv6.conf.all.forwarding=1
net.ipv4.tcp_syncookies=1
net.ipv4.conf.all.accept_redirects=0
net.ipv4.conf.all.send_redirects=0
EOF

sysctl -p

1.4 Timezone & NTP

# Set timezone Asia/Jakarta (WIB)
timedatectl set-timezone Asia/Jakarta

# Konfigurasi NTP servers Indonesia
cat > /etc/chrony/chrony.conf << 'EOF'
server 0.id.pool.ntp.org iburst
server 1.id.pool.ntp.org iburst
server 2.id.pool.ntp.org iburst
server 3.id.pool.ntp.org iburst
server asia.pool.ntp.org iburst
server time.google.com iburst
server time.cloudflare.com iburst

driftfile /var/lib/chrony/chrony.drift
makestep 1.0 3
rtcsync
allow 127.0.0.1
local stratum 10
EOF

systemctl restart chrony && systemctl enable chrony
chronyc makestep
hwclock --systohc
System packages selesai. Lanjut ke Step 2.

Step 2 — Node.js 20 LTS

# Install Node.js 20 via NodeSource
curl -fsSL https://deb.nodesource.com/setup_20.x | bash -
apt-get install -y nodejs

Verifikasi

node --version   # Harus v20.x.x
npm --version    # Harus v10.x.x

Optimasi npm untuk VPS

npm config set fetch-timeout 600000
npm config set fetch-retries 5
npm config set fetch-retry-mintimeout 10000
npm config set fetch-retry-maxtimeout 60000
Node.js terinstall. Lanjut ke Step 3.

Step 3 — MySQL 8.0

3.1 Install MySQL

apt-get install -y mysql-server mysql-client
systemctl start mysql && systemctl enable mysql

3.2 Secure MySQL

mysql -u root << 'SQLEOF'
ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'root123';
DELETE FROM mysql.user WHERE User='';
DROP DATABASE IF EXISTS test;
DELETE FROM mysql.db WHERE Db='test' OR Db='test\\_%';
FLUSH PRIVILEGES;
SQLEOF

3.3 Buat Database & User

mysql -u root -p'root123' << 'SQLEOF'
CREATE DATABASE IF NOT EXISTS salfanet_radius CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER IF NOT EXISTS 'salfanet_user'@'localhost' IDENTIFIED BY 'salfanetradius123';
GRANT ALL PRIVILEGES ON salfanet_radius.* TO 'salfanet_user'@'localhost';
FLUSH PRIVILEGES;
SQLEOF

3.4 Set Timezone MySQL

cat > /etc/mysql/mysql.conf.d/timezone.cnf << 'EOF'
[mysqld]
default-time-zone = '+07:00'
log_bin_trust_function_creators = 1
EOF

systemctl restart mysql

Verifikasi

mysql -u salfanet_user -p'salfanetradius123' salfanet_radius -e "SELECT NOW(), @@global.time_zone;"
MySQL siap. Lanjut ke Step 4.

Step 4 — Deploy Aplikasi

4.1 Upload & Extract

Upload ZIP production dari PC lokal ke VPS:

# Dari PC lokal (PowerShell/Terminal):
scp salfanet-radius-v*.zip root@VPS_IP:/root/
# Di VPS:
cd /root
apt-get install -y unzip
unzip salfanet-radius-v*.zip

# Copy ke app directory
mkdir -p /var/www/salfanet-radius
cp -r /root/salfanet-radius/* /var/www/salfanet-radius/
cp -r /root/salfanet-radius/.next /var/www/salfanet-radius/ 2>/dev/null || true
cp /root/salfanet-radius/.env* /var/www/salfanet-radius/ 2>/dev/null || true

4.2 Buat App User

# Buat user dedicated (opsional, bisa pakai root)
useradd -r -m -s /bin/bash -d /home/salfanet salfanet
usermod -aG sudo salfanet

4.3 Buat File .env

🔒
File .env berisi kredensial sensitif. Pastikan permission chmod 600.
cat > /var/www/salfanet-radius/.env << 'EOF'
DATABASE_URL="mysql://salfanet_user:salfanetradius123@localhost:3306/salfanet_radius?connection_limit=10&pool_timeout=20"
TZ="Asia/Jakarta"
NEXT_PUBLIC_TIMEZONE="Asia/Jakarta"
NEXT_PUBLIC_APP_NAME="SALFANET RADIUS ISP"
NEXT_PUBLIC_APP_URL="http://YOUR_VPS_IP"
NEXTAUTH_SECRET="GENERATE_ME"
NEXTAUTH_URL="http://YOUR_VPS_IP"
NODE_ENV="production"
EOF

chmod 600 /var/www/salfanet-radius/.env

4.4 Upload Firebase Service Account

🔥
File ini TIDAK ada di ZIP (keamanan). Upload terpisah dari PC lokal:
# Dari PC lokal:
scp src/lib/firebase-service-account.json root@YOUR_VPS_IP:/var/www/salfanet-radius/src/lib/

4.5 Install Dependencies

cd /var/www/salfanet-radius
npm install --production=false
Proses ini bisa memakan waktu 5-10 menit tergantung koneksi internet.

4.6 Setup Prisma (Database Schema)

cd /var/www/salfanet-radius

# Generate Prisma client
npx prisma generate

# Push schema ke database (buat tabel)
npx prisma db push --accept-data-loss --skip-generate

# Verifikasi tabel dibuat
mysql -u salfanet_user -p'salfanetradius123' salfanet_radius -e "SHOW TABLES;"

4.7 Seed Database (Data Awal)

cd /var/www/salfanet-radius

# Seed semua data awal (admin user, permissions, templates)
npx tsx prisma/seeds/seed-all.ts

4.8 Fix Permissions

chown -R salfanet:salfanet /var/www/salfanet-radius
find /var/www/salfanet-radius -type f -exec chmod 644 {} \;
find /var/www/salfanet-radius -type d -exec chmod 755 {} \;
chmod +x /var/www/salfanet-radius/node_modules/.bin/*
chmod +x /var/www/salfanet-radius/node_modules/@prisma/engines/* 2>/dev/null || true
Aplikasi deployed. Lanjut ke Step 5.

Step 5 — FreeRADIUS 3.x

5.1 Install FreeRADIUS

apt-get install -y freeradius freeradius-mysql freeradius-utils freeradius-rest
systemctl stop freeradius

5.2 Detect Config Directory

# Cari lokasi config FreeRADIUS
FR_DIR=""
for dir in /etc/freeradius/3.0 /etc/freeradius; do
  [ -d "$dir" ] && FR_DIR="$dir" && break
done
echo "FreeRADIUS config: $FR_DIR"

5.3 Konfigurasi SQL Module

cat > $FR_DIR/mods-available/sql << 'EOF'
sql {
    driver = "rlm_sql_mysql"
    dialect = "mysql"
    server = "localhost"
    port = 3306
    login = "salfanet_user"
    password = "salfanetradius123"
    radius_db = "salfanet_radius"
    read_clients = yes
    client_table = "nas"
    
    pool {
        start = 5
        min = 3
        max = 32
        spare = 3
        uses = 0
        retry_delay = 30
        lifetime = 0
        idle_timeout = 60
    }
}
EOF

# Enable SQL module
ln -sf $FR_DIR/mods-available/sql $FR_DIR/mods-enabled/sql

5.4 Konfigurasi REST Module

cat > $FR_DIR/mods-available/rest << 'EOF'
rest {
    connect_uri = "http://localhost:3000"
    connect_timeout = 5.0
    
    authorize {
        uri = "${..connect_uri}/api/radius/authorize"
        method = "post"
        body = "json"
        data = '{"username": "%{User-Name}", "nasIp": "%{NAS-IP-Address}"}'
        tls = {}
    }
    
    post-auth {
        uri = "${..connect_uri}/api/radius/post-auth"
        method = "post"
        body = "json"
        data = '{"username": "%{User-Name}", "reply": "%{reply:Packet-Type}", "nasIp": "%{NAS-IP-Address}", "framedIp": "%{reply:Framed-IP-Address}"}'
        tls = {}
    }
    
    accounting {
        uri = "${..connect_uri}/api/radius/accounting"
        method = "post"
        body = "json"
        data = '{"username": "%{User-Name}", "statusType": "%{Acct-Status-Type}", "sessionId": "%{Acct-Session-Id}", "nasIp": "%{NAS-IP-Address}", "framedIp": "%{Framed-IP-Address}", "sessionTime": "%{Acct-Session-Time}", "inputOctets": "%{Acct-Input-Octets}", "outputOctets": "%{Acct-Output-Octets}"}'
        tls = {}
    }
}
EOF
💡
REST module akan di-enable SETELAH aplikasi running (Step 7). Jangan enable sekarang karena app belum start.

5.5 Copy FreeRADIUS Config dari Project

# Copy konfigurasi dari project (sites, clients, policy)
cp /var/www/salfanet-radius/freeradius-config/clients.conf $FR_DIR/clients.conf 2>/dev/null
cp /var/www/salfanet-radius/freeradius-config/sites-available/default $FR_DIR/sites-available/default 2>/dev/null
cp /var/www/salfanet-radius/freeradius-config/policy.d/filter $FR_DIR/policy.d/filter 2>/dev/null

5.6 Setup Sudoers

cat > /etc/sudoers.d/salfanet-freeradius << 'EOF'
salfanet ALL=(ALL) NOPASSWD: /bin/systemctl restart freeradius
salfanet ALL=(ALL) NOPASSWD: /bin/systemctl start freeradius
salfanet ALL=(ALL) NOPASSWD: /bin/systemctl stop freeradius
salfanet ALL=(ALL) NOPASSWD: /bin/systemctl status freeradius
EOF
chmod 440 /etc/sudoers.d/salfanet-freeradius

5.7 Test & Start FreeRADIUS

# Test konfigurasi
freeradius -XC 2>&1 | tail -5

# Start & enable
systemctl start freeradius
systemctl enable freeradius
systemctl status freeradius
FreeRADIUS berjalan. Lanjut ke Step 6.

Step 6 — Nginx Reverse Proxy

6.1 Buat Site Config

cat > /etc/nginx/sites-available/salfanet-radius << 'NGINX'
server {
    listen 80;
    listen [::]:80;
    server_name YOUR_VPS_IP _;

    client_max_body_size 100M;
    proxy_connect_timeout 600;
    proxy_send_timeout 600;
    proxy_read_timeout 600;
    send_timeout 600;

    # Gzip
    gzip on;
    gzip_vary on;
    gzip_min_length 1024;
    gzip_types text/plain text/css application/json application/javascript text/xml application/xml;

    # 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;

    # APK download
    location /downloads/ {
        alias /var/www/salfanet-radius/public/downloads/;
        autoindex off;
    }

    # Next.js static assets (cache 1 tahun)
    location /_next/static/ {
        alias /var/www/salfanet-radius/.next/static/;
        expires 365d;
        add_header Cache-Control "public, immutable";
    }

    # Main proxy ke Next.js
    location / {
        proxy_pass http://localhost:3000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_cache_bypass $http_upgrade;
    }
}
NGINX

6.2 Enable Site & Restart

# Hapus default, enable salfanet
rm -f /etc/nginx/sites-enabled/default
ln -sf /etc/nginx/sites-available/salfanet-radius /etc/nginx/sites-enabled/

# Test & restart
nginx -t && systemctl restart nginx && systemctl enable nginx
Nginx aktif. Lanjut ke Step 7.

Step 7 — PM2, Swap & Build

7.1 Install PM2

npm install -g pm2
pm2 --version

7.2 Buat Swap (WAJIB untuk VPS 2GB RAM)

🚨
KRITIS: Tanpa swap, build Next.js AKAN gagal (OOM killed) pada VPS dengan RAM ≤ 2GB.
# Cek apakah sudah ada swap
swapon --show

# Jika belum ada, buat 2GB swap
dd if=/dev/zero of=/swapfile bs=1M count=2048 status=progress
chmod 600 /swapfile
mkswap /swapfile
swapon /swapfile

# Permanent (survive reboot)
echo '/swapfile none swap sw 0 0' >> /etc/fstab

# Verifikasi
free -h

7.3 Build Next.js

⚠️
Gunakan npm run build:vps — BUKAN npm run build. Command biasa menggunakan 4GB heap yang melebihi RAM.
cd /var/www/salfanet-radius

# Stop PM2 dulu untuk bebaskan RAM
pm2 stop all 2>/dev/null || true

# Bersihkan cache build lama
rm -rf .next .turbo node_modules/.cache

# Build dengan VPS memory limit (1.5GB heap)
NEXT_TELEMETRY_DISABLED=1 npm run build:vps
Build memakan waktu 5-10 menit. Jangan interrupt prosesnya.

7.4 Buat PM2 Ecosystem Config

cat > /var/www/salfanet-radius/ecosystem.config.js << 'EOF'
module.exports = {
  apps: [
    {
      name: 'salfanet-radius',
      script: 'node_modules/next/dist/bin/next',
      args: 'start',
      cwd: '/var/www/salfanet-radius',
      instances: 1,
      exec_mode: 'cluster',
      max_memory_restart: '400M',
      node_args: ['--max-old-space-size=350', '--optimize-for-size'],
      env: {
        NODE_ENV: 'production',
        PORT: 3000,
        TZ: 'Asia/Jakarta'
      },
      error_file: './logs/error.log',
      out_file: './logs/out.log',
      merge_logs: true,
      autorestart: true,
      cron_restart: '0 */6 * * *'
    },
    {
      name: 'salfanet-cron',
      script: './cron-service.js',
      cwd: '/var/www/salfanet-radius',
      instances: 1,
      exec_mode: 'fork',
      max_memory_restart: '150M',
      node_args: ['--max-old-space-size=120', '--optimize-for-size'],
      env: {
        NODE_ENV: 'production',
        API_URL: 'http://localhost:3000',
        TZ: 'Asia/Jakarta'
      },
      error_file: './logs/cron-error.log',
      out_file: './logs/cron-out.log',
      merge_logs: true,
      autorestart: true
    }
  ]
};
EOF

mkdir -p /var/www/salfanet-radius/logs

7.5 Start Aplikasi dengan PM2

cd /var/www/salfanet-radius

# Start sebagai app user
sudo su - salfanet -c "cd /var/www/salfanet-radius && pm2 start ecosystem.config.js"
sudo su - salfanet -c "pm2 save"

# Setup auto-start saat boot
sudo /usr/lib/node_modules/pm2/bin/pm2 startup systemd -u salfanet --hp /home/salfanet

# Verifikasi
sudo su - salfanet -c "pm2 status"

7.6 Enable FreeRADIUS REST Module

Sekarang app sudah running, enable REST module agar FreeRADIUS bisa memanggil API:

ln -sf $FR_DIR/mods-available/rest $FR_DIR/mods-enabled/rest
systemctl restart freeradius

Verifikasi Semua Berjalan

# Cek PM2
pm2 status

# Cek Next.js merespons
curl -s -o /dev/null -w "%{http_code}" http://localhost:3000

# Cek FreeRADIUS
systemctl status freeradius

# Cek Nginx
systemctl status nginx

# Cek app dari browser
echo "Buka: http://$(hostname -I | awk '{print $1}')"
🎉
Instalasi selesai! Buka http://VPS_IP di browser. Login default: admin / admin123

Step 8 — Redis Cache (Opsional, Direkomendasikan)

Redis meningkatkan performa signifikan: cache RADIUS auth, dashboard real-time, rate limiting terdistribusi, tracking online users, dan distributed lock untuk cron job.

💡
Redis opsional — semua fitur tetap berjalan tanpa Redis (fallback ke MySQL/in-memory). Namun sangat direkomendasikan untuk produksi dengan banyak pelanggan.

8.1 Install Redis

apt-get install -y redis-server

8.2 Konfigurasi Redis

Edit konfigurasi Redis untuk produksi:

# Backup config asli
cp /etc/redis/redis.conf /etc/redis/redis.conf.bak

# Set bind hanya localhost (keamanan)
sed -i 's/^bind .*/bind 127.0.0.1 -::1/' /etc/redis/redis.conf

# Aktifkan maxmemory (sesuaikan dengan RAM VPS, contoh 256MB)
sed -i 's/^# maxmemory .*/maxmemory 256mb/' /etc/redis/redis.conf
sed -i 's/^# maxmemory-policy .*/maxmemory-policy allkeys-lru/' /etc/redis/redis.conf
⚠️
Sesuaikan maxmemory dengan RAM VPS Anda: 128mb untuk 1GB RAM, 256mb untuk 2GB+, 512mb untuk 4GB+.

8.3 Enable & Start Redis

systemctl enable redis-server
systemctl start redis-server
systemctl status redis-server

# Test koneksi
redis-cli ping
# Output harus: PONG

8.4 Tambahkan REDIS_URL ke .env

Buka file .env dan tambahkan baris berikut:

echo '' >> /var/www/salfanet-radius/.env
echo '# Redis - Cache & Performance' >> /var/www/salfanet-radius/.env
echo 'REDIS_URL=redis://127.0.0.1:6379' >> /var/www/salfanet-radius/.env

# Verifikasi
grep REDIS_URL /var/www/salfanet-radius/.env

8.5 Restart Aplikasi

pm2 restart salfanet-radius
pm2 restart salfanet-cron
pm2 status

8.6 Verifikasi Redis Berjalan

# Cek Redis keys diisi oleh aplikasi (setelah beberapa request)
redis-cli keys "*"

# Monitor real-time
redis-cli monitor
# Tekan Ctrl+C untuk keluar
📊

Fitur yang Di-cache Redis

FiturTTLManfaat
RADIUS Auth Cache60 detikPPPoE login jauh lebih cepat
Dashboard Stats30 detikKurangi query DB berat
Online Users Tracking2 jamHitungan online real-time tanpa query radacct
Rate LimitingPer windowProteksi API terdistribusi
Cron Distributed LockPer jobCegah double-run jika multi-instance
Redis aktif dan terhubung. Lanjut ke Step 9 (Mobile APK) jika diperlukan, atau selesai!

Step 9 — Mobile APK Build (Opsional)

Build APK customer Android langsung di VPS. Membutuhkan 3GB+ disk space dan 20-40 menit.

9.1 Install Java 17

apt-get install -y openjdk-17-jdk
java -version

9.2 Install Android SDK

mkdir -p /opt/android-sdk/cmdline-tools
cd /opt/android-sdk/cmdline-tools
wget -q https://dl.google.com/android/repository/commandlinetools-linux-11076708_latest.zip -O tools.zip
unzip -q tools.zip && mv cmdline-tools latest && rm tools.zip

# Environment variables
cat > /etc/profile.d/android-sdk.sh << 'EOF'
export ANDROID_HOME=/opt/android-sdk
export ANDROID_SDK_ROOT=/opt/android-sdk
export PATH=$PATH:$ANDROID_HOME/cmdline-tools/latest/bin:$ANDROID_HOME/platform-tools
EOF
source /etc/profile.d/android-sdk.sh

# Accept licenses & install components
yes | sdkmanager --licenses
sdkmanager "platforms;android-35" "build-tools;35.0.0" "platform-tools"

9.3 Build APK

cd /var/www/salfanet-radius/mobile-app

# Set API URL
cat > .env << EOF
API_URL=http://YOUR_VPS_IP:3000
API_TIMEOUT=30000
APP_NAME=SALFANET RADIUS
EOF

# Install dependencies & build
npm install
cd android && chmod +x gradlew
./gradlew assembleRelease --max-workers=2 -Dorg.gradle.jvmargs="-Xmx1536m"

# Copy APK ke public downloads
mkdir -p /var/www/salfanet-radius/public/downloads
cp app/build/outputs/apk/release/app-release.apk /var/www/salfanet-radius/public/downloads/salfanet-radius.apk
echo "APK tersedia di: http://YOUR_VPS_IP/downloads/salfanet-radius.apk"

🔥 Firewall & Ports

💡
Jika menggunakan Proxmox LXC, UFW di-skip — konfigurasi firewall di host Proxmox.

Port Map Lengkap

PortProtocolServiceAkses
22TCPSSHExternal
80TCPHTTP (Nginx)External
443TCPHTTPS (Nginx)External
1812UDPRADIUS AuthMikroTik only
1813UDPRADIUS AccountingMikroTik only
3799UDPRADIUS CoAMikroTik only
500UDPIPSec IKEVPN
4500UDPIPSec NAT-TVPN
1701UDPL2TP TunnelVPN
3000TCPNext.js (internal)Localhost
3306TCPMySQL (internal)Localhost
6379TCPRedis (internal)Localhost

Setup UFW (VPS/VM)

# Enable UFW dengan rules
ufw allow 22/tcp        # SSH
ufw allow 80/tcp        # HTTP
ufw allow 443/tcp       # HTTPS
ufw allow 1812/udp      # RADIUS Auth
ufw allow 1813/udp      # RADIUS Accounting
ufw allow 3799/udp      # RADIUS CoA
ufw allow 500/udp       # IPSec IKE
ufw allow 4500/udp      # IPSec NAT-T
ufw allow 1701/udp      # L2TP

# Enable (ketik 'y' untuk konfirmasi)
ufw --force enable
ufw status verbose

🔧 Post-Install

Login Default

FieldValue
URLhttp://VPS_IP/admin/login
Usernameadmin
Passwordadmin123
🔒
SEGERA ganti password admin setelah login pertama kali di menu Settings → Profile.

Setup MikroTik RADIUS

Di MikroTik, tambahkan RADIUS server:

/radius add service=ppp address=VPS_IP secret=testing123 authentication-port=1812 accounting-port=1813 timeout=3000
/radius incoming set accept=yes port=3799

# Enable RADIUS pada PPP
/ppp profile set default use-radius=yes
/ppp aaa set use-radius=yes accounting=yes interim-update=5m

Setup SSL — Certbot (Opsional, Direkomendasikan)

🔒
Pastikan DNS {{domain}} sudah pointing ke IP {{ip}} sebelum jalankan certbot. Cek dengan: dig +short {{domain}}
# Pastikan DNS sudah pointing ke IP VPS
dig +short DOMAIN_OPSIONAL

# Request SSL certificate
certbot --nginx -d DOMAIN_OPSIONAL -m admin@yourdomain.com --agree-tos --non-interactive --redirect

# Verifikasi
nginx -t && systemctl reload nginx

# Test auto-renew
certbot renew --dry-run

Update .env Setelah SSL Aktif

Setelah SSL terpasang, update NEXTAUTH_URL dan NEXT_PUBLIC_APP_URL ke HTTPS:

# Update .env dengan HTTPS URL
sed -i 's|NEXTAUTH_URL=.*|NEXTAUTH_URL="https://DOMAIN_OPSIONAL"|' /var/www/salfanet-radius/.env
sed -i 's|NEXT_PUBLIC_APP_URL=.*|NEXT_PUBLIC_APP_URL="https://DOMAIN_OPSIONAL"|' /var/www/salfanet-radius/.env

# Restart app
pm2 restart salfanet-radius salfanet-cron

Deploy Update Script

/dev/null || true
echo \"[DEPLOY] Installing dependencies...\"
npm install --production=false
echo \"[DEPLOY] Generating Prisma client...\"
npx prisma generate
npx prisma db push --accept-data-loss --skip-generate
echo \"[DEPLOY] Building...\"
pm2 stop all
rm -rf .next node_modules/.cache
NEXT_TELEMETRY_DISABLED=1 npm run build:vps
echo \"[DEPLOY] Fixing permissions...\"
chown -R {{user}}:{{user}} {{appdir}}
echo \"[DEPLOY] Restarting PM2...\"
sudo su - {{user}} -c 'pm2 restart ecosystem.config.js'
echo \"[DEPLOY] Done!\"
DEPLOY
chmod +x {{appdir}}/deploy.sh">cat > /var/www/salfanet-radius/deploy.sh << 'DEPLOY'
#!/bin/bash
cd /var/www/salfanet-radius
echo "[DEPLOY] Pulling latest code..."
git pull origin main 2>/dev/null || true
echo "[DEPLOY] Installing dependencies..."
npm install --production=false
echo "[DEPLOY] Generating Prisma client..."
npx prisma generate
npx prisma db push --accept-data-loss --skip-generate
echo "[DEPLOY] Building..."
pm2 stop all
rm -rf .next node_modules/.cache
NEXT_TELEMETRY_DISABLED=1 npm run build:vps
echo "[DEPLOY] Fixing permissions..."
chown -R salfanet:salfanet /var/www/salfanet-radius
echo "[DEPLOY] Restarting PM2..."
sudo su - salfanet -c "pm2 restart ecosystem.config.js"
echo "[DEPLOY] Done!"
DEPLOY
chmod +x /var/www/salfanet-radius/deploy.sh

Useful Commands

PerintahFungsi
pm2 statusLihat status semua proses
pm2 logsLihat log realtime
pm2 restart allRestart semua proses
pm2 monitMonitor CPU/RAM realtime
systemctl status freeradiusStatus FreeRADIUS
systemctl status nginxStatus Nginx
systemctl status mysqlStatus MySQL
radtest user pass localhost 0 testing123Test RADIUS auth
free -hCek penggunaan RAM & swap
df -hCek disk space

🔧 Troubleshooting

Build Gagal — OOM Killed

💥

Error: "Killed" atau "JavaScript heap out of memory"

Penyebab: RAM tidak cukup untuk build Next.js (butuh minimal 1.5GB free)

Solusi:

  1. Pastikan swap sudah aktif: swapon --show
  2. Stop semua service dulu: pm2 stop all
  3. Free memory: sync && echo 3 > /proc/sys/vm/drop_caches
  4. Gunakan npm run build:vps (1.5GB) atau npm run build:low-mem (1GB)
  5. Jika masih gagal, tambah swap: dd if=/dev/zero of=/swapfile2 bs=1M count=2048 && mkswap /swapfile2 && swapon /swapfile2
# Panduan lengkap fix OOM:
pm2 stop all
sync && echo 3 > /proc/sys/vm/drop_caches
swapon --show  # Pastikan swap aktif
free -h        # Pastikan ada minimal 1GB free (RAM + swap)
cd /var/www/salfanet-radius
rm -rf .next node_modules/.cache
NEXT_TELEMETRY_DISABLED=1 npm run build:vps

FreeRADIUS Gagal Start

📡

Error: "Failed to start FreeRADIUS"

Debug:

# Jalankan debug mode
freeradius -X

# Cek log
journalctl -u freeradius -n 50 --no-pager

# Common fixes:
# 1. SQL module gagal connect → cek DB credentials di mods-available/sql
# 2. Port sudah terpakai → fuser -k 1812/udp
# 3. Permission error → chown -R freerad:freerad /etc/freeradius/3.0

Nginx 502 Bad Gateway

🌐

Error: "502 Bad Gateway" di browser

Penyebab: Next.js (PM2) belum running atau crash.

# Cek PM2
pm2 status
pm2 logs salfanet-radius --lines 50

# Cek port 3000
ss -tlnp | grep 3000

# Restart jika perlu
pm2 restart salfanet-radius

# Cek Nginx config
nginx -t
cat /var/log/nginx/error.log | tail -20

Prisma Error

🗄️

Error: "spawn schema-engine EACCES" atau Prisma client error

# Fix executable permissions
chmod +x node_modules/@prisma/engines/*
chmod +x node_modules/.prisma/client/*

# Regenerate Prisma client
npx prisma generate

# Fix schema push
npx prisma db push --accept-data-loss --skip-generate

# Nuclear option: reinstall
rm -rf node_modules/.prisma
npm install

MySQL Connection Refused

🗄️

Error: "Can't connect to MySQL" atau "Access denied"

# Cek MySQL running
systemctl status mysql

# Test koneksi
mysql -u salfanet_user -p'salfanetradius123' salfanet_radius -e "SELECT 1;"

# Jika access denied, reset user:
mysql -u root -p'root123' << 'EOF'
DROP USER IF EXISTS 'salfanet_user'@'localhost';
CREATE USER 'salfanet_user'@'localhost' IDENTIFIED BY 'salfanetradius123';
GRANT ALL PRIVILEGES ON salfanet_radius.* TO 'salfanet_user'@'localhost';
FLUSH PRIVILEGES;
EOF

# Cek DATABASE_URL di .env
cat /var/www/salfanet-radius/.env | grep DATABASE_URL

Port 3000 Already in Use

🔌

Error: "EADDRINUSE: address already in use :::3000"

# Cari proses yang pakai port 3000
lsof -i :3000 || ss -tlnp | grep 3000

# Kill proses
fuser -k 3000/tcp

# Restart PM2
pm2 restart salfanet-radius

RADIUS Auth Gagal dari MikroTik

📡

MikroTik: "RADIUS server not responding" atau "Access-Reject"

# 1. Cek FreeRADIUS jalan
systemctl status freeradius

# 2. Test lokal  
radtest testuser testpass localhost 0 testing123

# 3. Cek firewall (port 1812/1813 terbuka?)
ufw status | grep -E "1812|1813"

# 4. Cek NAS terdaftar di database
mysql -u salfanet_user -p'salfanetradius123' salfanet_radius \
  -e "SELECT * FROM nas;"

# 5. Cek log realtime saat MikroTik auth
journalctl -u freeradius -f

# 6. Pastikan IP MikroTik terdaftar di NAS (via admin panel)
# Admin → Network → Routers → tambahkan NAS

L2TP VPN Tidak Konek

🔐

VPN L2TP tidak bisa establish tunnel

# 1. Cek port IPSec
ufw status | grep -E "500|4500|1701"

# 2. Cek strongSwan
systemctl status strongswan-starter
ipsec statusall

# 3. Cek xl2tpd
systemctl status xl2tpd

# 4. Cek IP forwarding
sysctl net.ipv4.ip_forward   # Harus = 1

# 5. Cek kernel modules
lsmod | grep -E "l2tp|ppp"

# 6. Log debug
journalctl -u strongswan-starter -f
journalctl -u xl2tpd -f

Permission Denied

🔓

Error: "EACCES: permission denied" pada berbagai operasi

# Fix semua permission
chown -R salfanet:salfanet /var/www/salfanet-radius
find /var/www/salfanet-radius -type f -exec chmod 644 {} \;
find /var/www/salfanet-radius -type d -exec chmod 755 {} \;
chmod +x /var/www/salfanet-radius/node_modules/.bin/*
chmod +x /var/www/salfanet-radius/node_modules/@prisma/engines/* 2>/dev/null
chmod 600 /var/www/salfanet-radius/.env

# Fix PM2
mkdir -p /home/salfanet/.pm2/logs /home/salfanet/.pm2/pids
chown -R salfanet:salfanet /home/salfanet/.pm2

# Fix Node.js binaries
chmod 755 /usr/bin/node /usr/bin/npm /usr/bin/pm2 2>/dev/null

🗑 Uninstall

⚠️
PERINGATAN: Perintah di bawah akan menghapus SEMUA data dan konfigurasi Salfanet Radius. Backup dulu!

Backup Database

mysqldump -u root -p'root123' salfanet_radius > /root/salfanet_radius_backup_$(date +%Y%m%d).sql
echo "Backup tersedia di: /root/salfanet_radius_backup_*.sql"

Hapus Semua

# Stop PM2
sudo su - salfanet -c "pm2 delete all" 2>/dev/null
sudo su - salfanet -c "pm2 kill" 2>/dev/null

# Hapus app
rm -rf /var/www/salfanet-radius
userdel -r salfanet 2>/dev/null

# Hapus FreeRADIUS
systemctl stop freeradius
apt-get purge -y freeradius freeradius-mysql freeradius-utils freeradius-rest
rm -rf /etc/freeradius

# Hapus MySQL (HATI-HATI: semua DB hilang!)
systemctl stop mysql
apt-get purge -y mysql-server mysql-client
rm -rf /etc/mysql /var/lib/mysql /var/log/mysql

# Hapus Nginx config
rm -f /etc/nginx/sites-enabled/salfanet-radius
rm -f /etc/nginx/sites-available/salfanet-radius
systemctl restart nginx

# Hapus PM2
npm uninstall -g pm2

# Hapus swap (opsional)
swapoff /swapfile && rm -f /swapfile
sed -i '/swapfile/d' /etc/fstab

echo "Uninstall selesai."