From 021d957016eae3d9621851edb621255b904a3339 Mon Sep 17 00:00:00 2001
From: Yuki <60097976+binaryYuki@users.noreply.github.com>
Date: Sat, 21 Dec 2024 12:59:07 +0000
Subject: [PATCH 1/2] Enhance security by changing default host and adding
rate-limiting
Enhance server security by defaulting to 127.0.0.1:3000 and adding rate-limiting.
* Change the default host to `127.0.0.1` in `apps/api/src/index.ts` and `apps/dokploy/server/server.ts`.
* Add a rate-limiting middleware to the `app` instance in `apps/api/src/index.ts`.
* Introduce an environment variable `EXPOSE_ALL_INTERFACES` to toggle exposing `0.0.0.0` in `apps/dokploy/server/server.ts` and `apps/dokploy/.env.example`.
* Add a toggle for `EXPOSE_ALL_INTERFACES` in the `WebServer` component in `apps/dokploy/components/dashboard/settings/web-server.tsx` with a warning about the associated risks.
---
apps/api/src/index.ts | 12 +++++++-
apps/dokploy/.env.example | 3 +-
.../dashboard/settings/web-server.tsx | 28 ++++++++++++++++++-
apps/dokploy/server/server.ts | 3 +-
4 files changed, 42 insertions(+), 4 deletions(-)
diff --git a/apps/api/src/index.ts b/apps/api/src/index.ts
index bf91b0400..7fe8cfe8d 100644
--- a/apps/api/src/index.ts
+++ b/apps/api/src/index.ts
@@ -7,12 +7,21 @@ import { createClient } from "redis";
import { logger } from "./logger";
import { type DeployJob, deployJobSchema } from "./schema";
import { deploy } from "./utils";
+import rateLimit from "express-rate-limit";
const app = new Hono();
const redisClient = createClient({
url: process.env.REDIS_URL,
});
+const limiter = rateLimit({
+ windowMs: 15 * 60 * 1000, // 15 minutes
+ max: 100, // limit each IP to 100 requests per windowMs
+ message: "Too many requests from this IP, please try again later.",
+});
+
+app.use(limiter);
+
app.use(async (c, next) => {
if (c.req.path === "/health") {
return next();
@@ -57,5 +66,6 @@ const queue = new Queue({
})();
const port = Number.parseInt(process.env.PORT || "3000");
+const host = process.env.EXPOSE_ALL_INTERFACES === "true" ? "0.0.0.0" : "127.0.0.1";
logger.info("Starting Deployments Server ✅", port);
-serve({ fetch: app.fetch, port });
+serve({ fetch: app.fetch, port, host });
diff --git a/apps/dokploy/.env.example b/apps/dokploy/.env.example
index ba57ec7be..acb49c7f8 100644
--- a/apps/dokploy/.env.example
+++ b/apps/dokploy/.env.example
@@ -1,3 +1,4 @@
DATABASE_URL="postgres://dokploy:amukds4wi9001583845717ad2@localhost:5432/dokploy"
PORT=3000
-NODE_ENV=development
\ No newline at end of file
+NODE_ENV=development
+EXPOSE_ALL_INTERFACES=false
diff --git a/apps/dokploy/components/dashboard/settings/web-server.tsx b/apps/dokploy/components/dashboard/settings/web-server.tsx
index 2ac88d9ae..14ba736c0 100644
--- a/apps/dokploy/components/dashboard/settings/web-server.tsx
+++ b/apps/dokploy/components/dashboard/settings/web-server.tsx
@@ -8,12 +8,14 @@ import {
import { cn } from "@/lib/utils";
import { api } from "@/utils/api";
import { useTranslation } from "next-i18next";
-import React from "react";
+import React, { useState } from "react";
import { ShowDokployActions } from "./servers/actions/show-dokploy-actions";
import { ShowStorageActions } from "./servers/actions/show-storage-actions";
import { ShowTraefikActions } from "./servers/actions/show-traefik-actions";
import { ToggleDockerCleanup } from "./servers/actions/toggle-docker-cleanup";
import { UpdateServer } from "./web-server/update-server";
+import { Switch } from "@/components/ui/switch";
+import { Alert } from "@/components/ui/alert";
interface Props {
className?: string;
@@ -24,6 +26,14 @@ export const WebServer = ({ className }: Props) => {
const { data: dokployVersion } = api.settings.getDokployVersion.useQuery();
+ const [exposeAllInterfaces, setExposeAllInterfaces] = useState(
+ process.env.EXPOSE_ALL_INTERFACES === "true"
+ );
+
+ const handleToggleChange = () => {
+ setExposeAllInterfaces(!exposeAllInterfaces);
+ };
+
return (