Compare commits
8 Commits
60813e44d9
...
feat/initi
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ca2a725953 | ||
|
|
fdb0411c35 | ||
|
|
461b5e0cd6 | ||
|
|
0d743402ac | ||
|
|
28fcaf16c5 | ||
|
|
e3fbbbada7 | ||
|
|
cb21be71f0 | ||
|
|
5417565e34 |
@@ -1,10 +1,14 @@
|
|||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
# cameleer-website — Deploy to Hetzner Webhosting L
|
# cameleer-website — Deploy to Hetzner Webhosting L
|
||||||
#
|
#
|
||||||
# Runs ONLY on pushes to `main` and on manual dispatch from the Gitea UI.
|
# MANUAL TRIGGER ONLY. Runs exclusively on workflow_dispatch from the Gitea UI
|
||||||
# Does NOT run Lighthouse CI (that's in ci.yml — assume any commit that reached
|
# (Actions → deploy → Run workflow). Does NOT auto-deploy on push to main —
|
||||||
# main already passed the full gate). Rebuilds fresh, runs the TBD guard, and
|
# merges to main must be explicitly promoted to production.
|
||||||
# rsyncs `dist/` to the origin over SSH with host-key pinning.
|
#
|
||||||
|
# Build and deploy run in a single job so the built dist/ (including
|
||||||
|
# dotfiles like .htaccess) flows directly into rsync. An earlier split-job
|
||||||
|
# design was abandoned because actions/upload-artifact@v3 excludes dotfiles
|
||||||
|
# by default and the v4 client does not work on Gitea Actions / GHES.
|
||||||
#
|
#
|
||||||
# Runner: self-hosted arm64 Gitea runner. Adjust `runs-on` if your runner's
|
# Runner: self-hosted arm64 Gitea runner. Adjust `runs-on` if your runner's
|
||||||
# labels differ. Deploy target is Hetzner amd64 — arch mismatch is a non-issue
|
# labels differ. Deploy target is Hetzner amd64 — arch mismatch is a non-issue
|
||||||
@@ -12,15 +16,12 @@
|
|||||||
#
|
#
|
||||||
# Required secrets (repo settings → Actions → Secrets):
|
# Required secrets (repo settings → Actions → Secrets):
|
||||||
# SFTP_HOST, SFTP_USER, SFTP_PATH, SFTP_KEY, SFTP_KNOWN_HOSTS
|
# SFTP_HOST, SFTP_USER, SFTP_PATH, SFTP_KEY, SFTP_KNOWN_HOSTS
|
||||||
# Required variables (repo settings → Actions → Variables):
|
|
||||||
# PUBLIC_AUTH_SIGNIN_URL, PUBLIC_AUTH_SIGNUP_URL, PUBLIC_SALES_EMAIL
|
# PUBLIC_AUTH_SIGNIN_URL, PUBLIC_AUTH_SIGNUP_URL, PUBLIC_SALES_EMAIL
|
||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
|
|
||||||
name: deploy
|
name: deploy
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
|
||||||
branches: [main]
|
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
concurrency:
|
concurrency:
|
||||||
@@ -28,9 +29,9 @@ concurrency:
|
|||||||
cancel-in-progress: false
|
cancel-in-progress: false
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
deploy:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
timeout-minutes: 15
|
timeout-minutes: 25
|
||||||
env:
|
env:
|
||||||
PUBLIC_AUTH_SIGNIN_URL: ${{ secrets.PUBLIC_AUTH_SIGNIN_URL }}
|
PUBLIC_AUTH_SIGNIN_URL: ${{ secrets.PUBLIC_AUTH_SIGNIN_URL }}
|
||||||
PUBLIC_AUTH_SIGNUP_URL: ${{ secrets.PUBLIC_AUTH_SIGNUP_URL }}
|
PUBLIC_AUTH_SIGNUP_URL: ${{ secrets.PUBLIC_AUTH_SIGNUP_URL }}
|
||||||
@@ -53,6 +54,15 @@ jobs:
|
|||||||
- name: Build site
|
- name: Build site
|
||||||
run: npm run build
|
run: npm run build
|
||||||
|
|
||||||
|
# Astro/Vite does not copy dotfiles from public/ into dist/, so .htaccess
|
||||||
|
# never reaches the deployed origin and Apache never sees the security
|
||||||
|
# headers it sets. Copy it explicitly. Fail if the source is missing
|
||||||
|
# rather than silently shipping a header-less site.
|
||||||
|
- name: Copy .htaccess into dist
|
||||||
|
run: |
|
||||||
|
test -f public/.htaccess
|
||||||
|
cp public/.htaccess dist/.htaccess
|
||||||
|
|
||||||
- name: Guard — no TBD markers may ship in built HTML
|
- name: Guard — no TBD markers may ship in built HTML
|
||||||
run: |
|
run: |
|
||||||
if grep -rlE '(TBD):' dist 2>/dev/null | grep -E '\.(html|svg)$'; then
|
if grep -rlE '(TBD):' dist 2>/dev/null | grep -E '\.(html|svg)$'; then
|
||||||
@@ -61,28 +71,6 @@ jobs:
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Pin to v3 — Gitea Actions implements the v3 artifact protocol.
|
|
||||||
# upload/download-artifact@v4 talk to a github.com-only backend and
|
|
||||||
# fail with GHESNotSupportedError on Gitea / Forgejo / GHES.
|
|
||||||
- name: Upload dist artifact
|
|
||||||
uses: actions/upload-artifact@v3
|
|
||||||
with:
|
|
||||||
name: dist
|
|
||||||
path: dist/
|
|
||||||
retention-days: 7
|
|
||||||
|
|
||||||
deploy:
|
|
||||||
needs: build
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
timeout-minutes: 10
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Download dist artifact
|
|
||||||
uses: actions/download-artifact@v3
|
|
||||||
with:
|
|
||||||
name: dist
|
|
||||||
path: dist/
|
|
||||||
|
|
||||||
- name: Configure SSH
|
- name: Configure SSH
|
||||||
env:
|
env:
|
||||||
SFTP_KEY: ${{ secrets.SFTP_KEY }}
|
SFTP_KEY: ${{ secrets.SFTP_KEY }}
|
||||||
@@ -96,35 +84,33 @@ jobs:
|
|||||||
chmod 600 ~/.ssh/id_ed25519
|
chmod 600 ~/.ssh/id_ed25519
|
||||||
printf '%s\n' "$SFTP_KNOWN_HOSTS" > ~/.ssh/known_hosts
|
printf '%s\n' "$SFTP_KNOWN_HOSTS" > ~/.ssh/known_hosts
|
||||||
chmod 644 ~/.ssh/known_hosts
|
chmod 644 ~/.ssh/known_hosts
|
||||||
# Hetzner Webhosting accounts are SFTP-only — they accept SSH for file
|
# Ensure rsync + openssh are present even on a minimal runner image.
|
||||||
# transfer but refuse remote command exec ("exec request failed on
|
if ! command -v rsync >/dev/null 2>&1 || ! command -v ssh >/dev/null 2>&1; then
|
||||||
# channel 0"). rsync over SSH needs to spawn a remote rsync binary,
|
|
||||||
# so it cannot work here. Use lftp's mirror instead, which speaks
|
|
||||||
# SFTP end-to-end with the same key + known_hosts pinning.
|
|
||||||
if ! command -v lftp >/dev/null 2>&1 || ! command -v ssh >/dev/null 2>&1; then
|
|
||||||
if command -v sudo >/dev/null 2>&1; then SUDO=sudo; else SUDO=; fi
|
if command -v sudo >/dev/null 2>&1; then SUDO=sudo; else SUDO=; fi
|
||||||
$SUDO apt-get update -qq
|
$SUDO apt-get update -qq
|
||||||
$SUDO apt-get install -y --no-install-recommends lftp openssh-client
|
$SUDO apt-get install -y --no-install-recommends rsync openssh-client
|
||||||
fi
|
fi
|
||||||
|
|
||||||
- name: Deploy via lftp (mirror over SFTP)
|
- name: Deploy via rsync
|
||||||
env:
|
env:
|
||||||
SFTP_USER: ${{ secrets.SFTP_USER }}
|
SFTP_USER: ${{ secrets.SFTP_USER }}
|
||||||
SFTP_HOST: ${{ secrets.SFTP_HOST }}
|
SFTP_HOST: ${{ secrets.SFTP_HOST }}
|
||||||
SFTP_PATH: ${{ secrets.SFTP_PATH }}
|
SFTP_PATH: ${{ secrets.SFTP_PATH }}
|
||||||
run: |
|
run: |
|
||||||
# Fail loudly if any secret is missing — otherwise mirror --delete
|
# Fail loudly if any secret is missing — otherwise rsync --delete
|
||||||
# could be directed at the SSH user's home root.
|
# could be directed at the SSH user's home root.
|
||||||
: "${SFTP_USER:?SFTP_USER secret must be set}"
|
: "${SFTP_USER:?SFTP_USER secret must be set}"
|
||||||
: "${SFTP_HOST:?SFTP_HOST secret must be set}"
|
: "${SFTP_HOST:?SFTP_HOST secret must be set}"
|
||||||
: "${SFTP_PATH:?SFTP_PATH secret must be set}"
|
: "${SFTP_PATH:?SFTP_PATH secret must be set}"
|
||||||
lftp <<LFTP
|
# Hetzner Webhosting splits SSH into two ports:
|
||||||
set cmd:fail-exit yes
|
# port 22 — SFTP only, no remote command exec
|
||||||
set sftp:connect-program 'ssh -a -x -i $HOME/.ssh/id_ed25519 -o StrictHostKeyChecking=yes -o UserKnownHostsFile=$HOME/.ssh/known_hosts'
|
# port 222 — full SSH with shell exec (rsync needs this)
|
||||||
open sftp://$SFTP_USER@$SFTP_HOST
|
# `--rsync-path=/usr/bin/rsync` tells the local rsync where to find
|
||||||
mirror --reverse --delete --verbose --parallel=4 dist/ $SFTP_PATH/
|
# the remote binary on Hetzner's locked-down PATH.
|
||||||
bye
|
# `BatchMode=yes` disables interactive prompts.
|
||||||
LFTP
|
rsync -avz --delete --rsync-path=/usr/bin/rsync \
|
||||||
|
-e "ssh -p 222 -i $HOME/.ssh/id_ed25519 -o BatchMode=yes -o StrictHostKeyChecking=yes -o UserKnownHostsFile=$HOME/.ssh/known_hosts" \
|
||||||
|
dist/ "$SFTP_USER@$SFTP_HOST:$SFTP_PATH/"
|
||||||
|
|
||||||
- name: Post-deploy smoke test
|
- name: Post-deploy smoke test
|
||||||
run: |
|
run: |
|
||||||
|
|||||||
Reference in New Issue
Block a user