mirror of
https://github.com/ershisan99/coolify.git
synced 2025-12-26 20:49:29 +00:00
Compare commits
17 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
139aa7a0fc | ||
|
|
4955157e13 | ||
|
|
2ad634dbc6 | ||
|
|
de13f65a24 | ||
|
|
8994dde8f0 | ||
|
|
b7303a0828 | ||
|
|
5bc330162a | ||
|
|
0ebc0217f3 | ||
|
|
95c810b80a | ||
|
|
82d7fb883d | ||
|
|
b96e710543 | ||
|
|
24e5e85225 | ||
|
|
6d6f2454a7 | ||
|
|
9ff44ed46b | ||
|
|
adf3ef61b8 | ||
|
|
832107e0b8 | ||
|
|
0ea1e71808 |
32
.github/workflows/staging-release.yml
vendored
32
.github/workflows/staging-release.yml
vendored
@@ -6,6 +6,34 @@ on:
|
|||||||
- next
|
- next
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
|
arm64:
|
||||||
|
runs-on: [self-hosted, arm64]
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
ref: "next"
|
||||||
|
- name: Set up QEMU
|
||||||
|
uses: docker/setup-qemu-action@v1
|
||||||
|
- name: Set up Docker Buildx
|
||||||
|
uses: docker/setup-buildx-action@v1
|
||||||
|
- name: Login to DockerHub
|
||||||
|
uses: docker/login-action@v1
|
||||||
|
with:
|
||||||
|
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||||
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
|
- name: Get current package version
|
||||||
|
uses: martinbeentjes/npm-get-version-action@v1.2.3
|
||||||
|
id: package-version
|
||||||
|
- name: Build and push
|
||||||
|
uses: docker/build-push-action@v2
|
||||||
|
with:
|
||||||
|
context: .
|
||||||
|
platforms: linux/arm64
|
||||||
|
push: true
|
||||||
|
tags: coollabsio/coolify:next-arm64
|
||||||
|
cache-from: type=registry,ref=coollabsio/coolify:buildcache-next-arm64
|
||||||
|
cache-to: type=registry,ref=coollabsio/coolify:buildcache-next-arm64,mode=max
|
||||||
amd64:
|
amd64:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
@@ -36,7 +64,7 @@ jobs:
|
|||||||
cache-to: type=registry,ref=coollabsio/coolify:buildcache-next-amd64,mode=max
|
cache-to: type=registry,ref=coollabsio/coolify:buildcache-next-amd64,mode=max
|
||||||
merge-manifest:
|
merge-manifest:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
needs: [amd64]
|
needs: [arm64, amd64]
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
@@ -51,7 +79,7 @@ jobs:
|
|||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
- name: Create & publish manifest
|
- name: Create & publish manifest
|
||||||
run: |
|
run: |
|
||||||
docker manifest create coollabsio/coolify:next --amend coollabsio/coolify:next-amd64
|
docker manifest create coollabsio/coolify:next --amend coollabsio/coolify:next-amd64 --amend coollabsio/coolify:next-arm64
|
||||||
docker manifest push coollabsio/coolify:next
|
docker manifest push coollabsio/coolify:next
|
||||||
- uses: sarisia/actions-status-discord@v1
|
- uses: sarisia/actions-status-discord@v1
|
||||||
if: always()
|
if: always()
|
||||||
|
|||||||
@@ -1,57 +1,48 @@
|
|||||||
# Contribution
|
# Contributing
|
||||||
|
|
||||||
First, thanks for considering to contribute to my project. It really means a lot! :)
|
> "First, thanks for considering to contribute to my project.
|
||||||
|
It really means a lot! 😁" - [@andrasbacsai](https://github.com/andrasbacsai)
|
||||||
|
|
||||||
You can ask for guidance anytime on our Discord server in the #contribution channel.
|
You can ask for guidance anytime on our
|
||||||
|
[Discord server](https://coollabs.io/discord) in the `#contribution` channel.
|
||||||
|
|
||||||
## Setup your development environment
|
You'll need a set of skills to [get started](docs/contribution/GettingStarted.md).
|
||||||
### Container based development flow (recommended and the easiest)
|
|
||||||
All you need is to intall [Docker Engine 20.11+](https://docs.docker.com/engine/install/) on your local machine and run `pnpm dev:container`. It will build the base image for Coolify and start the development server inside Docker. All required ports (3000, 3001) will be exposed to your host.
|
|
||||||
|
|
||||||
### Github codespaces
|
## 1) Setup your development environment
|
||||||
|
|
||||||
If you have github codespaces enabled then you can just create a codespace and run `pnpm dev` to run your the dev environment. All the required dependencies and packages has been configured for you already.
|
- 🌟 [Container based](docs/dev_setup/Container.md) ← *Recomended*
|
||||||
|
- 📦 [DockerContainer](docs/dev_setup/DockerContiner.md) *WIP
|
||||||
|
- 🐙 [Github Codespaces](docs/dev_setup/GithubCodespaces.md)
|
||||||
|
- ☁️ [GitPod](docs/dev_setup/GitPod.md)
|
||||||
|
- 🍏 [Local Mac](docs/dev_setup/Mac.md)
|
||||||
|
|
||||||
### Gitpod
|
## 2) Basic requirements
|
||||||
1. Use [container based development flow](#container-based-development-flow-easiest)
|
|
||||||
2. Or setup your workspace manually:
|
|
||||||
|
|
||||||
Create a workspace from this repository, run `pnpm install && pnpm db:push && pnpm db:seed` and then `pnpm dev`. All the required dependencies and packages has been configured for you already.
|
- [Install Pnpm](https://pnpm.io/installation)
|
||||||
|
- [Install Docker Engine](https://docs.docker.com/engine/install/)
|
||||||
|
- [Setup Docker Compose Plugin](https://docs.docker.com/compose/install/compose-plugin/)
|
||||||
|
- [Setup GIT LFS Support](https://git-lfs.github.com/)
|
||||||
|
|
||||||
> Some packages, just `pack` are not installed in this way. You cannot test all the features. Please use the [container based development flow](#container-based-development-flow-easiest).
|
## 3) Setup Coolify
|
||||||
|
|
||||||
### Local Machine
|
- Copy `apps/api/.env.example` to `apps/api/.env`
|
||||||
> At the moment, Coolify `doesn't support Windows`. You must use `Linux` or `MacOS` or consider using Gitpod or Github Codespaces.
|
- Edit `apps/api/.env`, set the `COOLIFY_APP_ID` environment variable to something cool.
|
||||||
|
- Run `pnpm install` to install dependencies.
|
||||||
|
- Run `pnpm db:push` to o create a local SQlite database. This will apply all migrations at `db/dev.db`.
|
||||||
|
- Run `pnpm db:seed` seed the database.
|
||||||
|
- Run `pnpm dev` start coding.
|
||||||
|
|
||||||
Install all the prerequisites manually to your host system. If you would not like to install anything, I suggest to use the [container based development flow](#container-based-development-flow-easiest).
|
```sh
|
||||||
|
# Or... Copy and paste commands bellow:
|
||||||
|
cp apps/api/.env.example apps/api.env
|
||||||
|
pnpm install
|
||||||
|
pnpm db:push
|
||||||
|
pnpm db:seed
|
||||||
|
pnpm dev
|
||||||
|
```
|
||||||
|
|
||||||
- Due to the lock file, this repository is best with [pnpm](https://pnpm.io). I recommend you try and use `pnpm` because it is cool and efficient!
|
## 4) Start Coding
|
||||||
- You need to have [Docker Engine](https://docs.docker.com/engine/install/) installed locally.
|
|
||||||
- You need to have [Docker Compose Plugin](https://docs.docker.com/compose/install/compose-plugin/) installed locally.
|
|
||||||
- You need to have [GIT LFS Support](https://git-lfs.github.com/) installed locally.
|
|
||||||
|
|
||||||
Optional:
|
You should be able to access `http://localhost:3000`.
|
||||||
- To test Heroku buildpacks, you need [pack](https://github.com/buildpacks/pack) binary installed locally.
|
|
||||||
|
|
||||||
### Inside a Docker container
|
1. Click `Register` and setup your first user.
|
||||||
`WIP`
|
|
||||||
|
|
||||||
## Setup Coolify
|
|
||||||
- Copy `apps/api/.env.template` to `apps/api/.env.template` and set the `COOLIFY_APP_ID` environment variable to something cool.
|
|
||||||
- `pnpm install` to install dependencies.
|
|
||||||
- `pnpm db:push` to o create a local SQlite database.
|
|
||||||
|
|
||||||
This will apply all migrations at `db/dev.db`.
|
|
||||||
|
|
||||||
- `pnpm db:seed` seed the database.
|
|
||||||
- `pnpm dev` start coding.
|
|
||||||
|
|
||||||
## Technical skills required
|
|
||||||
|
|
||||||
- **Languages**: Node.js / Javascript / Typescript
|
|
||||||
- **Framework JS/TS**: [SvelteKit](https://kit.svelte.dev/) & [Fastify](https://www.fastify.io/)
|
|
||||||
- **Database ORM**: [Prisma.io](https://www.prisma.io/)
|
|
||||||
- **Docker Engine API**
|
|
||||||
|
|
||||||
## How to add a new service?
|
|
||||||
You can find all details [here](https://github.com/coollabsio/coolify-community-templates)
|
|
||||||
@@ -105,6 +105,10 @@ A fresh installation is necessary. v2 and v3 are not compatible with v1.
|
|||||||
- Email: [andras@coollabs.io](mailto:andras@coollabs.io)
|
- Email: [andras@coollabs.io](mailto:andras@coollabs.io)
|
||||||
- Discord: [Invitation](https://coollabs.io/discord)
|
- Discord: [Invitation](https://coollabs.io/discord)
|
||||||
|
|
||||||
|
## Development Contributions
|
||||||
|
|
||||||
|
Coolify is developed under the Apache License and you can help to make it grow → [Start coding!](./CONTRIBUTION.md)
|
||||||
|
|
||||||
## Financial Contributors
|
## Financial Contributors
|
||||||
|
|
||||||
Become a financial contributor and help us sustain our community. [[Contribute](https://opencollective.com/coollabsio/contribute)]
|
Become a financial contributor and help us sustain our community. [[Contribute](https://opencollective.com/coollabsio/contribute)]
|
||||||
|
|||||||
@@ -1861,6 +1861,215 @@
|
|||||||
defaultValue: $$generate_password
|
defaultValue: $$generate_password
|
||||||
description: ""
|
description: ""
|
||||||
showOnConfiguration: true
|
showOnConfiguration: true
|
||||||
|
- templateVersion: 1.0.0
|
||||||
|
ignore: true
|
||||||
|
defaultVersion: postgresql-v1.38.0
|
||||||
|
documentation: https://umami.is/docs/getting-started
|
||||||
|
type: umami
|
||||||
|
name: Umami
|
||||||
|
subname: (PostgreSQL)
|
||||||
|
description: >-
|
||||||
|
A simple, easy to use, self-hosted web analytics solution.
|
||||||
|
services:
|
||||||
|
$$id:
|
||||||
|
name: Umami
|
||||||
|
documentation: "Official docs are [here](https://umami.is/docs/getting-started)"
|
||||||
|
depends_on:
|
||||||
|
- $$id-postgresql
|
||||||
|
image: "ghcr.io/umami-software/umami:$$core_version"
|
||||||
|
volumes: []
|
||||||
|
environment:
|
||||||
|
- ADMIN_PASSWORD=$$secret_admin_password
|
||||||
|
- DATABASE_URL=$$secret_database_url
|
||||||
|
- DATABASE_TYPE=$$config_database_type
|
||||||
|
- HASH_SALT=$$secret_hash_salt
|
||||||
|
ports:
|
||||||
|
- "3000"
|
||||||
|
$$id-postgresql:
|
||||||
|
name: PostgreSQL
|
||||||
|
documentation: "Official docs are [here](https://umami.is/docs/getting-started)"
|
||||||
|
depends_on: []
|
||||||
|
image: "postgres:12-alpine"
|
||||||
|
volumes:
|
||||||
|
- "$$id-postgresql-data:/var/lib/postgresql/data"
|
||||||
|
environment:
|
||||||
|
- POSTGRES_USER=$$config_postgres_user
|
||||||
|
- POSTGRES_PASSWORD=$$secret_postgres_password
|
||||||
|
- POSTGRES_DB=$$config_postgres_db
|
||||||
|
ports: []
|
||||||
|
files:
|
||||||
|
- location: /docker-entrypoint-initdb.d/schema.postgresql.sql
|
||||||
|
content: |2-
|
||||||
|
|
||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "account" (
|
||||||
|
"user_id" SERIAL NOT NULL,
|
||||||
|
"username" VARCHAR(255) NOT NULL,
|
||||||
|
"password" VARCHAR(60) NOT NULL,
|
||||||
|
"is_admin" BOOLEAN NOT NULL DEFAULT false,
|
||||||
|
"created_at" TIMESTAMPTZ(6) DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
"updated_at" TIMESTAMPTZ(6) DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
|
||||||
|
PRIMARY KEY ("user_id")
|
||||||
|
);
|
||||||
|
|
||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "event" (
|
||||||
|
"event_id" SERIAL NOT NULL,
|
||||||
|
"website_id" INTEGER NOT NULL,
|
||||||
|
"session_id" INTEGER NOT NULL,
|
||||||
|
"created_at" TIMESTAMPTZ(6) DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
"url" VARCHAR(500) NOT NULL,
|
||||||
|
"event_type" VARCHAR(50) NOT NULL,
|
||||||
|
"event_value" VARCHAR(50) NOT NULL,
|
||||||
|
|
||||||
|
PRIMARY KEY ("event_id")
|
||||||
|
);
|
||||||
|
|
||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "pageview" (
|
||||||
|
"view_id" SERIAL NOT NULL,
|
||||||
|
"website_id" INTEGER NOT NULL,
|
||||||
|
"session_id" INTEGER NOT NULL,
|
||||||
|
"created_at" TIMESTAMPTZ(6) DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
"url" VARCHAR(500) NOT NULL,
|
||||||
|
"referrer" VARCHAR(500),
|
||||||
|
|
||||||
|
PRIMARY KEY ("view_id")
|
||||||
|
);
|
||||||
|
|
||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "session" (
|
||||||
|
"session_id" SERIAL NOT NULL,
|
||||||
|
"session_uuid" UUID NOT NULL,
|
||||||
|
"website_id" INTEGER NOT NULL,
|
||||||
|
"created_at" TIMESTAMPTZ(6) DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
"hostname" VARCHAR(100),
|
||||||
|
"browser" VARCHAR(20),
|
||||||
|
"os" VARCHAR(20),
|
||||||
|
"device" VARCHAR(20),
|
||||||
|
"screen" VARCHAR(11),
|
||||||
|
"language" VARCHAR(35),
|
||||||
|
"country" CHAR(2),
|
||||||
|
|
||||||
|
PRIMARY KEY ("session_id")
|
||||||
|
);
|
||||||
|
|
||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "website" (
|
||||||
|
"website_id" SERIAL NOT NULL,
|
||||||
|
"website_uuid" UUID NOT NULL,
|
||||||
|
"user_id" INTEGER NOT NULL,
|
||||||
|
"name" VARCHAR(100) NOT NULL,
|
||||||
|
"domain" VARCHAR(500),
|
||||||
|
"share_id" VARCHAR(64),
|
||||||
|
"created_at" TIMESTAMPTZ(6) DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
|
||||||
|
PRIMARY KEY ("website_id")
|
||||||
|
);
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE UNIQUE INDEX "account.username_unique" ON "account"("username");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE INDEX "event_created_at_idx" ON "event"("created_at");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE INDEX "event_session_id_idx" ON "event"("session_id");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE INDEX "event_website_id_idx" ON "event"("website_id");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE INDEX "pageview_created_at_idx" ON "pageview"("created_at");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE INDEX "pageview_session_id_idx" ON "pageview"("session_id");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE INDEX "pageview_website_id_created_at_idx" ON "pageview"("website_id", "created_at");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE INDEX "pageview_website_id_idx" ON "pageview"("website_id");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE INDEX "pageview_website_id_session_id_created_at_idx" ON "pageview"("website_id", "session_id", "created_at");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE UNIQUE INDEX "session.session_uuid_unique" ON "session"("session_uuid");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE INDEX "session_created_at_idx" ON "session"("created_at");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE INDEX "session_website_id_idx" ON "session"("website_id");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE UNIQUE INDEX "website.website_uuid_unique" ON "website"("website_uuid");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE UNIQUE INDEX "website.share_id_unique" ON "website"("share_id");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE INDEX "website_user_id_idx" ON "website"("user_id");
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "event" ADD FOREIGN KEY ("session_id") REFERENCES "session"("session_id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "event" ADD FOREIGN KEY ("website_id") REFERENCES "website"("website_id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "pageview" ADD FOREIGN KEY ("session_id") REFERENCES "session"("session_id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "pageview" ADD FOREIGN KEY ("website_id") REFERENCES "website"("website_id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "session" ADD FOREIGN KEY ("website_id") REFERENCES "website"("website_id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "website" ADD FOREIGN KEY ("user_id") REFERENCES "account"("user_id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
insert into account (username, password, is_admin) values ('admin', '$$hashed$$secret_admin_password', true);
|
||||||
|
variables:
|
||||||
|
- id: $$secret_database_url
|
||||||
|
name: DATABASE_URL
|
||||||
|
label: Database URL for PostgreSQL
|
||||||
|
defaultValue: >-
|
||||||
|
postgresql://$$config_postgres_user:$$secret_postgres_password@$$id-postgresql:5432/$$config_postgres_db
|
||||||
|
description: ""
|
||||||
|
- id: $$secret_hash_salt
|
||||||
|
name: HASH_SALT
|
||||||
|
label: Hash Salt
|
||||||
|
defaultValue: $$generate_hex(64)
|
||||||
|
description: ""
|
||||||
|
- id: $$config_database_type
|
||||||
|
name: DATABASE_TYPE
|
||||||
|
label: Database Type
|
||||||
|
defaultValue: "postgresql"
|
||||||
|
description: ""
|
||||||
|
- id: $$config_postgres_user
|
||||||
|
name: POSTGRES_USER
|
||||||
|
label: PostgreSQL User
|
||||||
|
defaultValue: $$generate_username
|
||||||
|
description: ""
|
||||||
|
- id: $$secret_postgres_password
|
||||||
|
name: POSTGRES_PASSWORD
|
||||||
|
label: PostgreSQL Password
|
||||||
|
defaultValue: $$generate_password
|
||||||
|
description: ""
|
||||||
|
- id: $$config_postgres_db
|
||||||
|
name: POSTGRES_DB
|
||||||
|
label: PostgreSQL Database
|
||||||
|
defaultValue: umami
|
||||||
|
description: ""
|
||||||
|
- id: $$secret_admin_password
|
||||||
|
name: ADMIN_PASSWORD
|
||||||
|
label: Initial Admin Password
|
||||||
|
defaultValue: $$generate_password
|
||||||
|
description: ""
|
||||||
|
showOnConfiguration: true
|
||||||
- templateVersion: 1.0.0
|
- templateVersion: 1.0.0
|
||||||
defaultVersion: v0.29.1
|
defaultVersion: v0.29.1
|
||||||
documentation: https://docs.meilisearch.com/learn/getting_started/quick_start.html
|
documentation: https://docs.meilisearch.com/learn/getting_started/quick_start.html
|
||||||
@@ -1891,6 +2100,7 @@
|
|||||||
description: ""
|
description: ""
|
||||||
showOnConfiguration: true
|
showOnConfiguration: true
|
||||||
- templateVersion: 1.0.0
|
- templateVersion: 1.0.0
|
||||||
|
ignore: true
|
||||||
defaultVersion: latest
|
defaultVersion: latest
|
||||||
documentation: https://ghost.org/resources/
|
documentation: https://ghost.org/resources/
|
||||||
type: ghost-mariadb
|
type: ghost-mariadb
|
||||||
|
|||||||
@@ -173,7 +173,13 @@ const host = '0.0.0.0';
|
|||||||
// Refresh and check templates
|
// Refresh and check templates
|
||||||
setInterval(async () => {
|
setInterval(async () => {
|
||||||
await refreshTemplates()
|
await refreshTemplates()
|
||||||
|
}, 60000)
|
||||||
|
|
||||||
|
setInterval(async () => {
|
||||||
await refreshTags()
|
await refreshTags()
|
||||||
|
}, 60000)
|
||||||
|
|
||||||
|
setInterval(async () => {
|
||||||
await migrateServicesToNewTemplate()
|
await migrateServicesToNewTemplate()
|
||||||
}, 60000)
|
}, 60000)
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import cuid from "cuid";
|
import cuid from "cuid";
|
||||||
import { decrypt, encrypt, fixType, generatePassword, getDomain, prisma } from "./lib/common";
|
import { decrypt, encrypt, fixType, generatePassword, prisma } from "./lib/common";
|
||||||
import { getTemplates } from "./lib/services";
|
import { getTemplates } from "./lib/services";
|
||||||
|
|
||||||
export async function migrateServicesToNewTemplate() {
|
export async function migrateServicesToNewTemplate() {
|
||||||
@@ -238,7 +238,6 @@ async function hasura(service: any, template: any) {
|
|||||||
async function umami(service: any, template: any) {
|
async function umami(service: any, template: any) {
|
||||||
const { postgresqlUser, postgresqlPassword, postgresqlDatabase, umamiAdminPassword, hashSalt } = service.umami
|
const { postgresqlUser, postgresqlPassword, postgresqlDatabase, umamiAdminPassword, hashSalt } = service.umami
|
||||||
const { id } = service
|
const { id } = service
|
||||||
|
|
||||||
const secrets = [
|
const secrets = [
|
||||||
`HASH_SALT@@@${hashSalt}`,
|
`HASH_SALT@@@${hashSalt}`,
|
||||||
`POSTGRES_PASSWORD@@@${postgresqlPassword}`,
|
`POSTGRES_PASSWORD@@@${postgresqlPassword}`,
|
||||||
@@ -253,6 +252,8 @@ async function umami(service: any, template: any) {
|
|||||||
await migrateSettings(settings, service, template);
|
await migrateSettings(settings, service, template);
|
||||||
await migrateSecrets(secrets, service);
|
await migrateSecrets(secrets, service);
|
||||||
|
|
||||||
|
await prisma.service.update({ where: { id: service.id }, data: { type: "umami-postgresql" } })
|
||||||
|
|
||||||
// Disconnect old service data
|
// Disconnect old service data
|
||||||
// await prisma.service.update({ where: { id: service.id }, data: { umami: { disconnect: true } } })
|
// await prisma.service.update({ where: { id: service.id }, data: { umami: { disconnect: true } } })
|
||||||
}
|
}
|
||||||
@@ -440,33 +441,41 @@ async function plausibleAnalytics(service: any, template: any) {
|
|||||||
|
|
||||||
async function migrateSettings(settings: any[], service: any, template: any) {
|
async function migrateSettings(settings: any[], service: any, template: any) {
|
||||||
for (const setting of settings) {
|
for (const setting of settings) {
|
||||||
if (!setting) continue;
|
try {
|
||||||
let [name, value] = setting.split('@@@')
|
if (!setting) continue;
|
||||||
let minio = name
|
let [name, value] = setting.split('@@@')
|
||||||
if (name === 'MINIO_SERVER_URL') {
|
let minio = name
|
||||||
name = 'coolify_fqdn_minio_console'
|
if (name === 'MINIO_SERVER_URL') {
|
||||||
|
name = 'coolify_fqdn_minio_console'
|
||||||
|
}
|
||||||
|
if (!value || value === 'null') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let variableName = template.variables.find((v: any) => v.name === name)?.id
|
||||||
|
if (!variableName) {
|
||||||
|
variableName = `$$config_${name.toLowerCase()}`
|
||||||
|
}
|
||||||
|
// console.log('Migrating setting', name, value, 'for service', service.id, ', service name:', service.name, 'variableName: ', variableName)
|
||||||
|
|
||||||
|
await prisma.serviceSetting.findFirst({ where: { name: minio, serviceId: service.id } }) || await prisma.serviceSetting.create({ data: { name: minio, value, variableName, service: { connect: { id: service.id } } } })
|
||||||
|
} catch(error) {
|
||||||
|
console.log(error)
|
||||||
}
|
}
|
||||||
if (!value || value === 'null') {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
let variableName = template.variables.find((v: any) => v.name === name)?.id
|
|
||||||
if (!variableName) {
|
|
||||||
variableName = `$$config_${name.toLowerCase()}`
|
|
||||||
}
|
|
||||||
// console.log('Migrating setting', name, value, 'for service', service.id, ', service name:', service.name, 'variableName: ', variableName)
|
|
||||||
|
|
||||||
await prisma.serviceSetting.findFirst({ where: { name: minio, serviceId: service.id } }) || await prisma.serviceSetting.create({ data: { name: minio, value, variableName, service: { connect: { id: service.id } } } })
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
async function migrateSecrets(secrets: any[], service: any) {
|
async function migrateSecrets(secrets: any[], service: any) {
|
||||||
for (const secret of secrets) {
|
for (const secret of secrets) {
|
||||||
if (!secret) continue;
|
try {
|
||||||
let [name, value] = secret.split('@@@')
|
if (!secret) continue;
|
||||||
if (!value || value === 'null') {
|
let [name, value] = secret.split('@@@')
|
||||||
continue
|
if (!value || value === 'null') {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
// console.log('Migrating secret', name, value, 'for service', service.id, ', service name:', service.name)
|
||||||
|
await prisma.serviceSecret.findFirst({ where: { name, serviceId: service.id } }) || await prisma.serviceSecret.create({ data: { name, value, service: { connect: { id: service.id } } } })
|
||||||
|
} catch(error) {
|
||||||
|
console.log(error)
|
||||||
}
|
}
|
||||||
// console.log('Migrating secret', name, value, 'for service', service.id, ', service name:', service.name)
|
|
||||||
await prisma.serviceSecret.findFirst({ where: { name, serviceId: service.id } }) || await prisma.serviceSecret.create({ data: { name, value, service: { connect: { id: service.id } } } })
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
async function createVolumes(service: any, template: any) {
|
async function createVolumes(service: any, template: any) {
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ import { day } from './dayjs';
|
|||||||
import { saveBuildLog } from './buildPacks/common';
|
import { saveBuildLog } from './buildPacks/common';
|
||||||
import { scheduler } from './scheduler';
|
import { scheduler } from './scheduler';
|
||||||
|
|
||||||
export const version = '3.11.1';
|
export const version = '3.11.3';
|
||||||
export const isDev = process.env.NODE_ENV === 'development';
|
export const isDev = process.env.NODE_ENV === 'development';
|
||||||
|
|
||||||
const algorithm = 'aes-256-ctr';
|
const algorithm = 'aes-256-ctr';
|
||||||
|
|||||||
@@ -1,145 +1,12 @@
|
|||||||
import { isDev } from "./common";
|
import { isDev } from "./common";
|
||||||
import fs from 'fs/promises';
|
import fs from 'fs/promises';
|
||||||
export async function getTemplates() {
|
export async function getTemplates() {
|
||||||
let templates: any = [];
|
const templatePath = isDev ? './templates.json' : '/app/templates.json';
|
||||||
if (isDev) {
|
const ts = await fs.readFile(templatePath, 'utf8')
|
||||||
templates = JSON.parse(await (await fs.readFile('./templates.json')).toString())
|
if (ts) {
|
||||||
} else {
|
return JSON.parse(ts);
|
||||||
templates = JSON.parse(await (await fs.readFile('/app/templates.json')).toString())
|
|
||||||
}
|
}
|
||||||
// if (!isDev) {
|
return [];
|
||||||
// templates.push({
|
|
||||||
// "templateVersion": "1.0.0",
|
|
||||||
// "defaultVersion": "latest",
|
|
||||||
// "name": "Test-Fake-Service",
|
|
||||||
// "description": "",
|
|
||||||
// "services": {
|
|
||||||
// "$$id": {
|
|
||||||
// "name": "Test-Fake-Service",
|
|
||||||
// "depends_on": [
|
|
||||||
// "$$id-postgresql",
|
|
||||||
// "$$id-redis"
|
|
||||||
// ],
|
|
||||||
// "image": "weblate/weblate:$$core_version",
|
|
||||||
// "volumes": [
|
|
||||||
// "$$id-data:/app/data",
|
|
||||||
// ],
|
|
||||||
// "environment": [
|
|
||||||
// `POSTGRES_SECRET=$$secret_postgres_secret`,
|
|
||||||
// `WEBLATE_SITE_DOMAIN=$$config_weblate_site_domain`,
|
|
||||||
// `WEBLATE_ADMIN_PASSWORD=$$secret_weblate_admin_password`,
|
|
||||||
// `POSTGRES_PASSWORD=$$secret_postgres_password`,
|
|
||||||
// `POSTGRES_USER=$$config_postgres_user`,
|
|
||||||
// `POSTGRES_DATABASE=$$config_postgres_db`,
|
|
||||||
// `POSTGRES_HOST=$$id-postgresql`,
|
|
||||||
// `POSTGRES_PORT=5432`,
|
|
||||||
// `REDIS_HOST=$$id-redis`,
|
|
||||||
// ],
|
|
||||||
// "ports": [
|
|
||||||
// "8080"
|
|
||||||
// ]
|
|
||||||
// },
|
|
||||||
// "$$id-postgresql": {
|
|
||||||
// "name": "PostgreSQL",
|
|
||||||
// "depends_on": [],
|
|
||||||
// "image": "postgres:14-alpine",
|
|
||||||
// "volumes": [
|
|
||||||
// "$$id-postgresql-data:/var/lib/postgresql/data",
|
|
||||||
// ],
|
|
||||||
// "environment": [
|
|
||||||
// "POSTGRES_USER=$$config_postgres_user",
|
|
||||||
// "POSTGRES_PASSWORD=$$secret_postgres_password",
|
|
||||||
// "POSTGRES_DB=$$config_postgres_db",
|
|
||||||
// ],
|
|
||||||
// "ports": []
|
|
||||||
// },
|
|
||||||
// "$$id-redis": {
|
|
||||||
// "name": "Redis",
|
|
||||||
// "depends_on": [],
|
|
||||||
// "image": "redis:7-alpine",
|
|
||||||
// "volumes": [
|
|
||||||
// "$$id-redis-data:/data",
|
|
||||||
// ],
|
|
||||||
// "environment": [],
|
|
||||||
// "ports": [],
|
|
||||||
// }
|
|
||||||
// },
|
|
||||||
// "variables": [
|
|
||||||
// {
|
|
||||||
// "id": "$$config_weblate_site_domain",
|
|
||||||
// "main": "$$id",
|
|
||||||
// "name": "WEBLATE_SITE_DOMAIN",
|
|
||||||
// "label": "Weblate Domain",
|
|
||||||
// "defaultValue": "$$generate_domain",
|
|
||||||
// "description": "",
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// "id": "$$secret_weblate_admin_password",
|
|
||||||
// "main": "$$id",
|
|
||||||
// "name": "WEBLATE_ADMIN_PASSWORD",
|
|
||||||
// "label": "Weblate Admin Password",
|
|
||||||
// "defaultValue": "$$generate_password",
|
|
||||||
// "description": "",
|
|
||||||
// "extras": {
|
|
||||||
// "isVisibleOnUI": true,
|
|
||||||
// }
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// "id": "$$secret_weblate_admin_password2",
|
|
||||||
// "name": "WEBLATE_ADMIN_PASSWORD2",
|
|
||||||
// "label": "Weblate Admin Password2",
|
|
||||||
// "defaultValue": "$$generate_password",
|
|
||||||
// "description": "",
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// "id": "$$config_postgres_user",
|
|
||||||
// "main": "$$id-postgresql",
|
|
||||||
// "name": "POSTGRES_USER",
|
|
||||||
// "label": "PostgreSQL User",
|
|
||||||
// "defaultValue": "$$generate_username",
|
|
||||||
// "description": "",
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// "id": "$$secret_postgres_password",
|
|
||||||
// "main": "$$id-postgresql",
|
|
||||||
// "name": "POSTGRES_PASSWORD",
|
|
||||||
// "label": "PostgreSQL Password",
|
|
||||||
// "defaultValue": "$$generate_password(32)",
|
|
||||||
// "description": "",
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// "id": "$$secret_postgres_password_hex32",
|
|
||||||
// "name": "POSTGRES_PASSWORD_hex32",
|
|
||||||
// "label": "PostgreSQL Password hex32",
|
|
||||||
// "defaultValue": "$$generate_hex(32)",
|
|
||||||
// "description": "",
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// "id": "$$config_postgres_something_hex32",
|
|
||||||
// "name": "POSTGRES_SOMETHING_HEX32",
|
|
||||||
// "label": "PostgreSQL Something hex32",
|
|
||||||
// "defaultValue": "$$generate_hex(32)",
|
|
||||||
// "description": "",
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// "id": "$$config_postgres_db",
|
|
||||||
// "main": "$$id-postgresql",
|
|
||||||
// "name": "POSTGRES_DB",
|
|
||||||
// "label": "PostgreSQL Database",
|
|
||||||
// "defaultValue": "weblate",
|
|
||||||
// "description": "",
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// "id": "$$secret_postgres_secret",
|
|
||||||
// "name": "POSTGRES_SECRET",
|
|
||||||
// "label": "PostgreSQL Secret",
|
|
||||||
// "defaultValue": "",
|
|
||||||
// "description": "",
|
|
||||||
// },
|
|
||||||
// ]
|
|
||||||
// })
|
|
||||||
// }
|
|
||||||
return templates
|
|
||||||
}
|
}
|
||||||
const compareSemanticVersions = (a: string, b: string) => {
|
const compareSemanticVersions = (a: string, b: string) => {
|
||||||
const a1 = a.split('.');
|
const a1 = a.split('.');
|
||||||
@@ -156,15 +23,14 @@ const compareSemanticVersions = (a: string, b: string) => {
|
|||||||
};
|
};
|
||||||
export async function getTags(type: string) {
|
export async function getTags(type: string) {
|
||||||
if (type) {
|
if (type) {
|
||||||
let tags: any = [];
|
const tagsPath = isDev ? './tags.json' : '/app/tags.json';
|
||||||
if (isDev) {
|
const data = await fs.readFile(tagsPath, 'utf8')
|
||||||
tags = JSON.parse(await (await fs.readFile('./tags.json')).toString())
|
let tags = JSON.parse(data)
|
||||||
} else {
|
if (tags) {
|
||||||
tags = JSON.parse(await (await fs.readFile('/app/tags.json')).toString())
|
tags = tags.find((tag: any) => tag.name.includes(type))
|
||||||
|
tags.tags = tags.tags.sort(compareSemanticVersions).reverse();
|
||||||
|
return tags
|
||||||
}
|
}
|
||||||
tags = tags.find((tag: any) => tag.name.includes(type))
|
|
||||||
tags.tags = tags.tags.sort(compareSemanticVersions).reverse();
|
|
||||||
return tags
|
|
||||||
}
|
}
|
||||||
return []
|
return []
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,10 +49,6 @@ export async function refreshTags() {
|
|||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(error)
|
console.log(error)
|
||||||
throw {
|
|
||||||
status: 500,
|
|
||||||
message: 'Could not fetch templates from get.coollabs.io'
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
@@ -73,12 +69,7 @@ export async function refreshTemplates() {
|
|||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(error)
|
console.log(error)
|
||||||
throw {
|
|
||||||
status: 500,
|
|
||||||
message: 'Could not fetch templates from get.coollabs.io'
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
} catch ({ status, message }) {
|
} catch ({ status, message }) {
|
||||||
return errorHandler({ status, message });
|
return errorHandler({ status, message });
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { FastifyPluginAsync } from 'fastify';
|
import { FastifyPluginAsync } from 'fastify';
|
||||||
import { checkUpdate, login, showDashboard, update, resetQueue, getCurrentUser, cleanupManually, restartCoolify, refreshTemplates } from './handlers';
|
import { checkUpdate, login, showDashboard, update, resetQueue, getCurrentUser, cleanupManually, restartCoolify } from './handlers';
|
||||||
import { GetCurrentUser } from './types';
|
import { GetCurrentUser } from './types';
|
||||||
|
|
||||||
export interface Update {
|
export interface Update {
|
||||||
@@ -52,10 +52,6 @@ const root: FastifyPluginAsync = async (fastify): Promise<void> => {
|
|||||||
fastify.post('/internal/cleanup', {
|
fastify.post('/internal/cleanup', {
|
||||||
onRequest: [fastify.authenticate]
|
onRequest: [fastify.authenticate]
|
||||||
}, async (request) => await cleanupManually(request));
|
}, async (request) => await cleanupManually(request));
|
||||||
|
|
||||||
fastify.post('/internal/refreshTemplates', {
|
|
||||||
onRequest: [fastify.authenticate]
|
|
||||||
}, async () => await refreshTemplates());
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default root;
|
export default root;
|
||||||
|
|||||||
@@ -129,10 +129,10 @@ function generateRouters(serviceId, domain, nakedDomain, pathPrefix, isHttps, is
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
[serviceId]: { ...http },
|
[`${serviceId}-${pathPrefix}`]: { ...http },
|
||||||
[`${serviceId}-secure`]: { ...https },
|
[`${serviceId}-${pathPrefix}-secure`]: { ...https },
|
||||||
[`${serviceId}-www`]: { ...httpWWW },
|
[`${serviceId}-${pathPrefix}-www`]: { ...httpWWW },
|
||||||
[`${serviceId}-secure-www`]: { ...httpsWWW },
|
[`${serviceId}-${pathPrefix}-secure-www`]: { ...httpsWWW },
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
export async function proxyConfiguration(request: FastifyRequest<OnlyId>, remote: boolean = false) {
|
export async function proxyConfiguration(request: FastifyRequest<OnlyId>, remote: boolean = false) {
|
||||||
@@ -287,11 +287,10 @@ export async function proxyConfiguration(request: FastifyRequest<OnlyId>, remote
|
|||||||
if (
|
if (
|
||||||
!runningContainers[destinationDockerId] ||
|
!runningContainers[destinationDockerId] ||
|
||||||
runningContainers[destinationDockerId].length === 0 ||
|
runningContainers[destinationDockerId].length === 0 ||
|
||||||
!runningContainers[destinationDockerId].includes(id)
|
runningContainers[destinationDockerId].filter((container) => container.startsWith(id)).length === 0
|
||||||
) {
|
) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if (buildPack === 'compose') {
|
if (buildPack === 'compose') {
|
||||||
const services = Object.entries(JSON.parse(dockerComposeConfiguration))
|
const services = Object.entries(JSON.parse(dockerComposeConfiguration))
|
||||||
if (services.length > 0) {
|
if (services.length > 0) {
|
||||||
@@ -310,7 +309,7 @@ export async function proxyConfiguration(request: FastifyRequest<OnlyId>, remote
|
|||||||
const pathPrefix = '/'
|
const pathPrefix = '/'
|
||||||
const isCustomSSL = false;
|
const isCustomSSL = false;
|
||||||
const dualCerts = false;
|
const dualCerts = false;
|
||||||
const serviceId = `${id}-${port || 'default'}-${pathPrefix}`
|
const serviceId = `${id}-${port || 'default'}`
|
||||||
|
|
||||||
traefik.http.routers = { ...traefik.http.routers, ...generateRouters(serviceId, domain, nakedDomain, pathPrefix, isHttps, isWWW, dualCerts, isCustomSSL) }
|
traefik.http.routers = { ...traefik.http.routers, ...generateRouters(serviceId, domain, nakedDomain, pathPrefix, isHttps, isWWW, dualCerts, isCustomSSL) }
|
||||||
traefik.http.services = { ...traefik.http.services, ...generateServices(serviceId, containerId, port) }
|
traefik.http.services = { ...traefik.http.services, ...generateServices(serviceId, containerId, port) }
|
||||||
@@ -329,7 +328,7 @@ export async function proxyConfiguration(request: FastifyRequest<OnlyId>, remote
|
|||||||
const isHttps = fqdn.startsWith('https://');
|
const isHttps = fqdn.startsWith('https://');
|
||||||
const isWWW = fqdn.includes('www.');
|
const isWWW = fqdn.includes('www.');
|
||||||
const pathPrefix = '/'
|
const pathPrefix = '/'
|
||||||
const serviceId = `${id}-${port || 'default'}-${pathPrefix}`
|
const serviceId = `${id}-${port || 'default'}`
|
||||||
traefik.http.routers = { ...traefik.http.routers, ...generateRouters(serviceId, domain, nakedDomain, pathPrefix, isHttps, isWWW, dualCerts, isCustomSSL) }
|
traefik.http.routers = { ...traefik.http.routers, ...generateRouters(serviceId, domain, nakedDomain, pathPrefix, isHttps, isWWW, dualCerts, isCustomSSL) }
|
||||||
traefik.http.services = { ...traefik.http.services, ...generateServices(serviceId, id, port) }
|
traefik.http.services = { ...traefik.http.services, ...generateServices(serviceId, id, port) }
|
||||||
if (previews) {
|
if (previews) {
|
||||||
@@ -344,7 +343,7 @@ export async function proxyConfiguration(request: FastifyRequest<OnlyId>, remote
|
|||||||
const previewDomain = `${container.split('-')[1]}.${domain}`;
|
const previewDomain = `${container.split('-')[1]}.${domain}`;
|
||||||
const nakedDomain = previewDomain.replace(/^www\./, '');
|
const nakedDomain = previewDomain.replace(/^www\./, '');
|
||||||
const pathPrefix = '/'
|
const pathPrefix = '/'
|
||||||
const serviceId = `${container}-${port || 'default'}-${pathPrefix}`
|
const serviceId = `${container}-${port || 'default'}`
|
||||||
traefik.http.routers = { ...traefik.http.routers, ...generateRouters(serviceId, previewDomain, nakedDomain, pathPrefix, isHttps, isWWW, dualCerts, isCustomSSL) }
|
traefik.http.routers = { ...traefik.http.routers, ...generateRouters(serviceId, previewDomain, nakedDomain, pathPrefix, isHttps, isWWW, dualCerts, isCustomSSL) }
|
||||||
traefik.http.services = { ...traefik.http.services, ...generateServices(serviceId, container, port) }
|
traefik.http.services = { ...traefik.http.services, ...generateServices(serviceId, container, port) }
|
||||||
}
|
}
|
||||||
@@ -426,7 +425,7 @@ export async function proxyConfiguration(request: FastifyRequest<OnlyId>, remote
|
|||||||
const isHttps = fqdn.startsWith('https://');
|
const isHttps = fqdn.startsWith('https://');
|
||||||
const isWWW = fqdn.includes('www.');
|
const isWWW = fqdn.includes('www.');
|
||||||
const isCustomSSL = false;
|
const isCustomSSL = false;
|
||||||
const serviceId = `${oneService}-${port || 'default'}-${pathPrefix}`
|
const serviceId = `${oneService}-${port || 'default'}`
|
||||||
traefik.http.routers = { ...traefik.http.routers, ...generateRouters(serviceId, domain, nakedDomain, pathPrefix, isHttps, isWWW, dualCerts, isCustomSSL) }
|
traefik.http.routers = { ...traefik.http.routers, ...generateRouters(serviceId, domain, nakedDomain, pathPrefix, isHttps, isWWW, dualCerts, isCustomSSL) }
|
||||||
traefik.http.services = { ...traefik.http.services, ...generateServices(serviceId, oneService, port) }
|
traefik.http.services = { ...traefik.http.services, ...generateServices(serviceId, oneService, port) }
|
||||||
}
|
}
|
||||||
@@ -443,7 +442,7 @@ export async function proxyConfiguration(request: FastifyRequest<OnlyId>, remote
|
|||||||
const isWWW = fqdn.includes('www.');
|
const isWWW = fqdn.includes('www.');
|
||||||
const pathPrefix = '/'
|
const pathPrefix = '/'
|
||||||
const isCustomSSL = false
|
const isCustomSSL = false
|
||||||
const serviceId = `${oneService}-${port || 'default'}-${pathPrefix}`
|
const serviceId = `${oneService}-${port || 'default'}`
|
||||||
traefik.http.routers = { ...traefik.http.routers, ...generateRouters(serviceId, domain, nakedDomain, pathPrefix, isHttps, isWWW, dualCerts, isCustomSSL) }
|
traefik.http.routers = { ...traefik.http.routers, ...generateRouters(serviceId, domain, nakedDomain, pathPrefix, isHttps, isWWW, dualCerts, isCustomSSL) }
|
||||||
traefik.http.services = { ...traefik.http.services, ...generateServices(serviceId, id, port) }
|
traefik.http.services = { ...traefik.http.services, ...generateServices(serviceId, id, port) }
|
||||||
}
|
}
|
||||||
@@ -468,7 +467,7 @@ export async function proxyConfiguration(request: FastifyRequest<OnlyId>, remote
|
|||||||
const port = 3000
|
const port = 3000
|
||||||
const pathPrefix = '/'
|
const pathPrefix = '/'
|
||||||
const isCustomSSL = false
|
const isCustomSSL = false
|
||||||
const serviceId = `${id}-${port || 'default'}-${pathPrefix}`
|
const serviceId = `${id}-${port || 'default'}`
|
||||||
traefik.http.routers = { ...traefik.http.routers, ...generateRouters(serviceId, domain, nakedDomain, pathPrefix, isHttps, isWWW, dualCerts, isCustomSSL) }
|
traefik.http.routers = { ...traefik.http.routers, ...generateRouters(serviceId, domain, nakedDomain, pathPrefix, isHttps, isWWW, dualCerts, isCustomSSL) }
|
||||||
traefik.http.services = { ...traefik.http.services, ...generateServices(serviceId, container, port) }
|
traefik.http.services = { ...traefik.http.services, ...generateServices(serviceId, container, port) }
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -79,9 +79,7 @@
|
|||||||
$isDeploymentEnabled = checkIfDeploymentEnabledServices($appSession.isAdmin, service);
|
$isDeploymentEnabled = checkIfDeploymentEnabledServices($appSession.isAdmin, service);
|
||||||
|
|
||||||
let statusInterval: any;
|
let statusInterval: any;
|
||||||
let loading = {
|
|
||||||
refreshTemplates: false
|
|
||||||
};
|
|
||||||
|
|
||||||
async function deleteService() {
|
async function deleteService() {
|
||||||
const sure = confirm($t('application.confirm_to_delete', { name: service.name }));
|
const sure = confirm($t('application.confirm_to_delete', { name: service.name }));
|
||||||
@@ -106,20 +104,6 @@
|
|||||||
await startService();
|
await startService();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
async function refreshTemplate() {
|
|
||||||
try {
|
|
||||||
loading.refreshTemplates = true;
|
|
||||||
await post(`/internal/refreshTemplates`, {});
|
|
||||||
addToast({
|
|
||||||
message: 'Services refreshed.',
|
|
||||||
type: 'success'
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
return errorNotification(error);
|
|
||||||
} finally {
|
|
||||||
loading.refreshTemplates = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
async function stopService(skip = false) {
|
async function stopService(skip = false) {
|
||||||
if (skip) {
|
if (skip) {
|
||||||
$status.service.initialLoading = true;
|
$status.service.initialLoading = true;
|
||||||
@@ -278,14 +262,6 @@
|
|||||||
Delete Service
|
Delete Service
|
||||||
</button>
|
</button>
|
||||||
{/if}
|
{/if}
|
||||||
{#if $page.url.pathname === `/services/${id}/configuration/type` && dev}
|
|
||||||
<button
|
|
||||||
disabled={loading.refreshTemplates}
|
|
||||||
class:loading={loading.refreshTemplates}
|
|
||||||
class="btn btn-sm btn-primary text-sm"
|
|
||||||
on:click={refreshTemplate}>Refresh Services List</button
|
|
||||||
>
|
|
||||||
{/if}
|
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
<div
|
<div
|
||||||
|
|||||||
@@ -116,7 +116,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class=" lg:pt-20 lg:p-0 px-8 pt-20">
|
<div class=" lg:pt-20 lg:p-0 px-8 pt-20">
|
||||||
<div class="grid grid-flow-rows grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-8">
|
<div class="grid grid-flow-rows grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-8">
|
||||||
{#each sortMe(filteredServices) as service}
|
{#each sortMe(filteredServices).filter(s=> !s.ignore) as service}
|
||||||
{#key service.name}
|
{#key service.name}
|
||||||
<button
|
<button
|
||||||
on:click={() => handleSubmit(service)}
|
on:click={() => handleSubmit(service)}
|
||||||
|
|||||||
21
docs/contribution/GettingStarted.md
Normal file
21
docs/contribution/GettingStarted.md
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
## Getting Started
|
||||||
|
|
||||||
|
To contribute to `Coolify` development, you'll benefit from knowing the following:
|
||||||
|
|
||||||
|
- **Languages**
|
||||||
|
- [Node.js]() - 📚 [Introduction](https://nodejs.dev/en/learn/introduction-to-nodejs/)
|
||||||
|
- Javascript - 📚 [Learn Javascript](https://learnjavascript.online/)
|
||||||
|
- Typescript - 📚 [Learn@FreecodeCamp](https://www.freecodecamp.org/news/learn-typescript-beginners-guide/)
|
||||||
|
|
||||||
|
- **Framework JS/TS**
|
||||||
|
- [SvelteKit](https://kit.svelte.dev/) - 📚 [Tutorial](https://svelte.dev/tutorial/basics)
|
||||||
|
- [Fastify](https://www.fastify.io/)
|
||||||
|
|
||||||
|
- **Database ORM**
|
||||||
|
- [Prisma.io](https://www.prisma.io/) - 📚 [Quickstart](https://www.prisma.io/docs/getting-started/quickstart)
|
||||||
|
|
||||||
|
- **Docker**
|
||||||
|
- [Docker Engine API](https://docs.docker.com/engine/api/)
|
||||||
|
|
||||||
|
## How to add a new service?
|
||||||
|
You can find all details [here](https://github.com/coollabsio/coolify-community-templates)
|
||||||
10
docs/dev_setup/Container.md
Normal file
10
docs/dev_setup/Container.md
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
### Container based development flow (recommended and the easiest)
|
||||||
|
|
||||||
|
All you need is to
|
||||||
|
|
||||||
|
1. Install [Docker Engine 20.11+](https://docs.docker.com/engine/install/) on your local machine
|
||||||
|
2. Run `pnpm dev:container`.
|
||||||
|
|
||||||
|
It will build the base image for Coolify and start the development server inside Docker.
|
||||||
|
|
||||||
|
All required ports (3000, 3001) will be exposed to your host.
|
||||||
2
docs/dev_setup/DockerContiner.md
Normal file
2
docs/dev_setup/DockerContiner.md
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
### Inside a Docker container
|
||||||
|
# `WIP`
|
||||||
19
docs/dev_setup/GitPod.md
Normal file
19
docs/dev_setup/GitPod.md
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
### Gitpod
|
||||||
|
|
||||||
|
#### Option 1 - Prefered:
|
||||||
|
|
||||||
|
Follow the same steps as [container based development flow](./Container.md)
|
||||||
|
|
||||||
|
#### Option 2 - Manual setup:
|
||||||
|
|
||||||
|
1. Create a workspace from this repository,
|
||||||
|
1. run `pnpm install && pnpm db:push && pnpm db:seed`
|
||||||
|
1. and then `pnpm dev`.
|
||||||
|
|
||||||
|
All the required dependencies and packages has been configured for you already.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
> Some packages, just `pack` are not installed in this way.
|
||||||
|
You cannot test all the features.
|
||||||
|
Please use the [container based development flow](./Container.md).
|
||||||
8
docs/dev_setup/GithubCodespaces.md
Normal file
8
docs/dev_setup/GithubCodespaces.md
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
### Github codespaces
|
||||||
|
|
||||||
|
If you have github codespaces enabled then you can just:
|
||||||
|
|
||||||
|
1. create a codespace and
|
||||||
|
2. run `pnpm dev` to run your the dev environment.
|
||||||
|
|
||||||
|
All the required dependencies and packages has been configured for you already.
|
||||||
17
docs/dev_setup/LocalMachine.md
Normal file
17
docs/dev_setup/LocalMachine.md
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
### Local Machine
|
||||||
|
|
||||||
|
At the moment, Coolify `doesn't support Windows`.
|
||||||
|
|
||||||
|
You must use `Linux` or `MacOS` or consider using Gitpod or Github Codespaces.
|
||||||
|
|
||||||
|
Install all the prerequisites manually to your host system.
|
||||||
|
If you would not like to install anything,
|
||||||
|
I suggest to use the [container based development flow](#container-based-development-flow-easiest).
|
||||||
|
|
||||||
|
- Due to the lock file, this repository is best with [pnpm](https://pnpm.io). I recommend you try and use `pnpm` because it is cool and efficient!
|
||||||
|
- You need to have [Docker Engine](https://docs.docker.com/engine/install/) installed locally.
|
||||||
|
- You need to have [Docker Compose Plugin](https://docs.docker.com/compose/install/compose-plugin/) installed locally.
|
||||||
|
- You need to have [GIT LFS Support](https://git-lfs.github.com/) installed locally.
|
||||||
|
|
||||||
|
Optional:
|
||||||
|
- To test Heroku buildpacks, you need [pack](https://github.com/buildpacks/pack) binary installed locally.
|
||||||
2
docs/dev_setup/Mac.md
Normal file
2
docs/dev_setup/Mac.md
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
### Mac Setup
|
||||||
|
|
||||||
1
docs/dev_setup/MacArm.md
Normal file
1
docs/dev_setup/MacArm.md
Normal file
@@ -0,0 +1 @@
|
|||||||
|
### Mac Setup
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "coolify",
|
"name": "coolify",
|
||||||
"description": "An open-source & self-hostable Heroku / Netlify alternative.",
|
"description": "An open-source & self-hostable Heroku / Netlify alternative.",
|
||||||
"version": "3.11.1",
|
"version": "3.11.3",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"repository": "github:coollabsio/coolify",
|
"repository": "github:coollabsio/coolify",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
@@ -25,7 +25,7 @@
|
|||||||
"build:api": "NODE_ENV=production pnpm run --filter api build",
|
"build:api": "NODE_ENV=production pnpm run --filter api build",
|
||||||
"build:ui": "NODE_ENV=production pnpm run --filter ui build",
|
"build:ui": "NODE_ENV=production pnpm run --filter ui build",
|
||||||
"dockerlogin": "echo $DOCKER_PASS | docker login --username=$DOCKER_USER --password-stdin",
|
"dockerlogin": "echo $DOCKER_PASS | docker login --username=$DOCKER_USER --password-stdin",
|
||||||
"release:staging:amd": "cross-var docker buildx build --platform linux/amd64 -t coollabsio/coolify:next --push .",
|
"release:staging:amd": "docker build -t coollabsio/coolify:next . && docker push coollabsio/coolify:next",
|
||||||
"release:local": "rm -fr ./local-serve && mkdir ./local-serve && pnpm build && cp -Rp apps/api/build/* ./local-serve && cp -Rp apps/ui/build/ ./local-serve/public && cp -Rp apps/api/prisma/ ./local-serve/prisma && cp -Rp apps/api/package.json ./local-serve && env | grep '^COOLIFY_' > ./local-serve/.env && cd ./local-serve && pnpm install . && pnpm start"
|
"release:local": "rm -fr ./local-serve && mkdir ./local-serve && pnpm build && cp -Rp apps/api/build/* ./local-serve && cp -Rp apps/ui/build/ ./local-serve/public && cp -Rp apps/api/prisma/ ./local-serve/prisma && cp -Rp apps/api/package.json ./local-serve && env | grep '^COOLIFY_' > ./local-serve/.env && cd ./local-serve && pnpm install . && pnpm start"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|||||||
Reference in New Issue
Block a user