Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/create-pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout Repository
uses: actions/checkout@v4
uses: actions/checkout@v6
with:
fetch-depth: 0

Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ jobs:

steps:
- name: Checkout repository
uses: actions/checkout@v3
uses: actions/checkout@v6

- name: Log in to Docker Hub
uses: docker/login-action@v2
Expand All @@ -38,7 +38,7 @@ jobs:

steps:
- name: Checkout repository
uses: actions/checkout@v3
uses: actions/checkout@v6

- name: Log in to Docker Hub
uses: docker/login-action@v2
Expand All @@ -61,7 +61,7 @@ jobs:

steps:
- name: Checkout repository
uses: actions/checkout@v3
uses: actions/checkout@v6

- name: Log in to Docker Hub
uses: docker/login-action@v2
Expand Down
8 changes: 4 additions & 4 deletions .github/workflows/dokploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ jobs:
runs-on: ubuntu-22.04
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v6

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
Expand Down Expand Up @@ -53,7 +53,7 @@ jobs:
runs-on: ubuntu-24.04-arm
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v6

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
Expand Down Expand Up @@ -96,7 +96,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v6

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
Expand Down Expand Up @@ -140,7 +140,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v6
with:
fetch-depth: 0

Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/format.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
uses: actions/checkout@v6

- name: Setup biomeJs
uses: biomejs/setup-biome@v2
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/monitoring.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ jobs:
runs-on: ubuntu-22.04
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v6

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
Expand Down Expand Up @@ -47,7 +47,7 @@ jobs:
runs-on: ubuntu-24.04-arm
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v6

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
Expand Down Expand Up @@ -84,7 +84,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v6

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/pull-request.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ jobs:
matrix:
job: [build, test, typecheck]
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- uses: pnpm/action-setup@v4
- uses: actions/setup-node@v4
- uses: actions/setup-node@v6
with:
node-version: 20.16.0
cache: "pnpm"
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/sync-openapi-docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,11 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout Dokploy repository
uses: actions/checkout@v4
uses: actions/checkout@v6
with:
token: ${{ secrets.GITHUB_TOKEN }}
- uses: pnpm/action-setup@v4
- uses: actions/setup-node@v4
- uses: actions/setup-node@v6
with:
node-version: 20.16.0
cache: "pnpm"
Expand Down
4 changes: 4 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install --frozen-lockfile
# Deploy only the dokploy app

ENV NODE_ENV=production
# Build-time only: use localhost to prevent slow DNS timeouts during Next.js static generation.
# These are NOT baked into the bundle (excluded in esbuild.config.ts) and do NOT persist to the final image stage.
ENV DATABASE_URL="postgres://dokploy:build@127.0.0.1:5432/dokploy"
ENV REDIS_HOST="127.0.0.1"
RUN pnpm --filter=@dokploy/server build
RUN pnpm --filter=./apps/dokploy run build

Expand Down
23 changes: 23 additions & 0 deletions apps/dokploy/.env.example
Original file line number Diff line number Diff line change
@@ -1,3 +1,26 @@
DATABASE_URL="postgres://dokploy:amukds4wi9001583845717ad2@localhost:5432/dokploy"
PORT=3000
NODE_ENV=development

# --- External PostgreSQL (optional) ---
# Set DATABASE_URL to point to your external PostgreSQL instance.
# When it points to a host other than 'dokploy-postgres', the built-in
# Docker Swarm Postgres service will NOT be created during setup.
# DATABASE_URL="postgres://user:password@your-postgres-host:5432/dokploy"

# Alternative: use Docker Secrets for the password
# POSTGRES_PASSWORD_FILE=/run/secrets/postgres_password
# POSTGRES_USER=dokploy
# POSTGRES_DB=dokploy
# POSTGRES_HOST=your-postgres-host
# POSTGRES_PORT=5432

# --- External Redis (optional) ---
# Set REDIS_URL to point to your external Redis instance.
# When set, the built-in Docker Swarm Redis service will NOT be created.
# REDIS_URL="redis://:password@your-redis-host:6379"

# Or configure individual Redis params:
# REDIS_HOST=your-redis-host
# REDIS_PORT=6379
# REDIS_PASSWORD=your-redis-password
12 changes: 11 additions & 1 deletion apps/dokploy/.env.production.example
Original file line number Diff line number Diff line change
@@ -1,2 +1,12 @@
PORT=3000
NODE_ENV=production
NODE_ENV=production

# --- External PostgreSQL (optional) ---
# DATABASE_URL="postgres://user:password@your-postgres-host:5432/dokploy"
# POSTGRES_PASSWORD_FILE=/run/secrets/postgres_password

# --- External Redis (optional) ---
# REDIS_URL="redis://:password@your-redis-host:6379"
# REDIS_HOST=your-redis-host
# REDIS_PORT=6379
# REDIS_PASSWORD=your-redis-password
16 changes: 14 additions & 2 deletions apps/dokploy/esbuild.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,22 @@ const result = dotenv.config({ path: ".env.production" });

