juntekim.com/juntekim_frontend/app/SelfHosted/page.tsx
2026-03-08 14:25:17 +00:00

159 lines
No EOL
4.6 KiB
TypeScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

const services = [
{
name: "Ollama",
description: "Local LLM server powering my AI experiments",
url: "https://ollama.juntekim.com",
icon: "🧠",
},
{
name: "Uptime Kuma",
description: "Service monitoring for my homelab and projects",
url: "https://uptime.kuma.juntekim.com",
icon: "🟢",
},
{
name: "n8n",
description: "Automation workflows I run for small tasks and integrations",
url: "https://n8n.juntekim.com",
icon: "⚙️",
},
{
name: "Home Assistant",
description: "Home automation hub for devices and sensors",
url: "https://ha.juntekim.com",
icon: "🏠",
},
{
name: "pgAdmin",
description: "Web interface I use to manage PostgreSQL databases",
url: "https://pgadmin.juntekim.com",
icon: "🗄️",
},
{
name: "DBeaver",
description: "Another Web interface I use to manage PostgreSQL databases. - Deciding which one I prefer",
url: "https://dbeaver.juntekim.com",
icon: "🐿️",
},
{
name: "Monica",
description: "Personal CRM to keep track of relationships",
url: "https://crm.juntekim.com",
icon: "📇",
},
{
name: "Tandoor Recipes",
description: "Recipe manager I use for cooking",
url: "https://mealcraft.com",
icon: "🍳",
},
{
name: "JS Paint",
description: "A nostalgic browser-based MS Paint clone",
url: "https://jspaint.juntekim.com",
icon: "🎨",
},
{
name: "Exercise Tracker",
description: "Workout tracking powered by wger",
url: "https://exercise.juntekim.com",
icon: "💪",
},
{
"name": "Code Server",
"description": "VS Code running on my server so I can code from anywhere",
"icon": "💻"
},
{
"name": "Whoami",
"description": "Tiny test service I use to debug Traefik routing",
"url": "https://whoami.mealcraft.com/",
"icon": "🧪"
},
{
"name": "PDF Tools",
"description": "Simple tools I host for generating and working with PDFs",
"url": "https://pdf.juntekim.com",
"icon": "📄"
},
{
"name": "Stripe → Invoice",
"description": "A tool I built to automatically create Xero invoices from Stripe payments",
"url": "https://stripetoinvoice.com",
"icon": "💳"
},
{
name: "My Website",
description: "Main personal website showcasing projects and experiments",
url: "https://juntekim.com",
icon: "🌐"
},
{
name: "Databasus",
description: "Automated sql-db backups to AWS S3",
url: "https://databasus.juntekim.com/",
icon: "🗃️"
},
{
name: "Traefik Dashboard",
description: "Dashboard for monitoring and managing Traefik reverse proxy",
url: "https://traefik.mealcraft.com/dashboard/",
icon: "📊"
},
{
name: "Kokoro TTS",
description: "Open-source text-to-speech API running locally with an OpenAI-compatible interface",
url: "https://kokoro.juntekim.com",
icon: "🔊"
},
];
export default function HomelabPage() {
return (
<div className="max-w-5xl mx-auto p-8">
<h1 className="text-3xl font-bold mb-4 text-zinc-900 dark:text-zinc-100">
🖥 My Self-Hosted Stack
</h1>
<p className="mb-8 text-zinc-600 dark:text-zinc-400 max-w-2xl leading-relaxed">
These are tools I run in my personal <strong>homelab</strong> a small server
I manage myself to experiment with technology and host useful services.
</p>
<div className="border-t border-zinc-200 dark:border-zinc-800 my-8" />
<div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 gap-6">
{services.map((service) => (
<a
key={service.name}
href={service.url}
target="_blank"
rel="noopener noreferrer"
className="
group block p-6 rounded-2xl
border border-zinc-200 dark:border-zinc-700
bg-white/80 dark:bg-zinc-900/80
backdrop-blur
hover:shadow-xl hover:-translate-y-1
transition-all duration-200
"
>
<div className="flex items-center gap-3 mb-3">
<span className="text-2xl">{service.icon}</span>
<h2 className="text-xl font-semibold">{service.name}</h2>
</div>
<p className="text-sm text-zinc-600 dark:text-zinc-400 mb-4">
{service.description}
</p>
<span className="text-xs font-medium text-zinc-500 dark:text-zinc-400 group-hover:text-zinc-900 dark:group-hover:text-zinc-200 transition">
Open
</span>
</a>
))}
</div>
</div>
);
}