306 lines
12 KiB
TypeScript
306 lines
12 KiB
TypeScript
import type { Metadata } from "next";
|
||
import Link from "next/link";
|
||
import JsonLd from "@/components/JsonLd";
|
||
import { site } from "@/lib/site";
|
||
import VPSDeployWizard from "./VPSDeployWizard";
|
||
|
||
export const metadata: Metadata = {
|
||
title: "Managed VPS Hosting — Hardened, Monitored & Restore-Tested | Van Hunen IT",
|
||
description:
|
||
"Secure, fast VPS hosting with server management, monitoring, and restore-tested backups. Choose managed or own your VPS through our platform.",
|
||
};
|
||
|
||
const plans = [
|
||
{
|
||
id: "solo",
|
||
name: "Solo",
|
||
price: "€24/mo",
|
||
specs: "2 vCPU • 4 GB RAM • 50 GB NVMe",
|
||
bestFor: "Small apps, staging, low-traffic services",
|
||
features: [
|
||
"CIS-style hardening & firewall",
|
||
"Automated updates & monitoring",
|
||
"Daily backups + monthly restore test",
|
||
],
|
||
},
|
||
{
|
||
id: "team",
|
||
name: "Team",
|
||
price: "€49/mo",
|
||
specs: "4 vCPU • 8 GB RAM • 100 GB NVMe",
|
||
bestFor: "Production apps, WordPress/Next.js, APIs",
|
||
features: [
|
||
"Advanced monitoring & alerts",
|
||
"Backups (2x/day) + restore test",
|
||
"Incident notes & SLA response",
|
||
],
|
||
},
|
||
{
|
||
id: "dedicated",
|
||
name: "Dedicated",
|
||
price: "Custom",
|
||
specs: "Dedicated VPS/metal — tailored",
|
||
bestFor: "High traffic, networks, or compliance",
|
||
features: [
|
||
"Custom sizing & network",
|
||
"Hourly backups + drills (configurable)",
|
||
"Custom SLA & runbook",
|
||
],
|
||
},
|
||
] as const;
|
||
|
||
const regions = [
|
||
{ id: "eu-nl", label: "EU — Netherlands" },
|
||
{ id: "eu-de", label: "EU — Germany" },
|
||
{ id: "us-east", label: "US — East" },
|
||
{ id: "us-west", label: "US — West" },
|
||
] as const;
|
||
|
||
const osImages = [
|
||
{ id: "ubuntu-24-04", label: "Ubuntu 24.04 LTS" },
|
||
{ id: "ubuntu-22-04", label: "Ubuntu 22.04 LTS" },
|
||
{ id: "debian-12", label: "Debian 12" },
|
||
] as const;
|
||
|
||
const faqItems = [
|
||
{
|
||
q: "Can I truly own the VPS?",
|
||
a: "Yes. Choose “Owned (your account)” during provisioning and we’ll provision into your cloud account after a secure connect flow. You retain full ownership and root access.",
|
||
},
|
||
{
|
||
q: "What’s included in management?",
|
||
a: "Hardening, updates, monitoring, backups with restore tests, incident notes, and SLA-backed response depending on your plan.",
|
||
},
|
||
{
|
||
q: "Can you migrate my existing app or site?",
|
||
a: "Yes. We’ll review your stack, plan the cutover, and provide a rollback path. We can also set up staging and blue/green deploys.",
|
||
},
|
||
{
|
||
q: "Do I get root access?",
|
||
a: "Yes. For Managed mode we provide least-privilege users by default and root on request. For Owned mode you have full control by default.",
|
||
},
|
||
{
|
||
q: "How are backups verified?",
|
||
a: "We schedule restore drills and record timing and notes so you know recovery is proven—not just configured.",
|
||
},
|
||
];
|
||
|
||
const serviceLd = {
|
||
"@context": "https://schema.org",
|
||
"@type": "Service",
|
||
serviceType: "Managed VPS Hosting",
|
||
provider: {
|
||
"@type": "Organization",
|
||
name: site.name,
|
||
url: site.url,
|
||
logo: site.org.logo,
|
||
},
|
||
areaServed: ["EU", "US"],
|
||
hasOfferCatalog: {
|
||
"@type": "OfferCatalog",
|
||
name: "VPS Plans",
|
||
itemListElement: plans.map((p) => ({
|
||
"@type": "Offer",
|
||
name: p.name,
|
||
price: p.price,
|
||
description: `${p.specs} — ${p.bestFor}`,
|
||
url: `${site.url}/vps#deploy`,
|
||
category: "Managed VPS Hosting",
|
||
})),
|
||
},
|
||
};
|
||
|
||
const faqLd = {
|
||
"@context": "https://schema.org",
|
||
"@type": "FAQPage",
|
||
mainEntity: faqItems.map((i) => ({
|
||
"@type": "Question",
|
||
name: i.q,
|
||
acceptedAnswer: { "@type": "Answer", text: i.a },
|
||
})),
|
||
};
|
||
|
||
export default function VPSPage() {
|
||
const hostname = new URL(site.url).hostname;
|
||
|
||
return (
|
||
<main className="relative isolate min-h-screen bg-gradient-to-b from-neutral-50 via-white to-neutral-100 dark:from-neutral-950 dark:via-neutral-900 dark:to-neutral-950">
|
||
{/* HERO */}
|
||
<section className="relative overflow-hidden">
|
||
<div className="absolute inset-0 pointer-events-none opacity-60 bg-[radial-gradient(50%_50%_at_50%_0%,rgba(99,102,241,0.20),rgba(168,85,247,0.15)_40%,transparent_70%)]" />
|
||
<div className="container mx-auto max-w-6xl px-4 py-24 text-center">
|
||
<h1 className="text-4xl sm:text-6xl font-extrabold tracking-tight">
|
||
<span className="bg-gradient-to-r from-blue-600 via-purple-600 to-blue-600 bg-clip-text text-transparent">
|
||
Managed VPS Hosting — Hardened, Monitored, Proven
|
||
</span>
|
||
</h1>
|
||
<p className="mx-auto mt-6 max-w-3xl text-lg sm:text-xl text-neutral-700 dark:text-neutral-300">
|
||
Fast, secure VPS hosting with <strong>server management</strong>,{" "}
|
||
<strong>monitoring</strong>, and <strong>restore-tested backups</strong>. Prefer ownership?{" "}
|
||
Provision an <strong>Owned VPS</strong> directly into your cloud account—still fully managed.
|
||
</p>
|
||
|
||
<div className="mt-8 flex flex-col sm:flex-row gap-3 justify-center">
|
||
<a
|
||
href="#deploy"
|
||
className="inline-flex items-center justify-center rounded-lg bg-gradient-to-r from-blue-600 via-purple-600 to-blue-600 px-6 py-3 text-white font-semibold hover:opacity-90 transition"
|
||
>
|
||
Provision a VPS
|
||
</a>
|
||
<Link
|
||
href="/contact?type=vps"
|
||
className="inline-flex items-center justify-center rounded-lg border border-neutral-300 dark:border-neutral-700 px-6 py-3 text-neutral-900 dark:text-white font-semibold hover:bg-neutral-50 dark:hover:bg-neutral-800 transition"
|
||
>
|
||
Talk to an Engineer
|
||
</Link>
|
||
</div>
|
||
|
||
{/* Proof badges */}
|
||
<div className="mt-10 grid grid-cols-1 sm:grid-cols-3 gap-4 max-w-4xl mx-auto">
|
||
<div className="rounded-xl border border-neutral-200 dark:border-neutral-800 bg-white/70 dark:bg-neutral-900/70 p-4">
|
||
<p className="text-2xl font-bold">CIS-Style Hardening</p>
|
||
<p className="text-sm text-neutral-600 dark:text-neutral-400">SSH, firewall, baseline checks</p>
|
||
</div>
|
||
<div className="rounded-xl border border-neutral-200 dark:border-neutral-800 bg-white/70 dark:bg-neutral-900/70 p-4">
|
||
<p className="text-2xl font-bold">Restore-Proven</p>
|
||
<p className="text-sm text-neutral-600 dark:text-neutral-400">backup drills with timing</p>
|
||
</div>
|
||
<div className="rounded-xl border border-neutral-200 dark:border-neutral-800 bg-white/70 dark:bg-neutral-900/70 p-4">
|
||
<p className="text-2xl font-bold">SLA-Backed</p>
|
||
<p className="text-sm text-neutral-600 dark:text-neutral-400">monitoring & incident notes</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
{/* BENEFITS */}
|
||
<section className="relative border-y border-neutral-200 dark:border-neutral-800">
|
||
<div className="container mx-auto max-w-6xl px-4 py-16">
|
||
<h2 className="text-3xl sm:text-5xl font-bold tracking-tight text-center">
|
||
Everything you need for reliable infrastructure
|
||
</h2>
|
||
<div className="mt-10 grid gap-6 sm:grid-cols-2 lg:grid-cols-4">
|
||
{[
|
||
{ t: "Security & Hardening", d: "SSH config, firewall, updates, baseline audits." },
|
||
{ t: "Backups + Restore Tests", d: "Automated backups and scheduled restore drills with notes." },
|
||
{ t: "Monitoring & Incidents", d: "Uptime, CPU/RAM/disk alerts, incident notes & follow-up." },
|
||
{ t: "Cloudflare Optional", d: "Edge hardening, HTTP/3, cache tuning for faster TTFB." },
|
||
].map((b) => (
|
||
<article
|
||
key={b.t}
|
||
className="rounded-2xl border border-neutral-200 dark:border-neutral-800 bg-white/60 dark:bg-neutral-900/60 p-6"
|
||
>
|
||
<h3 className="text-lg font-semibold">{b.t}</h3>
|
||
<p className="mt-2 text-sm text-neutral-700 dark:text-neutral-300">{b.d}</p>
|
||
</article>
|
||
))}
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
{/* PLANS */}
|
||
<section className="relative py-16">
|
||
<div className="container mx-auto max-w-6xl px-4">
|
||
<h2 className="text-3xl sm:text-5xl font-bold tracking-tight text-center">VPS Plans</h2>
|
||
<p className="mt-4 text-neutral-700 dark:text-neutral-300 text-center max-w-3xl mx-auto">
|
||
Pick a plan, then choose <em>Managed</em> or <em>Owned</em> provisioning during checkout.
|
||
</p>
|
||
|
||
<div className="mt-10 grid gap-6 sm:grid-cols-2 lg:grid-cols-3">
|
||
{plans.map((p) => (
|
||
<div
|
||
key={p.id}
|
||
className="rounded-2xl border border-neutral-200 dark:border-neutral-800 bg-white/60 dark:bg-neutral-900/60 p-6 flex flex-col"
|
||
>
|
||
<div className="flex items-baseline justify-between">
|
||
<h3 className="text-xl font-semibold">{p.name}</h3>
|
||
<div className="text-lg font-bold">{p.price}</div>
|
||
</div>
|
||
<div className="mt-2 text-sm text-neutral-700 dark:text-neutral-300">{p.specs}</div>
|
||
<div className="mt-1 text-xs text-neutral-500 dark:text-neutral-400">{p.bestFor}</div>
|
||
|
||
<ul className="mt-4 space-y-2 text-sm">
|
||
{p.features.map((f) => (
|
||
<li key={f} className="flex items-start gap-2">
|
||
<span className="mt-0.5">✅</span>
|
||
<span>{f}</span>
|
||
</li>
|
||
))}
|
||
</ul>
|
||
|
||
<a
|
||
href={`#deploy?plan=${p.id}`}
|
||
className="mt-6 inline-flex items-center justify-center rounded-lg bg-gradient-to-r from-blue-600 via-purple-600 to-blue-600 px-4 py-2 text-white font-semibold hover:opacity-90 transition"
|
||
>
|
||
{p.id === "dedicated" ? "Request Custom Plan" : `Provision ${p.name}`}
|
||
</a>
|
||
</div>
|
||
))}
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
{/* CTA */}
|
||
<section className="relative py-16 border-y border-neutral-200 dark:border-neutral-800">
|
||
<div className="container mx-auto max-w-6xl px-4 text-center">
|
||
<h2 className="text-3xl sm:text-4xl font-bold tracking-tight">
|
||
Prefer a recommendation?
|
||
</h2>
|
||
<p className="mt-3 text-neutral-700 dark:text-neutral-300">
|
||
Tell us about your stack and goals—we’ll size a VPS and outline next steps.
|
||
</p>
|
||
<div className="mt-6">
|
||
<Link
|
||
href="/contact?type=vps"
|
||
className="inline-flex items-center rounded-lg bg-neutral-900 dark:bg-white text-white dark:text-neutral-900 px-5 py-2 font-semibold hover:opacity-90 transition"
|
||
>
|
||
Get My Recommendation
|
||
</Link>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
{/* SELF-SERVICE DEPLOYMENT */}
|
||
<section id="deploy" className="relative py-16">
|
||
<div className="container mx-auto max-w-3xl px-4">
|
||
<h2 className="text-3xl sm:text-4xl font-bold tracking-tight text-center">
|
||
Provision a VPS (Managed or Owned)
|
||
</h2>
|
||
<p className="mt-3 text-center text-neutral-700 dark:text-neutral-300">
|
||
Choose a plan, region, and OS. Select management mode: <strong>Managed</strong> (we host & bill) or{" "}
|
||
<strong>Owned</strong> (we provision into <em>your</em> cloud account via a secure connect).
|
||
</p>
|
||
|
||
<VPSDeployWizard
|
||
plans={plans}
|
||
regions={regions}
|
||
osImages={osImages}
|
||
siteHostname={hostname}
|
||
/>
|
||
</div>
|
||
</section>
|
||
|
||
{/* FAQ */}
|
||
<section className="relative py-16 bg-gradient-to-b from-neutral-50 via-white to-neutral-100 dark:from-neutral-950 dark:via-neutral-900 dark:to-neutral-950">
|
||
<div className="container mx-auto max-w-4xl px-4">
|
||
<h2 className="text-3xl sm:text-4xl font-bold tracking-tight text-center">FAQ</h2>
|
||
<div className="mt-8 grid gap-6">
|
||
{faqItems.map((i) => (
|
||
<article
|
||
key={i.q}
|
||
className="rounded-2xl border border-neutral-200 dark:border-neutral-800 bg-white/60 dark:bg-neutral-900/60 p-6"
|
||
>
|
||
<h3 className="text-lg font-semibold">{i.q}</h3>
|
||
<p className="mt-2 text-sm text-neutral-700 dark:text-neutral-300">{i.a}</p>
|
||
</article>
|
||
))}
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<JsonLd data={serviceLd} />
|
||
<JsonLd data={faqLd} />
|
||
</main>
|
||
);
|
||
}
|