# 배포

이 문서는 절차입니다. DNS와 인증서를 이미 발급했다는 뜻이 아닙니다. 서버 IP는 여기에 적지 않습니다. 실제 주소는 호스팅 화면에서 확인하세요.

공식 호스트는 `vibepeer.app`입니다. `.app` 레지스트리는 HTTPS만 허용하므로 인증서 없이 열리지 않습니다.

## DNS

도메인 등록기관에서 다음만 만듭니다.

| 호스트 | 용도 |
| --- | --- |
| `@` | 웹 서버의 A 또는 AAAA. 값은 서버 제공 화면의 주소 |
| `www` | `@`와 같은 주소, 또는 서버가 안내하는 CNAME |

애플리케이션은 `www.vibepeer.app`를 `https://vibepeer.app`으로 308 리다이렉트합니다. 메일 인증(SPF, DKIM, DMARC)은 메일 업체 안내를 따른 뒤에만 추가하세요. 이 저장소를 기준으로 그 레코드가 검증되지는 않았습니다.

## 공통 환경

서버에는 PHP와 MariaDB가 이미 있다고 가정합니다. 데이터베이스 이름과 비밀번호는 배포 패키지에 넣지 않습니다. 파일을 올린 뒤 서버의 `.env`만 수정합니다.

1. 코드를 올리고 의존성을 설치합니다. 이 단계에서는 마이그레이션과 `config:cache`를 하지 않습니다.

```bash
composer install --no-dev --optimize-autoloader
npm ci && npm run build
cp .env.production.example .env
php artisan key:generate
```

2. 호스팅 패널에서 MariaDB 데이터베이스와 사용자를 확인합니다. 없는 경우에만 패널에서 새로 만듭니다. 앱이 데이터베이스 서버 자체를 설치하지는 않습니다.
3. 서버의 `.env`에 패널에 표시된 값을 넣습니다.

```bash
DB_CONNECTION=mariadb
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=
DB_USERNAME=
DB_PASSWORD=
```

cPanel처럼 소켓으로 붙는 환경은 `DB_HOST=localhost`로 바꾸고, 패널이 안내하면 `DB_SOCKET`도 채웁니다. 데이터베이스 이름에 계정 접두사가 있으면 그 전체 이름을 사용합니다.

4. 연결을 확인한 뒤 스키마를 만듭니다.

```bash
php artisan config:clear
php artisan vibepeer:install --check
php artisan vibepeer:install
php artisan vibepeer:make-admin ops@vibepeer.app
php artisan config:cache
php artisan route:cache
php artisan view:cache
```

`vibepeer:install`은 카테고리와 법률 초안만 넣습니다. `DevSeeder`는 운영에서 거부됩니다. `.env`를 나중에 고치면 `php artisan config:clear` 후 다시 `config:cache`를 실행합니다. 연결 전에는 사이트에 데이터베이스 설정 안내가 표시됩니다.

나머지 운영 값:

```bash
APP_ENV=production
APP_DEBUG=false
APP_URL=https://vibepeer.app
APP_TIMEZONE=Asia/Seoul
APP_LOCALE=ko
VIBEPEER_ORIGIN=https://vibepeer.app
SESSION_SECURE_COOKIE=true
SESSION_DOMAIN=
SECURITY_HSTS=false
TRUSTED_PROXIES=127.0.0.1
```

`SECURITY_HSTS`는 브라우저에서 `https://vibepeer.app`이 잠금 아이콘으로 열린 뒤에만 `true`로 바꿉니다. 그 전에 켜면 HTTP로 복구하기 어렵습니다.

큐는 `database` 또는 Redis. 크론:

```bash
* * * * * cd /path/to/vibepeer && php artisan schedule:run >> /dev/null 2>&1
```

워커는 `php artisan queue:work --sleep=1 --tries=3`. `storage`와 `bootstrap/cache`는 웹 사용자가 쓸 수 있어야 합니다. `storage/app/evidence`는 웹 루트 밖에 두거나 직접 접근을 막습니다.

## cPanel과 Apache

1. 계정 문서 루트를 `public`으로 지정합니다. 프로젝트 전체를 문서 루트에 두지 않습니다.
2. PHP 8.3 이상. `pdo_mysql` 또는 MariaDB, `gd`, `mbstring`, `openssl`, `tokenizer`, `xml`, `ctype`, `fileinfo`.
3. AutoSSL 또는 Let's Encrypt로 `vibepeer.app`과 `www.vibepeer.app` 인증서를 발급합니다.
4. HTTPS 강제 리다이렉트는 앱이 `vibepeer.app` 호스트에서 처리합니다. 패널에서 한 번 더 걸어도 됩니다.
5. 크론과 큐는 위의 명령을 사용합니다.

## VPS와 Nginx

서버 주소는 제공자의 할당 값을 씁니다. 아래 `server_name`만 고정입니다.

```nginx
server {
    listen 80;
    listen [::]:80;
    server_name vibepeer.app www.vibepeer.app;
    return 308 https://vibepeer.app$request_uri;
}

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name www.vibepeer.app;
    # ssl_certificate 경로는 발급 도구가 알려 주는 경로
    return 308 https://vibepeer.app$request_uri;
}

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name vibepeer.app;
    root /var/www/vibepeer/public;
    index index.php;
    client_max_body_size 12m;

    add_header X-Content-Type-Options nosniff always;
    add_header Referrer-Policy strict-origin-when-cross-origin always;

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    location ^~ /storage/app/evidence {
        deny all;
    }

    location ~ \.php$ {
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
        fastcgi_pass unix:/run/php/php8.4-fpm.sock;
    }
}
```

인증서 파일 경로는 certbot 또는 패널이 출력하는 값을 넣습니다. 프록시를 쓰면 `TRUSTED_PROXIES`를 그 프록시 주소로 좁히고 `X-Forwarded-Proto`를 넘깁니다.

데이터베이스는 MariaDB 11을 권장합니다. 로컬 개발은 SQLite로 충분합니다.
