Deploy static site previews via ssh.
Please note that this is in no way a secure solution for hosting static site previews.
-
You should only use this in repositories you DO trust.
-
You should only use this on a server
- you DO NOT care about.
- where you DO NOT have sensitive information stored.
- where you DO NOT run other sensitive services.
-
Unless you jail the specific ssh user, you are allowing a GitHub Action full ssh access to your server.
-
You allow any other repository with access to the same preview server to overwrite each other's previews.
(Though this should not happen under normal circumstances, as the GitHub Action uses a hash of repository name + pull request number)
name: preview
on: [pull_request]
jobs:
deploy:
runs-on: ubuntu-latest
permissions:
pull-requests: write # needed for preview pull request comment
actions: read
# Deploy to the preview environment
environment:
name: preview-${{ github.event.number }}
url: ${{ steps.deploy-preview.outputs.url }}
steps:
- uses: actions/download-artifact@v4
with:
path: ./dist
- name: deploy preview
id: deploy-preview
uses: dafnik/ssp@v1
# with:
# source: dist/*
# target: /var/www/preview
# host: preview.yxz.abc
# port: 22
# username: ubuntu
# key: ${{ secrets.PREVIEW_SSH_PRIVATE_KEY }}
# strip_components: 0
# delete_threshold_days: 30
Inputs | Default value | Required | Description |
---|---|---|---|
source |
x | Path to the files which should be deployed | |
target |
x | Preview server target path, must be a directory path. | |
host |
x | Preview server domain | |
port |
22 |
Preview server ssh port | |
username |
x | Preview server ssh username | |
key |
x | Preview server ssh key content of private key. ex raw content of ~/.ssh/id_rsa | |
strip_components |
0 |
remove the specified number of leading path elements | |
delete_threshold_days |
30 |
Number of days after inactive previews are deleted |
Furthermore, see action.yml
Previews are stored in the /var/www/preview
directory by default.
# /etc/nginx/site-enabled/preview
server {
listen 80;
server_name *.preview.xyz.abc;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
server_name ~^(?P<sub>.+)\.preview\.xyz\.abc$;
ssl_certificate /etc/letsencrypt/live/preview.xyz.abc/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/preview.xyz.abc/privkey.pem;
# GZIP
gzip on;
gzip_disable "msie6";
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_buffers 16 8k;
gzip_http_version 1.1;
gzip_min_length 256;
gzip_types text/xml text/javascript font/ttf font/eot font/otf application/rdf+xml application/x-javascript application/atom+xml application/javascript application/json application/ld+json application/manifest+json application/rss+xml application/vnd.geo+json application/vnd.ms-fontobject application/x-font-ttf application/x-web-app-manifest+json application/xhtml+xml application/xml font/opentype image/bmp image/svg+xml image/x-icon text/cache-manifest text/css text/plain text/vcard text/vnd.rim.location.xloc text/vtt text/x-component text/x-cross-domain-policy;
# Remove X-Powered-By, which is an information leak
fastcgi_hide_header X-Powered-By;
# Do not send nginx server header
server_tokens off;
add_header Access-Control-Allow-Origin *;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
add_header Referrer-Policy "strict-origin" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header X-Content-Type-Options "nosniff" always;
access_log on;
error_log off;
root /var/www/preview/$sub;
location / {
# Check if the root directory exists
if (!-d $document_root) {
return 404;
}
try_files $uri $uri/ /index.html;
index index.html;
}
}
Delete previews with no activity in the last 30 days.
# /home/ubuntu/cronDeleteUnusedPreviews.sh
# Define the directory to search in. Modify this variable to suit your needs.
SEARCH_DIR="/var/www/preview"
# Find and delete directories not modified in the last 30 days.
find "$SEARCH_DIR" -type d -mtime +30 -exec rm -rf {} +
# Explanation:
# - `find "$SEARCH_DIR"`: Start searching in the specified directory.
# - `-type d`: Only look for directories.
# - `-mtime +30`: Find directories that were last modified more than 30 days ago.
# - `-exec rm -rf {} +`: Delete each directory found ({} is replaced by the found directory name).
Crontab example:
@daily /home/ubuntu/cronDeleteUnusedPreviews.sh
In order to release a new version of this action:
-
Locate the semantic version of the upcoming release (a draft is maintained by the
draft-release
workflow). -
Publish the draft release from the
main
branch with semantic version as the tag name, with the checkbox to publish to the GitHub Marketplace checked. ☑️ -
After publishing the release, the
release
workflow will automatically run to create/update the corresponding the major version tag such asv0
.⚠️ Environment approval is required. Check the Release workflow run list.
The scripts and documentation in this project are released under the MIT License.