en

Static Site Hosting on Tor: Jekyll, Hugo, and Next.js on .onion

Static site hosting on a Tor hidden service provides the strongest combination of performance and security for .onion websites. Without server-side code execution, the attack surface is minimal - a static file server serves pre-built HTML, CSS, and JavaScript without any database queries, backend authentication flows, or dynamic code paths that could be exploited. Static sites also perform exceptionally well over Tor's high-latency circuits: serving pre-built files from memory or SSD is fast, and aggressive HTTP caching means repeat visitors load pages from their browser cache without Tor circuit roundtrips. Static site generators like Jekyll, Hugo, and Next.js (with static export) produce production-ready static files that can be served by Nginx with minimal configuration. This guide covers the full deployment pipeline from local development through automated build and .onion deployment.

Need this done for your project?

We implement, you ship. Async, documented, done in days.

Start a Brief

Static Site Generator Selection for .onion

Jekyll, Hugo, and Next.js serve different use cases. Jekyll: Ruby-based, excellent for documentation and blogs, native GitHub Pages integration (though deployment must be separate for .onion), extensive plugin ecosystem, build time increases with site size. Hugo: Go-based, extremely fast builds (thousands of pages in seconds), strong internationalization support (important for multilingual .onion sites), excellent for large content sites. Next.js static export (next export or output: 'export'): ideal for sites that also need a clearnet version, excellent React component ecosystem, supports Tailwind CSS natively, builds in 10-60 seconds for medium sites. For pure .onion content sites prioritizing build speed: Hugo. For developers familiar with React/Node.js: Next.js static export. For simplicity and blogging: Jekyll. All three produce static files servable by Nginx without modification.

Nginx Configuration for Static .onion Sites

Configure Nginx to serve static files for a .onion site. Install: apt install nginx. Create site configuration /etc/nginx/sites-available/onion-site: server { listen 127.0.0.1:80; root /var/www/onionsite; index index.html; location / { try_files $uri $uri/ =404; } add_header Cache-Control 'public, max-age=86400'; gzip on; gzip_types text/html text/css application/javascript; }. The listen 127.0.0.1:80 ensures Nginx only accepts connections from Tor's HiddenServicePort mapping, not directly from the internet. Add_header Cache-Control sets browser caching to 24 hours. For assets that change infrequently (fonts, images), use max-age=2592000 (30 days). Enable the site: ln -s /etc/nginx/sites-available/onion-site /etc/nginx/sites-enabled/ && nginx -t && systemctl reload nginx. Add to torrc: HiddenServiceDir /var/lib/tor/mysite/, HiddenServicePort 80 127.0.0.1:80.

Automated Build and Deployment Pipeline

Automate static site deployment to the .onion server. Local build pipeline: edit content locally, run hugo build (or jekyll build / next build) to generate static files in the public/ or out/ directory, rsync the built files over SSH via Tor to the server. Script: rsync -avz --delete -e 'ssh -o ProxyCommand="nc -x 127.0.0.1:9050 %h %p"' public/ deployuser@youronion.onion:/var/www/onionsite/. The ProxyCommand routes the rsync SSH connection through Tor. Set up SSH key authentication for the deploy user. For automated CI/CD builds (see CI/CD guide), push to .onion Gitea triggers a pipeline that builds the site in a Docker container and rsyncs the result to the production server. For Hugo sites with frequent content updates, the build-deploy cycle takes under 30 seconds.

JavaScript and Privacy Considerations

Static sites can include JavaScript that makes outbound requests from the user's browser - requests that could expose the user's Tor exit IP to third-party services. For maximum privacy, audit all JavaScript: remove any third-party analytics scripts (Google Analytics, Plausible), CDN-hosted fonts (Google Fonts - self-host instead), social media share buttons (make external requests), and comment systems requiring third-party JavaScript. Replace with privacy-preserving alternatives: self-hosted Umami or Plausible for analytics (routes through Tor exit), Commento or Isso for comments (self-hosted), system fonts instead of web fonts. For truly paranoid .onion sites targeting users with JavaScript disabled (Tor Browser's Safest setting): use no-JavaScript static HTML, ensure the site is fully functional without JavaScript, and include a visible notice that JavaScript is not required.

Search and Content Discovery on .onion Static Sites

Static sites on .onion cannot use server-side search (no backend). Client-side search options: Lunr.js generates a search index at build time (JSON file), JavaScript searches the index locally in the browser. Pagefind (pagefind.app) generates a highly efficient wasm-based search index as part of the build process, providing Google-quality search results locally. Both work without any server-side processing or external service requests. For Hugo sites: use the hugo-search-fuse or pagefind integration. For Jekyll: jekyll-lunr-js-search plugin. Build-time index generation adds seconds to build time (acceptable) and produces a few MB search index file. Include the search index in the rsync deployment. For .onion sites where JavaScript is disabled: provide a static tag/category navigation structure and pagination that allows browsing all content without search, as a fallback.

Why Anubiz Host

100% async — no calls, no meetings
Delivered in days, not weeks
Full documentation included
Production-grade from day one
Security-first approach
Post-delivery support included

Ready to get started?

Skip the research. Tell us what you need, and we'll scope it, implement it, and hand it back — fully documented and production-ready.

Anubiz Chat AI

Online