Skip to content

cargom98/secure-git-page

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

9 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Private Doc Viewer

Share private GitHub repository documentation (Markdown and PDFs) behind a simple 6-digit access code. Built on Cloudflare's free tier with zero ongoing server costs.

Visitors see a landing page with a code input. After entering the correct code, they get a 24-hour session cookie and can browse the full rendered documentation site freely.

Architecture

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  Visitor Browser │────▢│  Cloudflare Worker    │────▢│  Cloudflare Pages   β”‚
β”‚                  β”‚     β”‚  (travel.example.com) β”‚     β”‚  (*.pages.dev)      β”‚
β”‚                  β”‚     β”‚                       β”‚     β”‚                     β”‚
β”‚  6-digit code ──▢│     β”‚  β€’ Auth gate          β”‚     β”‚  β€’ Static HTML/PDF  β”‚
β”‚  Session cookie  β”‚     β”‚  β€’ Session cookies    β”‚     β”‚  β€’ Protected by     β”‚
β”‚                  β”‚     β”‚  β€’ Brute-force lockout β”‚     β”‚    Access + Service β”‚
β”‚                  β”‚     β”‚  β€’ Proxy with service  β”‚     β”‚    Token            β”‚
β”‚                  β”‚     β”‚    token auth          β”‚     β”‚                     β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜     β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜     β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
  • Cloudflare Worker β€” intercepts all requests on the custom domain, enforces 6-digit code authentication, manages sessions, and proxies to Pages using a service token
  • Cloudflare Pages β€” serves the rendered HTML documentation, PDFs, and images
  • Cloudflare Access β€” blocks direct public access to *.pages.dev; only the worker's service token can reach the origin
  • Terraform β€” provisions all Cloudflare infrastructure (Pages, Worker, KV, DNS, Access) with S3-backed remote state
  • Cloudflare Provider v5 β€” uses the latest auto-generated Terraform provider

Prerequisites

  • Terraform >= 1.0
  • Node.js >= 18 (for Wrangler CLI)
  • Python 3 (for the Markdown build pipeline)
  • A Cloudflare account (free tier works)
  • A Cloudflare API token with Workers, Pages, DNS, and Zero Trust permissions
  • An AWS S3 bucket for Terraform state storage

Setup

1. Clone this repo

git clone <this-repo-url>
cd private-doc-viewer

2. Configure Terraform variables

Create terraform/terraform.tfvars:

cloudflare_account_id = "your-account-id"
cloudflare_api_token  = "your-api-token"
access_code           = "123456"
cookie_secret         = "a-long-random-secret-string"

# Required for custom domain
cloudflare_zone_id = "your-zone-id"
custom_domain      = "docs.example.com"

# Optional
webhook_url = "https://hooks.slack.com/services/..."

Update the S3 backend in terraform/main.tf to point to your bucket.

3. Provision infrastructure

cd terraform
terraform init
terraform apply

This creates:

  • Cloudflare Pages project
  • Worker script with KV bindings and secrets
  • KV namespace for brute-force tracking
  • Custom domain DNS record (CNAME)
  • Access application + service token protecting the pages.dev origin

4. API token permissions

Your Cloudflare API token needs these permissions:

Scope Permission Access
Account Workers Scripts Edit
Account Workers KV Storage Edit
Account Cloudflare Pages Edit
Account Access: Apps and Policies Edit
Account Access: Service Tokens Edit
Zone DNS Edit

Deploying Documentation

There are two ways to deploy your source documentation to the site.

Option A: Local deploy (recommended for quick updates)

Use the included deploy.sh script to build and deploy from a local directory:

./deploy.sh ~/repos/my-private-docs

This will:

  1. Install Python build dependencies
  2. Convert all Markdown files to HTML (with link rewriting)
  3. Copy PDFs and images as-is
  4. Deploy the built _site/ to Cloudflare Pages via Wrangler

Your source repo should be a directory of Markdown files and assets:

my-private-docs/
β”œβ”€β”€ README.md              β†’ becomes index.html (home page)
β”œβ”€β”€ guide.md               β†’ becomes guide.html
β”œβ”€β”€ subfolder/
β”‚   β”œβ”€β”€ notes.md           β†’ becomes subfolder/notes.html
β”‚   └── receipt.pdf        β†’ copied as subfolder/receipt.pdf
└── images/
    └── photo.jpg          β†’ copied as images/photo.jpg

Option B: GitHub Actions (automated on push)

In your private documentation repository, add these GitHub Actions secrets:

Secret Value
CLOUDFLARE_API_TOKEN Cloudflare API token with Pages permission
CLOUDFLARE_ACCOUNT_ID Your Cloudflare account ID

Copy the workflow and build files into your source repo:

cp build/deploy-docs.yml <source-repo>/.github/workflows/deploy-docs.yml
cp -r build/ <source-repo>/build/

Push to main and the workflow will build and deploy automatically.

Build details

The build pipeline (build/build.py):

  • Converts .md files to styled HTML using markdown-it-py
  • Rewrites relative .md links to .html (so inter-doc links work)
  • Copies PDFs, PNGs, JPGs, GIFs, and SVGs as-is
  • Root README.md becomes index.html with title "Home"
  • All other files keep their name with .html extension

Changing the Access Code

Update access_code in terraform/terraform.tfvars and re-apply:

cd terraform
terraform apply

Existing sessions remain valid until their 24-hour cookie expires.

Project Structure

β”œβ”€β”€ build/
β”‚   β”œβ”€β”€ build.py              # Markdown-to-HTML build pipeline
β”‚   β”œβ”€β”€ deploy-docs.yml       # GitHub Actions workflow (copy to source repo .github/workflows/)
β”‚   └── requirements.txt      # Python build dependencies
β”œβ”€β”€ deploy.sh                 # Local deploy script
β”œβ”€β”€ terraform/
β”‚   β”œβ”€β”€ main.tf               # S3 backend configuration
β”‚   β”œβ”€β”€ providers.tf          # Cloudflare provider v5
β”‚   β”œβ”€β”€ resources.tf          # Pages, Worker, KV, DNS resources
β”‚   β”œβ”€β”€ access.tf             # Access application + service token
β”‚   β”œβ”€β”€ variables.tf          # Input variables
β”‚   └── outputs.tf            # Output values (URLs, IDs)
β”œβ”€β”€ worker/
β”‚   └── src/index.js          # Auth Worker source code
└── tests/                    # Unit and property-based tests

Security

  • Access code auth β€” 6-digit code verified by the Worker
  • Session cookies β€” HMAC-SHA256 signed, HttpOnly, Secure, SameSite=Strict, 24h expiry
  • Brute-force protection β€” IP lockout after 8 failed attempts (30 min cooldown via KV)
  • Cloudflare Access β€” blocks direct pages.dev access; only the worker's service token can reach the origin
  • Admin alerts β€” optional webhook notification on lockout events

License

MIT

About

Share private GitHub repo docs behind a 6-digit access code. Cloudflare Workers + Pages + Access, Terraform v5, zero server costs.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors