add docker for server demo

This commit is contained in:
arifal
2025-06-26 18:28:26 +07:00
parent c33193d5f0
commit a7f578ca3d
23 changed files with 2420 additions and 431 deletions

View File

@@ -61,6 +61,7 @@ WORKDIR /var/www
# Install PHP extensions # Install PHP extensions
RUN apt-get update && apt-get install -y \ RUN apt-get update && apt-get install -y \
git curl zip unzip libpng-dev libonig-dev libxml2-dev libzip-dev \ git curl zip unzip libpng-dev libonig-dev libxml2-dev libzip-dev \
supervisor \
&& docker-php-ext-install pdo_mysql mbstring exif pcntl bcmath gd zip && docker-php-ext-install pdo_mysql mbstring exif pcntl bcmath gd zip
# Install Node.js # Install Node.js
@@ -94,8 +95,15 @@ RUN php artisan config:clear \
RUN php artisan storage:link RUN php artisan storage:link
# Create supervisor directories
RUN mkdir -p /var/log/supervisor /var/run/supervisor
# Copy supervisor configuration
COPY docker/supervisor/supervisord.conf /etc/supervisor/supervisord.conf
COPY docker/supervisor/laravel-production.conf /etc/supervisor/conf.d/laravel-production.conf
# Permissions # Permissions
RUN chown -R www-data:www-data /var/www && chmod -R 755 /var/www/storage /var/www/public RUN chown -R www-data:www-data /var/www && chmod -R 755 /var/www/storage /var/www/public
EXPOSE 9000 EXPOSE 9000
CMD ["php-fpm"] CMD ["/usr/bin/supervisord", "-c", "/etc/supervisor/supervisord.conf"]

View File

@@ -1,210 +0,0 @@
# Struktur Tabel Retribusi PBG yang Dioptimalkan
## Ringkasan Optimasi
Struktur tabel baru ini **lebih sederhana**, **fokus pada perhitungan**, dan **menghilangkan redundansi** dari struktur sebelumnya.
## Perbandingan Struktur
### SEBELUM (Kompleks)
- `building_functions` - 8 kolom + relationship kompleks
- `building_function_parameters` - 12 kolom dengan mismatch model/migration
- `retribution_formulas` - Menyimpan formula sebagai string
- `retribution_proposals` - 15+ kolom dengan banyak redundansi
- `floor_height_indices` - OK, tidak berubah
### SESUDAH (Sederhana)
- `building_types` - **7 kolom**, hierarki sederhana
- `retribution_indices` - **6 kolom**, parameter calculation saja
- `height_indices` - **3 kolom**, sama seperti sebelumnya
- `retribution_configs` - **5 kolom**, konfigurasi global
- `retribution_calculations` - **8 kolom**, hasil perhitungan saja
---
## Detail Struktur Tabel Baru
### 1. `building_types`
**Fungsi:** Menyimpan jenis fungsi bangunan dengan hierarki sederhana
| Kolom | Tipe | Keterangan |
| ------------- | ------------ | ---------------------------------- |
| `id` | bigint | Primary key |
| `code` | varchar(10) | Kode unik (UMKM, KEAGAMAAN, dll) |
| `name` | varchar(100) | Nama fungsi bangunan |
| `parent_id` | bigint | ID parent (untuk hierarki) |
| `level` | tinyint | Level hierarki (1=parent, 2=child) |
| `coefficient` | decimal(8,4) | **Koefisien untuk perhitungan** |
| `is_free` | boolean | **Apakah gratis (keagamaan, MBR)** |
### 2. `retribution_indices`
**Fungsi:** Menyimpan parameter indeks untuk perhitungan (1:1 dengan building_types)
| Kolom | Tipe | Keterangan |
| ----------------------- | ------------ | ---------------------------------- |
| `id` | bigint | Primary key |
| `building_type_id` | bigint | FK ke building_types |
| `ip_permanent` | decimal(8,4) | **Indeks Permanensi** |
| `ip_complexity` | decimal(8,4) | **Indeks Kompleksitas** |
| `locality_index` | decimal(8,4) | **Indeks Lokalitas** |
| `infrastructure_factor` | decimal(8,4) | **Faktor prasarana (default 50%)** |
### 3. `height_indices`
**Fungsi:** Indeks ketinggian per lantai (sama seperti sebelumnya)
| Kolom | Tipe | Keterangan |
| -------------- | ------------ | ---------------------------------------- |
| `id` | bigint | Primary key |
| `floor_number` | tinyint | Nomor lantai (1,2,3,4,5,6) |
| `height_index` | decimal(8,6) | **IP Ketinggian (1.0, 1.09, 1.12, dst)** |
### 4. `retribution_configs`
**Fungsi:** Konfigurasi global untuk perhitungan (menggantikan hard-coded values)
| Kolom | Tipe | Keterangan |
| ------------- | ------------- | --------------------- |
| `id` | bigint | Primary key |
| `key` | varchar(50) | Kunci konfigurasi |
| `value` | decimal(15,2) | **Nilai konfigurasi** |
| `description` | varchar(200) | Deskripsi |
**Data yang disimpan:**
- `BASE_VALUE` = 70350 (nilai dasar)
- `INFRASTRUCTURE_MULTIPLIER` = 0.5 (50% prasarana)
- `HEIGHT_MULTIPLIER` = 0.5 (pengali indeks ketinggian)
### 5. `retribution_calculations`
**Fungsi:** Hasil perhitungan retribusi (history)
| Kolom | Tipe | Keterangan |
| -------------------- | ------------- | -------------------------------- |
| `id` | bigint | Primary key |
| `calculation_id` | varchar(20) | ID unik perhitungan |
| `building_type_id` | bigint | FK ke building_types |
| `floor_number` | tinyint | Lantai yang dipilih |
| `building_area` | decimal(12,2) | **Luas bangunan input** |
| `retribution_amount` | decimal(15,2) | **Hasil perhitungan** |
| `calculation_detail` | json | **Detail breakdown perhitungan** |
| `calculated_at` | timestamp | Waktu perhitungan |
---
## Formula Perhitungan
### Formula Excel yang Diimplementasikan:
```
H13 = coefficient * (ip_permanent + ip_complexity + (0.5 * height_index))
Main Calculation = building_area * (locality_index * BASE_VALUE * H13)
Infrastructure = INFRASTRUCTURE_MULTIPLIER * Main Calculation
Total Retribution = Main Calculation + Infrastructure
```
### Implementasi dalam Service:
```php
// Step 1: Calculate H13 coefficient
$h13 = $buildingType->coefficient * (
$indices->ip_permanent +
$indices->ip_complexity +
(0.5 * $heightIndex)
);
// Step 2: Main calculation
$mainCalculation = $buildingArea * ($indices->locality_index * $baseValue * $h13);
// Step 3: Infrastructure (50% additional)
$infrastructureCalculation = 0.5 * $mainCalculation;
// Step 4: Total
$totalRetribution = $mainCalculation + $infrastructureCalculation;
```
---
## Keuntungan Struktur Baru
### ✅ **Simplicity**
- **5 tabel** vs 8+ tabel sebelumnya
- **Kolom minimal** hanya yang diperlukan untuk perhitungan
- **No redundant data** seperti ip_ketinggian di proposals
### ✅ **Performance**
- **Proper indexes** untuk query yang sering digunakan
- **Normalized structure** mengurangi storage
- **Cached configs** untuk values yang jarang berubah
### ✅ **Maintainability**
- **Clear separation** antara master data dan calculation results
- **Configurable values** tidak hard-coded lagi
- **Single responsibility** setiap tabel punya tujuan jelas
### ✅ **Flexibility**
- **Easy to extend** untuk fungsi bangunan baru
- **Configurable formulas** lewat RetributionConfig
- **Audit trail** lewat calculation history
### ✅ **Data Integrity**
- **Proper constraints** untuk validasi data
- **Foreign key relationships** yang benar
- **No model-migration mismatch**
---
## Migration Guide
### Langkah Implementasi:
1. **Run Migration:** `php artisan migrate` untuk tabel baru
2. **Seed Data:** Data master berdasarkan Excel akan otomatis ter-seed
3. **Update Code:** Ganti penggunaan model lama dengan model baru
4. **Test Calculation:** Verifikasi hasil perhitungan sama dengan Excel
5. **Deploy:** Struktur siap production
### Data Migration (Optional):
Jika ada data existing di tabel lama yang perlu dipindahkan, buat script migration untuk transfer data dari struktur lama ke struktur baru.
---
## Usage Example
```php
// Initialize service
$calculator = new RetributionCalculatorService();
// Calculate retribution
$result = $calculator->calculate(
buildingTypeId: 8, // UMKM
floorNumber: 2, // 2 lantai
buildingArea: 100.50, // 100.5 m2
saveResult: true // Simpan ke database
);
// Result structure
[
'building_type' => [...],
'total_retribution' => 31658.25,
'formatted_amount' => 'Rp 31,658.25',
'calculation_steps' => [...],
'calculation_id' => 'RTB-20250130140530-123'
]
```
Struktur ini **jauh lebih clean**, **mudah dipahami**, dan **optimal untuk perhitungan retribusi PBG**!

View File

@@ -1,109 +0,0 @@
# Docker Usage Guide
Proyek ini memiliki dua konfigurasi Docker untuk keperluan yang berbeda:
## 📁 File Konfigurasi
### 1. `docker-compose.yml` - Production/Staging
- **Target**: `production` (optimized build)
- **Environment**: Production settings
- **Debug**: Disabled
- **Asset handling**: Built dan optimized
- **Use case**: Deploy ke server production/staging
### 2. `docker-compose.local.yml` - Local Development
- **Target**: `local` (development build)
- **Environment**: Local development settings
- **Debug**: Enabled
- **Asset handling**: Vite dev server terpisah
- **Use case**: Development di local machine
## 🚀 Cara Penggunaan
### Local Development (Recommended)
```bash
# Setup awal (otomatis)
./setup-local.sh
# Atau manual
docker-compose -f docker-compose.local.yml up -d --build
```
### Production/Staging
```bash
# Dengan environment variables
docker-compose up -d --build
# Atau dengan custom .env
APP_ENV=production APP_DEBUG=false docker-compose up -d --build
```
## 🔧 Perbedaan Utama
| Aspek | Local Development | Production |
| ---------------- | -------------------------- | --------------------- |
| **File** | `docker-compose.local.yml` | `docker-compose.yml` |
| **Target** | `local` | `production` |
| **Debug** | Enabled | Disabled |
| **Assets** | Vite dev server | Pre-built & optimized |
| **Permissions** | User mapping | Standard www-data |
| **Hot Reload** | ✅ Available | ❌ Not needed |
| **Node Modules** | Kept for dev | Removed after build |
## 📋 Command Cheat Sheet
### Local Development
```bash
# Start
docker-compose -f docker-compose.local.yml up -d
# Stop
docker-compose -f docker-compose.local.yml down
# Logs
docker-compose -f docker-compose.local.yml logs -f app
# Execute commands
docker-compose -f docker-compose.local.yml exec app php artisan [command]
```
### Production
```bash
# Start
docker-compose up -d
# Stop
docker-compose down
# Logs
docker-compose logs -f app
# Execute commands
docker-compose exec app php artisan [command]
```
## 🛠 Development Workflow
1. **Daily development**: Gunakan `docker-compose.local.yml`
2. **Testing production build**: Gunakan `docker-compose.yml`
3. **Deploy**: Gunakan `docker-compose.yml` di server
## ❓ FAQ
**Q: Apakah perlu kedua file?**
A: Ya, keduanya memiliki fungsi berbeda:
- `docker-compose.local.yml` untuk development
- `docker-compose.yml` untuk production/staging
**Q: File mana yang digunakan untuk development?**
A: Gunakan `docker-compose.local.yml` dengan menjalankan `./setup-local.sh`
**Q: Bagaimana cara switch antara development dan production?**
A: Gunakan flag `-f` untuk specify file yang ingin digunakan

