diff --git a/nginx.conf b/nginx.conf index 09dc0aa..f6da4c9 100644 --- a/nginx.conf +++ b/nginx.conf @@ -9,22 +9,26 @@ server { gzip on; gzip_vary on; gzip_min_length 1024; - gzip_types text/plain text/css text/xml text/javascript application/x-javascript application/xml+rss application/javascript application/json; + gzip_types text/plain text/css text/xml text/javascript application/x-javascript application/xml+rss application/javascript application/json image/svg+xml; # Security headers - add_header X-Frame-Options "SAMEORIGIN" always; add_header X-Content-Type-Options "nosniff" always; - add_header X-XSS-Protection "1; mode=block" always; + add_header X-Frame-Options "DENY" always; + add_header Referrer-Policy "strict-origin-when-cross-origin" always; + add_header Permissions-Policy "camera=(), microphone=(), geolocation=(), interest-cohort=()" always; + add_header Content-Security-Policy "default-src 'none'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self'; font-src 'self'; connect-src 'self'; base-uri 'self'; form-action 'self'; frame-ancestors 'none'" always; + add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always; # Cache static assets location ~* \.(jpg|jpeg|png|gif|ico|css|js|svg|woff|woff2|ttf|eot)$ { expires 1y; add_header Cache-Control "public, immutable"; + add_header X-Content-Type-Options "nosniff" always; } # Main location location / { - try_files $uri $uri/ /index.html; + try_files $uri $uri/ =404; } # Custom error pages diff --git a/public/images/avatar.png b/public/images/avatar.png new file mode 100644 index 0000000..06ae125 Binary files /dev/null and b/public/images/avatar.png differ diff --git a/src/components/Nav.astro b/src/components/Nav.astro new file mode 100644 index 0000000..726c5c6 --- /dev/null +++ b/src/components/Nav.astro @@ -0,0 +1,89 @@ +--- +const currentPath = Astro.url.pathname; + +const links = [ + { href: "/", label: "home" }, + { href: "/about", label: "about" }, + { href: "/projects", label: "projects" }, + { href: "/blog", label: "blog" }, +]; + +function isActive(href: string, current: string): boolean { + if (href === "/") return current === "/"; + return current.startsWith(href); +} +--- + + + + diff --git a/src/content/blog/hello-world.md b/src/content/blog/hello-world.md new file mode 100644 index 0000000..b6739dc --- /dev/null +++ b/src/content/blog/hello-world.md @@ -0,0 +1,35 @@ +--- +title: "Welcome to the Den" +date: 2026-03-04 +description: "First proper post. Why I built this site, what it runs on, and what to expect." +draft: true +--- + +So I finally got around to setting up a proper blog. Welcome. + +## Why This Exists + +I wanted a place to write that wasn't owned by a corporation. No Medium, no Substack, no algorithm deciding who sees what. Just markdown files on my own server, served by nginx from a Docker container I control. + +That's the whole point of the den — owning your own space on the internet. + +## What It Runs On + +This site is built with [Astro](https://astro.build), which spits out pure static HTML at build time. No JavaScript runtime, no hydration, no client-side framework. Just HTML and CSS. + +It's served by nginx inside a Docker container, deployed from my Gitea instance. The whole pipeline is mine. + +## What to Expect + +I'll write when I have something to say. Probably a mix of: + +- Self-hosting adventures and homelab stuff +- Privacy thoughts and digital autonomy +- Technical things I figured out the hard way +- Whatever else is on my mind + +No schedule, no engagement metrics, no SEO optimization. Just writing. + +--- + +*Thanks for reading. Welcome to the den.* diff --git a/src/data/projects.json b/src/data/projects.json new file mode 100644 index 0000000..1f8840d --- /dev/null +++ b/src/data/projects.json @@ -0,0 +1,38 @@ +[ + { + "name": "GuardDen", + "description": "Security and moderation tooling for keeping communities safe. Built for the den.", + "tags": ["bot", "self-hosted"], + "status": "stable", + "links": { + "gitea": "https://git.hiddenden.cafe/Hiddenden/GuardDen" + } + }, + { + "name": "openrabbit", + "description": "An open-source project with a focus on accessibility and community-driven development.", + "tags": ["tool"], + "status": "stable", + "links": { + "gitea": "https://git.hiddenden.cafe/Hiddenden/openrabbit" + } + }, + { + "name": "DevDen", + "description": "A development environment concept for the den ecosystem. Still in the planning phase.", + "tags": ["tool", "experiment"], + "status": "concept", + "links": { + "gitea": "https://git.hiddenden.cafe/Hiddenden/DevDen" + } + }, + { + "name": "loyal_companion", + "description": "A companion bot — loyal, helpful, and always around when you need it.", + "tags": ["bot"], + "status": "wip", + "links": { + "gitea": "https://git.hiddenden.cafe/Hiddenden/loyal_companion" + } + } +] diff --git a/src/layouts/BaseLayout.astro b/src/layouts/BaseLayout.astro index c70b4f3..98e57ac 100644 --- a/src/layouts/BaseLayout.astro +++ b/src/layouts/BaseLayout.astro @@ -6,6 +6,8 @@ interface Props { canonicalURL?: string; } +import Nav from "../components/Nav.astro"; + const { title, description = "Hidden Den Cafe - A cozy, self-hosted corner of the internet. Privacy-focused, furry-friendly, and built with love.", @@ -80,6 +82,7 @@ const fullOgImage = new URL(ogImage, Astro.site).href; +