added deployment file

This commit is contained in:
NikoKS committed 2026-10-14 19:08:59 +07:00
1 parent 061d5fd8a4
commit 125eab3cd4
14 files changed
+704 -1

No files matched your search

+42
View File
@@ -0,0 +1,42 @@
ServerName localhost
ServerTokens Prod
ServerSignature Off
TraceEnable Off
# Only expose this HTTP listener to a trusted reverse proxy. The proxy must
# overwrite X-Forwarded-Proto, not pass a client-supplied value through.
# PHP uses HTTPS to decide whether participant/admin cookies need Secure.
SetEnvIf X-Forwarded-Proto "^https$" HTTPS=on
<Directory /var/www/html>
Options -Indexes -MultiViews
AllowOverride None
DirectoryIndex index.php
Require all granted
</Directory>
# Internal code is still usable by PHP/CLI, never directly over HTTP.
<DirectoryMatch "^/var/www/html/(?:includes|DB|dev|docker|dashboard/(?:tools|migrations))(?:/|$)">
Require all denied
</DirectoryMatch>
# Also deny dotfiles and backup/config files if accidentally added later.
<LocationMatch "(?:^|/)\.">
Require all denied
</LocationMatch>
<FilesMatch "(?i)\.(?:sql(?:\.gz|\.zip)?|ini|env|toml|ya?ml|log|bak)$">
Require all denied
</FilesMatch>
Alias /healthz /usr/local/share/recruitment/health.php
<Directory /usr/local/share/recruitment>
Options -Indexes
AllowOverride None
Require all denied
<Files health.php>
Require all granted
</Files>
</Directory>
Header always set X-Content-Type-Options "nosniff"
Header always set Referrer-Policy "same-origin"
+16
View File
@@ -0,0 +1,16 @@
<?php
// Docker-only replacement for includes/conn.php; local/server config is untouched.
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
foreach (['MYSQL_HOST', 'MYSQL_DATABASE', 'MYSQL_USER', 'MYSQL_PASSWORD'] as $key) {
if (getenv($key) === false || getenv($key) === '') {
throw new RuntimeException('Missing database environment variable: ' . $key);
}
}
$conn = new mysqli(
getenv('MYSQL_HOST'),
getenv('MYSQL_USER'),
getenv('MYSQL_PASSWORD'),
getenv('MYSQL_DATABASE'),
(int) (getenv('MYSQL_PORT') ?: 3306)
);
$conn->set_charset('utf8mb4');
+17
View File
@@ -0,0 +1,17 @@
<?php
header('Content-Type: text/plain; charset=utf-8');
header('Cache-Control: no-store');
try {
require '/var/www/html/includes/conn.php';
// A database connection alone is insufficient: the initial import and
// migrations must also be present before this instance is ready for users.
foreach (['in_daper', 'in_soal', 'in_jawab', 'rec_admin', 'rec_exam_attempt', 'rec_exam_event', 'rec_candidate_login_guard'] as $table) {
$conn->query("SELECT 1 FROM `$table` LIMIT 0");
}
$conn->query('SELECT email, nama_de, nama_be, idkar, password_hash FROM rec_admin LIMIT 0');
echo "ok\n";
} catch (Throwable $error) {
http_response_code(503);
// Never expose connection details, credentials, or schema errors over HTTP.
echo "not ready\n";
}
+11
View File
@@ -0,0 +1,11 @@
<?php
// Check Apache + PHP + database readiness without requiring curl in the image.
$socket = @fsockopen('127.0.0.1', 80, $errno, $error, 3);
if (!$socket) {
exit(1);
}
stream_set_timeout($socket, 3);
fwrite($socket, "GET /healthz HTTP/1.0\r\nHost: localhost\r\nConnection: close\r\n\r\n");
$status = fgets($socket);
fclose($socket);
exit(is_string($status) && preg_match('/^HTTP\/\d\.\d 200\b/', $status) ? 0 : 1);
+33
View File
@@ -0,0 +1,33 @@
<?php
if (PHP_SAPI !== 'cli') {
http_response_code(404);
exit;
}
try {
require '/var/www/html/includes/conn.php';
foreach (['in_daper', 'in_soal', 'in_jawab'] as $table) {
$conn->query("SELECT 1 FROM `$table` LIMIT 0");
}
foreach (['001_admin.sql', '002_admin_identity.sql', '003_exam_attempts.sql'] as $file) {
// Only migrate the historical rec_admin schema, preserving identities.
if ($file === '002_admin_identity.sql'
&& $conn->query("SHOW COLUMNS FROM rec_admin LIKE 'name'")->num_rows === 0) {
continue;
}
$sql = file_get_contents('/var/www/html/dashboard/migrations/' . $file);
$conn->multi_query($sql);
do {
$result = $conn->store_result();
if ($result instanceof mysqli_result) {
$result->free();
}
} while ($conn->more_results() && $conn->next_result());
fwrite(STDOUT, "Applied: $file\n");
}
fwrite(STDOUT, "Database ready. Existing accounts and test data were preserved.\n");
} catch (Throwable $error) {
fwrite(STDERR, 'Migration failed: ' . $error->getMessage() . "\nImport the base database first; see docs/deployment.md.\n");
exit(1);
}
+16
View File
@@ -0,0 +1,16 @@
expose_php = Off
display_errors = Off
display_startup_errors = Off
log_errors = On
error_log = /proc/self/fd/2
error_reporting = E_ALL
date.timezone = Asia/Jakarta
session.use_strict_mode = 1
session.use_only_cookies = 1
session.cookie_httponly = 1
session.cookie_samesite = Lax
session.save_path = /var/lib/php/sessions
; Secure cookies are set by the application when Apache receives the HTTPS
; indication from the trusted proxy (see apache.conf).