> ## Documentation Index
> Fetch the complete documentation index at: https://kawax.biz/llms.txt
> Use this file to discover all available pages before exploring further.

# Laravel Octane

> FrankenPHP, Swoole, RoadRunner를 사용해 Laravel 애플리케이션을 고속화하기

## Octane이란

[Laravel Octane](https://github.com/laravel/octane)은 고성능 애플리케이션 서버를 사용해 Laravel 애플리케이션의 성능을 극적으로 향상시키는 패키지입니다.

일반적인 PHP-FPM에서는 요청이 있을 때마다 애플리케이션이 시작·종료됩니다. Octane에서는 애플리케이션을 한 번만 시작해 메모리에 보관하고, 이후 요청을 고속으로 처리합니다.

```mermaid theme={null}
sequenceDiagram
    participant Client
    participant Nginx
    participant Octane as Octane<br>(상주 프로세스)
    participant App as Laravel<br>앱
    Client->>Nginx: 요청
    Nginx->>Octane: 프록시
    Octane->>App: 요청 처리(메모리 내)
    App->>Nginx: 응답
    Nginx->>Client: 응답
```

PHP-FPM과의 가장 큰 차이는 애플리케이션의 부트 처리(서비스 프로바이더 등록 등)가 요청마다 반복되지 않는다는 점입니다. 한 번 시작하면 그 이후에는 초고속으로 요청을 처리할 수 있습니다.

## 지원 서버

Octane은 다음 세 가지 서버를 지원합니다.

```mermaid theme={null}
flowchart LR
    A["서버 선택"] --> B{"동시 태스크나<br>Swoole 기능이 필요?"}
    B -->|"Yes"| C["Swoole<br>(PECL 확장)"]
    B -->|"No"| D{"HTTP/3·Brotli<br>압축이 필요?"}
    D -->|"Yes"| E["FrankenPHP<br>(권장)"]
    D -->|"No"| F["RoadRunner<br>(Go 바이너리)"]
```

| 서버         | 언어     | 설치       | 동시 태스크 | 비고                     |
| ---------- | ------ | -------- | ------ | ---------------------- |
| FrankenPHP | Go     | 자동(바이너리) | —      | 권장. HTTP/3·Brotli 지원   |
| RoadRunner | Go     | 자동(바이너리) | —      | 심플하고 설정이 용이함           |
| Swoole     | PHP 확장 | PECL로 수동 | ✅      | 동시 태스크·Octane 캐시 사용 가능 |

<Info>
  Laravel Cloud에서는 FrankenPHP를 사용한 Octane 운영이 권장되며, 완전 관리형으로 지원됩니다.
</Info>

## 설치 및 설정

### 패키지 설치

```bash theme={null}
composer require laravel/octane
```

### Octane 초기 설정

```bash theme={null}
php artisan octane:install
```

실행하면 서버를 선택하는 프롬프트가 표시됩니다. 선택하면 `config/octane.php`가 생성됩니다.

### FrankenPHP

FrankenPHP를 선택하면 Octane이 자동으로 바이너리를 다운로드합니다. 추가 절차는 필요 없습니다.

### RoadRunner

RoadRunner를 선택하면 Octane이 자동으로 바이너리를 다운로드합니다.

### Swoole

Swoole은 PHP 확장으로 PECL을 통해 설치합니다.

```bash theme={null}
pecl install swoole
```

Open Swoole을 사용하는 경우 다음 명령으로 설치합니다.

```bash theme={null}
pecl install openswoole
```

## 실행 방법

### 서버 실행

```bash theme={null}
php artisan octane:start
```

기본적으로 포트 `8000`으로 실행됩니다. `http://localhost:8000`에서 접근할 수 있습니다.

### 서버 지정

```bash theme={null}
php artisan octane:start --server=frankenphp
php artisan octane:start --server=roadrunner
php artisan octane:start --server=swoole
```

### 워커 수 지정

```bash theme={null}
php artisan octane:start --workers=4
```

Swoole에서 태스크 워커도 지정하는 경우는 다음과 같습니다.

```bash theme={null}
php artisan octane:start --workers=4 --task-workers=6
```

### 파일 변경 감시

개발 중에는 파일을 변경해도 서버를 재시작하지 않으면 반영되지 않습니다. `--watch` 플래그를 사용하면 자동으로 재시작합니다.

```bash theme={null}
php artisan octane:start --watch
```

<Warning>
  `--watch`를 사용하려면 [Node.js](https://nodejs.org)와 Chokidar가 필요합니다.

  ```bash theme={null}
  npm install --save-dev chokidar
  ```
</Warning>

### 기타 관리 명령

```bash theme={null}
# 워커 리로드(배포 후 실행)
php artisan octane:reload

# 서버 정지
php artisan octane:stop

# 서버 상태 확인
php artisan octane:status
```

## 의존성 주입의 주의점

Octane에서는 애플리케이션이 메모리에 보관되기 때문에, **서비스 프로바이더의 `register`나 `boot`는 서버 시작 시 한 번만 실행됩니다**. 같은 애플리케이션 인스턴스가 요청 간에 재사용되므로 컨테이너나 리퀘스트를 객체 생성자에 주입할 때는 주의가 필요합니다.

```mermaid theme={null}
flowchart LR
    A["서버 시작<br>(1회만)"] --> B["ServiceProvider<br>register / boot"]
    B --> C["애플리케이션<br>인스턴스(메모리)"]
    C --> D["요청 1"]
    C --> E["요청 2"]
    C --> F["요청 3..."]
```

### 컨테이너 주입

싱글턴 생성자에 컨테이너를 직접 주입하면 오래된 컨테이너가 재사용됩니다.

```php theme={null}
// ❌ 문제가 있는 예 — 오래된 컨테이너가 재사용됨
$this->app->singleton(Service::class, function (Application $app) {
    return new Service($app);
});

// ✅ 안전한 예 — 클로저로 매번 최신 컨테이너를 취득
$this->app->singleton(Service::class, function () {
    return new Service(fn () => Container::getInstance());
});
```

전역 헬퍼 `app()`과 `Container::getInstance()`는 항상 최신 컨테이너를 반환하므로 안전합니다.

### 요청 주입

```php theme={null}
// ❌ 문제가 있는 예 — 오래된 요청이 재사용됨
$this->app->singleton(Service::class, function (Application $app) {
    return new Service($app['request']);
});

// ✅ 안전한 예 — 클로저로 매번 최신 요청을 취득
$this->app->singleton(Service::class, function (Application $app) {
    return new Service(fn () => $app['request']);
});

// ✅ 가장 권장 — 필요한 값만 메서드에 전달
$service->method($request->input('name'));
```

<Info>
  컨트롤러 메서드나 라우트 클로저에서 `Illuminate\Http\Request`를 타입힌트하는 것은 안전합니다. 전역 헬퍼 `request()`도 항상 현재 요청을 반환합니다.
</Info>

### 설정 리포지토리 주입

```php theme={null}
// ❌ 문제가 있는 예 — 설정 값이 바뀌어도 오래된 리포지토리가 사용됨
$this->app->singleton(Service::class, function (Application $app) {
    return new Service($app->make('config'));
});

// ✅ 안전한 예
$this->app->singleton(Service::class, function () {
    return new Service(fn () => Container::getInstance()->make('config'));
});
```

전역 헬퍼 `config()`는 항상 최신 설정 리포지토리를 반환하므로 안전합니다.

## 메모리 누수 대책

Octane은 애플리케이션을 메모리에 보관하므로 정적 프로퍼티 등에 데이터를 축적하면 메모리 누수가 발생합니다.

```php theme={null}
// ❌ 메모리 누수 예 — 요청마다 $data가 계속 증가
class Service
{
    public static array $data = [];
}

public function index(Request $request): array
{
    Service::$data[] = Str::random(10);
    return [];
}
```

### max-requests로 워커 재활용

워커가 일정 수의 요청을 처리하면 자동으로 재시작하도록 해서 메모리 누수를 완화할 수 있습니다. 기본값은 500 요청입니다.

```bash theme={null}
php artisan octane:start --max-requests=250
```

### 최대 실행 시간 설정

`config/octane.php`에서 요청의 최대 실행 시간을 설정할 수 있습니다. 기본값은 30초입니다.

```php theme={null}
'max_execution_time' => 30,
```

<Warning>
  `max_execution_time`을 변경한 경우 Octane 서버를 재시작하세요.
</Warning>

## 동시 태스크(Swoole 전용)

Swoole을 사용하는 경우 `Octane::concurrently()`로 여러 처리를 동시에 실행할 수 있습니다.

```php theme={null}
use App\Models\User;
use App\Models\Server;
use Laravel\Octane\Facades\Octane;

[$users, $servers] = Octane::concurrently([
    fn () => User::all(),
    fn () => Server::all(),
]);
```

동시 태스크는 Swoole의 "태스크 워커"로서 별도 프로세스에서 실행됩니다. 태스크 워커 수는 `--task-workers`로 지정합니다.

```bash theme={null}
php artisan octane:start --workers=4 --task-workers=6
```

<Warning>
  `concurrently`에 전달할 수 있는 태스크는 최대 1024개입니다(Swoole 제한).
</Warning>

## Tick과 Interval(Swoole 전용)

Swoole에서는 지정한 간격으로 정기 실행하는 처리를 등록할 수 있습니다. 서비스 프로바이더의 `boot` 메서드에서 등록합니다.

```php theme={null}
use Laravel\Octane\Facades\Octane;

// 10초마다 실행
Octane::tick('delayed-ticker', fn () => ray('Ticking...'))
    ->seconds(10);

// 서버 시작 직후에도 즉시 실행
Octane::tick('immediate-ticker', fn () => ray('Ticking...'))
    ->seconds(10)
    ->immediate();
```

## Octane 캐시(Swoole 전용)

Swoole의 [Swoole 테이블](https://www.swoole.co.uk/docs/modules/swoole-table)을 사용한 초고속 인메모리 캐시입니다. 초당 최대 200만 회의 읽기·쓰기가 가능합니다.

```php theme={null}
use Illuminate\Support\Facades\Cache;

Cache::store('octane')->put('framework', 'Laravel', 30);
```

### 인터벌 캐시

지정한 간격으로 자동 갱신되는 캐시입니다.

```php theme={null}
use Illuminate\Support\Str;

Cache::store('octane')->interval('random', function () {
    return Str::random(10);
}, seconds: 5);
```

<Warning>
  Octane 캐시의 데이터는 서버를 재시작하면 모두 사라집니다.
</Warning>

## Swoole 테이블(Swoole 전용)

모든 워커에서 접근 가능한 임의의 인메모리 테이블을 정의할 수 있습니다. `config/octane.php`의 `tables`에서 설정합니다.

```php theme={null}
'tables' => [
    'example:1000' => [
        'name' => 'string:1000',
        'votes' => 'int',
    ],
],
```

테이블에 접근하려면 `Octane::table()` 메서드를 사용합니다.

```php theme={null}
use Laravel\Octane\Facades\Octane;

Octane::table('example')->set('uuid', [
    'name' => 'Nuno Maduro',
    'votes' => 1000,
]);

$row = Octane::table('example')->get('uuid');
```

<Warning>
  Swoole 테이블에서 사용할 수 있는 컬럼 타입은 `string`, `int`, `float`뿐입니다. 데이터는 서버 재시작으로 사라집니다.
</Warning>

## 프로덕션 환경에서의 운영

### Nginx + Octane 구성

프로덕션 환경에서는 Nginx 뒤에서 Octane을 구동하는 것이 일반적입니다. Nginx가 정적 파일 전송과 SSL 종단을 담당하고, 동적 요청을 Octane에 프록시합니다.

```nginx theme={null}
map $http_upgrade $connection_upgrade {
    default upgrade;
    ''      close;
}

server {
    listen 80;
    server_name example.com;
    root /home/forge/example.com/public;

    location /index.php {
        try_files /not_exists @octane;
    }

    location / {
        try_files $uri $uri/ @octane;
    }

    location @octane {
        set $suffix "";

        if ($uri = /index.php) {
            set $suffix ?$query_string;
        }

        proxy_http_version 1.1;
        proxy_set_header Host $http_host;
        proxy_set_header Scheme $scheme;
        proxy_set_header SERVER_PORT $server_port;
        proxy_set_header REMOTE_ADDR $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection $connection_upgrade;

        proxy_pass http://127.0.0.1:8000$suffix;
    }
}
```

### Supervisor로 상주시키기

프로덕션 환경에서는 Supervisor를 사용해 Octane을 상시 실행 상태로 둡니다.

```ini theme={null}
[program:octane]
process_name=%(program_name)s_%(process_num)02d
command=php /home/forge/example.com/artisan octane:start --server=frankenphp --host=127.0.0.1 --port=8000
autostart=true
autorestart=true
user=forge
redirect_stderr=true
stdout_logfile=/home/forge/example.com/storage/logs/octane.log
stopwaitsecs=3600
```

### HTTPS 활성화

Octane 경유로 HTTPS 링크를 생성하려면 `.env`에 다음을 설정합니다.

```ini theme={null}
OCTANE_HTTPS=true
```

### Laravel Cloud와의 연동

[Laravel Cloud](https://cloud.laravel.com)에서는 FrankenPHP를 사용한 Octane을 완전 관리형으로 지원합니다. Nginx나 Supervisor 설정은 불필요하며, 단 2단계로 Octane을 활성화할 수 있습니다.

<Steps>
  <Step title="패키지 설치">
    Octane을 설치합니다. `octane:install` 명령은 실행해도 상관없지만 필수는 아닙니다.

    ```bash theme={null}
    composer require laravel/octane
    ```
  </Step>

  <Step title="Laravel Cloud에서 Octane 활성화">
    환경의 App 컴퓨트 클러스터 설정을 열고, **"Use Octane as runtime"** 를 켠 뒤 저장·배포합니다. Laravel Cloud가 자동으로 FrankenPHP + Octane으로 애플리케이션을 빌드·기동합니다.
  </Step>
</Steps>

자세한 내용은 [Laravel Cloud 문서](https://cloud.laravel.com/docs/compute#laravel-octane)를 참고하세요.

### 배포 후 워커 리로드

배포 후에는 새 코드를 메모리에 읽어들이기 위해 워커를 리로드합니다.

```bash theme={null}
php artisan octane:reload
```


## Related topics

- [Laravel Cloud — Laravel 전용 PaaS의 전모](/ko/blog/laravel-cloud.md)
- [Laravel에서 MCP 서버 만들기](/ko/advanced/mcp-server.md)
- [배포](/ko/deployment.md)
- [Laravel Telescope](/ko/telescope.md)
- [Laravel Bluesky](/ko/packages/laravel-bluesky/index.md)
