A GitHub Action that automates site provisioning, configuration, and deployment on Laravel Forge using a declarative YAML configuration file.
Create a workflow file at .github/workflows/deploy.yml:
name: Deploy to Forge
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: the-trybe/deploy-to-laravel-forge@v2
with:
forge_api_token: ${{ secrets.FORGE_API_TOKEN }}
secrets: |
APP_KEY=${{ secrets.APP_KEY }}Create a forge-deploy.yml file in your repository root:
organization: "your-forge-organization"
server: "production-server"
github_repository: "username/repository"
sites:
- name: "example"
domain_mode: "on-forge" # Creates example.on-forge.com
project_type: "laravel"
php_version: "php84"
deployment_script: |
composer install --no-dev
php artisan migrate --force
environment: |
APP_ENV=production
APP_KEY=${{ secrets.APP_KEY }}| Input | Required | Default | Description |
|---|---|---|---|
forge_api_token |
Yes | - | Laravel Forge API token |
deployment_file |
No | forge-deploy.yml |
Path to deployment configuration file |
secrets |
No | - | Secret values to replace in config (format: KEY=value) |
debug |
No | false |
Enable verbose logging |
# Required: Forge organization name
organization: "string"
# Required: Forge server name
server: "string"
# Required: GitHub repository (format: owner/repo)
github_repository: "string"
# Optional: Default branch to deploy (default: "main")
github_branch: "string"
# Required: List of sites to configure
sites:
- # Required: Site identifier (used to construct domain)
name: "string"
# Optional: Domain mode (default: "on-forge")
# "on-forge": Creates {name}.on-forge.com
# "custom": Uses {name} as the full domain
domain_mode: "on-forge|custom"
# Optional: WWW redirect behavior (default: "none")
# "from-www": Redirects www.domain to domain
# "to-www": Redirects domain to www.domain
# "none": No redirect
www_redirect_type: "from-www|to-www|none"
# Optional: Branch override for this site (default: uses global github_branch)
github_branch: "string"
# Optional: Directory containing the application root (default: ".")
root_dir: "string"
# Optional: Public web directory relative to root_dir (default: "public")
web_dir: "string"
# Optional: Project type (default: "laravel")
project_type: "laravel|other"
# Optional: PHP version (e.g., "php81", "php82", "php83", "php84")
# Installs version if not present on server
php_version: "string"
# Optional: Install Composer dependencies during site creation (default: false)
install_composer_dependencies: boolean
# Optional: Custom deployment script
# If omitted, uses Forge's default deployment script
deployment_script: |
# Your deployment commands
composer install --no-dev
php artisan migrate --force
# Optional: Background processes to run (default: [])
processes:
- name: "string" # Process name
command: "string" # Command to execute
# Optional: Enable Laravel scheduler (default: false)
# Creates cron job: {php_version} {root_dir}/artisan schedule:run
laravel_scheduler: boolean
# Optional: Environment variables from inline string
environment: |
KEY=value
ANOTHER_KEY=${{ secrets.SECRET_VAR }}
# Optional: Environment variables from file
# File path relative to repository root
# If both env_file and environment are set, environment takes precedence
env_file: "string"
# Optional: Additional domain aliases (default: [])
aliases:
- "www.example.com"
- "alias.example.com"
# Optional: Nginx template name from nginx_templates/ folder
# Built-in templates: reverse-proxy
nginx_template: "string"
# Optional: Variables to replace in nginx template (default: {})
# Use {{ VARIABLE_NAME }} in template file
nginx_template_variables:
KEY: "value"
# Optional: Path to custom nginx configuration file
# File path relative to repository root
# Overrides template if both are specified
nginx_custom_config: "string"
# Optional: Create SSL certificate for all non-.on-forge.com domains (default: false)
certificate: boolean
# Optional: Run site as isolated user (default: false)
isolated: boolean
# Optional: Isolated user name (required if isolated: true)
isolated_user: "string"
# Optional: Enable zero-downtime deployments (default: false)
zero_downtime_deployments: boolean
# Optional: Shared paths for zero-downtime deployments (default: [])
# Paths can be strings or objects with "from" and "to" keys
shared_paths:
- "storage" # Simple: links same path in shared and release
- from: "storage" # Explicit: custom source and destination
to: "public/storage"
# Optional: Clone repository during site creation (default: true)
# Set to false for manually deployed sites
clone_repository: booleanSecrets can be injected using ${{ secrets.NAME }} or ${{ env.NAME }} syntax in the deployment file.
Using GitHub Secrets:
# .github/workflows/deploy.yml
- uses: the-trybe/deploy-to-laravel-forge@v2
with:
forge_api_token: ${{ secrets.FORGE_API_TOKEN }}
secrets: |
DB_PASSWORD=${{ secrets.DB_PASSWORD }}
API_KEY=${{ secrets.API_KEY }}# forge-deploy.yml
environment: |
DB_PASSWORD=${{ secrets.DB_PASSWORD }}
API_KEY=${{ secrets.API_KEY }}Using Environment Variables:
# .github/workflows/deploy.yml
- name: Set environment variables
run: |
echo "APP_NAME=my-app-name" >> $GITHUB_ENV
echo "APP_DOMAIN=my-app-domain" >> $GITHUB_ENV
- uses: the-trybe/deploy-to-laravel-forge@v2
with:
forge_api_token: ${{ secrets.FORGE_API_TOKEN }}# forge-deploy.yml
environment: |
APP_NAME=${{ env.APP_NAME }}
APP_DOMAIN=${{ env.APP_DOMAIN }}Using HashiCorp Vault:
# .github/workflows/deploy.yml
- uses: hashicorp/vault-action@v2
with:
url: https://vault.example.com
path: jwt-github-actions
role: your-jwt-role
method: jwt
secrets: |
secrets/data/your-project/production/env *
- uses: the-trybe/deploy-to-laravel-forge@v2
with:
forge_api_token: ${{ env.FORGE_API_TOKEN }}
deployment_file: forge-deploy.ymlSee the HashiCorp Vault Action documentation for configuration details.
Nginx templates are loaded in the following order:
- Existing server templates: Templates already created in your Forge server
- Built-in community templates: Templates from the
nginx_templates/directory of this action (used if not found on server)
The action includes community-contributed templates that can be used directly. Current built-in templates:
reverse-proxy: Basic reverse proxy configuration for Node.js, Go, or other HTTP services
Templates support variable substitution using {{ VARIABLE_NAME }} syntax.
Example configuration:
nginx_template: "reverse-proxy"
nginx_template_variables:
PROXY_PORT: "3000"Example template content:
location / {
proxy_pass http://127.0.0.1:{{ PROXY_PORT }};
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}To use a custom template not available on your server:
- Add your template file to the
nginx_templates/directory in a fork of this action - Reference it by filename (without
.confextension) in your deployment file
Important: Avoid using Forge reserved variables in custom templates.
Enable zero-downtime deployments to minimize service interruption during updates. Forge creates a new release directory for each deployment and symlinks it to current after successful completion.
Configuration:
zero_downtime_deployments: true
shared_paths:
- "storage"
- "bootstrap/cache"
- from: ".env"
to: ".env"Important: The deployment_script must not include repository cloning commands when zero-downtime is enabled. The action automatically wraps your script with $CREATE_RELEASE() and $ACTIVATE_RELEASE() commands.
The action automatically installs PHP versions that don't exist on the server. Version format: php + major + minor (e.g., php81, php82, php84).
php_version: "php84"The action waits for installation to complete before proceeding with site creation.
Isolated sites run under a dedicated system user instead of the shared forge user. This provides process and filesystem isolation between sites.
isolated: true
isolated_user: "myappuser"The isolated_user is required when isolated is set to true.
Processes are managed by Supervisor. The action automatically restarts processes after deployment when a deployment_script is provided.
processes:
- name: "queue-worker"
command: "php artisan queue:work --tries=3"
- name: "websocket-server"
command: "php artisan websockets:serve"Deploy multiple sites to the same server by adding entries to the sites array. Each site is configured independently and can use different branches, PHP versions, and configurations.
sites:
- name: "production"
github_branch: "main"
php_version: "php84"
- name: "staging"
github_branch: "develop"
php_version: "php83"Some configuration examples are available in the examples/ directory.