first commit
This commit is contained in:
9
.env.example
Normal file
9
.env.example
Normal file
@@ -0,0 +1,9 @@
|
||||
APP_PORT=8099
|
||||
SPOTA_BASE_URL=https://spota.untan.ac.id/steven/API
|
||||
SPOTA_ALLOWED_ENDPOINTS=login.php,getListTugasAkhir.php,getListMahasiswa.php,getListDosen.php,sendMail.php
|
||||
|
||||
# Optional. If set, callers must send X-Proxy-Token: value or ?proxy_token=value.
|
||||
PROXY_TOKEN=
|
||||
|
||||
CONNECT_TIMEOUT=10
|
||||
REQUEST_TIMEOUT=30
|
||||
13
Dockerfile
Normal file
13
Dockerfile
Normal file
@@ -0,0 +1,13 @@
|
||||
FROM php:8.2-apache-bookworm
|
||||
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y --no-install-recommends curl libcurl4-openssl-dev \
|
||||
&& docker-php-ext-install curl \
|
||||
&& a2enmod rewrite \
|
||||
&& printf 'ServerName localhost\n' > /etc/apache2/conf-available/server-name.conf \
|
||||
&& a2enconf server-name \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
COPY public/ /var/www/html/
|
||||
|
||||
EXPOSE 80
|
||||
103
README.md
Normal file
103
README.md
Normal file
@@ -0,0 +1,103 @@
|
||||
# SPOTA Proxy
|
||||
|
||||
Aplikasi proxy kecil dan terpisah untuk meneruskan request dari project KP ke SPOTA melalui server yang masih bisa mengakses `spota.untan.ac.id`, misalnya `ifserver1`.
|
||||
|
||||
Proxy ini dibuat sebagai produk/deployable terpisah dari `service-portal-kp`. Deploy di `ifserver1`, lalu project KP di `ifserver2` memanggil proxy ini, bukan langsung ke SPOTA.
|
||||
|
||||
## Endpoint
|
||||
|
||||
Default endpoint yang diizinkan:
|
||||
|
||||
- `/login.php`
|
||||
- `/getListTugasAkhir.php`
|
||||
- `/getListMahasiswa.php`
|
||||
- `/getListDosen.php`
|
||||
- `/sendMail.php`
|
||||
- `/healthz`
|
||||
|
||||
Endpoint selain daftar `SPOTA_ALLOWED_ENDPOINTS` akan ditolak dengan `404` supaya service ini tidak menjadi open proxy bebas.
|
||||
|
||||
## Deploy Coolify di ifserver1
|
||||
|
||||
Gunakan resource Docker Compose terpisah.
|
||||
|
||||
Konfigurasi yang disarankan:
|
||||
|
||||
```text
|
||||
Repository: repository spota-proxy ini
|
||||
Branch: main
|
||||
Base directory: spota-proxy
|
||||
Compose file: docker-compose.yml
|
||||
Port aplikasi: 8099
|
||||
```
|
||||
|
||||
Jika repository hanya berisi folder ini, kosongkan `Base directory`.
|
||||
|
||||
Environment minimal:
|
||||
|
||||
```env
|
||||
APP_PORT=8099
|
||||
SPOTA_BASE_URL=https://spota.untan.ac.id/steven/API
|
||||
SPOTA_ALLOWED_ENDPOINTS=login.php,getListTugasAkhir.php,getListMahasiswa.php,getListDosen.php,sendMail.php
|
||||
PROXY_TOKEN=ganti_dengan_token_panjang
|
||||
CONNECT_TIMEOUT=10
|
||||
REQUEST_TIMEOUT=30
|
||||
```
|
||||
|
||||
`PROXY_TOKEN` opsional, tetapi disarankan jika service dapat diakses dari luar network internal.
|
||||
|
||||
## Tes dari ifserver1
|
||||
|
||||
```bash
|
||||
curl -i http://127.0.0.1:8099/healthz
|
||||
```
|
||||
|
||||
Tes akses SPOTA lewat proxy:
|
||||
|
||||
```bash
|
||||
curl -i -X POST "http://127.0.0.1:8099/login.php" \
|
||||
-H "X-Proxy-Token: ganti_dengan_token_panjang" \
|
||||
-d "username=USERNAME_SPOTA" \
|
||||
-d "password=PASSWORD_SPOTA"
|
||||
```
|
||||
|
||||
Jika username/password salah tetapi proxy sehat, respons akan tetap berasal dari SPOTA, misalnya:
|
||||
|
||||
```json
|
||||
{"status":0,"msg":"Username dan password tidak cocok!!!"}
|
||||
```
|
||||
|
||||
## Tes dari ifserver2
|
||||
|
||||
```bash
|
||||
curl -i http://IP_IFSERVER1:8099/healthz
|
||||
```
|
||||
|
||||
```bash
|
||||
curl -i -X POST "http://IP_IFSERVER1:8099/login.php" \
|
||||
-H "X-Proxy-Token: ganti_dengan_token_panjang" \
|
||||
-d "username=USERNAME_SPOTA" \
|
||||
-d "password=PASSWORD_SPOTA"
|
||||
```
|
||||
|
||||
Jika menggunakan domain internal di Coolify, ganti `http://IP_IFSERVER1:8099` dengan URL domain tersebut.
|
||||
|
||||
## Integrasi ke Project KP
|
||||
|
||||
Ubah base URL SPOTA di project KP dari:
|
||||
|
||||
```text
|
||||
https://spota.untan.ac.id/steven/API
|
||||
```
|
||||
|
||||
menjadi URL proxy di `ifserver1`, contoh:
|
||||
|
||||
```text
|
||||
http://IP_IFSERVER1:8099
|
||||
```
|
||||
|
||||
Jika `PROXY_TOKEN` diaktifkan, request dari project KP juga harus mengirim header:
|
||||
|
||||
```text
|
||||
X-Proxy-Token: ganti_dengan_token_panjang
|
||||
```
|
||||
21
docker-compose.yml
Normal file
21
docker-compose.yml
Normal file
@@ -0,0 +1,21 @@
|
||||
services:
|
||||
spota-proxy:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
container_name: spota-proxy
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "${APP_PORT:-8099}:80"
|
||||
environment:
|
||||
SPOTA_BASE_URL: "${SPOTA_BASE_URL:-https://spota.untan.ac.id/steven/API}"
|
||||
SPOTA_ALLOWED_ENDPOINTS: "${SPOTA_ALLOWED_ENDPOINTS:-login.php,getListTugasAkhir.php,getListMahasiswa.php,getListDosen.php,sendMail.php}"
|
||||
PROXY_TOKEN: "${PROXY_TOKEN:-}"
|
||||
CONNECT_TIMEOUT: "${CONNECT_TIMEOUT:-10}"
|
||||
REQUEST_TIMEOUT: "${REQUEST_TIMEOUT:-30}"
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "curl -fsS http://localhost/healthz >/dev/null || exit 1"]
|
||||
interval: 30s
|
||||
timeout: 5s
|
||||
retries: 3
|
||||
start_period: 10s
|
||||
3
public/.htaccess
Normal file
3
public/.htaccess
Normal file
@@ -0,0 +1,3 @@
|
||||
RewriteEngine On
|
||||
RewriteCond %{REQUEST_FILENAME} !-f
|
||||
RewriteRule ^ index.php [QSA,L]
|
||||
102
public/index.php
Normal file
102
public/index.php
Normal file
@@ -0,0 +1,102 @@
|
||||
<?php
|
||||
|
||||
ini_set('display_startup_errors', '0');
|
||||
ini_set('display_errors', '0');
|
||||
|
||||
function proxy_env($name, $default)
|
||||
{
|
||||
$value = getenv($name);
|
||||
return $value === false || $value === '' ? $default : $value;
|
||||
}
|
||||
|
||||
function proxy_json($statusCode, $payload)
|
||||
{
|
||||
http_response_code($statusCode);
|
||||
header('Content-Type: application/json');
|
||||
echo json_encode($payload);
|
||||
exit;
|
||||
}
|
||||
|
||||
function proxy_header($name)
|
||||
{
|
||||
$key = 'HTTP_'.strtoupper(str_replace('-', '_', $name));
|
||||
return isset($_SERVER[$key]) ? $_SERVER[$key] : '';
|
||||
}
|
||||
|
||||
$path = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
|
||||
$endpoint = ltrim($path, '/');
|
||||
|
||||
if ($endpoint === '' || $endpoint === 'healthz') {
|
||||
proxy_json(200, array('status' => 1, 'msg' => 'SPOTA proxy is running'));
|
||||
}
|
||||
|
||||
$endpoint = basename($endpoint);
|
||||
$allowedEndpoints = array_filter(array_map('trim', explode(',', proxy_env('SPOTA_ALLOWED_ENDPOINTS', 'login.php'))));
|
||||
|
||||
if (!in_array($endpoint, $allowedEndpoints, true)) {
|
||||
proxy_json(404, array('status' => 0, 'msg' => 'Endpoint not allowed'));
|
||||
}
|
||||
|
||||
$token = proxy_env('PROXY_TOKEN', '');
|
||||
if ($token !== '') {
|
||||
$providedToken = proxy_header('X-Proxy-Token');
|
||||
if ($providedToken === '' && isset($_GET['proxy_token'])) {
|
||||
$providedToken = $_GET['proxy_token'];
|
||||
unset($_GET['proxy_token']);
|
||||
}
|
||||
|
||||
if (!hash_equals($token, $providedToken)) {
|
||||
proxy_json(401, array('status' => 0, 'msg' => 'Unauthorized'));
|
||||
}
|
||||
}
|
||||
|
||||
$baseUrl = rtrim(proxy_env('SPOTA_BASE_URL', 'https://spota.untan.ac.id/steven/API'), '/');
|
||||
$targetUrl = $baseUrl.'/'.$endpoint;
|
||||
|
||||
if (!empty($_GET)) {
|
||||
$targetUrl .= '?'.http_build_query($_GET);
|
||||
}
|
||||
|
||||
$method = strtoupper($_SERVER['REQUEST_METHOD']);
|
||||
$body = file_get_contents('php://input');
|
||||
$headers = array('Accept: application/json');
|
||||
$contentType = isset($_SERVER['CONTENT_TYPE']) ? trim($_SERVER['CONTENT_TYPE']) : '';
|
||||
|
||||
if ($contentType !== '') {
|
||||
$headers[] = 'Content-Type: '.$contentType;
|
||||
}
|
||||
|
||||
$ch = curl_init($targetUrl);
|
||||
curl_setopt_array($ch, array(
|
||||
CURLOPT_RETURNTRANSFER => true,
|
||||
CURLOPT_CONNECTTIMEOUT => (int) proxy_env('CONNECT_TIMEOUT', '10'),
|
||||
CURLOPT_TIMEOUT => (int) proxy_env('REQUEST_TIMEOUT', '30'),
|
||||
CURLOPT_IPRESOLVE => CURL_IPRESOLVE_V4,
|
||||
CURLOPT_HTTPHEADER => $headers,
|
||||
));
|
||||
|
||||
if ($method === 'POST') {
|
||||
curl_setopt($ch, CURLOPT_POST, true);
|
||||
curl_setopt($ch, CURLOPT_POSTFIELDS, $body !== '' ? $body : http_build_query($_POST));
|
||||
} elseif ($method !== 'GET') {
|
||||
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);
|
||||
if ($body !== '') {
|
||||
curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
|
||||
}
|
||||
}
|
||||
|
||||
$response = curl_exec($ch);
|
||||
|
||||
if ($response === false) {
|
||||
error_log('SPOTA proxy failed for '.$endpoint.': '.curl_error($ch));
|
||||
curl_close($ch);
|
||||
proxy_json(502, array('status' => 0, 'msg' => 'Tidak dapat terhubung ke server SPOTA.'));
|
||||
}
|
||||
|
||||
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||
$responseType = curl_getinfo($ch, CURLINFO_CONTENT_TYPE);
|
||||
curl_close($ch);
|
||||
|
||||
http_response_code($httpCode > 0 ? $httpCode : 200);
|
||||
header('Content-Type: '.($responseType !== null && $responseType !== '' ? $responseType : 'application/json'));
|
||||
echo $response;
|
||||
3
public/login.php
Normal file
3
public/login.php
Normal file
@@ -0,0 +1,3 @@
|
||||
<?php
|
||||
|
||||
require __DIR__.'/index.php';
|
||||
Reference in New Issue
Block a user