function prepareDefine(config: DotenvParseOutput | undefined) {
const define = {};
// These environment variables must resolve at runtime, not build time
const runtimeEnvVars = new Set([
"DATABASE_URL",
"REDIS_URL",
"REDIS_HOST",
"REDIS_PORT",
"REDIS_PASSWORD",
"POSTGRES_PASSWORD_FILE",
"POSTGRES_USER",
"POSTGRES_DB",
"POSTGRES_HOST",
"POSTGRES_PORT",
]);
// @ts-ignore
for (const [key, value] of Object.entries(config)) {
// Skip DATABASE_URL to allow runtime environment variable override
if (key === "DATABASE_URL") {
if (runtimeEnvVars.has(key)) {
continue;
}
// @ts-ignore
Expand Down
10 changes: 10 additions & 0 deletions apps/dokploy/server/api/routers/settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {
getUpdateData,
getWebServerSettings,
IS_CLOUD,
isExternalRedis,
parseRawConfig,
paths,
prepareEnvironmentVariables,
Expand Down Expand Up @@ -96,6 +97,10 @@ export const settingsRouter = createTRPCRouter({
return true;
}

if (isExternalRedis()) {
throw new Error("Cannot flush external Redis from Dokploy. Please use your Redis provider's management tools.");
}

const { stdout: containerId } = await execAsync(
`docker ps --filter "name=dokploy-redis" --filter "status=running" -q | head -n 1`,
);
Expand All @@ -113,6 +118,11 @@ export const settingsRouter = createTRPCRouter({
if (IS_CLOUD) {
return true;
}

if (isExternalRedis()) {
throw new Error("Cannot reload external Redis from Dokploy. Please use your Redis provider's management tools.");
}

await reloadDockerResource("dokploy-redis");

return true;
Expand Down
41 changes: 37 additions & 4 deletions apps/dokploy/server/queues/redis-connection.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,41 @@
import type { ConnectionOptions } from "bullmq";

export const redisConfig: ConnectionOptions = {
host:
function buildRedisConfig(): ConnectionOptions {
const redisUrl = process.env.REDIS_URL;
if (redisUrl) {
try {
const url = new URL(redisUrl);
return {
host: url.hostname,
port: Number(url.port) || 6379,
...(url.password && { password: decodeURIComponent(url.password) }),
...(url.username &&
url.username !== "" && {
username: decodeURIComponent(url.username),
}),
...(url.protocol === "rediss:" && { tls: {} }),
};
} catch {
console.error(
"[redis-connection] Invalid REDIS_URL, falling back to defaults",
);
}
}

const host =
process.env.NODE_ENV === "production"
? process.env.REDIS_HOST || "dokploy-redis"
: "127.0.0.1",
};
: "127.0.0.1";

const port = Number(process.env.REDIS_PORT) || 6379;

return {
host,
port,
...(process.env.REDIS_PASSWORD && {
password: process.env.REDIS_PASSWORD,
}),
};
}

export const redisConfig: ConnectionOptions = buildRedisConfig();
Comment thread
VidhyaSanjeevi marked this conversation as resolved.
57 changes: 56 additions & 1 deletion packages/server/src/db/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ function readSecret(path: string): string {
}
export let dbUrl: string;
if (DATABASE_URL) {
// Compatibilidad legacy / overrides
dbUrl = DATABASE_URL;
} else if (POSTGRES_PASSWORD_FILE) {
const password = readSecret(POSTGRES_PASSWORD_FILE);
Expand All @@ -45,3 +44,59 @@ if (DATABASE_URL) {
"postgres://dokploy:amukds4wi9001583845717ad2@localhost:5432/dokploy";
}
}

const INTERNAL_DB_HOSTS = new Set(["dokploy-postgres", "localhost", "127.0.0.1"]);

/**
* Returns true when Dokploy is configured to use an external PostgreSQL
* instance (not the built-in Docker Swarm service or localhost dev).
*/
export const isExternalDatabase = (): boolean => {
try {
const url = new URL(dbUrl);
return !INTERNAL_DB_HOSTS.has(url.hostname);
} catch {
return false;
}
Comment thread
VidhyaSanjeevi marked this conversation as resolved.
};

/**
* Returns true when Dokploy is configured to use an external Redis
* instance (not the built-in Docker Swarm service).
*/
export const isExternalRedis = (): boolean => {
return !!(process.env.REDIS_URL || (process.env.REDIS_HOST && process.env.REDIS_HOST !== "dokploy-redis"));
};

export interface PostgresCredentials {
user: string;
database: string;
host: string;
port: string;
password: string;
}

/**
* Parses PostgreSQL credentials from the resolved database URL.
* Shared by backup and restore code paths.
*/
export const getPostgresCredentials = (): PostgresCredentials => {
try {
const url = new URL(dbUrl);
return {
user: decodeURIComponent(url.username) || POSTGRES_USER || "dokploy",
database: url.pathname.replace(/^\//, "") || POSTGRES_DB || "dokploy",
host: url.hostname,
port: url.port || "5432",
password: decodeURIComponent(url.password),
};
} catch {
return {
user: POSTGRES_USER || "dokploy",
database: POSTGRES_DB || "dokploy",
host: "dokploy-postgres",
port: "5432",
password: "",
};
}
};
5 changes: 5 additions & 0 deletions packages/server/src/setup/postgres-setup.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
import type { CreateServiceOptions } from "dockerode";
import { docker } from "../constants";
import { isExternalDatabase } from "../db/constants";
import { pullImage } from "../utils/docker/utils";
export const initializePostgres = async () => {
if (isExternalDatabase()) {
console.log("Using external PostgreSQL — skipping built-in Postgres service ✅");
return;
}
const imageName = "postgres:16";
const containerName = "dokploy-postgres";
const settings: CreateServiceOptions = {
Expand Down
5 changes: 5 additions & 0 deletions packages/server/src/setup/redis-setup.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
import type { CreateServiceOptions } from "dockerode";
import { docker } from "../constants";
import { isExternalRedis } from "../db/constants";
import { pullImage } from "../utils/docker/utils";

export const initializeRedis = async () => {
if (isExternalRedis()) {
console.log("Using external Redis — skipping built-in Redis service ✅");
return;
}
const imageName = "redis:7";
const containerName = "dokploy-redis";

Expand Down
Loading