VibeHost

Automated HTML Reports — Deploy to a Stable URL on a Schedule

Deploy cron-driven HTML reports to a permanent URL. Replace Notion, Google Sheets, or Tableau with a simple pipeline and a link that's always current.

The pattern: your data pipeline generates an HTML report (charts, tables, narrative). Deploy it to a stable VibeHost URL on a schedule. Stakeholders bookmark once; the URL always reflects the latest data.

In practice a growth team might run a fleet of date-stamped report apps (report-20260521-k7qz, report-20260520-a7k2, ...) alongside a couple of rolling apps (growth-daily, kpi-2026).

Two patterns

PatternURLUse when
Rolling — same URL, latest datahttps://growth-daily.vibehost.spaceStakeholders want a bookmark that's always current
Date-stamped — new app each dayhttps://gr-report-20260521.vibehost.spaceYou need historical snapshots and want each URL to be permanent

Rolling is simpler; date-stamped gives you a permanent "this was the state on day X" archive without relying on rollback.

Rolling pattern

Your pipeline produces report-output/index.html (plus assets) every morning; deploy that directory:

vibehost deploy ./report-output --app growth-daily

That's the whole thing. The bookmark https://growth-daily.vibehost.space always shows the latest deploy.

Wrap it in your cron / scheduler:

#!/usr/bin/env bash
# /opt/reports/daily-deploy.sh
set -euo pipefail

cd /opt/reports
export VIBEHOST_TOKEN="$(cat /run/secrets/vibehost_pat)"

# 1. Run the pipeline
python3 generate.py --date "$(date +%Y-%m-%d)" --out ./report-output

# 2. Deploy
vibehost deploy ./report-output --app growth-daily --json > /var/log/deploys/$(date +%F).json

# 3. Smoke check
URL="https://growth-daily.vibehost.space"
curl -fsS -o /dev/null "$URL"
echo "[$(date -u +%FT%TZ)] deployed: $URL" >> /var/log/deploys/history.log

systemd timer:

[Unit]
Description=Daily growth report deploy
[Timer]
OnCalendar=*-*-* 07:00:00
Persistent=true
[Install]
WantedBy=timers.target
[Unit]
Description=Daily growth report
[Service]
Type=oneshot
ExecStart=/opt/reports/daily-deploy.sh
User=reports
StandardOutput=journal
StandardError=journal

Date-stamped pattern

DATE=$(date +%Y%m%d)
APP="gr-report-$DATE"

vibehost app create "$APP"
vibehost deploy ./report-output --app "$APP"
vibehost app visibility "$APP" workspace

Each day = new app. URLs stay live indefinitely; you can reference "the report on May 21, 2026" forever by its URL.

Trade-offs:

  • ✓ Each historical snapshot has its own permanent URL.
  • ✓ Easy to A/B compare "today vs yesterday" by opening two tabs.
  • ✗ Apps accumulate. Free tier caps at 100 apps per workspace; you'll want to vibehost app delete old ones periodically (or move to the rolling pattern + use immutableUrl for archives).
  • ✗ The bookmark changes daily — stakeholders need a meta-page that lists "today's report" pointing at the latest.

Best of both — deploy to a rolling app for the always-current bookmark, capture the date-stamped immutable URL for archives, and log it to your wiki / sheet:

DEPLOY_RESP=$(vibehost deploy ./report-output --app growth-daily --json)
DEPLOY_ID=$(echo "$DEPLOY_RESP" | jq -r '.data.id')
IMMUTABLE_URL="https://${DEPLOY_ID}.vibehost.space"

echo "$(date -u +%F): $IMMUTABLE_URL" >> /opt/reports/archive-urls.tsv

Stakeholders bookmark growth-daily.vibehost.space. Anyone who wants to point at "the May 21 report specifically" links the immutable URL from your archive sheet. No per-day app proliferation.

CI variant

.github/workflows/daily-report.yml
name: Daily report
on:
  schedule:
    - cron: '0 7 * * *'   # 07:00 UTC daily
  workflow_dispatch:

jobs:
  report:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v6
      - uses: actions/setup-python@v6
        with: { python-version: '3.12' }
      - run: pip install -r requirements.txt
      - run: python generate.py --out ./report-output
      - run: curl -fsSL https://vibehost.com/install.sh | sh
      - env: { VIBEHOST_TOKEN: ${{ secrets.VIBEHOST_TOKEN }} }
        run: ~/.vibehost/bin/vibehost deploy ./report-output --app growth-daily

Pros over a self-hosted cron: no server to maintain; logs in GitHub Actions; can re-run any day on demand.

Cons: GitHub-hosted runners have data egress, so if your pipeline pulls 10GB of raw data daily, it's faster to run on a beefier self-hosted box.

Access control

Reports usually shouldn't be public. Make it workspace-only (everyone signed into your workspace can view), or invite specific stakeholders by email — including people outside your workspace, who sign in with Google:

vibehost app visibility growth-daily workspace

vibehost app grants add-email vp@acme.com viewer --app growth-daily

vibehost app grants add-email partner@vc.com viewer --app growth-daily

For external review without sign-up, use a share link.

Why not Notion / Sheets / a BI tool

SheetsNotionTableauVibeHost report
Interactive chartsLimitedNoAny JS lib
Mobile layoutBrokenPassableSlowYour HTML
Load timeSlow at scaleSlow at scaleSlowStatic HTML — instant
BrandingGoogleNotionTableauYours
Auth modelGoogle sharingNotion sharingLicense-basedVibeHost grants
Embed in emailLimitediframe-friendly
Cost$$$$$$$$

If your data team already has a BI tool, that's probably the right answer. VibeHost reports are best when you want full control over the visual (specific chart library, custom layout, brand polish) and low overhead (no server, no DB connection to manage).

See also

On this page