Compare commits

..

30 Commits

Author SHA1 Message Date
Andras Bacsai
d3a1bbc3d0 Merge pull request #596 from coollabsio/next
v3.9.2
2022-09-07 10:16:54 +02:00
Andras Bacsai
0078574ee6 fix: add php 8.1/8.2 2022-09-07 10:02:59 +02:00
Andras Bacsai
7cfd313531 ui: fix loading start/stop db/services 2022-09-07 09:45:16 +02:00
Andras Bacsai
e7919e9a1b ui: fix initial loading icon bg 2022-09-07 09:39:29 +02:00
Andras Bacsai
98073202e9 fix: minio default env variables 2022-09-07 09:28:53 +02:00
Andras Bacsai
8dee345f85 enable autoupdate option for everyone 2022-09-07 09:23:03 +02:00
Andras Bacsai
9161882f33 debug: add debug log 2022-09-07 09:21:28 +02:00
Andras Bacsai
eef313665b fix: service volume generation 2022-09-07 09:18:44 +02:00
Andras Bacsai
53e70fbfcb dev: update devcontainer 2022-09-07 09:15:10 +02:00
Andras Bacsai
05a1721499 fix: revert last change with domain check 2022-09-07 09:15:03 +02:00
Andras Bacsai
2f772080b8 fix: add initial DNS servers 2022-09-07 09:06:30 +02:00
Andras Bacsai
a5548c080c fix: service state update 2022-09-07 08:58:51 +02:00
Andras Bacsai
7e0a1ecc80 ui: fix login/register page 2022-09-07 08:58:40 +02:00
Andras Bacsai
3f2dcccc07 fix: use ip instead of window location host 2022-09-07 08:58:27 +02:00
Andras Bacsai
adc5965b32 fix: use ip address instead of window location 2022-09-07 08:57:32 +02:00
Andras Bacsai
6088f2e573 chore: version++ 2022-09-06 15:46:22 +02:00
Andras Bacsai
fc705746c0 fix: gitlab webhook 2022-09-06 15:45:29 +02:00
Andras Bacsai
8182359fe4 Merge branch 'main' into next 2022-09-06 15:41:22 +02:00
Andras Bacsai
e7ae15162c Update GH Actions prod release 2022-09-06 15:40:16 +02:00
Andras Bacsai
12ca20432d v3.9.1 (#594) 2022-09-06 15:33:32 +02:00
Andras Bacsai
8b7406e168 revert 2022-09-06 15:25:18 +02:00
Andras Bacsai
9d6317f782 fix 2022-09-06 15:13:51 +02:00
Andras Bacsai
d8bdb73140 test tagging 2022-09-06 14:59:24 +02:00
Andras Bacsai
476db15431 test 2022-09-06 14:49:48 +02:00
Andras Bacsai
20ce356296 fix: move restart button to settings 2022-09-06 14:47:37 +02:00
Andras Bacsai
ea594dcbc6 fix: workdir 2022-09-06 14:32:50 +02:00
Andras Bacsai
021b9746a8 update production release 2022-09-06 14:29:54 +02:00
Andras Bacsai
c4615ae557 Dockerfile 2022-09-06 14:20:14 +02:00
Andras Bacsai
95a5089bdc fix: debug api logging + gh actions 2022-09-06 14:08:10 +02:00
Andras Bacsai
73bd62c51e Merge pull request #582 from coollabsio/next
v3.9.0
2022-09-06 09:09:42 +02:00
29 changed files with 402 additions and 245 deletions

View File

@@ -20,7 +20,8 @@
"svelte.svelte-vscode",
"ardenivanov.svelte-intellisense",
"Prisma.prisma",
"bradlc.vscode-tailwindcss"
"bradlc.vscode-tailwindcss",
"waderyan.gitblame"
],
// Use 'forwardPorts' to make a list of ports inside the container available locally.
"forwardPorts": [3000, 3001],

View File

