# Deploy GroupVault trên shared hosting

## Điều kiện bắt buộc

Bản source này cần Next.js API routes, vì vậy hosting phải hỗ trợ:

- Node.js 20.9 trở lên.
- Chạy tiến trình Node lâu dài hoặc cPanel **Setup Node.js App**.
- Thiết lập biến môi trường.
- HTTPS.

Shared hosting chỉ hỗ trợ PHP/Apache và không có Node.js sẽ không chạy trực tiếp bản này. Trong trường hợp đó, phương án nhanh và ổn định nhất là deploy app lên Vercel, còn domain vẫn có thể trỏ về Vercel. File luôn nằm trên R2 nên không chiếm dung lượng hosting.

## Cách 1: cPanel có Setup Node.js App

1. Giải nén source vào thư mục, ví dụ `~/groupvault`.
2. Mở Terminal của cPanel hoặc SSH:

```bash
cd ~/groupvault
npm install
npm run build
```

3. Mở **Setup Node.js App**:
   - Node.js version: 20 hoặc 22.
   - Application mode: Production.
   - Application root: `groupvault`.
   - Application URL: domain/subdomain mong muốn.
   - Application startup file: `server.cjs`.
4. Thêm các biến môi trường giống `.env.example`.
5. Đặt `NEXT_PUBLIC_APP_URL` thành URL HTTPS thật.
6. Bấm Restart Application.
7. Thêm domain này vào Supabase Redirect URLs và R2 AllowedOrigins.

Một số cPanel yêu cầu chạy `npm install` bằng nút **Run NPM Install** thay vì Terminal.

## Cách 2: Hosting/VPS có SSH và PM2

```bash
cd /home/USER/groupvault
cp .env.example .env.local
nano .env.local
npm install
npm run build
npm install -g pm2
pm2 start ecosystem.config.cjs
pm2 save
```

Reverse proxy Nginx về `127.0.0.1:3000` và bật HTTPS.

## Cách 3: Docker

```bash
docker build -t groupvault .
docker run -d \
  --name groupvault \
  --restart unless-stopped \
  --env-file .env.local \
  -p 3000:3000 \
  groupvault
```

## Biến môi trường

Phải có đủ:

```env
NEXT_PUBLIC_SUPABASE_URL=
NEXT_PUBLIC_SUPABASE_ANON_KEY=
SUPABASE_SERVICE_ROLE_KEY=
R2_ACCOUNT_ID=
R2_ACCESS_KEY_ID=
R2_SECRET_ACCESS_KEY=
R2_BUCKET=
NEXT_PUBLIC_APP_URL=https://files.tenmiencuaban.vn
MAX_FILE_SIZE_BYTES=5497558138880
SIMPLE_UPLOAD_LIMIT_BYTES=104857600
SIGNED_URL_TTL_SECONDS=900
```

## Lưu ý

- Node process không nhận nội dung file upload; nó chỉ tạo signed URL và lưu metadata.
- Vì vậy file lớn không phụ thuộc `upload_max_filesize` của PHP hoặc ổ đĩa hosting.
- Không bật proxy upload qua Cloudflare Worker/custom domain; trình duyệt phải PUT trực tiếp vào endpoint S3 của R2.
- Sau khi đổi biến `NEXT_PUBLIC_*`, phải build lại vì các biến này được nhúng vào frontend khi build.
