- At Dokploy, we are committed to protecting your privacy. This Privacy
- Policy explains how we collect, use, and safeguard your personal
- information when you use our website and services.
+ At Dokploy, we are committed to protecting your privacy.
+ This Privacy Policy explains how we collect, use, and
+ safeguard your personal information when you use our website
+ and services.
- By using Dokploy, you agree to the collection and use of information
- in accordance with this Privacy Policy. If you do not agree with these
- practices, please do not use our services.
+ By using Dokploy, you agree to the collection and use of
+ information in accordance with this Privacy Policy. If you
+ do not agree with these practices, please do not use our
+ services.
-
+
1. Information We Collect
- We only collect limited, non-personal data through Umami Analytics, a
- privacy-focused analytics tool. No personal identifying information
- (PII) is collected. The data we collect includes:
+ We only collect limited, non-personal data through Umami
+ Analytics, a privacy-focused analytics tool. No personal
+ identifying information (PII) is collected. The data we
+ collect includes:
@@ -31,70 +37,77 @@ export default function Home() {
-
+
2. How We Use the Information
The information we collect is used solely for improving the
- functionality and user experience of our platform. Specifically, we
- use it to:
+ functionality and user experience of our platform.
+ Specifically, we use it to:
-
+
Monitor traffic and website performance
Optimize the user experience
Understand how users interact with our platform
- Additionally, we use a single cookie to manage user sessions, which is
- necessary for the proper functioning of the platform.
+ Additionally, we use a single cookie to manage user
+ sessions, which is necessary for the proper functioning of
+ the platform.
-
3. Data Security
+
+ 3. Data Security
+
- We take reasonable precautions to protect your data. Since we do not
- collect personal information, the risk of data misuse is minimized.
- Umami Analytics is privacy-friendly and does not rely on cookies or
- store PII.
+ We take reasonable precautions to protect your data. Since
+ we do not collect personal information, the risk of data
+ misuse is minimized. Umami Analytics is privacy-friendly and
+ does not rely on cookies or store PII.
-
4. Third-Party Services
+
+ 4. Third-Party Services
+
- We do not share your data with any third-party services other than
- Umami Analytics. We do not sell, trade, or transfer your data to
- outside parties.
+ We do not share your data with any third-party services
+ other than Umami Analytics. We do not sell, trade, or
+ transfer your data to outside parties.
-
5. Cookies
+
5. Cookies
- Dokploy does not use cookies to track user activity. Umami Analytics
- is cookie-free and does not require any tracking cookies for its
- functionality.
+ Dokploy does not use cookies to track user activity. Umami
+ Analytics is cookie-free and does not require any tracking
+ cookies for its functionality.
-
+
6. Changes to This Privacy Policy
- We may update this Privacy Policy from time to time. Any changes will
- be posted on this page, and it is your responsibility to review this
- policy periodically.
+ We may update this Privacy Policy from time to time. Any
+ changes will be posted on this page, and it is your
+ responsibility to review this policy periodically.
-
12. Contact Information
+
+ 12. Contact Information
+
- If you have any questions or concerns regarding these Privacy Policy,
- please contact us at:
+ If you have any questions or concerns regarding these
+ Privacy Policy, please contact us at:
Email:
@@ -107,5 +120,5 @@ export default function Home() {
- Welcome to Dokploy! These Terms and Conditions outline the rules and
- regulations for the use of Dokploy’s website and services.
+ Welcome to Dokploy! These Terms and Conditions outline the
+ rules and regulations for the use of Dokploy’s website and
+ services.
- By accessing or using our services, you agree to be bound by the
- following terms. If you do not agree with these terms, please do not
- use our website or services.
+ By accessing or using our services, you agree to be bound by
+ the following terms. If you do not agree with these terms,
+ please do not use our website or services.
- Dokploy is a platform that allows users to deploy and manage web
- applications on their own servers using custom builders and Docker
- technology. Dokploy offers both free and paid services, including
- subscriptions for adding additional servers, features, or increased
- capacity.
+ Dokploy is a platform that allows users to deploy and manage
+ web applications on their own servers using custom builders
+ and Docker technology. Dokploy offers both free and paid
+ services, including subscriptions for adding additional
+ servers, features, or increased capacity.
-
+
3. User Responsibilities
- Users are responsible for maintaining the security of their accounts,
- servers, and applications deployed through Dokploy.
+ Users are responsible for maintaining the security of their
+ accounts, servers, and applications deployed through
+ Dokploy.
- Users must not use the platform for illegal activities, including but
- not limited to distributing malware, violating intellectual property
- rights, or engaging in cyberattacks.
+ Users must not use the platform for illegal activities,
+ including but not limited to distributing malware, violating
+ intellectual property rights, or engaging in cyberattacks.
- Users must comply with all local, state, and international laws in
- connection with their use of Dokploy.
+ Users must comply with all local, state, and international
+ laws in connection with their use of Dokploy.
-
+
4. Subscription and Payment
-
+
- By purchasing a subscription, users agree to the pricing and payment
- terms detailed on the website or via Paddle (our payment processor).
+ By purchasing a subscription, users agree to the pricing
+ and payment terms detailed on the website or via Paddle
+ (our payment processor).
- Subscriptions renew automatically unless canceled by the user before
- the renewal date.
+ Subscriptions renew automatically unless canceled by the
+ user before the renewal date.
-
5. Refund Policy
+
+ 5. Refund Policy
+
- Due to the nature of our digital services, Dokploy operates on a
- no-refund policy for any paid subscriptions, except where required by
- law. We offer a self-hosted version of Dokploy with the same core
- functionalities, which users can deploy and use without any cost. We
- recommend users try the self-hosted version to evaluate the platform
- before committing to a paid subscription.
+ Due to the nature of our digital services, Dokploy operates
+ on a no-refund policy for any paid subscriptions, except
+ where required by law. We offer a self-hosted version of
+ Dokploy with the same core functionalities, which users can
+ deploy and use without any cost. We recommend users try the
+ self-hosted version to evaluate the platform before
+ committing to a paid subscription.
-
+
6. Limitations of Liability
- Dokploy is provided "as is" without any warranties, express or
- implied, including but not limited to the availability, reliability,
- or accuracy of the service.
+ Dokploy is provided "as is" without any warranties, express
+ or implied, including but not limited to the availability,
+ reliability, or accuracy of the service.
- Users are fully responsible for any modifications made to their remote
- servers or the environment where Dokploy is deployed. Any changes to
- the server configuration, system settings, security policies, or other
- environments that deviate from the recommended use of Dokploy may
- result in compatibility issues, performance degradation, or security
- vulnerabilities. Additionally, Dokploy may not function properly on
- unsupported operating systems or environments. We do not guarantee the
- platform will operate correctly or reliably under modified server
- conditions or on unsupported systems, and we will not be held liable
- for any disruptions, malfunctions, or damages resulting from such
- changes or unsupported configurations.
+ Users are fully responsible for any modifications made to
+ their remote servers or the environment where Dokploy is
+ deployed. Any changes to the server configuration, system
+ settings, security policies, or other environments that
+ deviate from the recommended use of Dokploy may result in
+ compatibility issues, performance degradation, or security
+ vulnerabilities. Additionally, Dokploy may not function
+ properly on unsupported operating systems or environments.
+ We do not guarantee the platform will operate correctly or
+ reliably under modified server conditions or on unsupported
+ systems, and we will not be held liable for any disruptions,
+ malfunctions, or damages resulting from such changes or
+ unsupported configurations.
-
+
7. Service Modifications and Downtime
- While we strive to provide uninterrupted service, there may be periods
- of downtime due to scheduled maintenance or upgrades to our
- infrastructure, such as server maintenance or system improvements. We
- will provide notice to users ahead of any planned maintenance.
+ While we strive to provide uninterrupted service, there may
+ be periods of downtime due to scheduled maintenance or
+ upgrades to our infrastructure, such as server maintenance
+ or system improvements. We will provide notice to users
+ ahead of any planned maintenance.
-
+
8. Intellectual Property
- Dokploy retains all intellectual property rights to the platform,
- including code, design, and content.
+ Dokploy retains all intellectual property rights to the
+ platform, including code, design, and content.
- Users are granted a limited, non-exclusive, and non-transferable
- license to use Dokploy in accordance with these terms.
+ Users are granted a limited, non-exclusive, and
+ non-transferable license to use Dokploy in accordance with
+ these terms.
- Users may not modify, reverse-engineer, or distribute any part of the
- platform without express permission.
+ Users may not modify, reverse-engineer, or distribute any
+ part of the platform without express permission.
-
9. Termination
+
9. Termination
- Dokploy reserves the right to suspend or terminate access to the
- platform for users who violate these terms or engage in harmful
- behavior.
+ Dokploy reserves the right to suspend or terminate access to
+ the platform for users who violate these terms or engage in
+ harmful behavior.
- Users may terminate their account at any time by contacting support.
- Upon termination, access to the platform will be revoked, and any
- stored data may be permanently deleted.
+ Users may terminate their account at any time by contacting
+ support. Upon termination, access to the platform will be
+ revoked, and any stored data may be permanently deleted.
-
10. Changes to Terms
+
+ 10. Changes to Terms
+
- Dokploy reserves the right to update these Terms & Conditions at any
- time. Changes will be effective immediately upon posting on the
- website. It is the user's responsibility to review these terms
- periodically.
+ Dokploy reserves the right to update these Terms &
+ Conditions at any time. Changes will be effective
+ immediately upon posting on the website. It is the user's
+ responsibility to review these terms periodically.
-
11. Governing Law
+
+ 11. Governing Law
+
- These Terms & Conditions are governed by applicable laws based on the
- user's location. Any disputes arising under these terms will be
- resolved in accordance with the legal jurisdiction relevant to the
- user’s location, unless otherwise required by applicable law.
+ These Terms & Conditions are governed by applicable laws
+ based on the user's location. Any disputes arising under
+ these terms will be resolved in accordance with the legal
+ jurisdiction relevant to the user’s location, unless
+ otherwise required by applicable law.
-
12. Contact Information
+
+ 12. Contact Information
+
- If you have any questions or concerns regarding these Terms, you can
- reach us at:
+ If you have any questions or concerns regarding these Terms,
+ you can reach us at:
Email:
@@ -201,5 +220,5 @@ export default function Home() {
- );
+ )
}
diff --git a/apps/website/app/api/contact/route.ts b/apps/website/app/api/contact/route.ts
index 26469e1..1322171 100644
--- a/apps/website/app/api/contact/route.ts
+++ b/apps/website/app/api/contact/route.ts
@@ -1,31 +1,31 @@
-import type { NextRequest } from "next/server";
-import { NextResponse } from "next/server";
-import { Resend } from "resend";
-import { submitToHubSpot, getHubSpotUTK } from "@/lib/hubspot";
+import type { NextRequest } from 'next/server'
+import { NextResponse } from 'next/server'
+import { Resend } from 'resend'
+import { submitToHubSpot, getHubSpotUTK } from '@/lib/hubspot'
interface ContactFormData {
- inquiryType: "support" | "sales" | "other";
- firstName: string;
- lastName: string;
- email: string;
- company: string;
- message: string;
+ inquiryType: 'support' | 'sales' | 'other'
+ firstName: string
+ lastName: string
+ email: string
+ company: string
+ message: string
}
export async function POST(request: NextRequest) {
try {
// Initialize Resend with API key check
- const apiKey = process.env.RESEND_API_KEY;
+ const apiKey = process.env.RESEND_API_KEY
if (!apiKey) {
- console.error("RESEND_API_KEY is not configured");
+ console.error('RESEND_API_KEY is not configured')
return NextResponse.json(
- { error: "Email service not configured" },
+ { error: 'Email service not configured' },
{ status: 500 },
- );
+ )
}
- const resend = new Resend(apiKey);
- const body: ContactFormData = await request.json();
+ const resend = new Resend(apiKey)
+ const body: ContactFormData = await request.json()
// Validate required fields
if (
@@ -37,41 +37,45 @@ export async function POST(request: NextRequest) {
!body.message
) {
return NextResponse.json(
- { error: "All fields are required" },
+ { error: 'All fields are required' },
{ status: 400 },
- );
+ )
}
// Validate email format
- const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
+ const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/
if (!emailRegex.test(body.email)) {
return NextResponse.json(
- { error: "Invalid email format" },
+ { error: 'Invalid email format' },
{ status: 400 },
- );
+ )
}
// Submit to HubSpot if it's a sales inquiry
- if (body.inquiryType === "sales") {
+ if (body.inquiryType === 'sales') {
try {
- const hutk = getHubSpotUTK(request.headers.get("cookie") || undefined);
- const hubspotSuccess = await submitToHubSpot(body, hutk);
+ const hutk = getHubSpotUTK(
+ request.headers.get('cookie') || undefined,
+ )
+ const hubspotSuccess = await submitToHubSpot(body, hutk)
if (hubspotSuccess) {
- console.log("Successfully submitted sales inquiry to HubSpot");
+ console.log(
+ 'Successfully submitted sales inquiry to HubSpot',
+ )
} else {
console.warn(
- "Failed to submit sales inquiry to HubSpot, but continuing with email",
- );
+ 'Failed to submit sales inquiry to HubSpot, but continuing with email',
+ )
}
} catch (error) {
- console.error("Error submitting to HubSpot:", error);
+ console.error('Error submitting to HubSpot:', error)
// Continue with email even if HubSpot fails
}
}
// Format email content
- const emailSubject = `[${body.inquiryType.toUpperCase()}] New contact form submission from ${body.firstName} ${body.lastName}`;
+ const emailSubject = `[${body.inquiryType.toUpperCase()}] New contact form submission from ${body.firstName} ${body.lastName}`
const emailBody = `
New contact form submission:
@@ -86,23 +90,23 @@ ${body.message}
---
Sent from Dokploy website contact form
- `.trim();
+ `.trim()
// Send email to Dokploy team
await resend.emails.send({
- from: "Dokploy Contact Form ",
+ from: 'Dokploy Contact Form ',
to:
- body.inquiryType === "sales"
- ? ["sales@dokploy.com", "contact@dokploy.com"]
- : ["contact@dokploy.com"],
+ body.inquiryType === 'sales'
+ ? ['sales@dokploy.com', 'contact@dokploy.com']
+ : ['contact@dokploy.com'],
subject: emailSubject,
text: emailBody,
replyTo: body.email,
- });
+ })
// Send confirmation email to the user
const confirmationSubject =
- "Thank you for contacting Dokploy - We received your message";
+ 'Thank you for contacting Dokploy - We received your message'
const confirmationBody = `
Hello ${body.firstName} ${body.lastName},
@@ -122,24 +126,24 @@ The Dokploy Team
---
This is an automated confirmation email. Please do not reply to this email.
If you need immediate assistance, contact us at contact@dokploy.com
- `.trim();
+ `.trim()
await resend.emails.send({
- from: "Dokploy Team ",
+ from: 'Dokploy Team ',
to: [body.email],
subject: confirmationSubject,
text: confirmationBody,
- });
+ })
return NextResponse.json(
- { message: "Contact form submitted successfully" },
+ { message: 'Contact form submitted successfully' },
{ status: 200 },
- );
+ )
} catch (error) {
- console.error("Error processing contact form:", error);
+ console.error('Error processing contact form:', error)
return NextResponse.json(
- { error: "Internal server error" },
+ { error: 'Internal server error' },
{ status: 500 },
- );
+ )
}
}
diff --git a/apps/website/app/api/github-stars/route.ts b/apps/website/app/api/github-stars/route.ts
index 57c7a4d..9426ff5 100644
--- a/apps/website/app/api/github-stars/route.ts
+++ b/apps/website/app/api/github-stars/route.ts
@@ -1,34 +1,32 @@
-import { NextResponse } from "next/server";
+import { NextResponse } from 'next/server'
// Cache the result for 5 minutes to avoid rate limiting
-let cachedStars: { count: number; timestamp: number } | null = null;
-const CACHE_DURATION = 5 * 60 * 1000; // 5 minutes in milliseconds
+let cachedStars: { count: number; timestamp: number } | null = null
+const CACHE_DURATION = 5 * 60 * 1000 // 5 minutes in milliseconds
export async function GET(request: Request) {
- const { searchParams } = new URL(request.url);
- const owner = searchParams.get("owner");
- const repo = searchParams.get("repo");
+ const { searchParams } = new URL(request.url)
+ const owner = searchParams.get('owner')
+ const repo = searchParams.get('repo')
if (!owner || !repo) {
return NextResponse.json(
- { error: "Owner and repo parameters are required" },
+ { error: 'Owner and repo parameters are required' },
{ status: 400 },
- );
+ )
}
// Check if we have a valid cached result
- if (
- cachedStars &&
- Date.now() - cachedStars.timestamp < CACHE_DURATION
- ) {
+ if (cachedStars && Date.now() - cachedStars.timestamp < CACHE_DURATION) {
return NextResponse.json(
{ stargazers_count: cachedStars.count },
{
headers: {
- "Cache-Control": "public, s-maxage=300, stale-while-revalidate=600",
+ 'Cache-Control':
+ 'public, s-maxage=300, stale-while-revalidate=600',
},
},
- );
+ )
}
try {
@@ -36,42 +34,42 @@ export async function GET(request: Request) {
`https://api.github.com/repos/${owner}/${repo}`,
{
headers: {
- Accept: "application/vnd.github.v3+json",
- "User-Agent": "Dokploy-Website",
+ Accept: 'application/vnd.github.v3+json',
+ 'User-Agent': 'Dokploy-Website',
},
},
- );
+ )
if (!response.ok) {
return NextResponse.json(
- { error: "Failed to fetch repository data" },
+ { error: 'Failed to fetch repository data' },
{ status: response.status },
- );
+ )
}
- const data = await response.json();
- const starCount = data.stargazers_count;
+ const data = await response.json()
+ const starCount = data.stargazers_count
// Cache the result
cachedStars = {
count: starCount,
timestamp: Date.now(),
- };
+ }
return NextResponse.json(
{ stargazers_count: starCount },
{
headers: {
- "Cache-Control": "public, s-maxage=300, stale-while-revalidate=600",
+ 'Cache-Control':
+ 'public, s-maxage=300, stale-while-revalidate=600',
},
},
- );
+ )
} catch (error) {
- console.error("Error fetching GitHub stars:", error);
+ console.error('Error fetching GitHub stars:', error)
return NextResponse.json(
- { error: "Internal server error" },
+ { error: 'Internal server error' },
{ status: 500 },
- );
+ )
}
}
-
diff --git a/apps/website/app/api/og/route.ts b/apps/website/app/api/og/route.ts
index 9883471..aafbde0 100644
--- a/apps/website/app/api/og/route.ts
+++ b/apps/website/app/api/og/route.ts
@@ -1,36 +1,36 @@
-import { getPost } from "@/lib/ghost";
-import { generateOGImage } from "@/lib/og-image";
-import type { NextRequest } from "next/server";
+import { getPost } from '@/lib/ghost'
+import { generateOGImage } from '@/lib/og-image'
+import type { NextRequest } from 'next/server'
export async function GET(request: NextRequest) {
try {
- const { searchParams } = new URL(request.url);
- const slug = searchParams.get("slug");
+ const { searchParams } = new URL(request.url)
+ const slug = searchParams.get('slug')
- console.log("Generating OG image for slug:", slug);
+ console.log('Generating OG image for slug:', slug)
if (!slug) {
- console.error("Missing slug parameter");
- return new Response("Missing slug parameter", { status: 400 });
+ console.error('Missing slug parameter')
+ return new Response('Missing slug parameter', { status: 400 })
}
- const post = await getPost(slug);
+ const post = await getPost(slug)
if (!post) {
- console.error("Post not found for slug:", slug);
- return new Response("Post not found", { status: 404 });
+ console.error('Post not found for slug:', slug)
+ return new Response('Post not found', { status: 404 })
}
- console.log("Found post:", post.title);
+ console.log('Found post:', post.title)
const formattedDate = new Date(post.published_at).toLocaleDateString(
- "en-US",
+ 'en-US',
{
- year: "numeric",
- month: "long",
- day: "numeric",
+ year: 'numeric',
+ month: 'long',
+ day: 'numeric',
},
- );
+ )
const ogImage = await generateOGImage({
title: post.title,
@@ -42,18 +42,18 @@ export async function GET(request: NextRequest) {
: undefined,
date: formattedDate,
readingTime: post.reading_time,
- });
+ })
- console.log("Successfully generated OG image");
+ console.log('Successfully generated OG image')
return new Response(ogImage, {
headers: {
- "Content-Type": "image/png",
- "Cache-Control": "public, max-age=31536000, immutable",
+ 'Content-Type': 'image/png',
+ 'Cache-Control': 'public, max-age=31536000, immutable',
},
- });
+ })
} catch (error) {
- console.error("Error generating OG image:", error);
- return new Response(`Error generating image: ${error}`, { status: 500 });
+ console.error('Error generating OG image:', error)
+ return new Response(`Error generating image: ${error}`, { status: 500 })
}
}
diff --git a/apps/website/app/blog/[slug]/components/CodeBlock.tsx b/apps/website/app/blog/[slug]/components/CodeBlock.tsx
index da8be4e..ac8ea91 100644
--- a/apps/website/app/blog/[slug]/components/CodeBlock.tsx
+++ b/apps/website/app/blog/[slug]/components/CodeBlock.tsx
@@ -1,39 +1,39 @@
-"use client";
+'use client'
-import { CopyButton } from "@/components/ui/copy-button";
-import * as babel from "prettier/plugins/babel";
-import * as estree from "prettier/plugins/estree";
-import * as yaml from "prettier/plugins/yaml";
-import * as prettier from "prettier/standalone";
-import { type JSX, useLayoutEffect, useState } from "react";
-import type { BundledLanguage } from "shiki/bundle/web";
-import { highlight } from "./shared";
+import { CopyButton } from '@/components/ui/copy-button'
+import * as babel from 'prettier/plugins/babel'
+import * as estree from 'prettier/plugins/estree'
+import * as yaml from 'prettier/plugins/yaml'
+import * as prettier from 'prettier/standalone'
+import { type JSX, useLayoutEffect, useState } from 'react'
+import type { BundledLanguage } from 'shiki/bundle/web'
+import { highlight } from './shared'
interface CodeBlockProps {
- code: string;
- lang: BundledLanguage;
- initial?: JSX.Element;
+ code: string
+ lang: BundledLanguage
+ initial?: JSX.Element
}
async function formatCode(code: string, lang: string) {
try {
- let parser: string;
- let plugins = [] as any[];
+ let parser: string
+ let plugins = [] as any[]
switch (lang.toLowerCase()) {
- case "yaml":
- case "yml":
- parser = "yaml";
- plugins = [yaml];
- break;
- case "javascript":
- case "typescript":
- case "jsx":
- case "tsx":
- parser = "babel-ts";
- plugins = [babel, estree];
- break;
+ case 'yaml':
+ case 'yml':
+ parser = 'yaml'
+ plugins = [yaml]
+ break
+ case 'javascript':
+ case 'typescript':
+ case 'jsx':
+ case 'tsx':
+ parser = 'babel-ts'
+ plugins = [babel, estree]
+ break
default:
- return code;
+ return code
}
const formatted = await prettier.format(code, {
parser,
@@ -43,50 +43,50 @@ async function formatCode(code: string, lang: string) {
tabWidth: 2,
useTabs: false,
printWidth: 120,
- });
- return formatted;
+ })
+ return formatted
} catch (error) {
- console.error("Error formatting code:", error);
- return code;
+ console.error('Error formatting code:', error)
+ return code
}
}
export function CodeBlock({ code, lang, initial }: CodeBlockProps) {
- const [nodes, setNodes] = useState(initial);
- const [formattedCode, setFormattedCode] = useState(code);
+ const [nodes, setNodes] = useState(initial)
+ const [formattedCode, setFormattedCode] = useState(code)
useLayoutEffect(() => {
async function formatAndHighlight() {
try {
- const formatted = await formatCode(code, lang);
- setFormattedCode(formatted);
- const highlighted = await highlight(formatted, lang);
- setNodes(highlighted);
+ const formatted = await formatCode(code, lang)
+ setFormattedCode(formatted)
+ const highlighted = await highlight(formatted, lang)
+ setNodes(highlighted)
} catch (error) {
- const highlighted = await highlight(code, lang);
- setNodes(highlighted);
+ const highlighted = await highlight(code, lang)
+ setNodes(highlighted)
}
}
- void formatAndHighlight();
- }, [code, lang]);
+ void formatAndHighlight()
+ }, [code, lang])
if (!nodes) {
return (