191
README.md
View File

@@ -1,112 +1,167 @@
# Usage icon # Sibedas PBG Web
search or pick icon in <a href="https://icon-sets.iconify.design/mingcute/?keyword=mingcute">here</a> Aplikasi web untuk manajemen data PBG (Pendidikan Berkelanjutan Guru) dengan fitur integrasi Google Sheets.
# Set up queue for running automatically ## 🚀 Quick Start
- Install Supervisor ### Prerequisites
``` - Docker & Docker Compose
sudo apt update && sudo apt install supervisor -y - Domain name (untuk production)
### Local Development
```bash
git clone <repository-url>
cd sibedas-pbg-web
./scripts/setup-local.sh
# Access: http://localhost:8000
``` ```
- Create Supervisor Config ### Production Deployment
``` ```bash
sudo nano /etc/supervisor/conf.d/laravel-worker.conf # 1. Setup environment
cp env.production.example .env
nano .env
[program:laravel-worker] # 2. Deploy with SSL (Recommended)
process_name=%(program_name)s_%(process_num)02d ./scripts/setup-reverse-proxy.sh setup
command=php /home/arifal/development/sibedas-pbg-web/artisan queue:work --queue=default --timeout=82800 --tries=1
autostart=true # 3. Check status
autorestart=true ./scripts/setup-reverse-proxy.sh status
numprocs=1 # Access: https://yourdomain.com
redirect_stderr=true
stdout_logfile=/home/arifal/development/sibedas-pbg-web/storage/logs/worker.log
stopasgroup=true
killasgroup=true
``` ```
- Reload Supervisor ## 🏗️ Architecture
### Local Development
``` ```
sudo supervisorctl reread Browser → Port 8000 → Nginx → PHP-FPM → MariaDB
sudo supervisorctl update
sudo supervisorctl start laravel-worker
sudo supervisorctl restart laravel-worker
sudo supervisorctl status
``` ```
# How to running ### Production dengan Reverse Proxy
- Install composer package
``` ```
composer install Internet → Reverse Proxy (80/443) → Internal Nginx → PHP-FPM → MariaDB
``` ```
- Install npm package ## 🔧 Configuration
``` ### Environment Variables
npm install && npm run build
```bash
# Domain & SSL
DOMAIN=sibedas.yourdomain.com
EMAIL=admin@yourdomain.com
SSL_TYPE=self-signed # atau letsencrypt
# Database
DB_PASSWORD=your_secure_password
MYSQL_ROOT_PASSWORD=your_root_password
# Laravel
APP_KEY=base64:your_app_key_here
APP_URL=https://sibedas.yourdomain.com
``` ```
- Create symlinks storage ## 🚀 Production Deployment Steps
``` ### 1. Server Preparation
php artisan storage:link
```bash
# Install Docker & Docker Compose
curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh
sudo usermod -aG docker $USER
# Install Docker Compose
sudo curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
``` ```
- Running migration ### 2. Clone & Setup
``` ```bash
php artisan migrate git clone <repository-url>
cd sibedas-pbg-web
chmod +x scripts/*.sh
cp env.production.example .env
nano .env
``` ```
- Running seeder ### 3. Deploy
``` ```bash
php artisan db:seed # Full deployment with SSL
./scripts/setup-reverse-proxy.sh setup
# Or step by step
./scripts/deploy-production.sh deploy
./scripts/setup-ssl.sh letsencrypt
``` ```
- Create view table ### 4. Verify
- excute all sql queries on folder database/view_query
# Add ENV variable ```bash
docker-compose ps
- API_KEY_GOOGLE ./scripts/setup-reverse-proxy.sh status
curl -f http://localhost/health-check
```
Get api key from google developer console for and turn on spreadsheet api or feaature for google sheet
``` ```
- SPREAD_SHEET_ID ## 📊 Monitoring
``` ```bash
Get spreadsheet id from google sheet link # Check status
./scripts/setup-reverse-proxy.sh status
# View logs
docker-compose logs [service]
# Check SSL certificate
./scripts/setup-ssl.sh check
``` ```
- OPENAI_API_KEY ## 🛠️ Common Commands
``` ```bash
Get OpenAI API key from chatgpt subscription # Start services
docker-compose up -d
# Stop services
docker-compose down
# Restart services
docker-compose restart
# Execute Laravel commands
docker-compose exec app php artisan [command]
# Backup database
docker exec sibedas_db mysqldump -u root -p sibedas > backup.sql
``` ```
- ENV ## 📁 Scripts
``` ### Essential Scripts
API_KEY_GOOGLE="xxxxx" - `scripts/setup-reverse-proxy.sh` - Setup lengkap reverse proxy dan SSL
SPREAD_SHEET_ID="xxxxx" - `scripts/deploy-production.sh` - Deployment production
OPENAI_API_KEY="xxxxx" - `scripts/setup-ssl.sh` - Setup SSL certificates
``` ### Optional Scripts
# Technology version - `scripts/setup-local.sh` - Setup local development
- `scripts/import-sibedas-database.sh` - Manual database import
- php 8.3 ## 📚 Documentation
- Laravel 11
- node v22.13.0 Untuk dokumentasi lengkap, lihat [docs/README.md](docs/README.md)
- npm 10.9.2
- mariadb Ver 15.1 Distrib 10.6.18-MariaDB, for debian-linux-gnu (x86_64) using EditLine wrapper ## 🆘 Support
- Ubuntu 24.04
1. Check logs: `docker-compose logs [service]`
2. Check status: `./scripts/setup-reverse-proxy.sh status`
3. Restart services: `docker-compose restart`
4. Review documentation di folder `docs/`

View File

@@ -54,10 +54,17 @@ class SyncGoogleSheetData extends Command
$result = $service->sync_leader_data(); $result = $service->sync_leader_data();
$this->info('✅ Leader data synchronized successfully!'); $this->info('✅ Leader data synchronized successfully!');
$this->table(['Section', 'Total', 'Nominal'], collect($result)->map(function($item, $key) { $this->table(['Section', 'Total', 'Nominal'], collect($result)->map(function($item, $key) {
// Convert nominal to numeric before formatting
$nominal = $item['nominal'] ?? 0;
if (is_string($nominal)) {
// Remove dots and convert to float
$nominal = (float) str_replace('.', '', $nominal);
}
return [ return [
$key, $key,
$item['total'] ?? 'N/A', $item['total'] ?? 'N/A',
number_format($item['nominal'] ?? 0, 0, ',', '.') number_format((float) $nominal, 0, ',', '.')
]; ];
})->toArray()); })->toArray());
break; break;

View File

@@ -24,7 +24,7 @@ services:
depends_on: depends_on:
- db - db
networks: networks:
- sibedas_net - sibedas_network_local
# Add user mapping for permission compatibility # Add user mapping for permission compatibility
user: "1000:1000" user: "1000:1000"
@@ -40,7 +40,7 @@ services:
depends_on: depends_on:
- app - app
networks: networks:
- sibedas_net - sibedas_network_local
db: db:
image: mariadb:10.6 image: mariadb:10.6
@@ -54,10 +54,10 @@ services:
ports: ports:
- "3306:3306" - "3306:3306"
volumes: volumes:
- dbdata_local:/var/lib/mysql - sibedas_dbdata_local:/var/lib/mysql
- ./sibedas.sql:/docker-entrypoint-initdb.d/sibedas.sql - ./sibedas.sql:/docker-entrypoint-initdb.d/sibedas.sql
networks: networks:
- sibedas_net - sibedas_network_local
vite: vite:
build: build:
@@ -74,11 +74,11 @@ services:
ports: ports:
- "5173:5173" - "5173:5173"
networks: networks:
- sibedas_net - sibedas_network_local
volumes: volumes:
dbdata_local: sibedas_dbdata_local:
networks: networks:
sibedas_net: sibedas_network_local:
driver: bridge driver: bridge

View File

@@ -1,4 +1,5 @@
services: services:
# Sibedas Application Container (Internal)
app: app:
build: build:
context: . context: .
@@ -7,57 +8,214 @@ services:
container_name: sibedas_app container_name: sibedas_app
restart: unless-stopped restart: unless-stopped
environment: environment:
APP_ENV: production APP_ENV: ${APP_ENV:-production}
APP_DEBUG: false APP_DEBUG: ${APP_DEBUG:-false}
APP_URL: ${APP_URL:-http://localhost:8000} APP_KEY: ${APP_KEY}
VITE_APP_URL: ${VITE_APP_URL:-http://localhost:8000} APP_URL: ${APP_URL:-https://sibedas.yourdomain.com}
DB_CONNECTION: mariadb VITE_APP_URL: ${VITE_APP_URL:-https://sibedas.yourdomain.com}
# Database Configuration
DB_CONNECTION: ${DB_CONNECTION:-mariadb}
DB_HOST: db DB_HOST: db
DB_PORT: 3306 DB_PORT: 3306
DB_DATABASE: ${DB_DATABASE:-sibedas} DB_DATABASE: ${DB_DATABASE:-sibedas}
DB_USERNAME: ${DB_USERNAME:-root} DB_USERNAME: ${DB_USERNAME:-sibedas_user}
DB_PASSWORD: ${DB_PASSWORD:-root} DB_PASSWORD: ${DB_PASSWORD}
volumes:
- .:/var/www
depends_on:
- db
networks:
- sibedas_net
nginx: # Cache Configuration (using database)
CACHE_DRIVER: ${CACHE_DRIVER:-database}
# Session Configuration (using database)
SESSION_DRIVER: ${SESSION_DRIVER:-database}
SESSION_LIFETIME: ${SESSION_LIFETIME:-120}
# Queue Configuration (using database)
QUEUE_CONNECTION: ${QUEUE_CONNECTION:-database}
# Mail Configuration
MAIL_MAILER: ${MAIL_MAILER:-smtp}
MAIL_HOST: ${MAIL_HOST}
MAIL_PORT: ${MAIL_PORT:-587}
MAIL_USERNAME: ${MAIL_USERNAME}
MAIL_PASSWORD: ${MAIL_PASSWORD}
MAIL_ENCRYPTION: ${MAIL_ENCRYPTION:-tls}
MAIL_FROM_ADDRESS: ${MAIL_FROM_ADDRESS}
MAIL_FROM_NAME: ${MAIL_FROM_NAME:-"Sibedas"}
# Google Sheets API
SPREAD_SHEET_ID: ${SPREAD_SHEET_ID}
volumes:
# Only mount specific directories for production security
- sibedas_app_storage:/var/www/storage
- sibedas_app_bootstrap_cache:/var/www/bootstrap/cache
- ./public:/var/www/public:ro
- ./docker/supervisor:/etc/supervisor/conf.d:ro
depends_on:
db:
condition: service_healthy
networks:
- sibedas_network
healthcheck:
test: ["CMD", "php", "-v"]
interval: 30s
timeout: 10s
retries: 3
start_period: 60s
deploy:
resources:
limits:
memory: 1G
cpus: "1.0"
reservations:
memory: 512M
cpus: "0.5"
# Use Supervisor for queue and scheduler
command:
["/usr/bin/supervisord", "-c", "/etc/supervisor/supervisord.conf"]
# Internal Nginx for Sibedas App
nginx-internal:
image: nginx:alpine image: nginx:alpine
container_name: sibedas_nginx container_name: sibedas_nginx_internal
restart: unless-stopped
volumes:
- ./public:/var/www/public:ro
- ./docker/nginx/conf.d/sibedas-internal.conf:/etc/nginx/conf.d/default.conf:ro
- sibedas_nginx_internal_logs:/var/log/nginx
depends_on:
app:
condition: service_healthy
networks:
- sibedas_network
healthcheck:
test:
[
"CMD",
"wget",
"--quiet",
"--tries=1",
"--spider",
"http://localhost/health-check",
]
interval: 30s
timeout: 10s
retries: 3
start_period: 30s
deploy:
resources:
limits:
memory: 128M
cpus: "0.25"
# Reverse Proxy Nginx (Main Entry Point)
nginx-proxy:
build:
context: ./docker/nginx
dockerfile: Dockerfile
container_name: sibedas_nginx_proxy
restart: unless-stopped restart: unless-stopped
ports: ports:
- "8000:80" - "${NGINX_HTTP_PORT:-80}:80"
- "${NGINX_HTTPS_PORT:-443}:443"
environment:
DOMAIN: ${DOMAIN:-sibedas.yourdomain.com}
EMAIL: ${EMAIL:-admin@yourdomain.com}
SSL_TYPE: ${SSL_TYPE:-self-signed}
volumes: volumes:
- .:/var/www - sibedas_nginx_proxy_logs:/var/log/nginx
- ./docker/nginx/conf.d/app.conf:/etc/nginx/conf.d/default.conf - sibedas_ssl_certs:/etc/nginx/ssl
- sibedas_letsencrypt:/etc/letsencrypt
depends_on: depends_on:
- app nginx-internal:
condition: service_healthy
networks: networks:
- sibedas_net - sibedas_network
healthcheck:
test:
[
"CMD",
"wget",
"--quiet",
"--tries=1",
"--spider",
"http://localhost/health-check",
]
interval: 30s
timeout: 10s
retries: 3
start_period: 30s
deploy:
resources:
limits:
memory: 256M
cpus: "0.5"
db: db:
image: mariadb:10.6 image: mariadb:10.6
container_name: sibedas_db container_name: sibedas_db
restart: unless-stopped restart: unless-stopped
environment: environment:
MYSQL_ROOT_PASSWORD: ${DB_PASSWORD:-root} MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
MYSQL_DATABASE: ${DB_DATABASE:-sibedas} MYSQL_DATABASE: ${DB_DATABASE:-sibedas}
MYSQL_USER: ${DB_USERNAME:-root} MYSQL_USER: ${DB_USERNAME:-sibedas_user}
MYSQL_PASSWORD: ${DB_PASSWORD:-root} MYSQL_PASSWORD: ${DB_PASSWORD}
MYSQL_INNODB_BUFFER_POOL_SIZE: ${MYSQL_INNODB_BUFFER_POOL_SIZE:-1G}
ports: ports:
- "3306:3306" # Only expose if needed for external access
- "${DB_EXTERNAL_PORT:-3306}:3306"
volumes: volumes:
- dbdata:/var/lib/mysql - sibedas_dbdata:/var/lib/mysql
- ./sibedas.sql:/docker-entrypoint-initdb.d/sibedas.sql - ./sibedas.sql:/docker-entrypoint-initdb.d/sibedas.sql:ro
- ./docker/mysql/conf.d:/etc/mysql/conf.d:ro
- sibedas_db_logs:/var/log/mysql
networks: networks:
- sibedas_net - sibedas_network
healthcheck:
test:
[
"CMD",
"mysqladmin",
"ping",
"-h",
"localhost",
"-u",
"${DB_USERNAME:-sibedas_user}",
"-p${DB_PASSWORD}",
]
interval: 30s
timeout: 10s
retries: 3
start_period: 60s
deploy:
resources:
limits:
memory: 2G
cpus: "1.0"
reservations:
memory: 1G
cpus: "0.5"
volumes: volumes:
dbdata: sibedas_dbdata:
driver: local
sibedas_app_storage:
driver: local
sibedas_app_bootstrap_cache:
driver: local
sibedas_nginx_internal_logs:
driver: local
sibedas_nginx_proxy_logs:
driver: local
sibedas_db_logs:
driver: local
sibedas_ssl_certs:
driver: local
sibedas_letsencrypt:
driver: local
networks: networks:
sibedas_net: sibedas_network:
driver: bridge driver: bridge
ipam:
config:
- subnet: 172.20.0.0/16

View File

@@ -0,0 +1,55 @@
[mysqld]
# Basic Settings
default-storage-engine = innodb
sql-mode = "STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION"
max_connections = 200
max_user_connections = 180
# Character Set
character-set-server = utf8mb4
collation-server = utf8mb4_unicode_ci
# InnoDB Settings
innodb_buffer_pool_size = 1G
innodb_buffer_pool_instances = 4
innodb_log_file_size = 256M
innodb_log_buffer_size = 64M
innodb_flush_log_at_trx_commit = 2
innodb_flush_method = O_DIRECT
innodb_file_per_table = 1
innodb_open_files = 400
# Query Cache (disabled in MySQL 8.0+, but kept for compatibility)
query_cache_type = OFF
query_cache_size = 0
# Temp Tables
tmp_table_size = 64M
max_heap_table_size = 64M
# Logging
slow_query_log = 1
slow_query_log_file = /var/log/mysql/slow.log
long_query_time = 2
log_queries_not_using_indexes = 1
# Binary Logging
log-bin = mysql-bin
binlog_format = ROW
expire_logs_days = 7
max_binlog_size = 100M
# Safety
max_allowed_packet = 64M
bind-address = 0.0.0.0
# Performance Schema
performance_schema = ON
performance_schema_max_table_instances = 400
performance_schema_max_table_handles = 4000
[mysql]
default-character-set = utf8mb4
[client]
default-character-set = utf8mb4

32
docker/nginx/Dockerfile Normal file
View File

@@ -0,0 +1,32 @@
FROM nginx:alpine
# Install required packages
RUN apk add --no-cache \
openssl \
certbot \
certbot-nginx \
bash
# Create SSL directory
RUN mkdir -p /etc/nginx/ssl
# Copy SSL certificates (if they exist)
COPY ssl/ /etc/nginx/ssl/
# Copy Nginx configuration
COPY conf.d/ /etc/nginx/conf.d/
# Create log directories
RUN mkdir -p /var/log/nginx
# Copy SSL setup script
COPY ssl-setup.sh /usr/local/bin/ssl-setup.sh
RUN chmod +x /usr/local/bin/ssl-setup.sh
# Health check
HEALTHCHECK --interval=30s --timeout=10s --start-period=30s --retries=3 \
CMD wget --quiet --tries=1 --spider http://localhost/health-check || exit 1
EXPOSE 80 443
CMD ["nginx", "-g", "daemon off;"]

View File

@@ -0,0 +1,113 @@
server {
listen 80;
server_name yourdomain.com www.yourdomain.com;
# Redirect HTTP to HTTPS
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
server_name yourdomain.com www.yourdomain.com;
root /var/www/public;
index index.php index.html index.htm;
# SSL Configuration
ssl_certificate /etc/nginx/ssl/certificate.crt;
ssl_certificate_key /etc/nginx/ssl/private.key;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384;
ssl_prefer_server_ciphers off;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
# Security Headers
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "no-referrer-when-downgrade" always;
add_header Content-Security-Policy "default-src 'self' http: https: data: blob: 'unsafe-inline'" always;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
# Gzip Compression
gzip on;
gzip_vary on;
gzip_min_length 1024;
gzip_proxied expired no-cache no-store private auth;
gzip_types
text/plain
text/css
text/xml
text/javascript
application/x-javascript
application/xml+rss
application/javascript
application/json
application/xml
image/svg+xml;
# Client Max Body Size
client_max_body_size 100M;
# Health check endpoint
location /health-check {
access_log off;
return 200 "healthy\n";
add_header Content-Type text/plain;
}
# Handle static files
location ~* \.(css|js|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
expires 1y;
add_header Cache-Control "public, immutable";
access_log off;
try_files $uri =404;
}
# Deny access to sensitive files
location ~ /\. {
deny all;
access_log off;
log_not_found off;
}
location ~ ^/(\.env|\.git|composer\.(json|lock)|package\.(json|lock)|webpack\.(mix\.js|config\.js)|.*\.md)$ {
deny all;
access_log off;
log_not_found off;
}
# Laravel-specific rules
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
fastcgi_pass app:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
include fastcgi_params;
# Production optimizations
fastcgi_buffer_size 128k;
fastcgi_buffers 4 256k;
fastcgi_busy_buffers_size 256k;
fastcgi_temp_file_write_size 256k;
fastcgi_connect_timeout 60s;
fastcgi_send_timeout 60s;
fastcgi_read_timeout 60s;
}
# Error pages
error_page 404 /index.php;
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
# Logging
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log warn;
}

View File

@@ -0,0 +1,137 @@
# Reverse Proxy Configuration for Sibedas PBG Web
# This configuration handles SSL termination and routes traffic to the appropriate containers
# Upstream for Sibedas application
upstream sibedas_backend {
server sibedas_app:9000;
keepalive 32;
}
# Rate limiting
limit_req_zone $binary_remote_addr zone=sibedas_limit:10m rate=10r/s;
# HTTP to HTTPS redirect
server {
listen 80;
server_name _;
# Redirect all HTTP traffic to HTTPS
return 301 https://$host$request_uri;
}
# HTTPS Server for Sibedas
server {
listen 443 ssl http2;
server_name sibedas.yourdomain.com; # Change this to your domain
# SSL Configuration
ssl_certificate /etc/nginx/ssl/sibedas.crt;
ssl_certificate_key /etc/nginx/ssl/sibedas.key;
# SSL Security Settings
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384;
ssl_prefer_server_ciphers off;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
# Security Headers
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header X-Frame-Options DENY always;
add_header X-Content-Type-Options nosniff always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' data:; connect-src 'self'; frame-ancestors 'none';" always;
# Rate limiting
limit_req zone=sibedas_limit burst=20 nodelay;
# Client max body size
client_max_body_size 100M;
# Gzip compression
gzip on;
gzip_vary on;
gzip_min_length 1024;
gzip_proxied any;
gzip_comp_level 6;
gzip_types
text/plain
text/css
text/xml
text/javascript
application/json
application/javascript
application/xml+rss
application/atom+xml
image/svg+xml;
# Root directory
root /var/www/public;
index index.php index.html index.htm;
# Handle Laravel routes
location / {
try_files $uri $uri/ /index.php?$query_string;
}
# PHP-FPM configuration
location ~ \.php$ {
fastcgi_pass sibedas_backend;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
include fastcgi_params;
# FastCGI optimizations
fastcgi_buffers 16 16k;
fastcgi_buffer_size 32k;
fastcgi_connect_timeout 300;
fastcgi_send_timeout 300;
fastcgi_read_timeout 300;
}
# Static files caching
location ~* \.(jpg|jpeg|png|gif|ico|css|js|pdf|txt)$ {
expires 1y;
add_header Cache-Control "public, immutable";
access_log off;
}
# Deny access to sensitive files
location ~ /\. {
deny all;
}
location ~ /\.ht {
deny all;
}
# Health check endpoint
location /health-check {
access_log off;
return 200 "healthy\n";
add_header Content-Type text/plain;
}
# Logging
access_log /var/log/nginx/sibedas_access.log;
error_log /var/log/nginx/sibedas_error.log;
}
# Additional server blocks for other applications can be added here
# Example:
# server {
# listen 443 ssl http2;
# server_name other-app.yourdomain.com;
#
# ssl_certificate /etc/nginx/ssl/other-app.crt;
# ssl_certificate_key /etc/nginx/ssl/other-app.key;
#
# location / {
# proxy_pass http://other_app_container:port;
# 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;
# }
# }

View File

@@ -0,0 +1,58 @@
# Internal Nginx Configuration for Sibedas PBG Web
# This configuration is for the internal container, accessed by reverse proxy
server {
listen 80;
server_name localhost;
# Root directory
root /var/www/public;
index index.php index.html index.htm;
# Handle Laravel routes
location / {
try_files $uri $uri/ /index.php?$query_string;
}
# PHP-FPM configuration
location ~ \.php$ {
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
include fastcgi_params;
# FastCGI optimizations
fastcgi_buffers 16 16k;
fastcgi_buffer_size 32k;
fastcgi_connect_timeout 300;
fastcgi_send_timeout 300;
fastcgi_read_timeout 300;
}
# Static files caching
location ~* \.(jpg|jpeg|png|gif|ico|css|js|pdf|txt)$ {
expires 1y;
add_header Cache-Control "public, immutable";
access_log off;
}
# Deny access to sensitive files
location ~ /\. {
deny all;
}
location ~ /\.ht {
deny all;
}
# Health check endpoint
location /health-check {
access_log off;
return 200 "healthy\n";
add_header Content-Type text/plain;
}
# Logging
access_log /var/log/nginx/sibedas_internal_access.log;
error_log /var/log/nginx/sibedas_internal_error.log;
}

123
docker/nginx/ssl-setup.sh Normal file
View File

@@ -0,0 +1,123 @@
#!/bin/bash
# SSL Setup Script for Sibedas PBG Web
# This script handles SSL certificate generation and renewal
set -e
DOMAIN="${DOMAIN:-sibedas.yourdomain.com}"
EMAIL="${EMAIL:-admin@yourdomain.com}"
SSL_DIR="/etc/nginx/ssl"
CERT_FILE="$SSL_DIR/sibedas.crt"
KEY_FILE="$SSL_DIR/sibedas.key"
# Function to generate self-signed certificate
generate_self_signed() {
echo "Generating self-signed SSL certificate for $DOMAIN..."
# Create SSL directory if it doesn't exist
mkdir -p "$SSL_DIR"
# Generate self-signed certificate
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
-keyout "$KEY_FILE" \
-out "$CERT_FILE" \
-subj "/C=ID/ST=Jakarta/L=Jakarta/O=Sibedas/OU=IT/CN=$DOMAIN/emailAddress=$EMAIL"
echo "Self-signed certificate generated successfully!"
}
# Function to setup Let's Encrypt certificate
setup_letsencrypt() {
echo "Setting up Let's Encrypt certificate for $DOMAIN..."
# Check if certbot is available
if ! command -v certbot &> /dev/null; then
echo "Certbot not found. Installing..."
apk add --no-cache certbot certbot-nginx
fi
# Stop nginx temporarily
nginx -s stop || true
# Get certificate
certbot certonly --standalone \
--email "$EMAIL" \
--agree-tos \
--no-eff-email \
-d "$DOMAIN"
# Copy certificates to nginx ssl directory
cp /etc/letsencrypt/live/$DOMAIN/fullchain.pem "$CERT_FILE"
cp /etc/letsencrypt/live/$DOMAIN/privkey.pem "$KEY_FILE"
# Set proper permissions
chmod 644 "$CERT_FILE"
chmod 600 "$KEY_FILE"
# Start nginx
nginx
echo "Let's Encrypt certificate setup completed!"
}
# Function to renew Let's Encrypt certificate
renew_certificate() {
echo "Renewing Let's Encrypt certificate..."
certbot renew --quiet
# Copy renewed certificates
cp /etc/letsencrypt/live/$DOMAIN/fullchain.pem "$CERT_FILE"
cp /etc/letsencrypt/live/$DOMAIN/privkey.pem "$KEY_FILE"
# Reload nginx
nginx -s reload
echo "Certificate renewal completed!"
}
# Function to check certificate validity
check_certificate() {
if [ -f "$CERT_FILE" ] && [ -f "$KEY_FILE" ]; then
echo "Certificate files exist."
echo "Certificate details:"
openssl x509 -in "$CERT_FILE" -text -noout | grep -E "(Subject:|Not Before|Not After)"
return 0
else
echo "Certificate files not found."
return 1
fi
}
# Main script logic
case "${1:-setup}" in
"setup")
if [ "$SSL_TYPE" = "letsencrypt" ]; then
setup_letsencrypt
else
generate_self_signed
fi
;;
"renew")
renew_certificate
;;
"check")
check_certificate
;;
"self-signed")
generate_self_signed
;;
"letsencrypt")
setup_letsencrypt
;;
*)
echo "Usage: $0 {setup|renew|check|self-signed|letsencrypt}"
echo ""
echo "Environment variables:"
echo " DOMAIN: Domain name (default: sibedas.yourdomain.com)"
echo " EMAIL: Email address for Let's Encrypt (default: admin@yourdomain.com)"
echo " SSL_TYPE: Type of SSL (letsencrypt or self-signed, default: self-signed)"
exit 1
;;
esac

14
docker/nginx/ssl/.gitignore vendored Normal file
View File

@@ -0,0 +1,14 @@
# SSL Certificates - Do not commit these files
*.crt
*.key
*.pem
*.p12
*.pfx
# Let's Encrypt
letsencrypt/
live/
archive/
# Keep this directory in git but ignore certificate files
!.gitignore

View File

@@ -6,13 +6,13 @@ pidfile=/var/run/supervisord.pid
[program:laravel-queue-worker] [program:laravel-queue-worker]
process_name=%(program_name)s_%(process_num)02d process_name=%(program_name)s_%(process_num)02d
command=php /var/www/pupr/artisan queue:work --queue=default --timeout=82800 --tries=3 --memory=512 --sleep=3 command=php /var/www/artisan queue:work --queue=default --timeout=82800 --tries=3 --memory=512 --sleep=3
directory=/var/www/pupr directory=/var/www
autostart=true autostart=true
autorestart=true autorestart=true
numprocs=2 numprocs=2
redirect_stderr=true redirect_stderr=true
stdout_logfile=/var/www/pupr/storage/logs/queue-worker.log stdout_logfile=/var/www/storage/logs/queue-worker.log
stdout_logfile_maxbytes=10MB stdout_logfile_maxbytes=10MB
stdout_logfile_backups=5 stdout_logfile_backups=5
stopasgroup=true stopasgroup=true
@@ -22,13 +22,13 @@ priority=10
[program:laravel-scheduler] [program:laravel-scheduler]
process_name=%(program_name)s_%(process_num)02d process_name=%(program_name)s_%(process_num)02d
command=php /var/www/pupr/artisan schedule:work command=php /var/www/artisan schedule:work
directory=/var/www/pupr directory=/var/www
autostart=true autostart=true
autorestart=true autorestart=true
numprocs=1 numprocs=1
redirect_stderr=true redirect_stderr=true
stdout_logfile=/var/www/pupr/storage/logs/scheduler.log stdout_logfile=/var/www/storage/logs/scheduler.log
stdout_logfile_maxbytes=10MB stdout_logfile_maxbytes=10MB
stdout_logfile_backups=5 stdout_logfile_backups=5
stopasgroup=true stopasgroup=true

449
docs/README.md Normal file
View File

@@ -0,0 +1,449 @@
# Sibedas PBG Web - Documentation
Dokumentasi lengkap untuk setup dan penggunaan aplikasi Sibedas PBG Web.
## 📋 Table of Contents
1. [Quick Start](#-quick-start)
2. [Architecture](#-architecture)
3. [Environment Setup](#-environment-setup)
4. [Production Deployment](#-production-deployment)
5. [SSL Configuration](#-ssl-configuration)
6. [Monitoring](#-monitoring)
7. [Troubleshooting](#-troubleshooting)
## 🚀 Quick Start
### Prerequisites
- Docker & Docker Compose
- Domain name (untuk production)
- Port 80 dan 443 terbuka (untuk Let's Encrypt)
### Local Development
```bash
# Clone repository
git clone <repository-url>
cd sibedas-pbg-web
# Setup local environment
./scripts/setup-local.sh
```
### Production Deployment
```bash
# Copy environment file
cp env.production.example .env
# Edit environment variables
nano .env
# Deploy dengan reverse proxy dan SSL
./scripts/setup-reverse-proxy.sh setup
```
## 🏗️ Architecture
### Local Development
```
Browser → Port 8000 → Nginx → PHP-FPM → MariaDB
```
### Production dengan Reverse Proxy
```
Internet → Reverse Proxy (80/443) → Internal Nginx → PHP-FPM → MariaDB
```
### Components
- **Reverse Proxy Nginx**: Entry point, SSL termination, routing
- **Internal Nginx**: Serves Sibedas application
- **Application Container**: PHP-FPM with Supervisor (queue & scheduler)
- **Database Container**: MariaDB with backup import
## ⚙️ Environment Setup
### Required Variables
```bash
# Domain & SSL
DOMAIN=sibedas.yourdomain.com
EMAIL=admin@yourdomain.com
SSL_TYPE=self-signed # atau letsencrypt
# Database
DB_PASSWORD=your_secure_password
MYSQL_ROOT_PASSWORD=your_root_password
# Laravel
APP_KEY=base64:your_app_key_here
APP_URL=https://sibedas.yourdomain.com
```
### Generate App Key
```bash
docker-compose exec app php artisan key:generate
```
## 🚀 Production Deployment
### Step-by-Step Production Deployment
#### 1. **Server Preparation**
```bash
# Update system
sudo apt update && sudo apt upgrade -y
# Install Docker & Docker Compose
curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh
sudo usermod -aG docker $USER
# Install Docker Compose
sudo curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
# Logout and login again for group changes
exit
# SSH back to server
```
#### 2. **Clone Repository**
```bash
# Clone project
git clone <repository-url>
cd sibedas-pbg-web
# Set proper permissions
chmod +x scripts/*.sh
```
#### 3. **Environment Configuration**
```bash
# Copy environment template
cp env.production.example .env
# Edit environment variables
nano .env
```
**Required Environment Variables:**
```bash
# Domain & SSL
DOMAIN=sibedas.yourdomain.com
EMAIL=admin@yourdomain.com
SSL_TYPE=letsencrypt # atau self-signed untuk testing
# Database
DB_DATABASE=sibedas
DB_USERNAME=sibedas_user
DB_PASSWORD=your_secure_database_password
MYSQL_ROOT_PASSWORD=your_secure_root_password
# Laravel
APP_NAME="Sibedas PBG Web"
APP_ENV=production
APP_DEBUG=false
APP_KEY=base64:your_app_key_here
APP_URL=https://sibedas.yourdomain.com
VITE_APP_URL=https://sibedas.yourdomain.com
# Mail Configuration
MAIL_MAILER=smtp
MAIL_HOST=smtp.gmail.com
MAIL_PORT=587
MAIL_USERNAME=your_email@gmail.com
MAIL_PASSWORD=your_app_password
MAIL_ENCRYPTION=tls
MAIL_FROM_ADDRESS=your_email@gmail.com
MAIL_FROM_NAME="Sibedas PBG Web"
# Google Sheets API
SPREAD_SHEET_ID=your_google_sheets_id_here
```
#### 4. **Generate Application Key**
```bash
# Generate Laravel app key
php artisan key:generate --show
# Copy the generated key to .env file
```
#### 5. **Deploy Application**
```bash
# Option A: Full deployment with SSL (Recommended)
./scripts/setup-reverse-proxy.sh setup
# Option B: Deploy without SSL first
./scripts/deploy-production.sh deploy
```
#### 6. **SSL Setup (if not done in step 5)**
```bash
# For Let's Encrypt (Production)
DOMAIN=yourdomain.com EMAIL=admin@yourdomain.com ./scripts/setup-ssl.sh letsencrypt
# For Self-Signed (Testing)
./scripts/setup-ssl.sh self-signed
```
#### 7. **Verify Deployment**
```bash
# Check container status
docker-compose ps
# Check application health
curl -f http://localhost/health-check
# Check SSL certificate
./scripts/setup-ssl.sh check
# View logs
docker-compose logs nginx-proxy
docker-compose logs app
```
### Scripts yang Diperlukan
#### **Essential Scripts (Wajib)**
- `scripts/setup-reverse-proxy.sh` - Setup lengkap reverse proxy dan SSL
- `scripts/deploy-production.sh` - Deployment production
- `scripts/setup-ssl.sh` - Setup SSL certificates
#### **Optional Scripts**
- `scripts/setup-local.sh` - Setup local development
- `scripts/import-sibedas-database.sh` - Manual database import (otomatis via docker-compose)
#### **Scripts yang Tidak Diperlukan**
- `scripts/build-and-zip.sh` - Tidak diperlukan karena menggunakan Docker build
### Deployment Commands Summary
```bash
# 1. Setup environment
cp env.production.example .env
nano .env
# 2. Deploy with SSL (Recommended)
./scripts/setup-reverse-proxy.sh setup
# 3. Or deploy step by step
./scripts/deploy-production.sh deploy
./scripts/setup-ssl.sh letsencrypt
# 4. Check status
./scripts/setup-reverse-proxy.sh status
```
## 🔒 SSL Configuration
### Self-Signed Certificate
```bash
SSL_TYPE=self-signed ./scripts/setup-reverse-proxy.sh setup
```
### Let's Encrypt Certificate
```bash
DOMAIN=myapp.com EMAIL=admin@myapp.com SSL_TYPE=letsencrypt ./scripts/setup-reverse-proxy.sh setup
```
### SSL Management
```bash
# Check certificate
./scripts/setup-ssl.sh check
# Renew certificate
./scripts/setup-ssl.sh renew
```
## 📊 Monitoring
### Container Status
```bash
# Check all containers
docker-compose ps
# Check specific service
docker-compose ps app
```
### Logs
```bash
# Application logs
docker-compose logs app
# Reverse proxy logs
docker-compose logs nginx-proxy
# Database logs
docker-compose logs db
# Follow logs
docker-compose logs -f nginx-proxy
```
### Health Checks
```bash
# Application health
curl -f http://localhost/health-check
# SSL certificate
./scripts/setup-ssl.sh check
```
## 🛠️ Troubleshooting
### SSL Issues
```bash
# Check certificate files
docker exec sibedas_nginx_proxy ls -la /etc/nginx/ssl/
# Test SSL connection
openssl s_client -connect yourdomain.com:443
# Check nginx config
docker exec sibedas_nginx_proxy nginx -t
```
### Container Issues
```bash
# Restart services
docker-compose restart
# Check network
docker network ls
# Check volumes
docker volume ls
```
### Database Issues
```bash
# Import database manually
./scripts/import-sibedas-database.sh
# Check database connection
docker exec sibedas_app php artisan db:monitor
```
### Performance Issues
```bash
# Check resource usage
docker stats
# Check nginx access logs
docker exec sibedas_nginx_proxy tail -f /var/log/nginx/sibedas_access.log
```
## 🔧 Maintenance
### Backup
```bash
# Database backup
docker exec sibedas_db mysqldump -u root -p sibedas > backup.sql
# Volume backup
docker run --rm -v sibedas_app_storage:/data -v $(pwd):/backup alpine tar czf /backup/storage.tar.gz -C /data .
```
### Update Application
```bash
# Pull latest changes
git pull
# Rebuild and restart
docker-compose up -d --build
```
### SSL Certificate Renewal
```bash
# Manual renewal
./scripts/setup-ssl.sh renew
# Automatic renewal (cron)
0 12 * * * /path/to/sibedas-pbg-web/scripts/setup-ssl.sh renew
```
## 📁 Project Structure
```
sibedas-pbg-web/
├── docker/ # Docker configurations
│ ├── nginx/ # Nginx configs
│ ├── mysql/ # MySQL configs
│ └── supervisor/ # Supervisor configs
├── scripts/ # Deployment scripts
│ ├── setup-local.sh # Local development
│ ├── setup-reverse-proxy.sh # Reverse proxy setup
│ ├── deploy-production.sh # Production deployment
│ ├── setup-ssl.sh # SSL setup
│ └── import-sibedas-database.sh # Database import
├── docs/ # Documentation
├── docker-compose.yml # Production compose
├── docker-compose.local.yml # Local development compose
└── README.md # Main README
```
## 🆘 Support
### Common Commands
```bash
# Start services
docker-compose up -d
# Stop services
docker-compose down
# View logs
docker-compose logs [service]
# Execute commands
docker-compose exec app php artisan [command]
# Check status
./scripts/setup-reverse-proxy.sh status
```
### Getting Help
1. Check logs: `docker-compose logs [service]`
2. Check status: `./scripts/setup-reverse-proxy.sh status`
3. Restart services: `docker-compose restart`
4. Review this documentation
## 📚 Additional Resources
- [Docker Documentation](https://docs.docker.com/)
- [Nginx Documentation](https://nginx.org/en/docs/)
- [Let's Encrypt Documentation](https://letsencrypt.org/docs/)
- [Laravel Documentation](https://laravel.com/docs/)

154
env.production.example Normal file
View File

@@ -0,0 +1,154 @@
# Production Environment Configuration for Sibedas PBG Web
# Copy this file to .env and update the values
# =============================================================================
# REVERSE PROXY & SSL CONFIGURATION
# =============================================================================
# Domain configuration
DOMAIN=sibedas.yourdomain.com
EMAIL=admin@yourdomain.com
SSL_TYPE=self-signed # Options: self-signed, letsencrypt
# Nginx ports (usually 80 and 443)
NGINX_HTTP_PORT=80
NGINX_HTTPS_PORT=443
# =============================================================================
# LARAVEL APPLICATION CONFIGURATION
# =============================================================================
# Application settings
APP_NAME="Sibedas PBG Web"
APP_ENV=production
APP_DEBUG=false
APP_KEY=base64:your_app_key_here
APP_URL=https://sibedas.yourdomain.com
APP_TIMEZONE=Asia/Jakarta
# Vite configuration
VITE_APP_URL=https://sibedas.yourdomain.com
# =============================================================================
# DATABASE CONFIGURATION
# =============================================================================
# Database connection
DB_CONNECTION=mariadb
DB_HOST=db
DB_PORT=3306
DB_DATABASE=sibedas
DB_USERNAME=sibedas_user
DB_PASSWORD=your_secure_database_password
# MySQL root password
MYSQL_ROOT_PASSWORD=your_secure_root_password
# MySQL performance tuning
MYSQL_INNODB_BUFFER_POOL_SIZE=1G
# External database port (optional, for external access)
DB_EXTERNAL_PORT=3306
# =============================================================================
# CACHE, SESSION & QUEUE CONFIGURATION
# =============================================================================
# Cache configuration (using database)
CACHE_DRIVER=database
# Session configuration (using database)
SESSION_DRIVER=database
SESSION_LIFETIME=120
# Queue configuration (using database)
QUEUE_CONNECTION=database
# =============================================================================
# MAIL CONFIGURATION
# =============================================================================
# Mail settings
MAIL_MAILER=smtp
MAIL_HOST=smtp.gmail.com
MAIL_PORT=587
MAIL_USERNAME=your_email@gmail.com
MAIL_PASSWORD=your_app_password
MAIL_ENCRYPTION=tls
MAIL_FROM_ADDRESS=your_email@gmail.com
MAIL_FROM_NAME="Sibedas PBG Web"
# =============================================================================
# GOOGLE SHEETS API CONFIGURATION
# =============================================================================
# Google Sheets API
SPREAD_SHEET_ID=your_google_sheets_id_here
# =============================================================================
# LOGGING CONFIGURATION
# =============================================================================
# Log settings
LOG_CHANNEL=stack
LOG_DEPRECATIONS_CHANNEL=null
LOG_LEVEL=warning
# =============================================================================
# SECURITY CONFIGURATION
# =============================================================================
# Security settings
SESSION_SECURE_COOKIE=true
SESSION_SAME_SITE=lax
# =============================================================================
# PERFORMANCE CONFIGURATION
# =============================================================================
# Performance settings
CACHE_TTL=3600
SESSION_SECURE_COOKIE=true
# =============================================================================
# BACKUP CONFIGURATION
# =============================================================================
# Backup settings
BACKUP_RETENTION_DAYS=30
BACKUP_PATH=./backups
# =============================================================================
# MONITORING CONFIGURATION
# =============================================================================
# Health check settings
HEALTH_CHECK_ENABLED=true
HEALTH_CHECK_INTERVAL=30s
# =============================================================================
# NOTES
# =============================================================================
# 1. Generate APP_KEY: php artisan key:generate
# 2. Update DOMAIN and EMAIL for your domain
# 3. Set secure passwords for database
# 4. Configure mail settings for notifications
# 5. Set Google Sheets API credentials
# 6. For Let's Encrypt: ensure domain points to server and ports 80/443 are open
# =============================================================================
# DEPLOYMENT COMMANDS
# =============================================================================
# Setup reverse proxy and SSL:
# ./setup-reverse-proxy.sh setup
# Setup SSL only:
# ./setup-reverse-proxy.sh ssl
# Check status:
# ./setup-reverse-proxy.sh status
# Deploy production:
# ./scripts/deploy-production.sh deploy

226
scripts/deploy-production.sh Executable file
View File

@@ -0,0 +1,226 @@
#!/bin/bash
# Production Deployment Script for Sibedas PBG Web
# This script deploys the application with reverse proxy and SSL support
set -e
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# Configuration
DOMAIN="${DOMAIN:-sibedas.yourdomain.com}"
EMAIL="${EMAIL:-admin@yourdomain.com}"
SSL_TYPE="${SSL_TYPE:-self-signed}"
echo -e "${BLUE}=== Production Deployment for Sibedas PBG Web ===${NC}"
echo -e "Domain: ${GREEN}$DOMAIN${NC}"
echo -e "Email: ${GREEN}$EMAIL${NC}"
echo -e "SSL Type: ${GREEN}$SSL_TYPE${NC}"
echo ""
# Function to check prerequisites
check_prerequisites() {
echo -e "${BLUE}Checking prerequisites...${NC}"
# Check if Docker is installed
if ! command -v docker &> /dev/null; then
echo -e "${RED}Error: Docker is not installed${NC}"
exit 1
fi
# Check if Docker Compose is installed
if ! command -v docker-compose &> /dev/null; then
echo -e "${RED}Error: Docker Compose is not installed${NC}"
exit 1
fi
# Check if .env file exists
if [ ! -f .env ]; then
echo -e "${RED}Error: .env file not found${NC}"
echo -e "${YELLOW}Please create .env file with required environment variables${NC}"
exit 1
fi
echo -e "${GREEN}Prerequisites check passed!${NC}"
}
# Function to backup existing data
backup_data() {
echo -e "${BLUE}Creating backup of existing data...${NC}"
BACKUP_DIR="backups/$(date +%Y%m%d_%H%M%S)"
mkdir -p "$BACKUP_DIR"
# Backup database
if docker ps | grep -q sibedas_db; then
echo -e "${YELLOW}Backing up database...${NC}"
docker exec sibedas_db mysqldump -u root -p"${MYSQL_ROOT_PASSWORD:-root}" sibedas > "$BACKUP_DIR/database.sql" || true
fi
# Backup volumes
echo -e "${YELLOW}Backing up volumes...${NC}"
docker run --rm -v sibedas_app_storage:/data -v "$(pwd)/$BACKUP_DIR":/backup alpine tar czf /backup/app_storage.tar.gz -C /data . || true
docker run --rm -v sibedas_dbdata:/data -v "$(pwd)/$BACKUP_DIR":/backup alpine tar czf /backup/dbdata.tar.gz -C /data . || true
echo -e "${GREEN}Backup created in $BACKUP_DIR${NC}"
}
# Function to stop existing containers
stop_containers() {
echo -e "${BLUE}Stopping existing containers...${NC}"
docker-compose down --remove-orphans || true
echo -e "${GREEN}Containers stopped!${NC}"
}
# Function to build and start containers
deploy_containers() {
echo -e "${BLUE}Building and starting containers...${NC}"
# Build images
echo -e "${YELLOW}Building Docker images...${NC}"
docker-compose build --no-cache
# Start containers
echo -e "${YELLOW}Starting containers...${NC}"
docker-compose up -d
# Wait for containers to be healthy
echo -e "${YELLOW}Waiting for containers to be healthy...${NC}"
sleep 30
# Check container status
if ! docker-compose ps | grep -q "Up"; then
echo -e "${RED}Error: Some containers failed to start${NC}"
docker-compose logs
exit 1
fi
echo -e "${GREEN}Containers deployed successfully!${NC}"
}
# Function to setup SSL
setup_ssl() {
echo -e "${BLUE}Setting up SSL certificate...${NC}"
# Wait for nginx proxy to be ready
echo -e "${YELLOW}Waiting for reverse proxy to be ready...${NC}"
sleep 10
# Setup SSL
if [ "$SSL_TYPE" = "letsencrypt" ]; then
echo -e "${YELLOW}Setting up Let's Encrypt certificate...${NC}"
echo -e "${YELLOW}Make sure your domain $DOMAIN points to this server${NC}"
read -p "Press Enter to continue..."
docker exec sibedas_nginx_proxy /usr/local/bin/ssl-setup.sh letsencrypt
else
echo -e "${YELLOW}Setting up self-signed certificate...${NC}"
docker exec sibedas_nginx_proxy /usr/local/bin/ssl-setup.sh self-signed
fi
echo -e "${GREEN}SSL setup completed!${NC}"
}
# Function to run post-deployment tasks
post_deployment() {
echo -e "${BLUE}Running post-deployment tasks...${NC}"
# Clear Laravel caches
echo -e "${YELLOW}Clearing Laravel caches...${NC}"
docker exec sibedas_app php artisan config:clear || true
docker exec sibedas_app php artisan route:clear || true
docker exec sibedas_app php artisan view:clear || true
docker exec sibedas_app php artisan cache:clear || true
# Optimize Laravel
echo -e "${YELLOW}Optimizing Laravel...${NC}"
docker exec sibedas_app php artisan optimize || true
# Check application health
echo -e "${YELLOW}Checking application health...${NC}"
sleep 5
if curl -f -s "http://localhost/health-check" > /dev/null; then
echo -e "${GREEN}Application is healthy!${NC}"
else
echo -e "${YELLOW}Warning: Health check failed, but deployment completed${NC}"
fi
}
# Function to show deployment status
show_status() {
echo -e "${BLUE}=== Deployment Status ===${NC}"
echo -e "${YELLOW}Container Status:${NC}"
docker-compose ps
echo -e "${YELLOW}SSL Certificate Status:${NC}"
docker exec sibedas_nginx_proxy /usr/local/bin/ssl-setup.sh check || true
echo -e "${YELLOW}Application URLs:${NC}"
echo -e " HTTP: ${GREEN}http://$DOMAIN${NC}"
echo -e " HTTPS: ${GREEN}https://$DOMAIN${NC}"
echo -e "${YELLOW}Logs:${NC}"
echo -e " Application: ${GREEN}docker-compose logs app${NC}"
echo -e " Reverse Proxy: ${GREEN}docker-compose logs nginx-proxy${NC}"
echo -e " Database: ${GREEN}docker-compose logs db${NC}"
}
# Function to show usage
show_usage() {
echo "Usage: $0 {deploy|status|backup|ssl}"
echo ""
echo "Commands:"
echo " deploy - Full deployment with SSL setup"
echo " status - Show deployment status"
echo " backup - Create backup of existing data"
echo " ssl - Setup SSL certificate only"
echo ""
echo "Environment variables:"
echo " DOMAIN - Domain name (default: sibedas.yourdomain.com)"
echo " EMAIL - Email address for Let's Encrypt (default: admin@yourdomain.com)"
echo " SSL_TYPE - Type of SSL (letsencrypt or self-signed, default: self-signed)"
echo ""
echo "Examples:"
echo " DOMAIN=myapp.com EMAIL=admin@myapp.com SSL_TYPE=letsencrypt $0 deploy"
echo " $0 status"
echo " $0 ssl"
}
# Main script logic
case "${1:-deploy}" in
"deploy")
check_prerequisites
backup_data
stop_containers
deploy_containers
setup_ssl
post_deployment
show_status
;;
"status")
show_status
;;
"backup")
backup_data
;;
"ssl")
setup_ssl
;;
*)
show_usage
exit 1
;;
esac
echo ""
echo -e "${GREEN}Deployment completed successfully!${NC}"
echo -e "${BLUE}Your application is now accessible at: https://$DOMAIN${NC}"

View File

@@ -0,0 +1,257 @@
#!/bin/bash
echo "🗃️ Import Database from sibedas.sql"
echo "===================================="
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
print_status() {
echo -e "${BLUE}[INFO]${NC} $1"
}
print_success() {
echo -e "${GREEN}[SUCCESS]${NC} $1"
}
print_warning() {
echo -e "${YELLOW}[WARNING]${NC} $1"
}
print_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
# Check if sibedas.sql exists
check_sql_file() {
if [[ ! -f "../sibedas.sql" ]]; then
print_error "sibedas.sql file not found!"
print_error "Please make sure sibedas.sql is in the project root directory."
exit 1
fi
print_success "Found sibedas.sql file"
}
# Import for local development
import_local() {
print_status "Importing database for LOCAL DEVELOPMENT..."
# Stop containers if running
print_status "Stopping containers..."
docker-compose -f ../docker-compose.local.yml down
# Remove existing database volume to force fresh import
print_warning "Removing old database volume for fresh import..."
docker volume rm sibedas-pbg-web_sibedas_dbdata_local 2>/dev/null || true
# Start database container first
print_status "Starting database container..."
docker-compose -f ../docker-compose.local.yml up -d db
# Wait for database to be ready
print_status "Waiting for database to be ready..."
sleep 20
# Verify sibedas.sql was imported automatically
print_status "Verifying database import..."
if docker-compose -f ../docker-compose.local.yml exec -T db mysql -uroot -proot -e "USE sibedas; SELECT COUNT(*) FROM users;" 2>/dev/null; then
print_success "✅ Database imported successfully from sibedas.sql!"
# Show table summary
print_status "Database tables summary:"
docker-compose -f ../docker-compose.local.yml exec -T db mysql -uroot -proot -e "
USE sibedas;
SELECT 'users' as table_name, COUNT(*) as count FROM users
UNION SELECT 'advertisements', COUNT(*) FROM advertisements
UNION SELECT 'business_or_industries', COUNT(*) FROM business_or_industries
UNION SELECT 'customers', COUNT(*) FROM customers
UNION SELECT 'cache', COUNT(*) FROM cache
UNION SELECT 'sessions', COUNT(*) FROM sessions
UNION SELECT 'jobs', COUNT(*) FROM jobs;"
else
print_error "❌ Database import failed or data not found!"
exit 1
fi
# Start all containers
print_status "Starting all containers..."
docker-compose -f ../docker-compose.local.yml up -d
# Wait for app to be ready
sleep 15
# Clear caches to ensure fresh start
print_status "Clearing application caches..."
docker-compose -f ../docker-compose.local.yml exec -T app php artisan config:clear
docker-compose -f ../docker-compose.local.yml exec -T app php artisan cache:clear
docker-compose -f ../docker-compose.local.yml exec -T app php artisan view:clear
print_success "✅ Local development setup completed with sibedas.sql data!"
print_status "Access your application at: http://localhost:8000"
}
# Import for production
import_production() {
print_status "Importing database for PRODUCTION..."
# Check if .env exists
if [[ ! -f "../.env" ]]; then
print_error ".env file not found! Please configure production environment first."
exit 1
fi
# Load environment variables
source ../.env
# Stop containers if running
print_status "Stopping containers..."
docker-compose -f ../docker-compose.yml down
# Remove existing database volume to force fresh import
print_warning "Removing old database volume for fresh import..."
docker volume rm sibedas-pbg-web_sibedas_dbdata 2>/dev/null || true
# Start database container first
print_status "Starting database container..."
docker-compose -f ../docker-compose.yml up -d db
# Wait for database to be ready
print_status "Waiting for database to be ready..."
sleep 30
# Verify sibedas.sql was imported automatically
print_status "Verifying database import..."
if docker-compose -f ../docker-compose.yml exec -T db mysql -uroot -p${MYSQL_ROOT_PASSWORD} -e "USE ${DB_DATABASE}; SELECT COUNT(*) FROM users;" 2>/dev/null; then
print_success "✅ Database imported successfully from sibedas.sql!"
# Show table summary
print_status "Database tables summary:"
docker-compose -f ../docker-compose.yml exec -T db mysql -uroot -p${MYSQL_ROOT_PASSWORD} -e "
USE ${DB_DATABASE};
SELECT 'users' as table_name, COUNT(*) as count FROM users
UNION SELECT 'advertisements', COUNT(*) FROM advertisements
UNION SELECT 'business_or_industries', COUNT(*) FROM business_or_industries
UNION SELECT 'customers', COUNT(*) FROM customers
UNION SELECT 'cache', COUNT(*) FROM cache
UNION SELECT 'sessions', COUNT(*) FROM sessions
UNION SELECT 'jobs', COUNT(*) FROM jobs;"
else
print_error "❌ Database import failed or data not found!"
exit 1
fi
# Start all containers
print_status "Starting all containers..."
docker-compose -f ../docker-compose.yml up -d
# Wait for app to be ready
sleep 30
# Generate app key if needed
if [[ -z "$APP_KEY" ]] || [[ "$APP_KEY" == "" ]]; then
print_status "Generating application key..."
docker-compose -f ../docker-compose.yml exec -T app php artisan key:generate --force
fi
# Optimize application
print_status "Optimizing application..."
docker-compose -f ../docker-compose.yml exec -T app php artisan config:cache
docker-compose -f ../docker-compose.yml exec -T app php artisan route:cache
docker-compose -f ../docker-compose.yml exec -T app php artisan view:cache
# Create storage link
print_status "Creating storage link..."
docker-compose -f ../docker-compose.yml exec -T app php artisan storage:link
print_success "✅ Production setup completed with sibedas.sql data!"
print_status "Access your application at: ${APP_URL}"
}
# Manual import to running container
manual_import() {
print_status "Manual import to running container..."
# Check which containers are running
if docker-compose -f ../docker-compose.local.yml ps | grep -q "sibedas_db_local"; then
print_status "Found local development database container"
print_status "Importing sibedas.sql..."
docker-compose -f ../docker-compose.local.yml exec -T db mysql -uroot -proot sibedas < ../sibedas.sql
print_success "✅ Import completed for local development!"
# Clear app caches
docker-compose -f ../docker-compose.local.yml exec -T app php artisan cache:clear 2>/dev/null || true
elif docker-compose -f ../docker-compose.yml ps | grep -q "sibedas_db"; then
print_status "Found production database container"
source ../.env 2>/dev/null || true
print_status "Importing sibedas.sql..."
docker-compose -f ../docker-compose.yml exec -T db mysql -uroot -p${MYSQL_ROOT_PASSWORD:-root} ${DB_DATABASE:-sibedas} < ../sibedas.sql
print_success "✅ Import completed for production!"
# Clear app caches
docker-compose -f ../docker-compose.yml exec -T app php artisan cache:clear 2>/dev/null || true
else
print_error "❌ No database container found running!"
print_error "Please start containers first:"
print_error " Local: docker-compose -f ../docker-compose.local.yml up -d"
print_error " Production: docker-compose -f ../docker-compose.yml up -d"
exit 1
fi
}
# Main execution
main() {
check_sql_file
echo ""
echo "🗃️ Choose import method:"
echo "1) 🔄 Fresh import for LOCAL development (recommended)"
echo "2) 🔄 Fresh import for PRODUCTION"
echo "3) 📥 Manual import to running container"
echo "4) ❌ Cancel"
echo ""
read -p "Enter your choice (1-4): " choice
case $choice in
1)
import_local
;;
2)
import_production
;;
3)
manual_import
;;
4)
print_status "Cancelled"
exit 0
;;
*)
print_error "Invalid choice"
exit 1
;;
esac
echo ""
print_success "🎉 Database import completed!"
echo ""
print_status "📋 Imported data includes:"
echo " ✅ All application tables with existing data"
echo " ✅ Cache table (for CACHE_DRIVER=database)"
echo " ✅ Sessions table (for SESSION_DRIVER=database)"
echo " ✅ Jobs & failed_jobs tables (for QUEUE_CONNECTION=database)"
echo ""
print_status "🚀 Your application is ready to use with all data!"
}
# Run main function
main "$@"

188
scripts/setup-local.sh Executable file
View File

@@ -0,0 +1,188 @@
#!/bin/bash
# Local Development Setup Script for Sibedas PBG Web
# This script sets up the local development environment
set -e
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
echo -e "${BLUE}=== Local Development Setup untuk Sibedas PBG Web ===${NC}"
echo ""
# Function to check prerequisites
check_prerequisites() {
echo -e "${BLUE}Checking prerequisites...${NC}"
# Check if Docker is installed
if ! command -v docker &> /dev/null; then
echo -e "${RED}Error: Docker is not installed${NC}"
exit 1
fi
# Check if Docker Compose is installed
if ! command -v docker-compose &> /dev/null; then
echo -e "${RED}Error: Docker Compose is not installed${NC}"
exit 1
fi
# Check if .env file exists
if [ ! -f .env ]; then
echo -e "${YELLOW}Warning: .env file not found${NC}"
echo -e "${YELLOW}Creating from example...${NC}"
if [ -f env.production.example ]; then
cp env.production.example .env
else
echo -e "${RED}Error: No environment example file found${NC}"
exit 1
fi
fi
echo -e "${GREEN}Prerequisites check passed!${NC}"
}
# Function to setup environment for local development
setup_environment() {
echo -e "${BLUE}Setting up environment for local development...${NC}"
# Update .env for local development
sed -i 's/APP_ENV=production/APP_ENV=local/g' .env
sed -i 's/APP_DEBUG=false/APP_DEBUG=true/g' .env
sed -i 's/APP_URL=https:\/\/sibedas.yourdomain.com/APP_URL=http:\/\/localhost:8000/g' .env
sed -i 's/VITE_APP_URL=https:\/\/sibedas.yourdomain.com/VITE_APP_URL=http:\/\/localhost:8000/g' .env
# Update database settings for local
sed -i 's/DB_USERNAME=sibedas_user/DB_USERNAME=root/g' .env
sed -i 's/DB_PASSWORD=your_secure_database_password/DB_PASSWORD=root/g' .env
sed -i 's/MYSQL_ROOT_PASSWORD=your_secure_root_password/MYSQL_ROOT_PASSWORD=root/g' .env
echo -e "${GREEN}Environment configured for local development!${NC}"
}
# Function to start local containers
start_containers() {
echo -e "${BLUE}Starting local development containers...${NC}"
# Stop any existing containers
docker-compose -f docker-compose.local.yml down --remove-orphans || true
# Build and start containers
docker-compose -f docker-compose.local.yml up -d --build
# Wait for containers to be ready
echo -e "${YELLOW}Waiting for containers to be ready...${NC}"
sleep 30
# Check container status
if docker-compose -f docker-compose.local.yml ps | grep -q "Up"; then
echo -e "${GREEN}Containers started successfully!${NC}"
else
echo -e "${RED}Error: Some containers failed to start${NC}"
docker-compose -f docker-compose.local.yml logs
exit 1
fi
}
# Function to setup database
setup_database() {
echo -e "${BLUE}Setting up database...${NC}"
# Wait for database to be ready
echo -e "${YELLOW}Waiting for database to be ready...${NC}"
sleep 10
# Check if database import was successful
if docker exec sibedas_db_local mysql -uroot -proot sibedas -e "SHOW TABLES LIKE 'users';" 2>/dev/null | grep -q "users"; then
echo -e "${GREEN}Database imported successfully from sibedas.sql!${NC}"
else
echo -e "${YELLOW}Warning: Database import verification failed${NC}"
echo -e "${YELLOW}You may need to manually import the database${NC}"
fi
}
# Function to run post-setup tasks
post_setup() {
echo -e "${BLUE}Running post-setup tasks...${NC}"
# Clear Laravel caches
echo -e "${YELLOW}Clearing Laravel caches...${NC}"
docker exec sibedas_app_local php artisan config:clear || true
docker exec sibedas_app_local php artisan route:clear || true
docker exec sibedas_app_local php artisan view:clear || true
docker exec sibedas_app_local php artisan cache:clear || true
# Optimize Laravel
echo -e "${YELLOW}Optimizing Laravel...${NC}"
docker exec sibedas_app_local php artisan optimize:clear || true
# Create storage link
echo -e "${YELLOW}Creating storage link...${NC}"
docker exec sibedas_app_local php artisan storage:link || true
echo -e "${GREEN}Post-setup tasks completed!${NC}"
}
# Function to show status
show_status() {
echo -e "${BLUE}=== Local Development Status ===${NC}"
echo -e "${YELLOW}Container Status:${NC}"
docker-compose -f docker-compose.local.yml ps
echo -e "${YELLOW}Application URLs:${NC}"
echo -e " Main App: ${GREEN}http://localhost:8000${NC}"
echo -e " Vite Dev: ${GREEN}http://localhost:5173${NC}"
echo -e "${YELLOW}Useful Commands:${NC}"
echo -e " View logs: ${GREEN}docker-compose -f docker-compose.local.yml logs -f [service]${NC}"
echo -e " Execute commands: ${GREEN}docker-compose -f docker-compose.local.yml exec app php artisan [command]${NC}"
echo -e " Stop services: ${GREEN}docker-compose -f docker-compose.local.yml down${NC}"
echo -e " Restart services: ${GREEN}docker-compose -f docker-compose.local.yml restart${NC}"
}
# Function to show usage
show_usage() {
echo "Usage: $0 {setup|status|help}"
echo ""
echo "Commands:"
echo " setup - Setup local development environment (default)"
echo " status - Show current status"
echo " help - Show this help message"
echo ""
echo "Examples:"
echo " $0 setup"
echo " $0 status"
}
# Main script logic
case "${1:-setup}" in
"setup")
check_prerequisites
setup_environment
start_containers
setup_database
post_setup
show_status
;;
"status")
show_status
;;
"help"|"-h"|"--help")
show_usage
;;
*)
echo -e "${RED}Unknown command: $1${NC}"
echo ""
show_usage
exit 1
;;
esac
echo ""
echo -e "${GREEN}Local development setup completed successfully!${NC}"
echo -e "${BLUE}You can now access your application at: http://localhost:8000${NC}"

129
scripts/setup-reverse-proxy.sh Executable file
View File

@@ -0,0 +1,129 @@
#!/bin/bash
# Reverse Proxy Setup Script for Sibedas PBG Web
# Wrapper script untuk setup reverse proxy dan SSL
set -e
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
echo -e "${BLUE}=== Reverse Proxy Setup untuk Sibedas PBG Web ===${NC}"
echo ""
# Function to show usage
show_usage() {
echo "Usage: $0 {setup|ssl|status|help}"
echo ""
echo "Commands:"
echo " setup - Setup reverse proxy dan SSL (default)"
echo " ssl - Setup SSL certificate only"
echo " status - Show current status"
echo " help - Show this help message"
echo ""
echo "Environment variables:"
echo " DOMAIN - Domain name (default: sibedas.yourdomain.com)"
echo " EMAIL - Email address for Let's Encrypt (default: admin@yourdomain.com)"
echo " SSL_TYPE - Type of SSL (letsencrypt or self-signed, default: self-signed)"
echo ""
echo "Examples:"
echo " $0 setup"
echo " DOMAIN=myapp.com EMAIL=admin@myapp.com SSL_TYPE=letsencrypt $0 setup"
echo " $0 ssl"
echo " $0 status"
}
# Function to check prerequisites
check_prerequisites() {
echo -e "${BLUE}Checking prerequisites...${NC}"
# Check if .env exists
if [ ! -f .env ]; then
echo -e "${RED}Error: .env file not found${NC}"
echo -e "${YELLOW}Please create .env file with required environment variables${NC}"
exit 1
fi
# Check if scripts directory exists
if [ ! -d scripts ]; then
echo -e "${RED}Error: scripts directory not found${NC}"
exit 1
fi
echo -e "${GREEN}Prerequisites check passed!${NC}"
}
# Function to setup reverse proxy
setup_reverse_proxy() {
echo -e "${BLUE}Setting up reverse proxy...${NC}"
# Run deployment script
./scripts/deploy-production.sh deploy
echo -e "${GREEN}Reverse proxy setup completed!${NC}"
}
# Function to setup SSL only
setup_ssl() {
echo -e "${BLUE}Setting up SSL certificate...${NC}"
# Run SSL setup script
./scripts/setup-ssl.sh setup
echo -e "${GREEN}SSL setup completed!${NC}"
}
# Function to show status
show_status() {
echo -e "${BLUE}=== Current Status ===${NC}"
# Check if containers are running
if command -v docker-compose &> /dev/null; then
echo -e "${YELLOW}Container Status:${NC}"
docker-compose ps 2>/dev/null || echo "Docker Compose not available"
fi
# Check SSL certificate
if [ -f scripts/setup-ssl.sh ]; then
echo -e "${YELLOW}SSL Certificate Status:${NC}"
./scripts/setup-ssl.sh check 2>/dev/null || echo "SSL check failed"
fi
# Show environment info
if [ -f .env ]; then
echo -e "${YELLOW}Environment Variables:${NC}"
grep -E "^(DOMAIN|EMAIL|SSL_TYPE|APP_URL)=" .env 2>/dev/null || echo "No environment variables found"
fi
}
# Main script logic
case "${1:-setup}" in
"setup")
check_prerequisites
setup_reverse_proxy
;;
"ssl")
check_prerequisites
setup_ssl
;;
"status")
show_status
;;
"help"|"-h"|"--help")
show_usage
;;
*)
echo -e "${RED}Unknown command: $1${NC}"
echo ""
show_usage
exit 1
;;
esac
echo ""
echo -e "${GREEN}Setup completed successfully!${NC}"
echo -e "${BLUE}For more information, see: docs/README-Reverse-Proxy-SSL.md${NC}"

145
scripts/setup-ssl.sh Executable file
View File

@@ -0,0 +1,145 @@
#!/bin/bash
# SSL Setup Script for Sibedas PBG Web
# This script sets up SSL certificates for the reverse proxy
set -e
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# Configuration
DOMAIN="${DOMAIN:-sibedas.yourdomain.com}"
EMAIL="${EMAIL:-admin@yourdomain.com}"
SSL_TYPE="${SSL_TYPE:-self-signed}"
echo -e "${BLUE}=== SSL Setup for Sibedas PBG Web ===${NC}"
echo -e "Domain: ${GREEN}$DOMAIN${NC}"
echo -e "Email: ${GREEN}$EMAIL${NC}"
echo -e "SSL Type: ${GREEN}$SSL_TYPE${NC}"
echo ""
# Function to check if Docker is running
check_docker() {
if ! docker info > /dev/null 2>&1; then
echo -e "${RED}Error: Docker is not running${NC}"
exit 1
fi
}
# Function to check if containers are running
check_containers() {
if ! docker ps | grep -q sibedas_nginx_proxy; then
echo -e "${YELLOW}Warning: Reverse proxy container is not running${NC}"
echo -e "${YELLOW}Starting containers first...${NC}"
docker-compose up -d
sleep 10
fi
}
# Function to setup self-signed certificate
setup_self_signed() {
echo -e "${BLUE}Setting up self-signed SSL certificate...${NC}"
docker exec sibedas_nginx_proxy /usr/local/bin/ssl-setup.sh self-signed
echo -e "${GREEN}Self-signed certificate setup completed!${NC}"
echo -e "${YELLOW}Note: Self-signed certificates will show security warnings in browsers${NC}"
}
# Function to setup Let's Encrypt certificate
setup_letsencrypt() {
echo -e "${BLUE}Setting up Let's Encrypt SSL certificate...${NC}"
# Check if domain is accessible
echo -e "${YELLOW}Important: Make sure your domain $DOMAIN points to this server${NC}"
echo -e "${YELLOW}and ports 80 and 443 are accessible from the internet${NC}"
read -p "Press Enter to continue..."
docker exec sibedas_nginx_proxy /usr/local/bin/ssl-setup.sh letsencrypt
echo -e "${GREEN}Let's Encrypt certificate setup completed!${NC}"
}
# Function to check certificate status
check_certificate() {
echo -e "${BLUE}Checking certificate status...${NC}"
docker exec sibedas_nginx_proxy /usr/local/bin/ssl-setup.sh check
}
# Function to renew certificate
renew_certificate() {
echo -e "${BLUE}Renewing SSL certificate...${NC}"
docker exec sibedas_nginx_proxy /usr/local/bin/ssl-setup.sh renew
echo -e "${GREEN}Certificate renewal completed!${NC}"
}
# Function to show usage
show_usage() {
echo "Usage: $0 {setup|check|renew|self-signed|letsencrypt}"
echo ""
echo "Commands:"
echo " setup - Setup SSL certificate (default: self-signed)"
echo " check - Check certificate status"
echo " renew - Renew Let's Encrypt certificate"
echo " self-signed - Setup self-signed certificate"
echo " letsencrypt - Setup Let's Encrypt certificate"
echo ""
echo "Environment variables:"
echo " DOMAIN - Domain name (default: sibedas.yourdomain.com)"
echo " EMAIL - Email address for Let's Encrypt (default: admin@yourdomain.com)"
echo " SSL_TYPE - Type of SSL (letsencrypt or self-signed, default: self-signed)"
echo ""
echo "Examples:"
echo " DOMAIN=myapp.com EMAIL=admin@myapp.com $0 letsencrypt"
echo " $0 self-signed"
echo " $0 check"
}
# Main script logic
case "${1:-setup}" in
"setup")
check_docker
check_containers
if [ "$SSL_TYPE" = "letsencrypt" ]; then
setup_letsencrypt
else
setup_self_signed
fi
;;
"check")
check_docker
check_containers
check_certificate
;;
"renew")
check_docker
check_containers
renew_certificate
;;
"self-signed")
check_docker
check_containers
setup_self_signed
;;
"letsencrypt")
check_docker
check_containers
setup_letsencrypt
;;
*)
show_usage
exit 1
;;
esac
echo ""
echo -e "${GREEN}SSL setup completed successfully!${NC}"
echo -e "${BLUE}You can now access your application at: https://$DOMAIN${NC}"