@@ -5,11 +5,11 @@ on:
types: [released]
jobs:
making-something-cool:
runs-on: ubuntu-latest
arm64-build:
runs-on: [self-hosted, arm64]
steps:
- name: Checkout
uses: actions/checkout@v2
uses: actions/checkout@v3
- name: Set up QEMU
uses: docker/setup-qemu-action@v1
- name: Set up Docker Buildx
@@ -26,11 +26,59 @@ jobs:
uses: docker/build-push-action@v2
with:
context: .
platforms: linux/amd64,linux/arm64
platforms: linux/arm64
push: true
tags: coollabsio/coolify:latest,coollabsio/coolify:${{steps.package-version.outputs.current-version}}
cache-from: type=registry,ref=coollabsio/coolify:buildcache
cache-to: type=registry,ref=coollabsio/coolify:buildcache,mode=max
tags: coollabsio/coolify:${{steps.package-version.outputs.current-version}}-arm64
cache-from: type=registry,ref=coollabsio/coolify:buildcache-arm64
cache-to: type=registry,ref=coollabsio/coolify:buildcache-arm64,mode=max
amd64-build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Set up QEMU
uses: docker/setup-qemu-action@v2
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Login to DockerHub
uses: docker/login-action@v2
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@v3
with:
context: .
platforms: linux/amd64
push: true
tags: coollabsio/coolify:${{steps.package-version.outputs.current-version}}-amd64
cache-from: type=registry,ref=coollabsio/coolify:buildcache-amd64
cache-to: type=registry,ref=coollabsio/coolify:buildcache-amd64,mode=max
merge-manifest:
runs-on: ubuntu-latest
needs: [amd64-build, arm64-build]
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Set up QEMU
uses: docker/setup-qemu-action@v2
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Login to DockerHub
uses: docker/login-action@v2
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: Create & publish manifest
run: |
docker manifest create coollabsio/coolify:${{steps.package-version.outputs.current-version}} --amend coollabsio/coolify:${{steps.package-version.outputs.current-version}}-amd64 --amend coollabsio/coolify:${{steps.package-version.outputs.current-version}}-arm64
docker manifest push coollabsio/coolify:${{steps.package-version.outputs.current-version}}
- uses: sarisia/actions-status-discord@v1
if: always()
with:

View File

@@ -85,6 +85,6 @@ jobs:
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Create & publish manifest
run: |
docker manifest create coollabsio/coolify:v3.9.1-rc.1 --amend coollabsio/coolify:v3.9.1-rc.1-amd64 --amend coollabsio/coolify:v3.9.1-rc.1-arm64
docker manifest push coollabsio/coolify:v3.9.1-rc.1
docker manifest create coollabsio/coolify:${{github.event.release.name}} --amend coollabsio/coolify:${{github.event.release.name}}-amd64 --amend coollabsio/coolify:${{github.event.release.name}}-arm64
docker manifest push coollabsio/coolify:${{github.event.release.name}}

View File

@@ -6,11 +6,13 @@ on:
- next
jobs:
staging-release:
runs-on: ubuntu-latest
arm64-making-something-cool:
runs-on: [self-hosted, arm64]
steps:
- name: Checkout
uses: actions/checkout@v2
uses: actions/checkout@v3
with:
ref: "next"
- name: Set up QEMU
uses: docker/setup-qemu-action@v1
- name: Set up Docker Buildx
@@ -20,15 +22,65 @@ jobs:
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-making-something-cool:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
with:
ref: "next"
- name: Set up QEMU
uses: docker/setup-qemu-action@v2
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Login to DockerHub
uses: docker/login-action@v2
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@v3
with:
context: .
platforms: linux/amd64
push: true
tags: coollabsio/coolify:next
cache-from: type=registry,ref=coollabsio/coolify:buildcache-next
cache-to: type=registry,ref=coollabsio/coolify:buildcache-next,mode=max
tags: coollabsio/coolify:next-amd64,coollabsio/coolify:next-test
cache-from: type=registry,ref=coollabsio/coolify:buildcache-next-amd64
cache-to: type=registry,ref=coollabsio/coolify:buildcache-next-amd64,mode=max
merge-manifest-to-be-cool:
runs-on: ubuntu-latest
needs: [arm64-making-something-cool, amd64-making-something-cool]
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Set up QEMU
uses: docker/setup-qemu-action@v2
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Login to DockerHub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Create & publish manifest
run: |
docker manifest create coollabsio/coolify:next --amend coollabsio/coolify:next-amd64 --amend coollabsio/coolify:next-arm64
docker manifest push coollabsio/coolify:next
- uses: sarisia/actions-status-discord@v1
if: always()
with:

View File

@@ -1,6 +1,5 @@
ARG PNPM_VERSION=7.11.0
ARG NPM_VERSION=8.19.1
ARG TARGETPLATFORM
FROM node:18-slim as build
WORKDIR /app
@@ -16,6 +15,7 @@ RUN pnpm build
FROM node:18-slim
WORKDIR /app
ENV NODE_ENV production
ARG TARGETPLATFORM
RUN apt update && apt -y install --no-install-recommends ca-certificates git git-lfs openssh-client curl jq cmake sqlite3 openssl psmisc python3
RUN apt-get clean autoclean && apt-get autoremove --yes && rm -rf /var/lib/{apt,dpkg,cache,log}/

View File

@@ -0,0 +1,2 @@
-- AlterTable
ALTER TABLE "Setting" ADD COLUMN "isAPIDebuggingEnabled" BOOLEAN DEFAULT false;

View File

