it/web/app/vps/page.tsx
2025-10-26 17:52:17 +01:00

306 lines
12 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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 well provision into your cloud account after a secure connect flow. You retain full ownership and root access.",
},
{
q: "Whats 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. Well 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 accountstill 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 goalswell 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>
);
}