# WSKYE Student Web Server & Project Hub

A modern, Docker-powered hosting platform and project hub designed for native PHP web applications (both static and dynamic) for students and educators.

---

## 🌟 Key Features

1. **Multi-Project Hosting (`/project`)**:
   - Host multiple independent static (HTML/CSS/JS) or dynamic (PHP + MySQL) applications in the `/project` folder.
   - Every project is instantly accessible via `http://localhost:8080/project/<project-name>/` (supports trailing-slash redirects and sub-routing).
2. **Automated Project Upload with Token Protection**:
   - Students can upload `.zip` project archives or standalone scripts directly via the web dashboard.
   - Protected with an authorization token (default: `WSKYE2026`, configurable via `.env`).
   - Secure extraction: guards against *Zip Slip* path traversal attacks and automatically flattens single root wrapper directories.
3. **Integrated MySQL 8.0 Database**:
   - Built-in MySQL 8.0 service defined in `compose.yaml` with persistent volume storage (`mysql_data`).
   - PHP extensions pre-installed: `pdo`, `pdo_mysql`, `mysqli`, `zip`, `gd`, `mbstring`, and `opcache`.
   - Live database health and connection status indicators displayed on the dashboard.
4. **External Database GUI Access (HeidiSQL / DBeaver)**:
   - Port `33061` is exposed to the host to prevent port conflicts with any existing MySQL/MariaDB instances.
   - Connect directly from HeidiSQL, DBeaver, TablePlus, or VS Code Database tools.
5. **Nginx Web Server & Reverse Proxy Ready**:
   - Pre-configured `default.conf` handling subproject routing, FastCGI PHP-FPM processing, and static file caching.
   - Reverse-proxy friendly: restores client real IPs (`X-Forwarded-For`), handles HTTPS headers (`X-Forwarded-Proto`), and supports upload file sizes up to **128MB**.

---

## 🚀 Quick Start

### 1. Configure Environment (Optional)
Copy the example environment file:
```bash
cp .env.example .env
```

### 2. Start the Stack with Docker Compose
```bash
docker compose up -d
```
*(Use `docker compose up --build -d` if you modified the Dockerfile or PHP configurations)*

### 3. Open in Browser
- **Main Dashboard**: [http://localhost:8080](http://localhost:8080)
- **Static App Demo**: [http://localhost:8080/project/demo-static/](http://localhost:8080/project/demo-static/)
- **Dynamic PHP + MySQL Demo**: [http://localhost:8080/project/demo-dynamic/](http://localhost:8080/project/demo-dynamic/)

---

## 🔑 Database & Credentials

### Upload Token
- **Default Token**: `WSKYE2026`
- Can be customized using the `UPLOAD_TOKEN` environment variable in `.env`.

### MySQL Database Configuration
| Parameter | Inside Docker Network | From Host Machine / Remote GUI |
|---|---|---|
| **Host** | `db` | `127.0.0.1` / `localhost` |
| **Port** | `3306` | `33061` *(custom port to avoid conflicts)* |
| **Database Name** | `wskye_db` | `wskye_db` |
| **Username** | `wskye_user` | `wskye_user` |
| **Password** | `wskye_password` | `wskye_password` |
| **Root Password** | `rootpassword` | `rootpassword` |

### Connecting via HeidiSQL / DBeaver
- **Network Type**: MySQL (TCP/IP)
- **Hostname / IP**: `127.0.0.1`
- **Port**: `33061`
- **User**: `wskye_user` (or `root`)
- **Password**: `wskye_password` (or `rootpassword`)

### PHP PDO Connection Example in Student Code
```php
<?php
$host = getenv('DB_HOST') ?: 'db';
$port = getenv('DB_PORT') ?: '3306'; // default internal docker port
$database = getenv('DB_DATABASE') ?: 'wskye_db';
$username = getenv('DB_USERNAME') ?: 'wskye_user';
$password = getenv('DB_PASSWORD') ?: 'wskye_password';

try {
    $dsn = "mysql:host=$host;port=$port;dbname=$database;charset=utf8mb4";
    $pdo = new PDO($dsn, $username, $password, [
        PDO::ATTR_ERRMODE            => PDO::ERRMODE_EXCEPTION,
        PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
        PDO::ATTR_TIMEOUT            => 5,
    ]);
} catch (PDOException $e) {
    die("Database connection failed: " . $e->getMessage());
}
```

---

## 🌐 Production Host Reverse Proxy (Nginx)

When deploying on a public VPS behind a host Nginx reverse proxy with SSL:

```nginx
server {
    listen 80;
    server_name student.yourdomain.com;
    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl http2;
    server_name student.yourdomain.com;

    ssl_certificate /etc/letsencrypt/live/student.yourdomain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/student.yourdomain.com/privkey.pem;

    client_max_body_size 128M;

    location / {
        proxy_pass http://127.0.0.1:8080;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header X-Forwarded-Host $host;
        proxy_read_timeout 300s;
        proxy_connect_timeout 300s;
    }
}
```

---

## 📁 Project Structure

```text
.
├── compose.yaml                # Multi-container Docker Compose definition (nginx, app, db)
├── Dockerfile                  # PHP 8.2-FPM Alpine image with MySQL, ZIP, GD extensions
├── index.php                   # Bento Grid Hub & Student Project Management Dashboard
├── README.md                   # Project documentation (English)
├── .env.example                # Sample environment variables
├── .gitignore                  # Git ignore rules for Docker, logs, and environments
├── docker/
│   ├── entrypoint.sh           # Directory permission setup & DB readiness wait-check
│   ├── nginx/
│   │   └── default.conf        # Nginx server configuration (subrouting & reverse proxy)
│   └── php/
│       └── custom.ini          # Custom PHP settings (128M upload limit, execution limits)
└── project/                    # Destination directory for student applications
    ├── demo-dynamic/           # Dynamic PHP + MySQL demo project
    └── demo-static/            # Static HTML/CSS demo project
```

---

## 🛠️ Handy Docker Commands

- **View real-time logs**:
  ```bash
  docker compose logs -f
  ```
- **Check container status**:
  ```bash
  docker compose ps
  ```
- **Restart services**:
  ```bash
  docker compose restart
  ```
- **Stop all containers**:
  ```bash
  docker compose down
  ```
- **Rebuild and restart containers**:
  ```bash
  docker compose up --build -d
  ```