@@ -11,6 +11,7 @@ datasource db {
model Setting {
id String @id @default(cuid())
fqdn String? @unique
isAPIDebuggingEnabled Boolean? @default(false)
isRegistrationEnabled Boolean @default(false)
dualCerts Boolean @default(false)
minPort Int @default(9000)

View File

@@ -17,7 +17,6 @@ const algorithm = 'aes-256-ctr';
async function main() {
// Enable registration for the first user
// Set initial HAProxy password
const settingsFound = await prisma.setting.findFirst({});
if (!settingsFound) {
await prisma.setting.create({
@@ -25,7 +24,8 @@ async function main() {
isRegistrationEnabled: true,
proxyPassword: encrypt(generatePassword()),
proxyUser: cuid(),
arch: process.arch
arch: process.arch,
DNSServers: '1.1.1.1,8.8.8.8'
}
});
} else {

View File

@@ -26,140 +26,143 @@ declare module 'fastify' {
const port = isDev ? 3001 : 3000;
const host = '0.0.0.0';
const fastify = Fastify({
logger: false,
trustProxy: true
});
const schema = {
type: 'object',
required: ['COOLIFY_SECRET_KEY', 'COOLIFY_DATABASE_URL', 'COOLIFY_IS_ON'],
properties: {
COOLIFY_APP_ID: {
type: 'string',
},
COOLIFY_SECRET_KEY: {
type: 'string',
},
COOLIFY_DATABASE_URL: {
type: 'string',
default: 'file:../db/dev.db'
},
COOLIFY_SENTRY_DSN: {
type: 'string',
default: null
},
COOLIFY_IS_ON: {
type: 'string',
default: 'docker'
},
COOLIFY_WHITE_LABELED: {
type: 'string',
default: 'false'
},
COOLIFY_WHITE_LABELED_ICON: {
type: 'string',
default: null
},
COOLIFY_AUTO_UPDATE: {
type: 'string',
default: 'false'
},
}
};
const options = {
schema,
dotenv: true
};
fastify.register(env, options);
if (!isDev) {
fastify.register(serve, {
root: path.join(__dirname, './public'),
preCompressed: true
prisma.setting.findFirst().then(async (settings) => {
const fastify = Fastify({
logger: settings?.isAPIDebuggingEnabled || false,
trustProxy: true
});
fastify.setNotFoundHandler(async function (request, reply) {
if (request.raw.url && request.raw.url.startsWith('/api')) {
return reply.status(404).send({
success: false
});
const schema = {
type: 'object',
required: ['COOLIFY_SECRET_KEY', 'COOLIFY_DATABASE_URL', 'COOLIFY_IS_ON'],
properties: {
COOLIFY_APP_ID: {
type: 'string',
},
COOLIFY_SECRET_KEY: {
type: 'string',
},
COOLIFY_DATABASE_URL: {
type: 'string',
default: 'file:../db/dev.db'
},
COOLIFY_SENTRY_DSN: {
type: 'string',
default: null
},
COOLIFY_IS_ON: {
type: 'string',
default: 'docker'
},
COOLIFY_WHITE_LABELED: {
type: 'string',
default: 'false'
},
COOLIFY_WHITE_LABELED_ICON: {
type: 'string',
default: null
},
COOLIFY_AUTO_UPDATE: {
type: 'string',
default: 'false'
},
}
return reply.status(200).sendFile('index.html');
};
const options = {
schema,
dotenv: true
};
fastify.register(env, options);
if (!isDev) {
fastify.register(serve, {
root: path.join(__dirname, './public'),
preCompressed: true
});
fastify.setNotFoundHandler(async function (request, reply) {
if (request.raw.url && request.raw.url.startsWith('/api')) {
return reply.status(404).send({
success: false
});
}
return reply.status(200).sendFile('index.html');
});
}
fastify.register(autoLoad, {
dir: join(__dirname, 'plugins')
});
fastify.register(autoLoad, {
dir: join(__dirname, 'routes')
});
}
fastify.register(autoLoad, {
dir: join(__dirname, 'plugins')
});
fastify.register(autoLoad, {
dir: join(__dirname, 'routes')
});
fastify.register(cookie)
fastify.register(cors);
fastify.addHook('onRequest', async (request, reply) => {
let allowedList = ['coolify:3000'];
const { ipv4, ipv6, fqdn } = await prisma.setting.findFirst({})
fastify.register(cookie)
fastify.register(cors);
fastify.addHook('onRequest', async (request, reply) => {
let allowedList = ['coolify:3000'];
const { ipv4, ipv6, fqdn } = await prisma.setting.findFirst({})
ipv4 && allowedList.push(`${ipv4}:3000`);
ipv6 && allowedList.push(ipv6);
fqdn && allowedList.push(getDomain(fqdn));
ipv4 && allowedList.push(`${ipv4}:3000`);
ipv6 && allowedList.push(ipv6);
fqdn && allowedList.push(getDomain(fqdn));
isDev && allowedList.push('localhost:3000') && allowedList.push('localhost:3001') && allowedList.push('host.docker.internal:3001');
const remotes = await prisma.destinationDocker.findMany({ where: { remoteEngine: true, remoteVerified: true } })
if (remotes.length > 0) {
remotes.forEach(remote => {
allowedList.push(`${remote.remoteIpAddress}:3000`);
})
}
if (!allowedList.includes(request.headers.host)) {
// console.log('not allowed', request.headers.host)
}
})
fastify.listen({ port, host }, async (err: any, address: any) => {
if (err) {
console.error(err);
process.exit(1);
}
console.log(`Coolify's API is listening on ${host}:${port}`);
await initServer();
const remotes = await prisma.destinationDocker.findMany({ where: { remoteEngine: true, remoteVerified: true } })
if (remotes.length > 0) {
remotes.forEach(remote => {
allowedList.push(`${remote.remoteIpAddress}:3000`);
})
}
if (!allowedList.includes(request.headers.host)) {
console.log('not allowed', request.headers.host)
}
const graceful = new Graceful({ brees: [scheduler] });
graceful.listen();
setInterval(async () => {
if (!scheduler.workers.has('deployApplication')) {
scheduler.run('deployApplication');
}
if (!scheduler.workers.has('infrastructure')) {
scheduler.run('infrastructure');
}
}, 2000)
// autoUpdater
setInterval(async () => {
scheduler.workers.has('infrastructure') && scheduler.workers.get('infrastructure').postMessage("action:autoUpdater")
}, isDev ? 5000 : 60000 * 15)
// cleanupStorage
setInterval(async () => {
scheduler.workers.has('infrastructure') && scheduler.workers.get('infrastructure').postMessage("action:cleanupStorage")
}, isDev ? 6000 : 60000 * 10)
// checkProxies
setInterval(async () => {
scheduler.workers.has('infrastructure') && scheduler.workers.get('infrastructure').postMessage("action:checkProxies")
}, 10000)
// cleanupPrismaEngines
// setInterval(async () => {
// scheduler.workers.has('infrastructure') && scheduler.workers.get('infrastructure').postMessage("action:cleanupPrismaEngines")
// }, 60000)
await Promise.all([
getArch(),
getIPAddress(),
configureRemoteDockers(),
])
});
})
fastify.listen({ port, host }, async (err: any, address: any) => {
if (err) {
console.error(err);
process.exit(1);
}
console.log(`Coolify's API is listening on ${host}:${port}`);
await initServer();
const graceful = new Graceful({ brees: [scheduler] });
graceful.listen();
setInterval(async () => {
if (!scheduler.workers.has('deployApplication')) {
scheduler.run('deployApplication');
}
if (!scheduler.workers.has('infrastructure')) {
scheduler.run('infrastructure');
}
}, 2000)
// autoUpdater
setInterval(async () => {
scheduler.workers.has('infrastructure') && scheduler.workers.get('infrastructure').postMessage("action:autoUpdater")
}, isDev ? 5000 : 60000 * 15)
// cleanupStorage
setInterval(async () => {
scheduler.workers.has('infrastructure') && scheduler.workers.get('infrastructure').postMessage("action:cleanupStorage")
}, isDev ? 6000 : 60000 * 10)
// checkProxies
setInterval(async () => {
scheduler.workers.has('infrastructure') && scheduler.workers.get('infrastructure').postMessage("action:checkProxies")
}, 10000)
// cleanupPrismaEngines
// setInterval(async () => {
// scheduler.workers.has('infrastructure') && scheduler.workers.get('infrastructure').postMessage("action:cleanupPrismaEngines")
// }, 60000)
await Promise.all([
getArch(),
getIPAddress(),
// configureRemoteDockers(),
])
});
async function getIPAddress() {
const { publicIpv4, publicIpv6 } = await import('public-ip')
try {

View File

@@ -357,21 +357,15 @@ import * as buildpacks from '../lib/buildPacks';
await saveBuildLog({ line: error, buildId, applicationId: application.id });
}
});
}
await pAll.default(actions, { concurrency })
}
} catch (error) {
console.log(error)
} finally {
}
})
while (true) {
await th()
}
} else process.exit(0);
})();

View File

@@ -89,6 +89,22 @@ export function setDefaultBaseImage(buildPack: string | null, deploymentType: st
}
];
const phpVersions = [
{
value: 'webdevops/php-apache:8.2',
label: 'webdevops/php-apache:8.2'
},
{
value: 'webdevops/php-nginx:8.2',
label: 'webdevops/php-nginx:8.2'
},
{
value: 'webdevops/php-apache:8.1',
label: 'webdevops/php-apache:8.1'
},
{
value: 'webdevops/php-nginx:8.1',
label: 'webdevops/php-nginx:8.1'
},
{
value: 'webdevops/php-apache:8.0',
label: 'webdevops/php-apache:8.0'
@@ -145,6 +161,22 @@ export function setDefaultBaseImage(buildPack: string | null, deploymentType: st
value: 'webdevops/php-nginx:5.6',
label: 'webdevops/php-nginx:5.6'
},
{
value: 'webdevops/php-apache:8.2-alpine',
label: 'webdevops/php-apache:8.2-alpine'
},
{
value: 'webdevops/php-nginx:8.2-alpine',
label: 'webdevops/php-nginx:8.2-alpine'
},
{
value: 'webdevops/php-apache:8.1-alpine',
label: 'webdevops/php-apache:8.1-alpine'
},
{
value: 'webdevops/php-nginx:8.1-alpine',
label: 'webdevops/php-nginx:8.1-alpine'
},
{
value: 'webdevops/php-apache:8.0-alpine',
label: 'webdevops/php-apache:8.0-alpine'
@@ -305,11 +337,11 @@ export function setDefaultBaseImage(buildPack: string | null, deploymentType: st
payload.baseImage = 'denoland/deno:latest';
}
if (buildPack === 'php') {
payload.baseImage = 'webdevops/php-apache:8.0-alpine';
payload.baseImage = 'webdevops/php-apache:8.2-alpine';
payload.baseImages = phpVersions;
}
if (buildPack === 'laravel') {
payload.baseImage = 'webdevops/php-apache:8.0-alpine';
payload.baseImage = 'webdevops/php-apache:8.2-alpine';
payload.baseBuildImage = 'node:18';
payload.baseBuildImages = nodeVersions;
}

View File

@@ -21,7 +21,7 @@ import { scheduler } from './scheduler';
import { supportedServiceTypesAndVersions } from './services/supportedVersions';
import { includeServices } from './services/common';
export const version = '3.9.1-rc.1';
export const version = '3.9.2';
export const isDev = process.env.NODE_ENV === 'development';
const algorithm = 'aes-256-ctr';
@@ -974,13 +974,14 @@ export const createDirectories = async ({
}): Promise<{ workdir: string; repodir: string }> => {
const repodir = `/tmp/build-sources/${repository}/`;
const workdir = `/tmp/build-sources/${repository}/${buildId}`;
let workdirFound = false;
try {
await fs.stat(workdir);
workdirFound = !!(await fs.stat(workdir));
} catch (error) { }
if (workdirFound) {
await asyncExecShell(`rm -fr ${workdir}`);
await asyncExecShell(`mkdir -p ${workdir}`);
} catch(error) {
await asyncExecShell(`mkdir -p ${workdir}`);
}
await asyncExecShell(`mkdir -p ${workdir}`);
return {
workdir,
repodir

View File

@@ -198,7 +198,7 @@ COPY ./init-db.sh /docker-entrypoint-initdb.d/init-db.sh`;
await fs.writeFile(`${workdir}/Dockerfile`, Dockerfile);
const { volumeMounts } = persistentVolumes(id, persistentStorage, config.plausibleAnalytics)
const { volumeMounts } = persistentVolumes(id, persistentStorage, config)
const composeFile: ComposeFile = {
version: '3.8',
@@ -333,6 +333,8 @@ async function startMinioService(request: FastifyRequest<ServiceStartStop>) {
image: `${image}:${version}`,
volumes: [`${id}-minio-data:/data`],
environmentVariables: {
MINIO_SERVER_URL: fqdn,
MINIO_DOMAIN: getDomain(fqdn),
MINIO_ROOT_USER: rootUser,
MINIO_ROOT_PASSWORD: rootUserPassword,
MINIO_BROWSER_REDIRECT_URL: fqdn
@@ -852,7 +854,7 @@ async function startGhostService(request: FastifyRequest<ServiceStartStop>) {
});
}
const { volumeMounts } = persistentVolumes(id, persistentStorage, config.ghost)
const { volumeMounts } = persistentVolumes(id, persistentStorage, config)
const composeFile: ComposeFile = {
version: '3.8',
services: {
@@ -1086,7 +1088,7 @@ async function startUmamiService(request: FastifyRequest<ServiceStartStop>) {
FROM ${config.postgresql.image}
COPY ./schema.postgresql.sql /docker-entrypoint-initdb.d/schema.postgresql.sql`;
await fs.writeFile(`${workdir}/Dockerfile`, Dockerfile);
const { volumeMounts } = persistentVolumes(id, persistentStorage, config.umami)
const { volumeMounts } = persistentVolumes(id, persistentStorage, config)
const composeFile: ComposeFile = {
version: '3.8',
services: {
@@ -1114,6 +1116,7 @@ async function startUmamiService(request: FastifyRequest<ServiceStartStop>) {
},
volumes: volumeMounts
};
console.log(composeFile)
const composeFileDestination = `${workdir}/docker-compose.yaml`;
await fs.writeFile(composeFileDestination, yaml.dump(composeFile));
await startServiceContainers(destinationDocker.id, composeFileDestination)
@@ -1167,7 +1170,7 @@ async function startHasuraService(request: FastifyRequest<ServiceStartStop>) {
});
}
const { volumeMounts } = persistentVolumes(id, persistentStorage, config.hasura)
const { volumeMounts } = persistentVolumes(id, persistentStorage, config)
const composeFile: ComposeFile = {
version: '3.8',
services: {
@@ -1272,7 +1275,7 @@ async function startFiderService(request: FastifyRequest<ServiceStartStop>) {
config.fider.environmentVariables[secret.name] = secret.value;
});
}
const { volumeMounts } = persistentVolumes(id, persistentStorage, config.fider)
const { volumeMounts } = persistentVolumes(id, persistentStorage, config)
const composeFile: ComposeFile = {
version: '3.8',
services: {
@@ -1880,7 +1883,7 @@ async function startMoodleService(request: FastifyRequest<ServiceStartStop>) {
config.moodle.environmentVariables[secret.name] = secret.value;
});
}
const { volumeMounts } = persistentVolumes(id, persistentStorage, config.moodle)
const { volumeMounts } = persistentVolumes(id, persistentStorage, config)
const composeFile: ComposeFile = {
version: '3.8',
services: {
@@ -2006,7 +2009,7 @@ async function startGlitchTipService(request: FastifyRequest<ServiceStartStop>)
config.glitchTip.environmentVariables[secret.name] = secret.value;
});
}
const { volumeMounts } = persistentVolumes(id, persistentStorage, config.glitchTip)
const { volumeMounts } = persistentVolumes(id, persistentStorage, config)
const composeFile: ComposeFile = {
version: '3.8',
services: {
@@ -2475,7 +2478,7 @@ async function startTaigaService(request: FastifyRequest<ServiceStartStop>) {
TAIGA_SECRET_KEY: secretKey,
}
},
postgresql: {
image: `postgres:12.3`,
volumes: [`${id}-postgresql-data:/var/lib/postgresql/data`],

View File

@@ -525,9 +525,7 @@ export async function checkDomain(request: FastifyRequest<CheckDomain>) {
}
export async function checkDNS(request: FastifyRequest<CheckDNS>) {
try {
const { id } = request.params
let { exposePort, fqdn, forceSave, dualCerts } = request.body
if (!fqdn) {
return {}

View File

@@ -28,6 +28,7 @@ export async function saveSettings(request: FastifyRequest<SaveSettings>, reply:
try {
const {
fqdn,
isAPIDebuggingEnabled,
isRegistrationEnabled,
dualCerts,
minPort,
@@ -39,7 +40,7 @@ export async function saveSettings(request: FastifyRequest<SaveSettings>, reply:
const { id } = await listSettings();
await prisma.setting.update({
where: { id },
data: { isRegistrationEnabled, dualCerts, isAutoUpdateEnabled, isDNSCheckEnabled, DNSServers }
data: { isRegistrationEnabled, dualCerts, isAutoUpdateEnabled, isDNSCheckEnabled, DNSServers, isAPIDebuggingEnabled }
});
if (fqdn) {
await prisma.setting.update({ where: { id }, data: { fqdn } });

View File

@@ -3,6 +3,7 @@ import { OnlyId } from "../../../../types"
export interface SaveSettings {
Body: {
fqdn: string,
isAPIDebuggingEnabled: boolean,
isRegistrationEnabled: boolean,
dualCerts: boolean,
minPort: number,

View File

@@ -133,7 +133,7 @@ export async function gitLabEvents(request: FastifyRequest<GitLabEvents>) {
await prisma.build.create({
data: {
id: buildId,
pullmergeRequestId,
pullmergeRequestId: pullmergeRequestId.toString(),
sourceBranch,
applicationId: application.id,
destinationDockerId: application.destinationDocker.id,

View File

@@ -20,13 +20,12 @@
let usageInterval: any;
let loading = {
usage: false,
cleanup: false,
restart: false
cleanup: false
};
import { addToast, appSession } from '$lib/store';
import { onDestroy, onMount } from 'svelte';
import { get, post } from '$lib/api';
import { asyncSleep, errorNotification } from '$lib/common';
import { errorNotification } from '$lib/common';
async function getStatus() {
if (loading.usage) return;
loading.usage = true;
@@ -34,45 +33,7 @@
usage = data.usage;
loading.usage = false;
}
async function restartCoolify() {
const sure = confirm(
'Are you sure you would like to restart Coolify? Currently running deployments will be stopped and restarted.'
);
if (sure) {
loading.restart = true;
try {
await post(`/internal/restart`, {});
await asyncSleep(10000);
let reachable = false;
let tries = 0;
do {
await asyncSleep(4000);
try {
await get(`/undead`);
reachable = true;
} catch (error) {
reachable = false;
}
if (reachable) break;
tries++;
} while (!reachable || tries < 120);
addToast({
message: 'New version reachable. Reloading...',
type: 'success'
});
await asyncSleep(3000);
return window.location.reload();
addToast({
type: 'success',
message: 'Coolify restarted successfully. It will take a moment.'
});
} catch (error) {
return errorNotification(error);
} finally {
loading.restart = false;
}
}
}
onDestroy(() => {
clearInterval(usageInterval);
});
@@ -112,11 +73,6 @@
<button on:click={manuallyCleanupStorage} class:loading={loading.cleanup} class="btn btn-sm"
>Cleanup Storage</button
>
<button
on:click={restartCoolify}
class:loading={loading.restart}
class="btn btn-sm bg-red-600 hover:bg-red-500">Restart Coolify</button
>
{/if}
</div>
</div>

View File

@@ -244,7 +244,7 @@
{/if}
{#if $status.application.initialLoading}
<button
class="icons flex animate-spin items-center space-x-2 bg-transparent text-sm duration-500 ease-in-out"
class="icons flex animate-spin items-center space-x-2 bg-transparent text-sm duration-500 ease-in-out hover:bg-transparent"
>
<svg
xmlns="http://www.w3.org/2000/svg"

View File

@@ -218,7 +218,8 @@
if (loading) return;
loading = true;
try {
nonWWWDomain = application.fqdn != null && getDomain(application.fqdn).replace(/^www\./, '');
nonWWWDomain = application.fqdn && getDomain(application.fqdn).replace(/^www\./, '');
console.log({debug: nonWWWDomain})
if (application.deploymentType)
application.deploymentType = application.deploymentType.toLowerCase();
!isBot &&

View File

@@ -87,12 +87,15 @@
const sure = confirm($t('database.confirm_stop', { name: database.name }));
if (sure) {
$status.database.initialLoading = true;
$status.database.loading = true;
try {
await post(`/databases/${database.id}/stop`, {});
} catch (error) {
return errorNotification(error);
} finally {
$status.database.initialLoading = false;
$status.database.loading = false;
await getStatus();
}
}
}
@@ -175,7 +178,7 @@
{/if}
{#if $status.database.initialLoading}
<button
class="icons flex animate-spin items-center space-x-2 bg-transparent text-sm duration-500 ease-in-out"
class="icons flex animate-spin items-center space-x-2 bg-transparent text-sm duration-500 ease-in-out hover:bg-transparent"
>
<svg
xmlns="http://www.w3.org/2000/svg"

View File

@@ -70,7 +70,7 @@
</div>
</div>
<div class="prose">
<h4>Coolify dashboard</h4>
<h4>Coolify</h4>
</div>
{/if}
</div>

View File

@@ -100,7 +100,7 @@
</div>
</div>
<div class="prose">
<h4>Coolify dashboard</h4>
<h4>Coolify</h4>
</div>
{/if}
</div>

View File

@@ -12,7 +12,14 @@
import { get, post } from '$lib/api';
import { errorNotification, getDomain } from '$lib/common';
import { t } from '$lib/translations';
import { appSession, disabledButton, status, location, setLocation, addToast } from '$lib/store';
import {
appSession,
status,
setLocation,
addToast,
checkIfDeploymentEnabledServices,
isDeploymentEnabled
} from '$lib/store';
import CopyPasswordField from '$lib/components/CopyPasswordField.svelte';
import Setting from '$lib/components/Setting.svelte';
@@ -78,8 +85,8 @@
});
await post(`/services/${id}`, { ...service });
setLocation(service);
$disabledButton = false;
forceSave = false;
$isDeploymentEnabled = checkIfDeploymentEnabledServices($appSession.isAdmin, service);
return addToast({
message: 'Configuration saved.',
type: 'success'

View File

@@ -12,7 +12,7 @@
export let readOnly: any;
export let settings: any;
const { id } = $page.params;
const { ipv4, ipv6 } = settings;
let ftpUrl = generateUrl(service.wordpress.ftpPublicPort);
let ftpUser = service.wordpress.ftpUser;
let ftpPassword = service.wordpress.ftpPassword;
@@ -22,7 +22,7 @@
function generateUrl(publicPort: any) {
return browser
? `sftp://${
settings?.fqdn ? getDomain(settings.fqdn) : window.location.hostname
settings?.fqdn ? getDomain(settings.fqdn) : ipv4 || ipv6
}:${publicPort}`
: 'Loading...';
}

View File

@@ -97,12 +97,15 @@
const sure = confirm($t('database.confirm_stop', { name: service.name }));
if (sure) {
$status.service.initialLoading = true;
$status.service.loading = true;
try {
await post(`/services/${service.id}/${service.type}/stop`, {});
} catch (error) {
return errorNotification(error);
} finally {
$status.service.initialLoading = false;
$status.service.loading = false;
await getStatus();
}
}
}

View File

@@ -23,10 +23,11 @@
import { browser } from '$app/env';
import { t } from '$lib/translations';
import { addToast, appSession, features } from '$lib/store';
import { errorNotification, getDomain } from '$lib/common';
import { asyncSleep, errorNotification, getDomain } from '$lib/common';
import Menu from './_Menu.svelte';
import Explainer from '$lib/components/Explainer.svelte';
let isAPIDebuggingEnabled = settings.isAPIDebuggingEnabled;
let isRegistrationEnabled = settings.isRegistrationEnabled;
let dualCerts = settings.dualCerts;
let isAutoUpdateEnabled = settings.isAutoUpdateEnabled;
@@ -44,7 +45,8 @@
let loading = {
save: false,
remove: false,
proxyMigration: false
proxyMigration: false,
restart: false
};
async function removeFqdn() {
@@ -75,8 +77,11 @@
if (name === 'isDNSCheckEnabled') {
isDNSCheckEnabled = !isDNSCheckEnabled;
}
if (name === 'isAPIDebuggingEnabled') {
isAPIDebuggingEnabled = !isAPIDebuggingEnabled;
}
await post(`/settings`, {
isAPIDebuggingEnabled,
isRegistrationEnabled,
dualCerts,
isAutoUpdateEnabled,
@@ -152,6 +157,41 @@
function resetView() {
forceSave = false;
}
async function restartCoolify() {
const sure = confirm(
'Are you sure you would like to restart Coolify? Currently running deployments will be stopped and restarted.'
);
if (sure) {
loading.restart = true;
try {
await post(`/internal/restart`, {});
await asyncSleep(10000);
let reachable = false;
let tries = 0;
do {
await asyncSleep(4000);
try {
await get(`/undead`);
reachable = true;
} catch (error) {
reachable = false;
}
if (reachable) break;
tries++;
} while (!reachable || tries < 120);
addToast({
message: 'New version reachable. Reloading...',
type: 'success'
});
await asyncSleep(3000);
return window.location.reload();
} catch (error) {
return errorNotification(error);
} finally {
loading.restart = false;
}
}
}
</script>
<div class="flex space-x-1 p-6 font-bold">
@@ -182,11 +222,14 @@
on:click|preventDefault={removeFqdn}
disabled={loading.remove}
class="btn btn-sm"
class:bg-red-600={!loading.remove}
class:hover:bg-red-500={!loading.remove}
>{loading.remove ? $t('forms.removing') : $t('forms.remove_domain')}</button
>
{/if}
<button
on:click={restartCoolify}
class:loading={loading.restart}
class="btn btn-sm bg-red-600 hover:bg-red-500">Restart Coolify</button
>
</div>
<div class="grid grid-flow-row gap-2 px-10">
<!-- <Language /> -->
@@ -310,17 +353,24 @@
on:click={() => changeSettings('isRegistrationEnabled')}
/>
</div>
{#if browser && $features.beta}
<div class="grid grid-cols-2 items-center">
<Setting
id="isAutoUpdateEnabled"
bind:setting={isAutoUpdateEnabled}
title={$t('setting.auto_update_enabled')}
description={$t('setting.auto_update_enabled_explainer')}
on:click={() => changeSettings('isAutoUpdateEnabled')}
/>
</div>
{/if}
<div class="grid grid-cols-2 items-center">
<Setting
id="isAPIDebuggingEnabled"
bind:setting={isAPIDebuggingEnabled}
title="API Debugging"
description="Enable API debugging. This will log all API requests and responses.<br><br>You need to restart the Coolify for this to take effect."
on:click={() => changeSettings('isAPIDebuggingEnabled')}
/>
</div>
<div class="grid grid-cols-2 items-center">
<Setting
id="isAutoUpdateEnabled"
bind:setting={isAutoUpdateEnabled}
title={$t('setting.auto_update_enabled')}
description={$t('setting.auto_update_enabled_explainer')}
on:click={() => changeSettings('isAutoUpdateEnabled')}
/>
</div>
</div>
</form>
</div>

View File

@@ -46,8 +46,8 @@
customPort: source.customPort
});
const { organization, htmlUrl } = source;
const { fqdn } = settings;
const host = dev ? getAPIUrl() : fqdn ? fqdn : `http://${window.location.host}` || '';
const { fqdn, ipv4, ipv6 } = settings;
const host = dev ? getAPIUrl() : fqdn ? fqdn : `http://${ipv4 || ipv6}` || '';
const domain = getDomain(fqdn);
let url = 'settings/apps/new';

View File

@@ -1,7 +1,7 @@
{
"name": "coolify",
"description": "An open-source & self-hostable Heroku / Netlify alternative.",
"version": "3.9.1-rc.1",
"version": "3.9.2",
"license": "Apache-2.0",
"repository": "github:coollabsio/coolify",
"scripts": {