A high-security, 100% browser-based (serverless) CMS for Hugo sites.
HugoGuard CMS is a content management system that runs entirely in your web browser. It's designed for security-conscious users who want a simple interface to manage their Hugo static site content without the complexity of a traditional backend. It operates offline-first, stores all data securely in your browser's IndexedDB, and interacts directly with your GitHub repository.
- Serverless & Browser-Based: No backend to manage, no server costs. Everything runs client-side.
- Offline-First: Write and edit posts even without an internet connection. Your work is safely stored in the browser and ready to sync when you're back online.
- Two-Way Git Sync: Pull existing content and media from GitHub, detect conflicts, and publish changes back upstream with custom commit messages.
- Asset Management: Browse, upload, and delete files from your configured asset directory—directly against the GitHub Contents API.
- WYSIWYG Markdown Editing: Craft posts with a Tiptap-powered editor that keeps the Markdown source in sync with rich text formatting.
- End-to-End Encryption: Your sensitive data (like API tokens) is encrypted with a master password using the powerful Web Crypto API. This password never leaves your browser.
- Git-Based Workflow: HugoGuard commits your content changes directly to your GitHub repository, seamlessly integrating with the static site deployment flow (e.g., Netlify, Vercel, Cloudflare Pages).
- Zero Tracking, 100% Privacy: Because it's purely a client-side application, there is absolutely no user tracking or data collection. Your data is yours alone.
- Security-conscious bloggers who want to manage content without exposing a server to the internet.
- Developers looking for a simple, Git-based CMS to hand off to clients.
- Anyone with a Hugo static site who needs a lightweight, secure, and free content management interface.
For a beginner, it might seem like magic, but the architecture is quite simple and powerful. Here’s a breakdown:
-
Storage (Browser's IndexedDB):
- Think of IndexedDB as a mini-database that lives inside your web browser.
- HugoGuard uses it to store everything: your posts, assets, and application settings.
- We use a library called
Dexie.jsto make working with IndexedDB easy and efficient.
-
Encryption (Web Crypto API):
- When you first set up the app, you create a Master Password.
- This password, combined with a unique "salt" stored in your browser's local storage, is used to generate a powerful encryption key.
- This key is held only in memory while the app is unlocked. It is never stored.
- Any sensitive information, like your GitHub API token, is encrypted using this key (with the AES-GCM algorithm) before being saved to IndexedDB. This means even if someone could access your browser's database, the token would be unreadable gibberish.
-
GitHub Integration:
- The app uses the official GitHub REST API to communicate with your repository.
- On unlock, HugoGuard pulls the latest content and assets from GitHub, caching the blob SHAs for conflict detection.
- When you save a post, HugoGuard formats the front matter, lets you choose a commit message, and writes directly to your configured branch.
- Media uploads and deletions run through the same GitHub Contents API, so your static host redeploys automatically.
-
Deployment:
- The magic of static sites! By pushing a commit to your GitHub repository, HugoGuard automatically triggers the build and deploy process you've already set up with your hosting provider (like Netlify, Vercel, or Cloudflare Pages). The CMS just acts as a friendly interface for making those commits.
Follow these steps to get your own HugoGuard CMS up and running.
- You have a Hugo website.
- Your site's code is hosted in a GitHub repository.
- You have a deployment service (Netlify, Vercel, etc.) linked to your GitHub repo, which automatically builds and deploys your site on new commits.
HUGOCMS needs permission to create files in your repository. You grant this permission with a PAT.
- Go to the GitHub Personal Access Tokens page.
- Give your token a descriptive name, like "HugoGuard CMS".
- Set an expiration date (90 days is a good practice).
- Under Repository access, select "Only select repositories" and choose your Hugo site's repository.
- Under Permissions, click "Repository permissions" and grant it "Contents" access (Read and Write). This is the only permission it needs.
- Click "Generate token".
- IMPORTANT: Copy the token immediately and save it somewhere safe for the next step. GitHub will not show it to you again.
This project is designed to be run locally. Simply open the index.html file in your web browser.
The first time you open the app, you'll see the setup screen.
- Create a Master Password: Choose a strong password that you will not forget. THIS CANNOT BE RECOVERED! If you lose it, you will have to clear your browser data and set up the CMS again.
- Connect to GitHub:
- GitHub Personal Access Token: Paste the token you generated in Step 1.
- owner/repository: Enter your repository path, for example
homer-simpson/my-hugo-blog. - HugoGuard will automatically pull any existing posts and assets from the repo into your encrypted workspace.
That's it! You're in. You'll be taken to the main dashboard where you can start writing and managing your content.
From the Settings view you can:
- Update the repository branch, default content section, and asset directory.
- Modify the front-matter schema used by the editor.
- Refresh content from GitHub on demand.
- Store deployment provider tokens (Cloudflare, Netlify, Vercel) securely—encrypted with your master password.
For those curious to look at the code, here is a map of the most important files and directories:
/
├── public/
│ └── ...
├── src/
│ ├── components/ # Reusable React components
│ │ ├── auth/ # Setup and Unlock screens
│ │ ├── layout/ # Main app layout (sidebar, etc.)
│ │ ├── ui/ # Basic UI elements (Button, Input)
│ │ └── views/ # The main pages (Post List, Assets, etc.)
│ │
│ ├── lib/ # Core logic
│ │ ├── crypto.ts # All encryption/decryption functions
│ │ └── db.ts # Database (Dexie.js) setup
│ │
│ ├── state/ # Global state management
│ │ └── store.ts # Zustand store for auth, settings, etc.
│ │
│ ├── types.ts # TypeScript type definitions for our data
│ ├── App.tsx # Main application component and view routing
│ └── index.tsx # The entry point that mounts the React app
│
├── index.html # The main and only HTML file
└── README.md # You are here!
- Clone the repository.
- Install dependencies:
pnpm install
- Start the development server:
pnpm run dev
- Build for production:
pnpm run build
This is an open-source project, and contributions are welcome! Whether it's a bug fix, a new feature, or documentation improvement, feel free to:
- Fork the repository.
- Create a new branch (
git checkout -b feature/my-amazing-feature). - Make your changes.
- Commit your changes (
git commit -m 'Add some amazing feature'). - Push to the branch (
git push origin feature/my-amazing-feature). - Open a Pull Request.
This project is licensed under the MIT License. See the LICENSE file for details.