Skip to content

Repository files navigation

hostdoc

Publish a local HTML file or folder to your own AWS and get a short shareable link.

📖 Full guide & documentation

hostdoc has three hosting modes that share one publish path — you pick a mode by how you configure it, and the mode is derived, never stored:

  • No-domain (S3 website) — an HTTP link served straight from a public S3 static-website bucket. Set up with hostdoc setup.
  • Domain (CloudFront) — HTTPS on your own domain from a private S3 bucket fronted by CloudFront (OAC), provisioned with Terraform.
  • Self-hosted — publish to a local directory served by your own Caddy/nginx on your NAS or PC. No AWS involved.

Install

npm install -g hostdoc

Quick start (no domain)

Requires AWS credentials available to the SDK (env vars, a shared profile via --profile, or SSO).

# 1) Create a public website bucket and save config
hostdoc setup --bucket my-unique-bucket --region us-east-1

# 2) Publish
hostdoc publish ./report.html            # → http://<bucket>.s3-website-...amazonaws.com/<code>/
hostdoc publish ./site/ --slug aws-design
hostdoc publish ./site/ --slug team/q1/report   # nested path → .../team/q1/report/

# 3) Manage
hostdoc list
hostdoc open aws-design
hostdoc rm aws-design --yes

--dry-run prints the URL it would publish to without uploading — and without any AWS call, so it works offline / with no credentials configured.

open builds and opens the URL without verifying the document exists; an unknown id just opens a 403/404 page. rm asks for confirmation before deleting — pass --yes to skip it (required when stdin is not a TTY).

Note: no-domain mode serves content publicly over HTTP (S3 website endpoints do not support HTTPS). For public-facing HTTPS, see Domain mode below.

Domain mode (HTTPS via CloudFront)

Domain mode serves your docs over HTTPS from a fully private S3 bucket fronted by CloudFront (OAC). It is provisioned with Terraform.

Prerequisites: a Route53 hosted zone for your domain, AWS credentials, and Terraform installed. No repo checkout needed — the Terraform templates ship with the npm package and are extracted for you.

hostdoc provision \
  --hosted-zone example.com \
  --subdomain shared \
  --region us-east-1
# extracts bundled Terraform into ~/.local/state/hostdoc/infra, writes
# terraform.tfvars.json from the flags, then runs terraform init + apply and saves
# the config (~15-30 min).
# non-interactive (e.g. driving hostdoc from an agent): add --approve
hostdoc publish ./mydoc      # → https://shared.example.com/<code>/

The templates land in a per-user, cwd-independent directory by default — $XDG_STATE_HOME/hostdoc/infra (i.e. ~/.local/state/hostdoc/infra) — so the single local terraform.tfstate is reused no matter where you run hostdoc from, and deprovision always finds it. Override with --dir. Re-running provision never clobbers a dir you have already edited. Optional --price-class overrides the default PriceClass_100.

Already provisioned the infra yourself? Import it without applying: hostdoc init --from-terraform <dir>.

Tear it all down with hostdoc deprovision (it reuses the terraform.tfvars.json written during provision; or pass the same flags). Add --approve to run it non-interactively.

Overwriting (--force) and hostdoc rm automatically invalidate /<code>/* on the distribution.

External (non-Route53) DNS

Automated ACM validation and alias records require a Route53 hosted zone. If your domain is hosted elsewhere (e.g. Cloudflare), provisioning is manual: add the ACM validation CNAME shown by AWS, then point your subdomain at the CloudFront distribution domain via a CNAME/ALIAS record. This is outside the automated path.

Security note

The Terraform publisher_policy_json output is a minimal IAM policy for publishing. Prefer a dedicated IAM user (create_publisher_user = true) over root credentials for day-to-day hostdoc use. Enabling it stores the access-key secret in plaintext in terraform.tfstate; keep state private and rotate/destroy the key when done.

Self-hosted mode (your own NAS/PC)

Self-hosted mode publishes to a local directory served by your own web server — no AWS at all. hostdoc copies files into <serve-root>/<code>/ and returns a link on your own host.

# Configure the serve directory and print a Caddy (default) or nginx snippet
hostdoc setup --serve-root /srv/hostdoc --host docs.example.com
# → paste the printed snippet into your web-server config, then reload it
hostdoc publish ./report.html --slug aws-design   # → http://docs.example.com/aws-design/

--host is your public host (a DDNS name, domain, or static IP). Add --port for a non-standard port and --scheme https if your server terminates TLS. --nginx emits an nginx server block instead of a Caddyfile (nginx is also auto-selected when it is on PATH); --caddy forces a Caddyfile.

Auto-install (Caddy only). Add --install and hostdoc downloads Caddy and registers a boot service (Linux/macOS/Windows) so it survives reboot:

hostdoc setup --serve-root /srv/hostdoc --host docs.example.com --install

Non-privileged prep (config, Caddyfile, binary) runs as your user; the privileged service step runs automatically when you are root/admin, otherwise hostdoc prints the exact sudo (or elevated PowerShell) commands to finish. An --nginx choice falls back to the manual snippet — nginx is not a single static binary.

Tear it down with hostdoc deprovision (stops and unregisters the service; published files and the Caddy binary are left in place). Only the serve directory is served — directory listing is off and /_* (hostdoc's _meta sidecars) is blocked.

Network exposure — port-forwarding, firewall, router — is your responsibility. Expose only what you intend.

Use with an agent (skill)

hostdoc ships an installable agent skill so coding agents can drive it conversationally — "publish this folder", "list my docs", "remove that slug" — without memorizing flags.

npx skills add jkas2016/hostdoc

This installs the hostdoc skill into your agent. The skill shells out to the hostdoc CLI, preferring a global install and falling back to npx -y hostdoc, so no global install is required. It runs an AWS-free preflight check and turns missing config/credentials into guidance instead of raw errors.

Example prompts: "publish ./report.html and give me the link", "list my published docs", "open aws-design", "remove aws-design".

Credentials

hostdoc never stores AWS keys. It uses the AWS SDK default credential chain (environment variables → SSO → shared ~/.aws profile). Select a profile with --profile <name> and a region with --region <region>.

Configuration precedence

Flags (--bucket/--region/...) > HOSTDOC_* env vars > ~/.config/hostdoc/config.json.

Precedence merges fields, but the mode is derived from the merged result (domain+distribution → cloudfront; serveRoot → self-hosted; else bucket+region → s3-website). So setting only HOSTDOC_BUCKET on top of a cloudfront config file does not switch to s3-website — the file's domain still wins the derivation, and the bucket is ignored for mode (hostdoc prints a warning when it detects this).

To pin the mode regardless of which fields merged in, use --mode or HOSTDOC_MODE (s3-website | cloudfront | self-hosted, case-insensitive):

# force s3-website for a one-off, even though the config file is cloudfront
HOSTDOC_BUCKET=demo-bucket HOSTDOC_REGION=us-east-1 \
  hostdoc publish ./x.html --mode s3-website

A forced mode validates only that mode's required fields and ignores the others (printing a note about what it ignored).

License

MIT

Releases

Packages

Contributors

Languages