Merge pull request #25 from Dokploy/canary

Main release
This commit is contained in:
Mauricio Siu
2024-05-01 21:40:40 -06:00
committed by GitHub
53 changed files with 575 additions and 298 deletions

5
.dockerignore Normal file
View File

@@ -0,0 +1,5 @@
node_modules
.git
.gitignore
*.md
dist

3
.env.production.example Normal file
View File

@@ -0,0 +1,3 @@
DATABASE_URL="postgres://dokploy:amukds4wi9001583845717ad2@dokploy-postgres:5432/dokploy"
PORT=3000
NODE_ENV=production

View File

@@ -3,8 +3,15 @@ on:
pull_request:
branches:
- main
- canary
push:
branches:
- main
- canary
jobs:
build:
build-app:
if: github.event_name == 'pull_request'
runs-on: ubuntu-20.04
strategy:
matrix:
@@ -22,4 +29,53 @@ jobs:
- name: Install dependencies
run: pnpm install
- name: Run Build
run: pnpm build
run: pnpm build
build-docker-on-pr:
if: github.event_name == 'pull_request'
needs: build-app
runs-on: ubuntu-latest
steps:
- name: Check out the code
uses: actions/checkout@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Prepare .env file
run: |
cp .env.production.example .env.production
- name: Run custom Docker build script
run: |
chmod +x ./docker/build.sh
echo "Building Docker image for ${{ github.base_ref }}"
./docker/build.sh ${{ github.base_ref == 'canary' && 'canary' || '' }}
build-and-push-docker-on-push:
if: github.event_name == 'push'
runs-on: ubuntu-latest
steps:
- name: Check out the code
uses: actions/checkout@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Prepare .env file
run: |
cp .env.production.example .env.production
- name: Build and push Docker image using custom script
run: |
chmod +x ./docker/build.sh
chmod +x ./docker/push.sh
./docker/build.sh ${{ github.ref_name == 'canary' && 'canary' || '' }}
./docker/push.sh ${{ github.ref_name == 'canary' && 'canary' || '' }}

2
.gitignore vendored
View File

@@ -6,6 +6,8 @@
.pnp.js
/redis-data
traefik.yml
.docker
.env.production
# testing
/coverage

View File

