Deploys a built website artifact to a production and preview environment via SSH, with optional link checking.
- Downloads the specified artifact
- Deploys it via SSH/SCP to a production and preview directory
- Optionally runs a link checker (via Lychee)
- Can post/update sticky PR comments and GitHub step summaries (if enabled)
You can define which conditions have to be met in order to start a productive deployment. Preview deployments are made for all pull requests.
name: Preview and deploy Website
on:
# Pushes to your main branch, triggering
push:
branches: [main]
pull_request:
# 'closed' is required to trigger cleanup of preview deployments when a PR is closed/merged
types: [opened, reopened, synchronize, closed]
# Allows to run this workflow manually from the Actions tab
workflow_dispatch:
# Allow only one concurrent deployment per branch. However, do NOT cancel in-progress runs as we
# want to allow especially production deployments to complete.
concurrency:
group: pages-${{ github.ref_name }}
cancel-in-progress: false
# Set environment variables to reduce duplicated variables
env:
artifact_name: website
# Define permissions globally. The deploy job needs additional permissions depending on
# configuration, which are defined in the respective job.
permissions:
contents: read
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6 # consider pinning hash
# Insert here your website build process, below a boilerplate
- name: Build Website
run: |
mkdir -p dist && echo "<html>Hello</html>" > dist/index.html
# Artifact has to be uploaded. `name` has to be the action's input `artifact_name`
- uses: actions/upload-artifact@v7 # consider pinning hash
with:
name: ${{ env.artifact_name }}
path: dist
include-hidden-files: true
retention-days: 1
deploy:
name: Deploy website
needs: build
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: write # required unless you explicitly set sticky_comment_enabled: false
# deployments: write # required if gh_deployment is set
steps:
- uses: OpenRailAssociation/web-deployment-action@v1 # consider pinning hash
with:
artifact_name: ${{ env.artifact_name }}
condition_production: ${{ github.ref == 'refs/heads/main' }}
domain_production: example.com
domain_preview: preview.example.com
ssh_host: ssh.example.com
ssh_user: webmaster
ssh_key: ${{ secrets.SSH_PRIVATE_KEY }}
dir_base: /var/www/
dir_production: html
dir_preview_base: preview
dir_preview_subdir: pr-${{ github.event.number }}- A built website must be uploaded as an artifact in a previous job.
- A valid SSH Private Key must be provided via repository or organization secrets. SSH passwords are not supported.
GitHub does not expose repository secrets to workflows triggered by pull requests from forks. As a result, the SSH key required for deployment will be unavailable and all deployment steps are automatically skipped. A notice is emitted in the Actions log and an explanation is written to the step summary.
The link checker still runs on fork PRs — the artifact is downloaded and checked normally.
This behaviour is expected and is not a failure. To trigger a deployment for a fork PR, a maintainer can manually run the workflow via workflow_dispatch on the contributor's branch, or push the fork branch to the base repository so the normal triggers fire with secrets available.
| name | description | required | default |
|---|---|---|---|
artifact_name |
The name of the uploaded artifact to deploy. |
true |
"" |
condition_production |
Condition to deploy to production. E.g., compare |
true |
"" |
domain_production |
Domain name for the production deployment, e.g. https://example.com |
true |
"" |
domain_preview |
Domain name for the preview deployment, e.g. https://preview.example.com |
true |
"" |
dir_base |
Remote base directory (e.g. /var/www/virtual) |
true |
"" |
dir_production |
Full path for production deployment |
true |
"" |
dir_preview_base |
Preview base domain (e.g. preview) |
true |
"" |
dir_preview_subdir |
Preview subdir (e.g. pr-123) |
true |
"" |
ssh_host |
SSH hostname (e.g. webspace.example.org) |
true |
"" |
ssh_user |
SSH username |
true |
"" |
ssh_key |
SSH private key for authenticating with the deployment server |
true |
"" |
ssh_port |
SSH port |
false |
22 |
ssh_timeout |
SSH connection timeout (e.g. 1m) |
false |
1m |
ssh_command_timeout |
SSH command timeout (e.g. 2m) |
false |
2m |
ssh_rm |
Remove remote directory before deploying (true/false) |
false |
true |
ssh_strip_components |
How many path components to strip (for tar/scp unpacking) |
false |
1 |
linkchecker_enabled |
Enable link checker (true/false) |
false |
true |
linkchecker_exclude |
Comma-separated list of domains to exclude from link checker |
false |
"" |
linkchecker_include_fragments |
Include anchor fragments in link checking |
false |
true |
linkchecker_offline |
Only check local/relative links, do not fetch remote links (true/false) |
false |
false |
linkchecker_max_concurrency |
Max concurrent requests for link checker |
false |
1 |
linkchecker_user_agent |
User-Agent for link checking |
false |
Mozilla/5.0 (Windows NT 10.0; Win64; x64) Apple WebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36 |
linkchecker_retry_times |
Retry delay in seconds for link checking |
false |
5 |
linkchecker_fail_on_errors |
Fail workflow on link check errors (true/false) |
false |
false |
linkchecker_verbose |
Turn on verbose linkchecker logging in action logs (true/false) |
false |
false |
linkchecker_extra_args |
Extra arguments to pass to the link checker (e.g. --some-flag value) |
false |
"" |
sticky_comment_enabled |
Whether to enable sticky comments for the pull request. Defaults to true. |
false |
true |
step_summary_enabled |
Whether to enable step summaries in the GitHub Actions UI. Defaults to true. |
false |
true |
gh_deployment |
Name of the optional GitHub deployment to create. Requires the deployments permission. Defaults to empty, in which case no deployment is created. |
false |
"" |
| name | description |
|---|---|
url |
The URL of the deployed production or preview website |
This action is a composite action.
We welcome contributions to improve this action. Please read CONTRIBUTING.md for all information.
The content of this repository is licensed under the Apache 2.0 license.
There may be components under different, but compatible licenses or from different copyright holders. The project is REUSE compliant which makes these portions transparent. You will find all used licenses in the LICENSES directory.
The project has been started by the OpenRail Association. You are welcome to contribute!