add docker for server demo
This commit is contained in:
10
Dockerfile
10
Dockerfile
@@ -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"]
|
||||||
|
|||||||
@@ -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**!
|
|
||||||
@@ -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
191
README.md
@@ -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/`
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
55
docker/mysql/conf.d/production.cnf
Normal file
55
docker/mysql/conf.d/production.cnf
Normal 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
32
docker/nginx/Dockerfile
Normal 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;"]
|
||||||
113
docker/nginx/conf.d/production.conf
Normal file
113
docker/nginx/conf.d/production.conf
Normal 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;
|
||||||
|
}
|
||||||
137
docker/nginx/conf.d/reverse-proxy.conf
Normal file
137
docker/nginx/conf.d/reverse-proxy.conf
Normal 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;
|
||||||
|
# }
|
||||||
|
# }
|
||||||
58
docker/nginx/conf.d/sibedas-internal.conf
Normal file
58
docker/nginx/conf.d/sibedas-internal.conf
Normal 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
123
docker/nginx/ssl-setup.sh
Normal 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
14
docker/nginx/ssl/.gitignore
vendored
Normal 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
|
||||||
@@ -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
449
docs/README.md
Normal 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
154
env.production.example
Normal 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
226
scripts/deploy-production.sh
Executable 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}"
|
||||||
257
scripts/import-sibedas-database.sh
Executable file
257
scripts/import-sibedas-database.sh
Executable 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
188
scripts/setup-local.sh
Executable 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
129
scripts/setup-reverse-proxy.sh
Executable 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
145
scripts/setup-ssl.sh
Executable 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}"
|
||||||
Reference in New Issue
Block a user