@@ -49,12 +49,16 @@ feat: add new feature
```
## Setup
Before you start, please make the clone based on the `canary` branch, since the `main` branch is the source of truth and should always reflect the latest stable release, also the PRs will be merged to the `canary` branch.
```bash
git clone https://github.com/dokploy/dokploy.git
cd dokploy
npm install
pnpm install
cp .env.example .env
```
@@ -62,28 +66,40 @@ cp .env.example .env
Is required to have **Docker** installed on your machine.
### Setup
Run the command that will spin up all the required services and files.
```bash
npm run dev
pnpm run setup
```
Now run the development server.
```bash
pnpm run dev
```
Go to http://localhost:3000 to see the development server
## Build
```bash
npm run build
pnpm run build
```
## Docker
To build the docker image
```bash
npm run docker:build
pnpm run docker:build
```
To push the docker image
```bash
npm run docker:push
pnpm run docker:push
```
## Password Reset

View File

@@ -65,7 +65,7 @@ export const Login2FA = ({ authId }: Props) => {
duration: 2000,
});
push("/dashboard");
push("/dashboard/projects");
})
.catch(() => {
toast.error("Signin failed", {

View File

@@ -21,19 +21,19 @@ import { api } from "@/utils/api";
import { toast } from "sonner";
import { Textarea } from "@/components/ui/textarea";
const addEnviromentSchema = z.object({
enviroment: z.string(),
const addEnvironmentSchema = z.object({
environment: z.string(),
});
type EnviromentSchema = z.infer<typeof addEnviromentSchema>;
type EnvironmentSchema = z.infer<typeof addEnvironmentSchema>;
interface Props {
applicationId: string;
}
export const ShowEnviroment = ({ applicationId }: Props) => {
export const ShowEnvironment = ({ applicationId }: Props) => {
const { mutateAsync, isLoading } =
api.application.saveEnviroment.useMutation();
api.application.saveEnvironment.useMutation();
const { data, refetch } = api.application.one.useQuery(
{
@@ -43,32 +43,32 @@ export const ShowEnviroment = ({ applicationId }: Props) => {
enabled: !!applicationId,
},
);
const form = useForm<EnviromentSchema>({
const form = useForm<EnvironmentSchema>({
defaultValues: {
enviroment: "",
environment: "",
},
resolver: zodResolver(addEnviromentSchema),
resolver: zodResolver(addEnvironmentSchema),
});
useEffect(() => {
if (data) {
form.reset({
enviroment: data.env || "",
environment: data.env || "",
});
}
}, [form.reset, data, form]);
const onSubmit = async (data: EnviromentSchema) => {
const onSubmit = async (data: EnvironmentSchema) => {
mutateAsync({
env: data.enviroment,
env: data.environment,
applicationId,
})
.then(async () => {
toast.success("Enviroments Added");
toast.success("Environments Added");
await refetch();
})
.catch(() => {
toast.error("Error to add enviroment");
toast.error("Error to add environment");
});
};
@@ -76,9 +76,9 @@ export const ShowEnviroment = ({ applicationId }: Props) => {
<div className="flex w-full flex-col gap-5 ">
<Card className="bg-background">
<CardHeader>
<CardTitle className="text-xl">Enviroment Settings</CardTitle>
<CardTitle className="text-xl">Environment Settings</CardTitle>
<CardDescription>
You can add enviroment variables to your resource.
You can add environment variables to your resource.
</CardDescription>
</CardHeader>
<CardContent>
@@ -90,7 +90,7 @@ export const ShowEnviroment = ({ applicationId }: Props) => {
>
<FormField
control={form.control}
name="enviroment"
name="environment"
render={({ field }) => (
<FormItem className="w-full">
<FormControl>

View File

@@ -21,18 +21,18 @@ import { api } from "@/utils/api";
import { toast } from "sonner";
import { Textarea } from "@/components/ui/textarea";
const addEnviromentSchema = z.object({
enviroment: z.string(),
const addEnvironmentSchema = z.object({
environment: z.string(),
});
type EnviromentSchema = z.infer<typeof addEnviromentSchema>;
type EnvironmentSchema = z.infer<typeof addEnvironmentSchema>;
interface Props {
mariadbId: string;
}
export const ShowMariadbEnviroment = ({ mariadbId }: Props) => {
const { mutateAsync, isLoading } = api.mariadb.saveEnviroment.useMutation();
export const ShowMariadbEnvironment = ({ mariadbId }: Props) => {
const { mutateAsync, isLoading } = api.mariadb.saveEnvironment.useMutation();
const { data, refetch } = api.mariadb.one.useQuery(
{
@@ -42,32 +42,32 @@ export const ShowMariadbEnviroment = ({ mariadbId }: Props) => {
enabled: !!mariadbId,
},
);
const form = useForm<EnviromentSchema>({
const form = useForm<EnvironmentSchema>({
defaultValues: {
enviroment: "",
environment: "",
},
resolver: zodResolver(addEnviromentSchema),
resolver: zodResolver(addEnvironmentSchema),
});
useEffect(() => {
if (data) {
form.reset({
enviroment: data.env || "",
environment: data.env || "",
});
}
}, [form.reset, data, form]);
const onSubmit = async (data: EnviromentSchema) => {
const onSubmit = async (data: EnvironmentSchema) => {
mutateAsync({
env: data.enviroment,
env: data.environment,
mariadbId,
})
.then(async () => {
toast.success("Enviroments Added");
toast.success("Environments Added");
await refetch();
})
.catch(() => {
toast.error("Error to add enviroment");
toast.error("Error to add environment");
});
};
@@ -75,9 +75,9 @@ export const ShowMariadbEnviroment = ({ mariadbId }: Props) => {
<div className="flex w-full flex-col gap-5 ">
<Card className="bg-background">
<CardHeader>
<CardTitle className="text-xl">Enviroment Settings</CardTitle>
<CardTitle className="text-xl">Environment Settings</CardTitle>
<CardDescription>
You can add enviroment variables to your database.
You can add environment variables to your database.
</CardDescription>
</CardHeader>
<CardContent>
@@ -89,7 +89,7 @@ export const ShowMariadbEnviroment = ({ mariadbId }: Props) => {
>
<FormField
control={form.control}
name="enviroment"
name="environment"
render={({ field }) => (
<FormItem className="w-full">
<FormControl>

View File

@@ -21,18 +21,18 @@ import { useForm } from "react-hook-form";
import { toast } from "sonner";
import { z } from "zod";
const addEnviromentSchema = z.object({
enviroment: z.string(),
const addEnvironmentSchema = z.object({
environment: z.string(),
});
type EnviromentSchema = z.infer<typeof addEnviromentSchema>;
type EnvironmentSchema = z.infer<typeof addEnvironmentSchema>;
interface Props {
mongoId: string;
}
export const ShowMongoEnviroment = ({ mongoId }: Props) => {
const { mutateAsync, isLoading } = api.mongo.saveEnviroment.useMutation();
export const ShowMongoEnvironment = ({ mongoId }: Props) => {
const { mutateAsync, isLoading } = api.mongo.saveEnvironment.useMutation();
const { data, refetch } = api.mongo.one.useQuery(
{
@@ -42,32 +42,32 @@ export const ShowMongoEnviroment = ({ mongoId }: Props) => {
enabled: !!mongoId,
},
);
const form = useForm<EnviromentSchema>({
const form = useForm<EnvironmentSchema>({
defaultValues: {
enviroment: "",
environment: "",
},
resolver: zodResolver(addEnviromentSchema),
resolver: zodResolver(addEnvironmentSchema),
});
useEffect(() => {
if (data) {
form.reset({
enviroment: data.env || "",
environment: data.env || "",
});
}
}, [form.reset, data, form]);
const onSubmit = async (data: EnviromentSchema) => {
const onSubmit = async (data: EnvironmentSchema) => {
mutateAsync({
env: data.enviroment,
env: data.environment,
mongoId,
})
.then(async () => {
toast.success("Enviroments Added");
toast.success("Environments Added");
await refetch();
})
.catch(() => {
toast.error("Error to add enviroment");
toast.error("Error to add environment");
});
};
@@ -75,9 +75,9 @@ export const ShowMongoEnviroment = ({ mongoId }: Props) => {
<div className="flex w-full flex-col gap-5 ">
<Card className="bg-background">
<CardHeader>
<CardTitle className="text-xl">Enviroment Settings</CardTitle>
<CardTitle className="text-xl">Environment Settings</CardTitle>
<CardDescription>
You can add enviroment variables to your database.
You can add environment variables to your database.
</CardDescription>
</CardHeader>
<CardContent>
@@ -89,7 +89,7 @@ export const ShowMongoEnviroment = ({ mongoId }: Props) => {
>
<FormField
control={form.control}
name="enviroment"
name="environment"
render={({ field }) => (
<FormItem className="w-full">
<FormControl>

View File

@@ -21,18 +21,18 @@ import { api } from "@/utils/api";
import { toast } from "sonner";
import { Textarea } from "@/components/ui/textarea";
const addEnviromentSchema = z.object({
enviroment: z.string(),
const addEnvironmentSchema = z.object({
environment: z.string(),
});
type EnviromentSchema = z.infer<typeof addEnviromentSchema>;
type EnvironmentSchema = z.infer<typeof addEnvironmentSchema>;
interface Props {
mysqlId: string;
}
export const ShowMysqlEnviroment = ({ mysqlId }: Props) => {
const { mutateAsync, isLoading } = api.mysql.saveEnviroment.useMutation();
export const ShowMysqlEnvironment = ({ mysqlId }: Props) => {
const { mutateAsync, isLoading } = api.mysql.saveEnvironment.useMutation();
const { data, refetch } = api.mysql.one.useQuery(
{
@@ -42,32 +42,32 @@ export const ShowMysqlEnviroment = ({ mysqlId }: Props) => {
enabled: !!mysqlId,
},
);
const form = useForm<EnviromentSchema>({
const form = useForm<EnvironmentSchema>({
defaultValues: {
enviroment: "",
environment: "",
},
resolver: zodResolver(addEnviromentSchema),
resolver: zodResolver(addEnvironmentSchema),
});
useEffect(() => {
if (data) {
form.reset({
enviroment: data.env || "",
environment: data.env || "",
});
}
}, [form.reset, data, form]);
const onSubmit = async (data: EnviromentSchema) => {
const onSubmit = async (data: EnvironmentSchema) => {
mutateAsync({
env: data.enviroment,
env: data.environment,
mysqlId,
})
.then(async () => {
toast.success("Enviroments Added");
toast.success("Environments Added");
await refetch();
})
.catch(() => {
toast.error("Error to add enviroment");
toast.error("Error to add environment");
});
};
@@ -75,9 +75,9 @@ export const ShowMysqlEnviroment = ({ mysqlId }: Props) => {
<div className="flex w-full flex-col gap-5 ">
<Card className="bg-background">
<CardHeader>
<CardTitle className="text-xl">Enviroment Settings</CardTitle>
<CardTitle className="text-xl">Environment Settings</CardTitle>
<CardDescription>
You can add enviroment variables to your database.
You can add environment variables to your database.
</CardDescription>
</CardHeader>
<CardContent>
@@ -89,7 +89,7 @@ export const ShowMysqlEnviroment = ({ mysqlId }: Props) => {
>
<FormField
control={form.control}
name="enviroment"
name="environment"
render={({ field }) => (
<FormItem className="w-full">
<FormControl>

View File

@@ -21,18 +21,18 @@ import { api } from "@/utils/api";
import { toast } from "sonner";
import { Textarea } from "@/components/ui/textarea";
const addEnviromentSchema = z.object({
enviroment: z.string(),
const addEnvironmentSchema = z.object({
environment: z.string(),
});
type EnviromentSchema = z.infer<typeof addEnviromentSchema>;
type EnvironmentSchema = z.infer<typeof addEnvironmentSchema>;
interface Props {
postgresId: string;
}
export const ShowPostgresEnviroment = ({ postgresId }: Props) => {
const { mutateAsync, isLoading } = api.postgres.saveEnviroment.useMutation();
export const ShowPostgresEnvironment = ({ postgresId }: Props) => {
const { mutateAsync, isLoading } = api.postgres.saveEnvironment.useMutation();
const { data, refetch } = api.postgres.one.useQuery(
{
@@ -42,32 +42,32 @@ export const ShowPostgresEnviroment = ({ postgresId }: Props) => {
enabled: !!postgresId,
},
);
const form = useForm<EnviromentSchema>({
const form = useForm<EnvironmentSchema>({
defaultValues: {
enviroment: "",
environment: "",
},
resolver: zodResolver(addEnviromentSchema),
resolver: zodResolver(addEnvironmentSchema),
});
useEffect(() => {
if (data) {
form.reset({
enviroment: data.env || "",
environment: data.env || "",
});
}
}, [form.reset, data, form]);
const onSubmit = async (data: EnviromentSchema) => {
const onSubmit = async (data: EnvironmentSchema) => {
mutateAsync({
env: data.enviroment,
env: data.environment,
postgresId,
})
.then(async () => {
toast.success("Enviroments Added");
toast.success("Environments Added");
await refetch();
})
.catch(() => {
toast.error("Error to add enviroment");
toast.error("Error to add environment");
});
};
@@ -75,9 +75,9 @@ export const ShowPostgresEnviroment = ({ postgresId }: Props) => {
<div className="flex w-full flex-col gap-5 ">
<Card className="bg-background">
<CardHeader>
<CardTitle className="text-xl">Enviroment Settings</CardTitle>
<CardTitle className="text-xl">Environment Settings</CardTitle>
<CardDescription>
You can add enviroment variables to your database.
You can add environment variables to your database.
</CardDescription>
</CardHeader>
<CardContent>
@@ -89,7 +89,7 @@ export const ShowPostgresEnviroment = ({ postgresId }: Props) => {
>
<FormField
control={form.control}
name="enviroment"
name="environment"
render={({ field }) => (
<FormItem className="w-full">
<FormControl>

View File

@@ -21,7 +21,8 @@ import { Textarea } from "@/components/ui/textarea";
import { api } from "@/utils/api";
import { zodResolver } from "@hookform/resolvers/zod";
import { AlertTriangle, PlusIcon } from "lucide-react";
import { useEffect } from "react";
import { useRouter } from "next/router";
import { useEffect, useState } from "react";
import { useForm } from "react-hook-form";
import { toast } from "sonner";
import { z } from "zod";
@@ -37,10 +38,9 @@ type AddProject = z.infer<typeof AddProjectSchema>;
export const AddProject = () => {
const utils = api.useUtils();
const { mutateAsync, isLoading, error, isError } =
api.project.create.useMutation();
const [isOpen, setIsOpen] = useState(false);
const { mutateAsync, error, isError } = api.project.create.useMutation();
const router = useRouter();
const form = useForm<AddProject>({
defaultValues: {
description: "",
@@ -61,16 +61,19 @@ export const AddProject = () => {
name: data.name,
description: data.description,
})
.then(async () => {
toast.success("Project Created");
.then(async (data) => {
await utils.project.all.invalidate();
toast.success("Project Created");
setIsOpen(false);
router.push(`/dashboard/project/${data.projectId}`);
})
.catch(() => {
toast.error("Error to create a project");
});
};
return (
<Dialog>
<Dialog open={isOpen} onOpenChange={setIsOpen}>
<DialogTrigger asChild>
<Button>
<PlusIcon className="h-4 w-4" />
@@ -134,7 +137,7 @@ export const AddProject = () => {
<DialogFooter>
<Button
isLoading={isLoading}
isLoading={form.formState.isSubmitting}
form="hook-form-add-project"
type="submit"
>

View File

@@ -21,18 +21,18 @@ import { api } from "@/utils/api";
import { toast } from "sonner";
import { Textarea } from "@/components/ui/textarea";
const addEnviromentSchema = z.object({
enviroment: z.string(),
const addEnvironmentSchema = z.object({
environment: z.string(),
});
type EnviromentSchema = z.infer<typeof addEnviromentSchema>;
type EnvironmentSchema = z.infer<typeof addEnvironmentSchema>;
interface Props {
redisId: string;
}
export const ShowRedisEnviroment = ({ redisId }: Props) => {
const { mutateAsync, isLoading } = api.redis.saveEnviroment.useMutation();
export const ShowRedisEnvironment = ({ redisId }: Props) => {
const { mutateAsync, isLoading } = api.redis.saveEnvironment.useMutation();
const { data, refetch } = api.redis.one.useQuery(
{
@@ -42,32 +42,32 @@ export const ShowRedisEnviroment = ({ redisId }: Props) => {
enabled: !!redisId,
},
);
const form = useForm<EnviromentSchema>({
const form = useForm<EnvironmentSchema>({
defaultValues: {
enviroment: "",
environment: "",
},
resolver: zodResolver(addEnviromentSchema),
resolver: zodResolver(addEnvironmentSchema),
});
useEffect(() => {
if (data) {
form.reset({
enviroment: data.env || "",
environment: data.env || "",
});
}
}, [form.reset, data, form]);
const onSubmit = async (data: EnviromentSchema) => {
const onSubmit = async (data: EnvironmentSchema) => {
mutateAsync({
env: data.enviroment,
env: data.environment,
redisId,
})
.then(async () => {
toast.success("Enviroments Added");
toast.success("Environments Added");
await refetch();
})
.catch(() => {
toast.error("Error to add enviroment");
toast.error("Error to add environment");
});
};
@@ -75,9 +75,9 @@ export const ShowRedisEnviroment = ({ redisId }: Props) => {
<div className="flex w-full flex-col gap-5 ">
<Card className="bg-background">
<CardHeader>
<CardTitle className="text-xl">Enviroment Settings</CardTitle>
<CardTitle className="text-xl">Environment Settings</CardTitle>
<CardDescription>
You can add enviroment variables to your database.
You can add environment variables to your database.
</CardDescription>
</CardHeader>
<CardContent>
@@ -89,7 +89,7 @@ export const ShowRedisEnviroment = ({ redisId }: Props) => {
>
<FormField
control={form.control}
name="enviroment"
name="environment"
render={({ field }) => (
<FormItem className="w-full">
<FormControl>

View File

@@ -31,6 +31,14 @@ export const generateName = () => {
n2[Math.round(Math.random() * (n2.length - 1))]
}`;
};
function slugify(text: string) {
return text
.toLowerCase()
.replace(/[\s\^&*()+=!]+/g, "-")
.replace(/[\$.,*+~()'"!:@^&]+/g, "")
.replace(/-+/g, "-")
.replace(/^-+|-+$/g, "");
}
export const GithubSetup = () => {
const [isOrganization, setIsOrganization] = useState(false);
@@ -98,12 +106,17 @@ export const GithubSetup = () => {
your GitHub account.
</span>
<Link
href={`https://github.com/apps/${data.githubAppName}/installations/new?state=gh_setup:${data?.authId}`}
className={buttonVariants({ className: "w-fit" })}
>
Install Github App
</Link>
<div className="flex flex-row gap-4">
<Link
href={`https://github.com/apps/${slugify(
data.githubAppName,
)}/installations/new?state=gh_setup:${data?.authId}`}
className={buttonVariants({ className: "w-fit" })}
>
Install Github App
</Link>
<RemoveGithubApp />
</div>
</div>
) : (
<div>

View File

@@ -39,6 +39,7 @@ export const RemoveGithubApp = () => {
await mutateAsync()
.then(async () => {
await refetch();
utils.admin.one.invalidate();
await utils.admin.haveGithubConfigured.invalidate();
toast.success("Github application deleted succesfully.");
})

View File

@@ -1,7 +1,18 @@
#!/bin/bash
VERSION=$(node -p "require('./package.json').version")
# Determine the type of build based on the first script argument
BUILD_TYPE=${1:-production}
docker build --platform linux/amd64 --pull --rm -f 'Dockerfile' -t "dokploy/dokploy:${VERSION}" .
if [ "$BUILD_TYPE" == "canary" ]; then
TAG="canary"
else
VERSION=$(node -p "require('./package.json').version")
TAG="$VERSION"
fi
docker tag "dokploy/dokploy:${VERSION}" "dokploy/dokploy:latest"
docker build --platform linux/amd64 --pull --rm -f 'Dockerfile' -t "dokploy/dokploy:${TAG}" .
if [ "$BUILD_TYPE" != "canary" ]; then
# Tag the production build as latest
docker tag "dokploy/dokploy:${TAG}" "dokploy/dokploy:latest"
fi

90
docker/canary.sh Normal file
View File

@@ -0,0 +1,90 @@
#!/bin/bash
if [ "$(id -u)" != "0" ]; then
echo "This script must be run as root" >&2
exit 1
fi
# check if is Mac OS
if [ "$(uname)" = "Darwin" ]; then
echo "This script must be run on Linux" >&2
exit 1
fi
# check if is running inside a container
if [ -f /.dockerenv ]; then
echo "This script must be run on Linux" >&2
exit 1
fi
# check if something is running on port 80
if ss -tulnp | grep ':80 ' >/dev/null; then
echo "Error: something is already running on port 80" >&2
exit 1
fi
# check if something is running on port 443
if ss -tulnp | grep ':443 ' >/dev/null; then
echo "Error: something is already running on port 443" >&2
exit 1
fi
command_exists() {
command -v "$@" > /dev/null 2>&1
}
if command_exists docker; then
echo "Docker already installed"
else
curl -sSL https://get.docker.com | sh
fi
docker swarm leave --force 2>/dev/null
docker swarm init --advertise-addr 127.0.0.1 --listen-addr 0.0.0.0;
echo "Swarm initialized"
docker network rm -f dokploy-network 2>/dev/null
docker network create --driver overlay --attachable dokploy-network
echo "Network created"
mkdir -p /etc/dokploy
chmod -R 777 /etc/dokploy
docker pull dokploy/dokploy:canary
# Installation
docker service create \
--name dokploy \
--replicas 1 \
--network dokploy-network \
--mount type=bind,source=/var/run/docker.sock,target=/var/run/docker.sock \
--mount type=bind,source=/etc/dokploy,target=/etc/dokploy \
--publish published=3000,target=3000,mode=host \
--update-parallelism 1 \
--update-order stop-first \
-e RELEASE_TAG=canary \
dokploy/dokploy:canary
public_ip=$(hostname -I | awk '{print $1}')
GREEN="\033[0;32m"
YELLOW="\033[1;33m"
BLUE="\033[0;34m"
NC="\033[0m" # No Color
echo ""
printf "${GREEN}Congratulations, Dokploy is installed!${NC}\n"
printf "${BLUE}Wait 15 seconds for the server to start${NC}\n"
printf "${YELLOW}Please go to http://${public_ip}:3000${NC}\n\n"
echo ""

View File

@@ -19,39 +19,21 @@ if [ -f /.dockerenv ]; then
fi
# check if something is running on port 80
if lsof -i :80 >/dev/null; then
if ss -tulnp | grep ':80 ' >/dev/null; then
echo "Error: something is already running on port 80" >&2
exit 1
fi
# check if something is running on port 443
if lsof -i :443 >/dev/null; then
if ss -tulnp | grep ':443 ' >/dev/null; then
echo "Error: something is already running on port 443" >&2
exit 1
fi
# Network
network_exists=$(docker network ls | grep dokploy-network)
if [ -z "$network_exists" ]; then
docker network create --driver overlay --attachable dokploy-network
echo "Network was initialized"
else
echo "Network is already initialized"
fi
# Swarm
swarm_status=$(docker info --format '{{.Swarm.LocalNodeState}}')
if [ "$swarm_status" = "active" ]; then
docker swarm leave --force 1> /dev/null 2> /dev/null || true
echo "Swarm is already initialized"
else
docker swarm init --advertise-addr 127.0.0.1 --listen-addr 0.0.0.0
echo "Swarm was initialized"
fi
command_exists() {
command -v "$@" > /dev/null 2>&1
@@ -63,6 +45,20 @@ else
curl -sSL https://get.docker.com | sh
fi
docker swarm leave --force 2>/dev/null
docker swarm init --advertise-addr 127.0.0.1 --listen-addr 0.0.0.0;
echo "Swarm initialized"
docker network rm -f dokploy-network 2>/dev/null
docker network create --driver overlay --attachable dokploy-network
echo "Network created"
mkdir -p /etc/dokploy
chmod -R 777 /etc/dokploy
docker pull dokploy/dokploy:latest
# Installation
@@ -75,4 +71,19 @@ docker service create \
--publish published=3000,target=3000,mode=host \
--update-parallelism 1 \
--update-order stop-first \
dokploy/dokploy:latest
dokploy/dokploy:latest
public_ip=$(hostname -I | awk '{print $1}')
GREEN="\033[0;32m"
YELLOW="\033[1;33m"
BLUE="\033[0;34m"
NC="\033[0m" # No Color
echo ""
printf "${GREEN}Congratulations, Dokploy is installed!${NC}\n"
printf "${BLUE}Wait 15 seconds for the server to start${NC}\n"
printf "${YELLOW}Please go to http://${public_ip}:3000${NC}\n\n"
echo ""

View File

@@ -1,6 +1,15 @@
#!/bin/bash
VERSION=$(node -p "require('./package.json').version")
# Determine the type of build based on the first script argument
BUILD_TYPE=${1:-production}
docker push "dokploy/dokploy:${VERSION}"
docker push "dokploy/dokploy:latest"
if [ "$BUILD_TYPE" == "canary" ]; then
TAG="canary"
echo PUSHING CANARY
docker push "dokploy/dokploy:${TAG}"
else
echo "PUSHING PRODUCTION"
VERSION=$(node -p "require('./package.json').version")
docker push "dokploy/dokploy:${VERSION}"
docker push "dokploy/dokploy:latest"
fi

20
migration.ts Normal file
View File

@@ -0,0 +1,20 @@
import { drizzle } from "drizzle-orm/postgres-js";
import { migrate } from "drizzle-orm/postgres-js/migrator";
import postgres from "postgres";
const connectionString = process.env.DATABASE_URL || "";
const sql = postgres(connectionString, { max: 1 });
const db = drizzle(sql);
await migrate(db, { migrationsFolder: "drizzle" })
.then(() => {
console.log("Migration complete");
sql.end();
})
.catch((error) => {
console.log("Migration failed", error);
})
.finally(() => {
sql.end();
});

View File

@@ -9,18 +9,22 @@
"start": "node dist/server.mjs",
"build-server": "tsx esbuild.config.ts",
"build-next": "next build",
"setup": "tsx -r dotenv/config setup.ts && sleep 5 && pnpm run migration:run",
"reset-password": "node dist/reset-password.mjs",
"dev": "tsx watch -r dotenv/config ./server/server.ts --project tsconfig.server.json ",
"migration:generate": "drizzle-kit generate:pg --config ./server/db/drizzle.config.ts",
"migration:run": "tsx -r dotenv/config migration.ts",
"migration:drop": "drizzle-kit drop --config ./server/db/drizzle.config.ts",
"db:push": "drizzle-kit push:pg --config ./server/db/drizzle.config.ts",
"db:truncate": "tsx -r dotenv/config ./server/db/reset.ts",
"db:studio": "drizzle-kit studio",
"lint": "biome lint",
"db:seed": "dotenv tsx ./server/db/seed.ts",
"db:clean": "dotenv tsx ./server/db/reset.ts",
"docker:build": "./docker/build.sh",
"docker:push": "./docker/push.sh",
"docker:build:canary": "./docker/build.sh canary",
"docker:push:canary": "./docker/push.sh canary",
"version": "echo $(node -p \"require('./package.json').version\")"
},
"dependencies": {
@@ -127,6 +131,7 @@
"initVersion": "7.25.2"
},
"engines": {
"node": "18.x"
"node": "^18.18.0",
"pnpm": ">=8.15.4"
}
}

View File

@@ -8,7 +8,7 @@ import { ShowVolumes } from "@/components/dashboard/application/advanced/volumes
import { DeleteApplication } from "@/components/dashboard/application/delete-application";
import { ShowDeployments } from "@/components/dashboard/application/deployments/show-deployments";
import { ShowDomains } from "@/components/dashboard/application/domains/show-domains";
import { ShowEnviroment } from "@/components/dashboard/application/enviroment/show";
import { ShowEnvironment } from "@/components/dashboard/application/environment/show";
import { ShowGeneralApplication } from "@/components/dashboard/application/general/show";
import { ShowDockerLogs } from "@/components/dashboard/application/logs/show";
import { UpdateApplication } from "@/components/dashboard/application/update-application";
@@ -127,7 +127,7 @@ const Service = (
<div className="flex flex-row items-center justify-between w-full gap-4">
<TabsList className="md:grid md:w-fit md:grid-cols-7 max-md:overflow-y-scroll justify-start">
<TabsTrigger value="general">General</TabsTrigger>
<TabsTrigger value="enviroment">Enviroment</TabsTrigger>
<TabsTrigger value="environment">Environment</TabsTrigger>
<TabsTrigger value="monitoring">Monitoring</TabsTrigger>
<TabsTrigger value="logs">Logs</TabsTrigger>
<TabsTrigger value="deployments">Deployments</TabsTrigger>
@@ -147,9 +147,9 @@ const Service = (
<ShowGeneralApplication applicationId={applicationId} />
</div>
</TabsContent>
<TabsContent value="enviroment">
<TabsContent value="environment">
<div className="flex flex-col gap-4 pt-2.5">
<ShowEnviroment applicationId={applicationId} />
<ShowEnvironment applicationId={applicationId} />
</div>
</TabsContent>
<TabsContent value="monitoring">
@@ -242,7 +242,7 @@ export async function getServerSideProps(
return {
redirect: {
permanent: false,
destination: "/dashboard",
destination: "/dashboard/projects",
},
};
}

View File

@@ -2,7 +2,7 @@ import { ShowDockerLogs } from "@/components/dashboard/application/logs/show";
import { ShowAdvancedMariadb } from "@/components/dashboard/mariadb/advanced/show-mariadb-advanced-settings";
import { ShowBackupMariadb } from "@/components/dashboard/mariadb/backups/show-backup-mariadb";
import { DeleteMariadb } from "@/components/dashboard/mariadb/delete-mariadb";
import { ShowMariadbEnviroment } from "@/components/dashboard/mariadb/enviroment/show-mariadb-enviroment";
import { ShowMariadbEnvironment } from "@/components/dashboard/mariadb/environment/show-mariadb-environment";
import { ShowExternalMariadbCredentials } from "@/components/dashboard/mariadb/general/show-external-mariadb-credentials";
import { ShowGeneralMariadb } from "@/components/dashboard/mariadb/general/show-general-mariadb";
import { ShowInternalMariadbCredentials } from "@/components/dashboard/mariadb/general/show-internal-mariadb-credentials";
@@ -110,7 +110,7 @@ const Mariadb = (
<div className="flex flex-row items-center justify-between w-full gap-4">
<TabsList className="md:grid md:w-fit md:grid-cols-6 max-md:overflow-y-scroll justify-start">
<TabsTrigger value="general">General</TabsTrigger>
<TabsTrigger value="enviroment">Enviroment</TabsTrigger>
<TabsTrigger value="environment">Environment</TabsTrigger>
<TabsTrigger value="monitoring">Monitoring</TabsTrigger>
<TabsTrigger value="backups">Backups</TabsTrigger>
<TabsTrigger value="logs">Logs</TabsTrigger>
@@ -131,9 +131,9 @@ const Mariadb = (
<ShowExternalMariadbCredentials mariadbId={mariadbId} />
</div>
</TabsContent>
<TabsContent value="enviroment">
<TabsContent value="environment">
<div className="flex flex-col gap-4 pt-2.5">
<ShowMariadbEnviroment mariadbId={mariadbId} />
<ShowMariadbEnvironment mariadbId={mariadbId} />
</div>
</TabsContent>
<TabsContent value="monitoring">
@@ -211,7 +211,7 @@ export async function getServerSideProps(
return {
redirect: {
permanent: false,
destination: "/dashboard",
destination: "/dashboard/projects",
},
};
}

View File

@@ -2,7 +2,7 @@ import { ShowDockerLogs } from "@/components/dashboard/application/logs/show";
import { ShowAdvancedMongo } from "@/components/dashboard/mongo/advanced/show-mongo-advanced-settings";
import { ShowBackupMongo } from "@/components/dashboard/mongo/backups/show-backup-mongo";
import { DeleteMongo } from "@/components/dashboard/mongo/delete-mongo";
import { ShowMongoEnviroment } from "@/components/dashboard/mongo/enviroment/show-mongo-enviroment";
import { ShowMongoEnvironment } from "@/components/dashboard/mongo/environment/show-mongo-environment";
import { ShowExternalMongoCredentials } from "@/components/dashboard/mongo/general/show-external-mongo-credentials";
import { ShowGeneralMongo } from "@/components/dashboard/mongo/general/show-general-mongo";
import { ShowInternalMongoCredentials } from "@/components/dashboard/mongo/general/show-internal-mongo-credentials";
@@ -111,7 +111,7 @@ const Mongo = (
<div className="flex flex-row items-center justify-between w-full gap-4">
<TabsList className="md:grid md:w-fit md:grid-cols-6 max-md:overflow-y-scroll justify-start">
<TabsTrigger value="general">General</TabsTrigger>
<TabsTrigger value="enviroment">Enviroment</TabsTrigger>
<TabsTrigger value="environment">Environment</TabsTrigger>
<TabsTrigger value="monitoring">Monitoring</TabsTrigger>
<TabsTrigger value="backups">Backups</TabsTrigger>
<TabsTrigger value="logs">Logs</TabsTrigger>
@@ -133,9 +133,9 @@ const Mongo = (
<ShowExternalMongoCredentials mongoId={mongoId} />
</div>
</TabsContent>
<TabsContent value="enviroment">
<TabsContent value="environment">
<div className="flex flex-col gap-4 pt-2.5">
<ShowMongoEnviroment mongoId={mongoId} />
<ShowMongoEnvironment mongoId={mongoId} />
</div>
</TabsContent>
<TabsContent value="monitoring">
@@ -213,7 +213,7 @@ export async function getServerSideProps(
return {
redirect: {
permanent: false,
destination: "/dashboard",
destination: "/dashboard/projects",
},
};
}

View File

@@ -1,7 +1,7 @@
import { ShowAdvancedMysql } from "@/components/dashboard/mysql/advanced/show-mysql-advanced-settings";
import { ShowBackupMySql } from "@/components/dashboard/mysql/backups/show-backup-mysql";
import { DeleteMysql } from "@/components/dashboard/mysql/delete-mysql";
import { ShowMysqlEnviroment } from "@/components/dashboard/mysql/enviroment/show-mysql-enviroment";
import { ShowMysqlEnvironment } from "@/components/dashboard/mysql/environment/show-mysql-environment";
import { ShowExternalMysqlCredentials } from "@/components/dashboard/mysql/general/show-external-mysql-credentials";
import { ShowGeneralMysql } from "@/components/dashboard/mysql/general/show-general-mysql";
import { ShowInternalMysqlCredentials } from "@/components/dashboard/mysql/general/show-internal-mysql-credentials";
@@ -110,7 +110,7 @@ const MySql = (
<div className="flex flex-row items-center justify-between w-full gap-4">
<TabsList className="md:grid md:w-fit md:grid-cols-6 max-md:overflow-y-scroll justify-start">
<TabsTrigger value="general">General</TabsTrigger>
<TabsTrigger value="enviroment">Enviroment</TabsTrigger>
<TabsTrigger value="environment">Environment</TabsTrigger>
<TabsTrigger value="monitoring">Monitoring</TabsTrigger>
<TabsTrigger value="backups">Backups</TabsTrigger>
<TabsTrigger value="logs">Logs</TabsTrigger>
@@ -132,9 +132,9 @@ const MySql = (
<ShowExternalMysqlCredentials mysqlId={mysqlId} />
</div>
</TabsContent>
<TabsContent value="enviroment" className="w-full">
<TabsContent value="environment" className="w-full">
<div className="flex flex-col gap-4 pt-2.5">
<ShowMysqlEnviroment mysqlId={mysqlId} />
<ShowMysqlEnvironment mysqlId={mysqlId} />
</div>
</TabsContent>
<TabsContent value="monitoring">
@@ -212,7 +212,7 @@ export async function getServerSideProps(
return {
redirect: {
permanent: false,
destination: "/dashboard",
destination: "/dashboard/projects",
},
};
}

View File

@@ -1,7 +1,7 @@
import { ShowAdvancedPostgres } from "@/components/dashboard/postgres/advanced/show-postgres-advanced-settings";
import { ShowBackupPostgres } from "@/components/dashboard/postgres/backups/show-backup-postgres";
import { DeletePostgres } from "@/components/dashboard/postgres/delete-postgres";
import { ShowPostgresEnviroment } from "@/components/dashboard/postgres/enviroment/show-postgres-enviroment";
import { ShowPostgresEnvironment } from "@/components/dashboard/postgres/environment/show-postgres-environment";
import { ShowExternalPostgresCredentials } from "@/components/dashboard/postgres/general/show-external-postgres-credentials";
import { ShowGeneralPostgres } from "@/components/dashboard/postgres/general/show-general-postgres";
import { ShowInternalPostgresCredentials } from "@/components/dashboard/postgres/general/show-internal-postgres-credentials";
@@ -111,7 +111,7 @@ const Postgresql = (
<div className="flex flex-row items-center justify-between w-full gap-4">
<TabsList className="md:grid md:w-fit md:grid-cols-6 max-md:overflow-y-scroll justify-start">
<TabsTrigger value="general">General</TabsTrigger>
<TabsTrigger value="enviroment">Enviroment</TabsTrigger>
<TabsTrigger value="environment">Environment</TabsTrigger>
<TabsTrigger value="monitoring">Monitoring</TabsTrigger>
<TabsTrigger value="backups">Backups</TabsTrigger>
<TabsTrigger value="logs">Logs</TabsTrigger>
@@ -133,9 +133,9 @@ const Postgresql = (
<ShowExternalPostgresCredentials postgresId={postgresId} />
</div>
</TabsContent>
<TabsContent value="enviroment">
<TabsContent value="environment">
<div className="flex flex-col gap-4 pt-2.5">
<ShowPostgresEnviroment postgresId={postgresId} />
<ShowPostgresEnvironment postgresId={postgresId} />
</div>
</TabsContent>
<TabsContent value="monitoring">
@@ -212,7 +212,7 @@ export async function getServerSideProps(
return {
redirect: {
permanent: false,
destination: "/dashboard",
destination: "/dashboard/projects",
},
};
}

View File

@@ -1,6 +1,6 @@
import { ShowAdvancedRedis } from "@/components/dashboard/redis/advanced/show-redis-advanced-settings";
import { DeleteRedis } from "@/components/dashboard/redis/delete-redis";
import { ShowRedisEnviroment } from "@/components/dashboard/redis/enviroment/show-redis-enviroment";
import { ShowRedisEnvironment } from "@/components/dashboard/redis/environment/show-redis-environment";
import { ShowExternalRedisCredentials } from "@/components/dashboard/redis/general/show-external-redis-credentials";
import { ShowGeneralRedis } from "@/components/dashboard/redis/general/show-general-redis";
import { ShowInternalRedisCredentials } from "@/components/dashboard/redis/general/show-internal-redis-credentials";
@@ -110,7 +110,7 @@ const Redis = (
<div className="flex flex-row items-center justify-between w-full gap-4">
<TabsList className="md:grid md:w-fit md:grid-cols-5 max-md:overflow-y-scroll justify-start">
<TabsTrigger value="general">General</TabsTrigger>
<TabsTrigger value="enviroment">Enviroment</TabsTrigger>
<TabsTrigger value="environment">Environment</TabsTrigger>
<TabsTrigger value="monitoring">Monitoring</TabsTrigger>
<TabsTrigger value="logs">Logs</TabsTrigger>
<TabsTrigger value="advanced">Advanced</TabsTrigger>
@@ -131,9 +131,9 @@ const Redis = (
<ShowExternalRedisCredentials redisId={redisId} />
</div>
</TabsContent>
<TabsContent value="enviroment">
<TabsContent value="environment">
<div className="flex flex-col gap-4 pt-2.5">
<ShowRedisEnviroment redisId={redisId} />
<ShowRedisEnvironment redisId={redisId} />
</div>
</TabsContent>
<TabsContent value="monitoring">
@@ -205,7 +205,7 @@ export async function getServerSideProps(
return {
redirect: {
permanent: false,
destination: "/dashboard",
destination: "/dashboard/projects",
},
};
}

View File

@@ -38,7 +38,6 @@ export async function getServerSideProps(
},
};
}
console.log(user);
if (user.rol === "user") {
return {
redirect: {

View File

@@ -7,7 +7,7 @@ import {
apiReloadApplication,
apiSaveBuildType,
apiSaveDockerProvider,
apiSaveEnviromentVariables,
apiSaveEnvironmentVariables,
apiSaveGitProvider,
apiSaveGithubProvider,
apiUpdateApplication,
@@ -170,8 +170,8 @@ export const applicationRouter = createTRPCRouter({
},
);
}),
saveEnviroment: protectedProcedure
.input(apiSaveEnviromentVariables)
saveEnvironment: protectedProcedure
.input(apiSaveEnvironmentVariables)
.mutation(async ({ input }) => {
await updateApplication(input.applicationId, {
env: input.env,

View File

@@ -5,7 +5,7 @@ import {
apiDeployMariaDB,
apiFindOneMariaDB,
apiResetMariadb,
apiSaveEnviromentVariablesMariaDB,
apiSaveEnvironmentVariablesMariaDB,
apiSaveExternalPortMariaDB,
apiUpdateMariaDB,
} from "@/server/db/schema/mariadb";
@@ -134,8 +134,8 @@ export const mariadbRouter = createTRPCRouter({
return mongo;
}),
saveEnviroment: protectedProcedure
.input(apiSaveEnviromentVariablesMariaDB)
saveEnvironment: protectedProcedure
.input(apiSaveEnvironmentVariablesMariaDB)
.mutation(async ({ input }) => {
const service = await updateMariadbById(input.mariadbId, {
env: input.env,
@@ -144,7 +144,7 @@ export const mariadbRouter = createTRPCRouter({
if (!service) {
throw new TRPCError({
code: "BAD_REQUEST",
message: "Update: Error to add enviroment variables",
message: "Update: Error to add environment variables",
});
}

View File

@@ -5,7 +5,7 @@ import {
apiDeployMongo,
apiFindOneMongo,
apiResetMongo,
apiSaveEnviromentVariablesMongo,
apiSaveEnvironmentVariablesMongo,
apiSaveExternalPortMongo,
apiUpdateMongo,
} from "@/server/db/schema/mongo";
@@ -148,8 +148,8 @@ export const mongoRouter = createTRPCRouter({
return mongo;
}),
saveEnviroment: protectedProcedure
.input(apiSaveEnviromentVariablesMongo)
saveEnvironment: protectedProcedure
.input(apiSaveEnvironmentVariablesMongo)
.mutation(async ({ input }) => {
const service = await updateMongoById(input.mongoId, {
env: input.env,
@@ -158,7 +158,7 @@ export const mongoRouter = createTRPCRouter({
if (!service) {
throw new TRPCError({
code: "BAD_REQUEST",
message: "Update: Error to add enviroment variables",
message: "Update: Error to add environment variables",
});
}

View File

@@ -5,7 +5,7 @@ import {
apiDeployMySql,
apiFindOneMySql,
apiResetMysql,
apiSaveEnviromentVariablesMySql,
apiSaveEnvironmentVariablesMySql,
apiSaveExternalPortMySql,
apiUpdateMySql,
} from "@/server/db/schema/mysql";
@@ -147,8 +147,8 @@ export const mysqlRouter = createTRPCRouter({
return mongo;
}),
saveEnviroment: protectedProcedure
.input(apiSaveEnviromentVariablesMySql)
saveEnvironment: protectedProcedure
.input(apiSaveEnvironmentVariablesMySql)
.mutation(async ({ input }) => {
const service = await updateMySqlById(input.mysqlId, {
env: input.env,
@@ -157,7 +157,7 @@ export const mysqlRouter = createTRPCRouter({
if (!service) {
throw new TRPCError({
code: "BAD_REQUEST",
message: "Update: Error to add enviroment variables",
message: "Update: Error to add environment variables",
});
}

View File

@@ -5,7 +5,7 @@ import {
apiDeployPostgres,
apiFindOnePostgres,
apiResetPostgres,
apiSaveEnviromentVariablesPostgres,
apiSaveEnvironmentVariablesPostgres,
apiSaveExternalPortPostgres,
apiUpdatePostgres,
} from "@/server/db/schema/postgres";
@@ -130,8 +130,8 @@ export const postgresRouter = createTRPCRouter({
return postgres;
}),
saveEnviroment: protectedProcedure
.input(apiSaveEnviromentVariablesPostgres)
saveEnvironment: protectedProcedure
.input(apiSaveEnvironmentVariablesPostgres)
.mutation(async ({ input }) => {
const service = await updatePostgresById(input.postgresId, {
env: input.env,
@@ -140,7 +140,7 @@ export const postgresRouter = createTRPCRouter({
if (!service) {
throw new TRPCError({
code: "BAD_REQUEST",
message: "Update: Error to add enviroment variables",
message: "Update: Error to add environment variables",
});
}

View File

@@ -42,6 +42,8 @@ export const projectRouter = createTRPCRouter({
if (ctx.user.rol === "user") {
await addNewProject(ctx.user.authId, project.projectId);
}
return project;
} catch (error) {
console.log(error);
throw new TRPCError({

View File

@@ -5,7 +5,7 @@ import {
apiDeployRedis,
apiFindOneRedis,
apiResetRedis,
apiSaveEnviromentVariablesRedis,
apiSaveEnvironmentVariablesRedis,
apiSaveExternalPortRedis,
apiUpdateRedis,
} from "@/server/db/schema/redis";
@@ -147,8 +147,8 @@ export const redisRouter = createTRPCRouter({
return redis;
}),
saveEnviroment: protectedProcedure
.input(apiSaveEnviromentVariablesRedis)
saveEnvironment: protectedProcedure
.input(apiSaveEnvironmentVariablesRedis)
.mutation(async ({ input }) => {
const redis = await updateRedisById(input.redisId, {
env: input.env,
@@ -157,7 +157,7 @@ export const redisRouter = createTRPCRouter({
if (!redis) {
throw new TRPCError({
code: "BAD_REQUEST",
message: "Update: Error to add enviroment variables",
message: "Update: Error to add environment variables",
});
}

View File

@@ -16,7 +16,7 @@ const updateIsAvailable = async () => {
};
export const getDokployImage = () => {
return "dokploy/dokploy:latest";
return `dokploy/dokploy:${process.env.RELEASE_TAG || "latest"}`;
};
export const pullLatestRelease = async () => {

View File

@@ -1,6 +1,10 @@
import Docker from "dockerode";
import path from "node:path";
export const BASE_PATH = "/etc/dokploy";
export const BASE_PATH =
process.env.NODE_ENV === "production"
? "/etc/dokploy"
: path.join(process.cwd(), ".docker");
export const MAIN_TRAEFIK_PATH = `${BASE_PATH}/traefik`;
export const DYNAMIC_TRAEFIK_PATH = `${BASE_PATH}/traefik/dynamic`;
export const LOGS_PATH = `${BASE_PATH}/logs`;

View File

@@ -10,9 +10,10 @@ const db = drizzle(pg);
const clearDb = async (): Promise<void> => {
try {
const tablesQuery = sql<string>`DROP SCHEMA public CASCADE; CREATE SCHEMA public;`;
const tablesQuery = sql<string>`DROP SCHEMA public CASCADE; CREATE SCHEMA public; DROP schema drizzle CASCADE;`;
const tables = await db.execute(tablesQuery);
console.log(tables);
await pg.end();
} catch (error) {
console.error("Error to clean database", error);
} finally {

View File

@@ -181,7 +181,7 @@ export const apiSaveGitProvider = createSchema
})
.required();
export const apiSaveEnviromentVariables = createSchema
export const apiSaveEnvironmentVariables = createSchema
.pick({
applicationId: true,
env: true,

View File

@@ -102,7 +102,7 @@ export const apiChangeMariaDBStatus = createSchema
})
.required();
export const apiSaveEnviromentVariablesMariaDB = createSchema
export const apiSaveEnvironmentVariablesMariaDB = createSchema
.pick({
mariadbId: true,
env: true,

View File

@@ -94,7 +94,7 @@ export const apiChangeMongoStatus = createSchema
})
.required();
export const apiSaveEnviromentVariablesMongo = createSchema
export const apiSaveEnvironmentVariablesMongo = createSchema
.pick({
mongoId: true,
env: true,

View File

@@ -100,7 +100,7 @@ export const apiChangeMySqlStatus = createSchema
})
.required();
export const apiSaveEnviromentVariablesMySql = createSchema
export const apiSaveEnvironmentVariablesMySql = createSchema
.pick({
mysqlId: true,
env: true,

View File

@@ -96,7 +96,7 @@ export const apiChangePostgresStatus = createSchema
})
.required();
export const apiSaveEnviromentVariablesPostgres = createSchema
export const apiSaveEnvironmentVariablesPostgres = createSchema
.pick({
postgresId: true,
env: true,

View File

@@ -90,7 +90,7 @@ export const apiChangeRedisStatus = createSchema
})
.required();
export const apiSaveEnviromentVariablesRedis = createSchema
export const apiSaveEnvironmentVariablesRedis = createSchema
.pick({
redisId: true,
env: true,

View File

@@ -34,31 +34,32 @@ void app.prepare().then(async () => {
handle(req, res);
});
setupDirectories();
createDefaultMiddlewares();
await initializeNetwork();
await initializeSwarm();
createDefaultTraefikConfig();
createDefaultServerTraefikConfig();
await initializeTraefik();
await initializeRedis();
await initializePostgres();
// WEBSOCKET
setupDeploymentLogsWebSocketServer(server);
setupDockerContainerLogsWebSocketServer(server);
setupDockerContainerTerminalWebSocketServer(server);
setupTerminalWebSocketServer(server);
setupDockerStatsMonitoringSocketServer(server);
if (process.env.NODE_ENV === "production") {
// Cron Jobs
setupDirectories();
createDefaultMiddlewares();
await initializeSwarm();
await initializeNetwork();
createDefaultTraefikConfig();
createDefaultServerTraefikConfig();
await initializeTraefik();
await initializeRedis();
await initializePostgres();
initCronJobs();
welcomeServer();
// Timeout to wait for the database to be ready
await new Promise((resolve) => setTimeout(resolve, 7000));
await migration();
}
server.listen(PORT);
console.log("Server Started:", PORT);
deploymentWorker.run();
} catch (e) {
console.error("Main Server Error", e);

View File

@@ -56,7 +56,6 @@ export const initializePostgres = async () => {
console.log("Postgres Started ✅");
} catch (error) {
console.log(error);
await docker.createService(settings);
console.log("Postgres Not Found: Starting ✅");
}

View File

@@ -19,7 +19,6 @@ export const dockerSwarmInitialized = async () => {
return true;
} catch (e) {
console.log(e);
return false;
}
};

View File

@@ -133,7 +133,7 @@ export const createDefaultTraefikConfig = () => {
},
}),
file: {
directory: DYNAMIC_TRAEFIK_PATH,
directory: "/etc/dokploy/traefik/dynamic",
watch: true,
},
},

View File

@@ -6,35 +6,35 @@ import type { WriteStream } from "node:fs";
// TODO: integrate in the vps sudo chown -R $(whoami) ~/.docker
export const buildHeroku = async (
application: ApplicationNested,
writeStream: WriteStream,
application: ApplicationNested,
writeStream: WriteStream,
) => {
const { env, appName } = application;
const buildAppDirectory = getBuildAppDirectory(application);
const envVariables = prepareEnvironmentVariables(env);
try {
const args = [
"build",
appName,
"--path",
buildAppDirectory,
"--builder",
"heroku/builder:22",
];
const { env, appName } = application;
const buildAppDirectory = getBuildAppDirectory(application);
const envVariables = prepareEnvironmentVariables(env);
try {
const args = [
"build",
appName,
"--path",
buildAppDirectory,
"--builder",
"heroku/builder:22",
];
for (const env in envVariables) {
args.push("--env", env);
}
for (const env of envVariables) {
args.push("--env", env);
}
await spawnAsync("pack", args, (data) => {
if (writeStream.writable) {
writeStream.write(data);
}
// Stream the data
console.log(data);
});
return true;
} catch (e) {
throw e;
}
await spawnAsync("pack", args, (data) => {
if (writeStream.writable) {
writeStream.write(data);
}
// Stream the data
console.log(data);
});
return true;
} catch (e) {
throw e;
}
};

View File

@@ -6,25 +6,26 @@ import type { WriteStream } from "node:fs";
// TODO: integrate in the vps sudo chown -R $(whoami) ~/.docker
export const buildNixpacks = async (
application: ApplicationNested,
writeStream: WriteStream,
application: ApplicationNested,
writeStream: WriteStream,
) => {
const { env, appName } = application;
const buildAppDirectory = getBuildAppDirectory(application);
const envVariables = prepareEnvironmentVariables(env);
try {
const args = ["build", buildAppDirectory, "--name", appName];
const { env, appName } = application;
const buildAppDirectory = getBuildAppDirectory(application);
const envVariables = prepareEnvironmentVariables(env);
try {
const args = ["build", buildAppDirectory, "--name", appName];
for (const env in envVariables) {
args.push("--env", env);
}
await spawnAsync("nixpacks", args, (data) => {
if (writeStream.writable) {
writeStream.write(data);
}
});
return true;
} catch (e) {
throw e;
}
for (const env of envVariables) {
args.push("--env", env);
}
await spawnAsync("nixpacks", args, (data) => {
if (writeStream.writable) {
writeStream.write(data);
}
});
return true;
} catch (e) {
throw e;
}
};

View File

@@ -6,33 +6,33 @@ import { prepareEnvironmentVariables } from "../docker/utils";
// TODO: integrate in the vps sudo chown -R $(whoami) ~/.docker
export const buildPaketo = async (
application: ApplicationNested,
writeStream: WriteStream,
application: ApplicationNested,
writeStream: WriteStream,
) => {
const { env, appName } = application;
const buildAppDirectory = getBuildAppDirectory(application);
const envVariables = prepareEnvironmentVariables(env);
try {
const args = [
"build",
appName,
"--path",
buildAppDirectory,
"--builder",
"paketobuildpacks/builder-jammy-full",
];
const { env, appName } = application;
const buildAppDirectory = getBuildAppDirectory(application);
const envVariables = prepareEnvironmentVariables(env);
try {
const args = [
"build",
appName,
"--path",
buildAppDirectory,
"--builder",
"paketobuildpacks/builder-jammy-full",
];
for (const env in envVariables) {
args.push("--env", env);
}
for (const env of envVariables) {
args.push("--env", env);
}
await spawnAsync("pack", args, (data) => {
if (writeStream.writable) {
writeStream.write(data);
}
});
return true;
} catch (e) {
throw e;
}
await spawnAsync("pack", args, (data) => {
if (writeStream.writable) {
writeStream.write(data);
}
});
return true;
} catch (e) {
throw e;
}
};

26
setup.ts Normal file
View File

@@ -0,0 +1,26 @@
import {
createDefaultMiddlewares,
createDefaultServerTraefikConfig,
createDefaultTraefikConfig,
initializeTraefik,
} from "./server/setup/traefik-setup";
import { initializeRedis } from "./server/setup/redis-setup";
import { initializePostgres } from "./server/setup/postgres-setup";
import { setupDirectories } from "./server/setup/config-paths";
import { initializeNetwork, initializeSwarm } from "./server/setup/setup";
(async () => {
try {
setupDirectories();
createDefaultMiddlewares();
await initializeSwarm();
await initializeNetwork();
createDefaultTraefikConfig();
createDefaultServerTraefikConfig();
await initializeTraefik();
await initializeRedis();
await initializePostgres();
} catch (e) {
console.error("Error to setup dokploy", e);
}
})();

View File

@@ -39,5 +39,5 @@
".next/types/**/*.ts",
"env.js"
, "next.config.mjs" ],
"exclude": ["node_modules", "dokploy", "config", "dist","webpack.config.server.js"]
"exclude": ["node_modules", "dokploy", "config", "dist","webpack.config.server.js","migration.ts","setup.ts"]
}