mirror of
https://github.com/ershisan99/coolify.git
synced 2025-12-18 20:59:24 +00:00
Compare commits
64 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4dcc76d366 | ||
|
|
d2fad19a11 | ||
|
|
7c92c4c964 | ||
|
|
5a71d33236 | ||
|
|
1b4db4f793 | ||
|
|
c084b22815 | ||
|
|
acacef95cd | ||
|
|
5d722183d3 | ||
|
|
ac19ea5407 | ||
|
|
d19b05b970 | ||
|
|
a0795136ac | ||
|
|
d2566e345a | ||
|
|
66cd7cf90e | ||
|
|
9a599981ef | ||
|
|
f51f7bc82a | ||
|
|
dbcbac0137 | ||
|
|
e722f8a87c | ||
|
|
61679749eb | ||
|
|
23e12c9c44 | ||
|
|
6da78cd3e5 | ||
|
|
78ce8100a3 | ||
|
|
76ba338b45 | ||
|
|
823fe2deb2 | ||
|
|
cb90f692f2 | ||
|
|
0325343ede | ||
|
|
69d1556a1d | ||
|
|
2daa043840 | ||
|
|
f340ca9d05 | ||
|
|
02abd038fa | ||
|
|
b9da68ec28 | ||
|
|
88b3910d80 | ||
|
|
160412f6e4 | ||
|
|
59a86b25fc | ||
|
|
49e58b39f5 | ||
|
|
58e0757bbd | ||
|
|
5ff4197572 | ||
|
|
b56e28d27a | ||
|
|
c3d39e1dd4 | ||
|
|
716aa36bfd | ||
|
|
f01460170e | ||
|
|
a414ce282d | ||
|
|
6c32f3b130 | ||
|
|
4cf907c572 | ||
|
|
b28baaa5aa | ||
|
|
980dea64e0 | ||
|
|
c340f6436f | ||
|
|
54376fd105 | ||
|
|
ef006578b2 | ||
|
|
b0b1ee0c60 | ||
|
|
4e2026aa2d | ||
|
|
e0e50b4bd5 | ||
|
|
c9b52f1310 | ||
|
|
0195213dfb | ||
|
|
d6225cbde3 | ||
|
|
7b4c194b97 | ||
|
|
a5ecff24a3 | ||
|
|
c9c003dc9b | ||
|
|
fd95936219 | ||
|
|
15a3fd4456 | ||
|
|
df896542e4 | ||
|
|
8927e81274 | ||
|
|
340f061827 | ||
|
|
15cbac97c2 | ||
|
|
bb32d0f7d1 |
27
package.json
27
package.json
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "coolify",
|
||||
"description": "An open-source & self-hostable Heroku / Netlify alternative.",
|
||||
"version": "2.0.20",
|
||||
"version": "2.0.26",
|
||||
"license": "AGPL-3.0",
|
||||
"scripts": {
|
||||
"dev": "docker-compose -f docker-compose-dev.yaml up -d && NODE_ENV=development svelte-kit dev --host 0.0.0.0",
|
||||
@@ -25,31 +25,31 @@
|
||||
"prepare": "husky install"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@sveltejs/adapter-node": "1.0.0-next.68",
|
||||
"@sveltejs/adapter-node": "1.0.0-next.69",
|
||||
"@sveltejs/adapter-static": "1.0.0-next.28",
|
||||
"@sveltejs/kit": "1.0.0-next.278",
|
||||
"@sveltejs/kit": "1.0.0-next.283",
|
||||
"@types/bcrypt": "5.0.0",
|
||||
"@types/js-cookie": "3.0.1",
|
||||
"@types/node": "17.0.18",
|
||||
"@types/node": "17.0.20",
|
||||
"@types/node-forge": "1.0.0",
|
||||
"@typescript-eslint/eslint-plugin": "4.31.1",
|
||||
"@typescript-eslint/parser": "4.31.1",
|
||||
"@zerodevx/svelte-toast": "0.6.3",
|
||||
"@zerodevx/svelte-toast": "0.7.0",
|
||||
"autoprefixer": "10.4.2",
|
||||
"cross-var": "1.1.0",
|
||||
"eslint": "7.32.0",
|
||||
"eslint-config-prettier": "8.3.0",
|
||||
"eslint-plugin-svelte3": "3.2.1",
|
||||
"eslint-config-prettier": "8.4.0",
|
||||
"eslint-plugin-svelte3": "3.4.0",
|
||||
"husky": "7.0.4",
|
||||
"lint-staged": "12.3.4",
|
||||
"postcss": "8.4.6",
|
||||
"prettier": "2.5.1",
|
||||
"prettier-plugin-svelte": "2.6.0",
|
||||
"prettier-plugin-tailwindcss": "0.1.7",
|
||||
"prisma": "3.9.2",
|
||||
"prisma": "3.10.0",
|
||||
"svelte": "3.46.4",
|
||||
"svelte-check": "2.4.3",
|
||||
"svelte-preprocess": "4.10.3",
|
||||
"svelte-check": "2.4.5",
|
||||
"svelte-preprocess": "4.10.4",
|
||||
"tailwindcss": "3.0.23",
|
||||
"ts-node": "10.5.0",
|
||||
"tslib": "2.3.1",
|
||||
@@ -58,10 +58,10 @@
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
"@iarna/toml": "2.2.5",
|
||||
"@prisma/client": "3.9.2",
|
||||
"@prisma/client": "3.10.0",
|
||||
"@sentry/node": "6.17.9",
|
||||
"bcrypt": "5.0.1",
|
||||
"bullmq": "1.73.0",
|
||||
"bullmq": "1.74.2",
|
||||
"compare-versions": "4.1.3",
|
||||
"cookie": "0.4.2",
|
||||
"cuid": "2.1.8",
|
||||
@@ -69,11 +69,12 @@
|
||||
"dockerode": "3.3.1",
|
||||
"dotenv-extended": "2.9.0",
|
||||
"generate-password": "1.7.0",
|
||||
"get-port": "6.1.0",
|
||||
"get-port": "6.1.1",
|
||||
"got": "12.0.1",
|
||||
"js-cookie": "3.0.1",
|
||||
"js-yaml": "4.1.0",
|
||||
"jsonwebtoken": "8.5.1",
|
||||
"mustache": "^4.2.0",
|
||||
"node-forge": "1.2.1",
|
||||
"svelte-kit-cookie-session": "2.1.2",
|
||||
"tailwindcss-scrollbar": "^0.1.0",
|
||||
|
||||
142
pnpm-lock.yaml
generated
142
pnpm-lock.yaml
generated
@@ -2,21 +2,21 @@ lockfileVersion: 5.3
|
||||
|
||||
specifiers:
|
||||
'@iarna/toml': 2.2.5
|
||||
'@prisma/client': 3.9.2
|
||||
'@prisma/client': 3.10.0
|
||||
'@sentry/node': 6.17.9
|
||||
'@sveltejs/adapter-node': 1.0.0-next.68
|
||||
'@sveltejs/adapter-node': 1.0.0-next.69
|
||||
'@sveltejs/adapter-static': 1.0.0-next.28
|
||||
'@sveltejs/kit': 1.0.0-next.278
|
||||
'@sveltejs/kit': 1.0.0-next.283
|
||||
'@types/bcrypt': 5.0.0
|
||||
'@types/js-cookie': 3.0.1
|
||||
'@types/node': 17.0.18
|
||||
'@types/node': 17.0.20
|
||||
'@types/node-forge': 1.0.0
|
||||
'@typescript-eslint/eslint-plugin': 4.31.1
|
||||
'@typescript-eslint/parser': 4.31.1
|
||||
'@zerodevx/svelte-toast': 0.6.3
|
||||
'@zerodevx/svelte-toast': 0.7.0
|
||||
autoprefixer: 10.4.2
|
||||
bcrypt: 5.0.1
|
||||
bullmq: 1.73.0
|
||||
bullmq: 1.74.2
|
||||
compare-versions: 4.1.3
|
||||
cookie: 0.4.2
|
||||
cross-var: 1.1.0
|
||||
@@ -25,26 +25,27 @@ specifiers:
|
||||
dockerode: 3.3.1
|
||||
dotenv-extended: 2.9.0
|
||||
eslint: 7.32.0
|
||||
eslint-config-prettier: 8.3.0
|
||||
eslint-plugin-svelte3: 3.2.1
|
||||
eslint-config-prettier: 8.4.0
|
||||
eslint-plugin-svelte3: 3.4.0
|
||||
generate-password: 1.7.0
|
||||
get-port: 6.1.0
|
||||
get-port: 6.1.1
|
||||
got: 12.0.1
|
||||
husky: 7.0.4
|
||||
js-cookie: 3.0.1
|
||||
js-yaml: 4.1.0
|
||||
jsonwebtoken: 8.5.1
|
||||
lint-staged: 12.3.4
|
||||
mustache: ^4.2.0
|
||||
node-forge: 1.2.1
|
||||
postcss: 8.4.6
|
||||
prettier: 2.5.1
|
||||
prettier-plugin-svelte: 2.6.0
|
||||
prettier-plugin-tailwindcss: 0.1.7
|
||||
prisma: 3.9.2
|
||||
prisma: 3.10.0
|
||||
svelte: 3.46.4
|
||||
svelte-check: 2.4.3
|
||||
svelte-check: 2.4.5
|
||||
svelte-kit-cookie-session: 2.1.2
|
||||
svelte-preprocess: 4.10.3
|
||||
svelte-preprocess: 4.10.4
|
||||
tailwindcss: 3.0.23
|
||||
tailwindcss-scrollbar: ^0.1.0
|
||||
ts-node: 10.5.0
|
||||
@@ -54,10 +55,10 @@ specifiers:
|
||||
|
||||
dependencies:
|
||||
'@iarna/toml': 2.2.5
|
||||
'@prisma/client': 3.9.2_prisma@3.9.2
|
||||
'@prisma/client': 3.10.0_prisma@3.10.0
|
||||
'@sentry/node': 6.17.9
|
||||
bcrypt: 5.0.1
|
||||
bullmq: 1.73.0
|
||||
bullmq: 1.74.2
|
||||
compare-versions: 4.1.3
|
||||
cookie: 0.4.2
|
||||
cuid: 2.1.8
|
||||
@@ -65,44 +66,45 @@ dependencies:
|
||||
dockerode: 3.3.1
|
||||
dotenv-extended: 2.9.0
|
||||
generate-password: 1.7.0
|
||||
get-port: 6.1.0
|
||||
get-port: 6.1.1
|
||||
got: 12.0.1
|
||||
js-cookie: 3.0.1
|
||||
js-yaml: 4.1.0
|
||||
jsonwebtoken: 8.5.1
|
||||
mustache: 4.2.0
|
||||
node-forge: 1.2.1
|
||||
svelte-kit-cookie-session: 2.1.2
|
||||
tailwindcss-scrollbar: 0.1.0_tailwindcss@3.0.23
|
||||
unique-names-generator: 4.7.1
|
||||
|
||||
devDependencies:
|
||||
'@sveltejs/adapter-node': 1.0.0-next.68
|
||||
'@sveltejs/adapter-node': 1.0.0-next.69
|
||||
'@sveltejs/adapter-static': 1.0.0-next.28
|
||||
'@sveltejs/kit': 1.0.0-next.278_svelte@3.46.4
|
||||
'@sveltejs/kit': 1.0.0-next.283_svelte@3.46.4
|
||||
'@types/bcrypt': 5.0.0
|
||||
'@types/js-cookie': 3.0.1
|
||||
'@types/node': 17.0.18
|
||||
'@types/node': 17.0.20
|
||||
'@types/node-forge': 1.0.0
|
||||
'@typescript-eslint/eslint-plugin': 4.31.1_5d7752337e5ea49772097d8af1823bf9
|
||||
'@typescript-eslint/parser': 4.31.1_eslint@7.32.0+typescript@4.5.5
|
||||
'@zerodevx/svelte-toast': 0.6.3
|
||||
'@zerodevx/svelte-toast': 0.7.0
|
||||
autoprefixer: 10.4.2_postcss@8.4.6
|
||||
cross-var: 1.1.0
|
||||
eslint: 7.32.0
|
||||
eslint-config-prettier: 8.3.0_eslint@7.32.0
|
||||
eslint-plugin-svelte3: 3.2.1_eslint@7.32.0+svelte@3.46.4
|
||||
eslint-config-prettier: 8.4.0_eslint@7.32.0
|
||||
eslint-plugin-svelte3: 3.4.0_eslint@7.32.0+svelte@3.46.4
|
||||
husky: 7.0.4
|
||||
lint-staged: 12.3.4
|
||||
postcss: 8.4.6
|
||||
prettier: 2.5.1
|
||||
prettier-plugin-svelte: 2.6.0_prettier@2.5.1+svelte@3.46.4
|
||||
prettier-plugin-tailwindcss: 0.1.7_prettier@2.5.1
|
||||
prisma: 3.9.2
|
||||
prisma: 3.10.0
|
||||
svelte: 3.46.4
|
||||
svelte-check: 2.4.3_postcss@8.4.6+svelte@3.46.4
|
||||
svelte-preprocess: 4.10.3_88b359da5cac6d8f6ee1bbb7080a3fa9
|
||||
svelte-check: 2.4.5_postcss@8.4.6+svelte@3.46.4
|
||||
svelte-preprocess: 4.10.4_88b359da5cac6d8f6ee1bbb7080a3fa9
|
||||
tailwindcss: 3.0.23_c940fbabf228b85b1c73d314b43e31f1
|
||||
ts-node: 10.5.0_f3bd4037939c2ed2942ba074291f8ef2
|
||||
ts-node: 10.5.0_e04e69b201f218c8d0d59acefc9ea8a6
|
||||
tslib: 2.3.1
|
||||
typescript: 4.5.5
|
||||
|
||||
@@ -252,10 +254,10 @@ packages:
|
||||
fastq: 1.13.0
|
||||
dev: true
|
||||
|
||||
/@prisma/client/3.9.2_prisma@3.9.2:
|
||||
/@prisma/client/3.10.0_prisma@3.10.0:
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-VlEIYVMyfFZHbVBOlunPl47gmP/Z0zzPjPj8I7uKEIaABqrUy50ru3XS0aZd8GFvevVwt7p91xxkUjNjrWhKAQ==
|
||||
integrity: sha512-6P4sV7WFuODSfSoSEzCH1qfmWMrCUBk1LIIuTbQf6m1LI/IOpLN4lnqGDmgiBGprEzuWobnGLfe9YsXLn0inrg==
|
||||
}
|
||||
engines: { node: '>=12.6' }
|
||||
requiresBuild: true
|
||||
@@ -265,21 +267,21 @@ packages:
|
||||
prisma:
|
||||
optional: true
|
||||
dependencies:
|
||||
'@prisma/engines-version': 3.9.0-58.bcc2ff906db47790ee902e7bbc76d7ffb1893009
|
||||
prisma: 3.9.2
|
||||
'@prisma/engines-version': 3.10.0-50.73e60b76d394f8d37d8ebd1f8918c79029f0db86
|
||||
prisma: 3.10.0
|
||||
dev: false
|
||||
|
||||
/@prisma/engines-version/3.9.0-58.bcc2ff906db47790ee902e7bbc76d7ffb1893009:
|
||||
/@prisma/engines-version/3.10.0-50.73e60b76d394f8d37d8ebd1f8918c79029f0db86:
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-5Dh+qTDhpPR66w6NNAnPs+/W/Qt4r1DSd+qhfPFcDThUK4uxoZKGlPb2IYQn5LL+18aIGnmteDf7BnVMmvBNSQ==
|
||||
integrity: sha512-cVYs5gyQH/qyut24hUvDznCfPrWiNMKNfPb9WmEoiU6ihlkscIbCfkmuKTtspVLWRdl0LqjYEC7vfnPv17HWhw==
|
||||
}
|
||||
dev: false
|
||||
|
||||
/@prisma/engines/3.9.0-58.bcc2ff906db47790ee902e7bbc76d7ffb1893009:
|
||||
/@prisma/engines/3.10.0-50.73e60b76d394f8d37d8ebd1f8918c79029f0db86:
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-qM+uJbkelB21bnK44gYE049YTHIjHysOuj0mj5U2gDGyNLfmiazlggzFPCgEjgme4U5YB2tYs6Z5Hq08Kl8pjA==
|
||||
integrity: sha512-LjRssaWu9w2SrXitofnutRIyURI7l0veQYIALz7uY4shygM9nMcK3omXcObRm7TAcw3Z+9ytfK1B+ySOsOesxQ==
|
||||
}
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
@@ -394,10 +396,10 @@ packages:
|
||||
engines: { node: '>=10' }
|
||||
dev: false
|
||||
|
||||
/@sveltejs/adapter-node/1.0.0-next.68:
|
||||
/@sveltejs/adapter-node/1.0.0-next.69:
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-MiEjtl15Aupm6bjirVlq0kkc9AL8qDXz/blsh4jYMsaiidmcEHeDgfZQFM5YiXy95DbxV30MAkhwCQiYK/J8Kw==
|
||||
integrity: sha512-tVKwJ8vYG4NGFJ5L+tRuyRglGPaJ1khNqTKq4bYIUahk/pjXIu9USbMmFtNHd6IyDdxjPtRoVwHubAYfTQLTpg==
|
||||
}
|
||||
dependencies:
|
||||
tiny-glob: 0.2.9
|
||||
@@ -412,10 +414,10 @@ packages:
|
||||
tiny-glob: 0.2.9
|
||||
dev: true
|
||||
|
||||
/@sveltejs/kit/1.0.0-next.278_svelte@3.46.4:
|
||||
/@sveltejs/kit/1.0.0-next.283_svelte@3.46.4:
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-WT93Wnu05X9WG9BMMk/dj0gy6R7iXm9aXRDVgmIl9z8jT2ukejgmkhi5IwBYrK0OMIUALRVfukn+iy+srPc91Q==
|
||||
integrity: sha512-QFhL7cdBKXUKhJ3sHZnL7q07Eohc54N7OpX2ZsJuNTA43Z6vX/HF/Jh4TK62kqT+thDVlT5J1iEEMppxA2IxoQ==
|
||||
}
|
||||
engines: { node: '>=14.13' }
|
||||
hasBin: true
|
||||
@@ -504,7 +506,7 @@ packages:
|
||||
integrity: sha512-agtcFKaruL8TmcvqbndlqHPSJgsolhf/qPWchFlgnW1gECTN/nKbFcoFnvKAQRFfKbh+BO6A3SWdJu9t+xF3Lw==
|
||||
}
|
||||
dependencies:
|
||||
'@types/node': 17.0.18
|
||||
'@types/node': 17.0.20
|
||||
dev: true
|
||||
|
||||
/@types/cacheable-request/6.0.2:
|
||||
@@ -515,7 +517,7 @@ packages:
|
||||
dependencies:
|
||||
'@types/http-cache-semantics': 4.0.1
|
||||
'@types/keyv': 3.1.3
|
||||
'@types/node': 17.0.18
|
||||
'@types/node': 17.0.20
|
||||
'@types/responselike': 1.0.0
|
||||
dev: false
|
||||
|
||||
@@ -546,7 +548,7 @@ packages:
|
||||
integrity: sha512-FXCJgyyN3ivVgRoml4h94G/p3kY+u/B86La+QptcqJaWtBWtmc6TtkNfS40n9bIvyLteHh7zXOtgbobORKPbDg==
|
||||
}
|
||||
dependencies:
|
||||
'@types/node': 17.0.18
|
||||
'@types/node': 17.0.20
|
||||
dev: false
|
||||
|
||||
/@types/node-forge/1.0.0:
|
||||
@@ -555,13 +557,13 @@ packages:
|
||||
integrity: sha512-h0bgwPKq5u99T9Gor4qtV1lCZ41xNkai0pie1n/a2mh2/4+jENWOlo7AJ4YKxTZAnSZ8FRurUpdIN7ohaPPuHA==
|
||||
}
|
||||
dependencies:
|
||||
'@types/node': 17.0.18
|
||||
'@types/node': 17.0.20
|
||||
dev: true
|
||||
|
||||
/@types/node/17.0.18:
|
||||
/@types/node/17.0.20:
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-eKj4f/BsN/qcculZiRSujogjvp5O/k4lOW5m35NopjZM/QwLOR075a8pJW5hD+Rtdm2DaCVPENS6KtSQnUD6BA==
|
||||
integrity: sha512-Q15Clj3lZSLnhVA6yKw1G7SQz46DeL9gO1TEgfK1OQGvMdQ6TUWmCeWf1QBUNkw2BDfV52i2YuYd9OF3ZwGhjw==
|
||||
}
|
||||
|
||||
/@types/parse-json/4.0.0:
|
||||
@@ -584,7 +586,7 @@ packages:
|
||||
integrity: sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA==
|
||||
}
|
||||
dependencies:
|
||||
'@types/node': 17.0.18
|
||||
'@types/node': 17.0.20
|
||||
dev: false
|
||||
|
||||
/@types/sass/1.16.1:
|
||||
@@ -593,7 +595,7 @@ packages:
|
||||
integrity: sha512-iZUcRrGuz/Tbg3loODpW7vrQJkUtpY2fFSf4ELqqkApcS2TkZ1msk7ie8iZPB86lDOP8QOTTmuvWjc5S0R9OjQ==
|
||||
}
|
||||
dependencies:
|
||||
'@types/node': 17.0.18
|
||||
'@types/node': 17.0.20
|
||||
dev: true
|
||||
|
||||
/@typescript-eslint/eslint-plugin/4.31.1_5d7752337e5ea49772097d8af1823bf9:
|
||||
@@ -722,10 +724,10 @@ packages:
|
||||
eslint-visitor-keys: 2.1.0
|
||||
dev: true
|
||||
|
||||
/@zerodevx/svelte-toast/0.6.3:
|
||||
/@zerodevx/svelte-toast/0.7.0:
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-k0W1JFoqHIcIQaP9ij99+Rv0ugaQSSNwOuNwwmTGRjWtIqrQr+ExLDE8LQGXLlJIprqDyMWB4lJkUql/r0RAtA==
|
||||
integrity: sha512-Xvpy1dTE/bUcYJKrbBxc5KuXtbwhyUjEzmTNtg92bS558SvsH6FDu02pgFbBWNjK9g9f2eQCDBhBhJM4q6vhDw==
|
||||
}
|
||||
dev: true
|
||||
|
||||
@@ -1748,10 +1750,10 @@ packages:
|
||||
ieee754: 1.2.1
|
||||
dev: false
|
||||
|
||||
/bullmq/1.73.0:
|
||||
/bullmq/1.74.2:
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-+BF7yeGagYD/iMkM3FA8Wvb3j3MyKE/OdXv404+nQjUsKXfL7PbqX5NSA9lBtFzOdyFx9ZWyKRnBwuGQsLfM0w==
|
||||
integrity: sha512-qf0xjF3NDbZqi6ovxAA9QPrPdEgl3BrdYzQO5Pr+ECNIfscLpSXz87kVXI0oTPeDqxw5EJx4sh8EFf2RvVPYTg==
|
||||
}
|
||||
dependencies:
|
||||
cron-parser: 2.18.0
|
||||
@@ -2706,10 +2708,10 @@ packages:
|
||||
engines: { node: '>=10' }
|
||||
dev: true
|
||||
|
||||
/eslint-config-prettier/8.3.0_eslint@7.32.0:
|
||||
/eslint-config-prettier/8.4.0_eslint@7.32.0:
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-BgZuLUSeKzvlL/VUjx/Yb787VQ26RU3gGjA3iiFvdsp/2bMfVIWUVP7tjxtjS0e+HP409cPlPvNkQloz8C91ew==
|
||||
integrity: sha512-CFotdUcMY18nGRo5KGsnNxpznzhkopOcOo0InID+sgQssPrzjvsyKZPvOgymTFeHrFuC3Tzdf2YndhXtULK9Iw==
|
||||
}
|
||||
hasBin: true
|
||||
peerDependencies:
|
||||
@@ -2718,10 +2720,10 @@ packages:
|
||||
eslint: 7.32.0
|
||||
dev: true
|
||||
|
||||
/eslint-plugin-svelte3/3.2.1_eslint@7.32.0+svelte@3.46.4:
|
||||
/eslint-plugin-svelte3/3.4.0_eslint@7.32.0+svelte@3.46.4:
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-YoBR9mLoKCjGghJ/gvpnFZKaMEu/VRcuxpSRS8KuozuEo7CdBH7bmBHa6FmMm0i4kJnOyx+PVsaptz96K6H/4Q==
|
||||
integrity: sha512-MIQUTuRv3o7LyQ+360qOc9mLT35j1I5YzHr04g/UDcvJTpg0X/kHWELY99ve869Rp/9wjqD7I26Aq5H8OH5RIg==
|
||||
}
|
||||
engines: { node: '>=10' }
|
||||
peerDependencies:
|
||||
@@ -3116,10 +3118,10 @@ packages:
|
||||
engines: { node: '>=8' }
|
||||
dev: false
|
||||
|
||||
/get-port/6.1.0:
|
||||
/get-port/6.1.1:
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-JKnPFW/G2ZRirH/25sLK1aLBQktJfQLixzMMuMBP8A2G/ivSaIwdTnlJeO7PWeyhyIGVorezNf6+CXZU9i0cIQ==
|
||||
integrity: sha512-RQOsDPSd2PcoLwakY1dwEtLiAbTR7IfmnxsKswfcHEfRKKbhWAG2R5Qo7C8ga6Ne4Mq4lFbogXfDGNfqFxwAaw==
|
||||
}
|
||||
engines: { node: ^12.20.0 || ^14.13.1 || >=16.0.0 }
|
||||
dev: false
|
||||
@@ -4091,6 +4093,14 @@ packages:
|
||||
msgpackr-extract: 1.0.15
|
||||
dev: false
|
||||
|
||||
/mustache/4.2.0:
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==
|
||||
}
|
||||
hasBin: true
|
||||
dev: false
|
||||
|
||||
/nan/2.15.0:
|
||||
resolution:
|
||||
{
|
||||
@@ -4399,7 +4409,7 @@ packages:
|
||||
dependencies:
|
||||
import-cwd: 3.0.0
|
||||
lilconfig: 2.0.4
|
||||
ts-node: 10.5.0_f3bd4037939c2ed2942ba074291f8ef2
|
||||
ts-node: 10.5.0_e04e69b201f218c8d0d59acefc9ea8a6
|
||||
yaml: 1.10.2
|
||||
dev: true
|
||||
|
||||
@@ -4488,16 +4498,16 @@ packages:
|
||||
hasBin: true
|
||||
dev: true
|
||||
|
||||
/prisma/3.9.2:
|
||||
/prisma/3.10.0:
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-i9eK6cexV74OgeWaH3+e6S07kvC9jEZTl6BqtBH398nlCU0tck7mE9dicY6YQd+euvMjjCtY89q4NgmaPnUsSg==
|
||||
integrity: sha512-dAld12vtwdz9Rz01nOjmnXe+vHana5PSog8t0XGgLemKsUVsaupYpr74AHaS3s78SaTS5s2HOghnJF+jn91ZrA==
|
||||
}
|
||||
engines: { node: '>=12.6' }
|
||||
hasBin: true
|
||||
requiresBuild: true
|
||||
dependencies:
|
||||
'@prisma/engines': 3.9.0-58.bcc2ff906db47790ee902e7bbc76d7ffb1893009
|
||||
'@prisma/engines': 3.10.0-50.73e60b76d394f8d37d8ebd1f8918c79029f0db86
|
||||
dev: true
|
||||
|
||||
/private/0.1.8:
|
||||
@@ -5162,10 +5172,10 @@ packages:
|
||||
engines: { node: '>= 0.4' }
|
||||
dev: true
|
||||
|
||||
/svelte-check/2.4.3_postcss@8.4.6+svelte@3.46.4:
|
||||
/svelte-check/2.4.5_postcss@8.4.6+svelte@3.46.4:
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-0zJMMgqYHoP7QEG3tfc5DekpHAOqoy4QOL8scWMSdHIpVVDVC0MuYK57nFyj3XVTW8Zfm85FlgnAdQYsVmST2Q==
|
||||
integrity: sha512-nRft8BbG2wcxyCdHDZ7X43xLcvDzua3xLwq6wzHGcAF3ka3Jyhv2rvgq0+SF9NwHLMefp9C2XkM6etzsxK/cMQ==
|
||||
}
|
||||
hasBin: true
|
||||
peerDependencies:
|
||||
@@ -5179,7 +5189,7 @@ packages:
|
||||
sade: 1.7.4
|
||||
source-map: 0.7.3
|
||||
svelte: 3.46.4
|
||||
svelte-preprocess: 4.10.3_88b359da5cac6d8f6ee1bbb7080a3fa9
|
||||
svelte-preprocess: 4.10.4_88b359da5cac6d8f6ee1bbb7080a3fa9
|
||||
typescript: 4.5.5
|
||||
transitivePeerDependencies:
|
||||
- '@babel/core'
|
||||
@@ -5212,10 +5222,10 @@ packages:
|
||||
}
|
||||
dev: false
|
||||
|
||||
/svelte-preprocess/4.10.3_88b359da5cac6d8f6ee1bbb7080a3fa9:
|
||||
/svelte-preprocess/4.10.4_88b359da5cac6d8f6ee1bbb7080a3fa9:
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-ttw17lJfb/dx2ZJT9sesaXT5l7mPQ9Apx1H496Kli3Hkk7orIRGpOw6rCPkRNzr6ueVPqb4vzodS5x7sBFhKHw==
|
||||
integrity: sha512-fuwol0N4UoHsNQolLFbMqWivqcJ9N0vfWO9IuPAiX/5okfoGXURyJ6nECbuEIv0nU3M8Xe2I1ONNje2buk7l6A==
|
||||
}
|
||||
engines: { node: '>= 9.11.2' }
|
||||
requiresBuild: true
|
||||
@@ -5420,7 +5430,7 @@ packages:
|
||||
engines: { node: '>=0.10.0' }
|
||||
dev: true
|
||||
|
||||
/ts-node/10.5.0_f3bd4037939c2ed2942ba074291f8ef2:
|
||||
/ts-node/10.5.0_e04e69b201f218c8d0d59acefc9ea8a6:
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-6kEJKwVxAJ35W4akuiysfKwKmjkbYxwQMTBaAxo9KKAx/Yd26mPUyhGz3ji+EsJoAgrLqVsYHNuuYwQe22lbtw==
|
||||
@@ -5442,7 +5452,7 @@ packages:
|
||||
'@tsconfig/node12': 1.0.9
|
||||
'@tsconfig/node14': 1.0.1
|
||||
'@tsconfig/node16': 1.0.2
|
||||
'@types/node': 17.0.18
|
||||
'@types/node': 17.0.20
|
||||
acorn: 8.5.0
|
||||
acorn-walk: 8.2.0
|
||||
arg: 4.1.3
|
||||
|
||||
2
prisma/migrations/20220301101928_proxyhash/migration.sql
Normal file
2
prisma/migrations/20220301101928_proxyhash/migration.sql
Normal file
@@ -0,0 +1,2 @@
|
||||
-- AlterTable
|
||||
ALTER TABLE "Setting" ADD COLUMN "proxyHash" TEXT;
|
||||
@@ -16,6 +16,7 @@ model Setting {
|
||||
maxPort Int @default(9100)
|
||||
proxyPassword String
|
||||
proxyUser String
|
||||
proxyHash String?
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
}
|
||||
@@ -54,9 +55,9 @@ model Team {
|
||||
permissions Permission[]
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
database Database[] @relation(fields: [databaseId], references: [id])
|
||||
database Database[] @relation(references: [id])
|
||||
databaseId String?
|
||||
service Service[] @relation(fields: [serviceId], references: [id])
|
||||
service Service[] @relation(references: [id])
|
||||
serviceId String?
|
||||
}
|
||||
|
||||
|
||||
@@ -27,6 +27,15 @@ async function main() {
|
||||
proxyUser: cuid()
|
||||
}
|
||||
});
|
||||
} else {
|
||||
await prisma.setting.update({
|
||||
where: {
|
||||
id: settingsFound.id
|
||||
},
|
||||
data: {
|
||||
proxyHash: null
|
||||
}
|
||||
});
|
||||
}
|
||||
const localDocker = await prisma.destinationDocker.findFirst({
|
||||
where: { engine: '/var/run/docker.sock' }
|
||||
|
||||
@@ -1,112 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
clear
|
||||
ARG1=$1
|
||||
WHO=$(whoami)
|
||||
APP_ID=$(cat /proc/sys/kernel/random/uuid)
|
||||
RANDOM_SECRET=$(echo $(($(date +%s%N) / 1000000)) | sha256sum | base64 | head -c 32)
|
||||
SENTRY_DSN="https://9e7a74326f29422584d2d0bebdc8b7d3@o1082494.ingest.sentry.io/6091062"
|
||||
DOCKER_MAJOR=20
|
||||
DOCKER_MINOR=10
|
||||
DOCKER_VERSION_OK="nok"
|
||||
|
||||
set -eou pipefail
|
||||
|
||||
if [ $ARG1 ] && [ $ARG1 == "-d" ]; then
|
||||
set -x
|
||||
fi
|
||||
|
||||
function errorchecker() {
|
||||
exitCode=$?
|
||||
if [ $exitCode -ne "0" ]; then
|
||||
echo "$0 exited unexpectedly with status: $exitCode"
|
||||
exit $exitCode
|
||||
fi
|
||||
}
|
||||
trap 'errorchecker' EXIT
|
||||
|
||||
echo -e "Welcome to Coolify installer! \n"
|
||||
echo "This script will install all the required packages and services to run Coolify."
|
||||
echo -e "If you want to install Coolify on a different OS, please open an issue on Github to get supported version.\n\n"
|
||||
|
||||
echo -e "To see what I'm doing, please check:"
|
||||
echo -e "https://github.com/coollabsio/get.coollabs.io/blob/main/static/coolify/install_v2.sh\n\n"
|
||||
|
||||
if [ $WHO != 'root' ]; then
|
||||
echo 'Run as root please: sudo sh -c "$(curl -fsSL https://get.coollabs.io/coolify/install.sh)"'
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ ! -x "$(command -v docker)" ]; then
|
||||
while true; do
|
||||
read -p "Docker Engine not found, should I install it automatically? [Yy/Nn] " yn
|
||||
case $yn in
|
||||
[Yy]*)
|
||||
sh -c "$(curl -fsSL https://get.docker.com)"
|
||||
break
|
||||
;;
|
||||
[Nn]*)
|
||||
echo "Please install docker manually and update it to the latest, but at least to $DOCKER_MAJOR.$DOCKER_MINOR"
|
||||
exit 0
|
||||
;;
|
||||
*) echo "Please answer Y or N." ;;
|
||||
esac
|
||||
done
|
||||
fi
|
||||
|
||||
SERVER_VERSION=$(docker version -f "{{.Server.Version}}")
|
||||
SERVER_VERSION_MAJOR=$(echo "$SERVER_VERSION" | cut -d'.' -f 1)
|
||||
SERVER_VERSION_MINOR=$(echo "$SERVER_VERSION" | cut -d'.' -f 2)
|
||||
|
||||
if [ "$SERVER_VERSION_MAJOR" -ge "$DOCKER_MAJOR" ] &&
|
||||
[ "$SERVER_VERSION_MINOR" -ge "$DOCKER_MINOR" ]; then
|
||||
DOCKER_VERSION_OK="ok"
|
||||
fi
|
||||
|
||||
if [ $DOCKER_VERSION_OK == 'nok' ]; then
|
||||
echo "Docker version less than $DOCKER_MAJOR.$DOCKER_MINOR, please update it to at least to $DOCKER_MAJOR.$DOCKER_MINOR"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Adding docker daemon configuration
|
||||
cat <<EOF >/etc/docker/daemon.json
|
||||
{
|
||||
"log-driver": "json-file",
|
||||
"log-opts": {
|
||||
"max-size": "100m",
|
||||
"max-file": "5"
|
||||
},
|
||||
"features": {
|
||||
"buildkit": true
|
||||
},
|
||||
"live-restore": true
|
||||
}
|
||||
EOF
|
||||
|
||||
# Restarting docker daemon
|
||||
sh -c "systemctl daemon-reload && systemctl restart docker"
|
||||
|
||||
# Downloading docker compose cli plugin
|
||||
mkdir -p ~/.docker/cli-plugins/
|
||||
curl -SL https://github.com/docker/compose/releases/download/v2.2.2/docker-compose-linux-x86_64 -o ~/.docker/cli-plugins/docker-compose
|
||||
chmod +x ~/.docker/cli-plugins/docker-compose
|
||||
|
||||
# Making base directory for coolify
|
||||
if [ ! -d coolify ]; then
|
||||
mkdir coolify
|
||||
fi
|
||||
|
||||
if [ -f coolify/.env ]; then
|
||||
echo -e "Coolify is already installed, using some of the existing settings."
|
||||
else
|
||||
echo "COOLIFY_APP_ID=$APP_ID
|
||||
COOLIFY_SECRET_KEY=$RANDOM_SECRET
|
||||
COOLIFY_DATABASE_URL=file:../db/prod.db
|
||||
COOLIFY_SENTRY_DSN=$SENTRY_DSN
|
||||
COOLIFY_HOSTED_ON=docker" > coolify/.env
|
||||
fi
|
||||
|
||||
cd coolify && docker run -tid --env-file .env -v /var/run/docker.sock:/var/run/docker.sock -v coolify-db-sqlite coollabsio/coolify:latest /bin/sh -c "env | grep COOLIFY > .env && docker compose up -d --force-recreate"
|
||||
|
||||
echo -e "Congratulations! Your coolify is ready to use.\n"
|
||||
echo "Please visit http://<Your Public IP Address>:3000/ to get started."
|
||||
echo "It will take a few minutes to start up, don't worry."
|
||||
@@ -1,114 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
clear
|
||||
ARG1=$1
|
||||
WHO=$(whoami)
|
||||
APP_ID=$(cat /proc/sys/kernel/random/uuid)
|
||||
RANDOM_SECRET=$(echo $(($(date +%s%N) / 1000000)) | sha256sum | base64 | head -c 32)
|
||||
SENTRY_DSN="https://9e7a74326f29422584d2d0bebdc8b7d3@o1082494.ingest.sentry.io/6091062"
|
||||
|
||||
UBUNTU_MAJOR_MIN=20
|
||||
UBUNTU_MINOR_MIN=04
|
||||
OS_OK="nok"
|
||||
|
||||
set -eou pipefail
|
||||
|
||||
if [ $ARG1 ] && [ $ARG1 == "-d" ]; then
|
||||
set -x
|
||||
fi
|
||||
|
||||
function errorchecker() {
|
||||
exitCode=$?
|
||||
if [ $exitCode -ne "0" ]; then
|
||||
echo "$0 exited unexpectedly with status: $exitCode"
|
||||
exit $exitCode
|
||||
fi
|
||||
}
|
||||
trap 'errorchecker' EXIT
|
||||
|
||||
if [ $WHO != 'root' ]; then
|
||||
echo 'Run as root please: sudo sh -c "$(curl -fsSL https://get.coollabs.io/coolify/install.sh)"'
|
||||
exit 1
|
||||
fi
|
||||
|
||||
. /etc/lsb-release
|
||||
if [ $DISTRIB_ID != 'Ubuntu' ]; then
|
||||
echo 'Not supported OS, please open an issue on Github to get supported version.'
|
||||
exit 1
|
||||
fi
|
||||
|
||||
DISTRIB_RELEASE_MAJOR=$(echo "$DISTRIB_RELEASE" | cut -d'.' -f 1)
|
||||
DISTRIB_RELEASE_MINOR=$(echo "$DISTRIB_RELEASE" | cut -d'.' -f 2)
|
||||
|
||||
if [ "$DISTRIB_RELEASE_MAJOR" -ge "$UBUNTU_MAJOR_MIN" ] &&
|
||||
[ "$DISTRIB_RELEASE_MINOR" -ge "$UBUNTU_MINOR_MIN" ]; then
|
||||
OS_OK="ok"
|
||||
fi
|
||||
|
||||
if [ $OS_OK == 'nok' ]; then
|
||||
echo "Ubuntu version less than $UBUNTU_MAJOR_MIN.$UBUNTU_MINOR_MIN."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
function installPodman() {
|
||||
apt-get update -y
|
||||
apt-get install curl wget gnupg2 -y
|
||||
if [ "$DISTRIB_RELEASE_MAJOR" -eq "20" ] && [ "$DISTRIB_RELEASE_MINOR" -eq "04" ]; then
|
||||
echo 'Installing on 20.04'
|
||||
source /etc/os-release
|
||||
sh -c "echo 'deb http://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/xUbuntu_${VERSION_ID}/ /' > /etc/apt/sources.list.d/devel:kubic:libcontainers:stable.list"
|
||||
wget -nv https://download.opensuse.org/repositories/devel:kubic:libcontainers:stable/xUbuntu_${VERSION_ID}/Release.key -O- | apt-key add -
|
||||
apt-get update -y
|
||||
apt-get -y install podman
|
||||
return 0
|
||||
elif [ "$DISTRIB_RELEASE_MAJOR" -eq "20" ] && [ "$DISTRIB_RELEASE_MINOR" -eq "10" ]; then
|
||||
apt-get -y install podman
|
||||
return 0
|
||||
elif [ "$DISTRIB_RELEASE_MAJOR" -gt "20" ]; then
|
||||
apt-get -y install podman
|
||||
return 0
|
||||
else
|
||||
exit 1
|
||||
fi
|
||||
|
||||
}
|
||||
|
||||
if [ ! -x "$(command -v podman)" ]; then
|
||||
while true; do
|
||||
read -p "Podman not found, should I install it automatically? [Yy/Nn] " yn
|
||||
case $yn in
|
||||
[Yy]*)
|
||||
installPodman
|
||||
break
|
||||
;;
|
||||
[Nn]*)
|
||||
echo "Please install docker manually and update it to the latest, but at least to $DOCKER_MAJOR.$DOCKER_MINOR"
|
||||
exit 0
|
||||
;;
|
||||
*) echo "Please answer Yy or Nn." ;;
|
||||
esac
|
||||
done
|
||||
fi
|
||||
|
||||
# Making base directory for coolify
|
||||
if [ ! -d coolify ]; then
|
||||
mkdir coolify
|
||||
fi
|
||||
|
||||
echo "COOLIFY_APP_ID=$APP_ID
|
||||
COOLIFY_SECRET_KEY=$RANDOM_SECRET
|
||||
COOLIFY_DATABASE_URL=file:../db/prod.db
|
||||
COOLIFY_SENTRY_DSN=$SENTRY_DSN
|
||||
COOLIFY_HOSTED_ON=docker" >coolify/.env
|
||||
|
||||
systemctl start podman.socket
|
||||
systemctl enable podman.socket
|
||||
|
||||
podman volume create coolify-db
|
||||
podman volume create coolify-ssl-certs
|
||||
podman volume create coolify-letsencrypt
|
||||
|
||||
|
||||
cd coolify && podman run --privileged -tid --env-file .env -v /var/run/podman/podman.sock:/var/run/podman/podman.sock -v coolify-db-sqlite:/app/db docker.io/coollabsio/coolify:latest /bin/sh -c "env | grep COOLIFY > .env && docker-compose up -d --force-recreate"
|
||||
echo "Done"
|
||||
exit 0
|
||||
@@ -7,6 +7,7 @@ const createDockerfile = async (data, imageforBuild): Promise<void> => {
|
||||
|
||||
Dockerfile.push(`FROM ${imageforBuild}`);
|
||||
Dockerfile.push('WORKDIR /usr/share/nginx/html');
|
||||
Dockerfile.push(`LABEL coolify.image=true`);
|
||||
Dockerfile.push(`COPY --from=${applicationId}:${tag}-cache /usr/src/app/${publishDirectory} ./`);
|
||||
Dockerfile.push(`EXPOSE 80`);
|
||||
Dockerfile.push('CMD ["nginx", "-g", "daemon off;"]');
|
||||
|
||||
@@ -10,6 +10,8 @@ import nuxtjs from './nuxtjs';
|
||||
import vuejs from './vuejs';
|
||||
import php from './php';
|
||||
import rust from './rust';
|
||||
import astro from './static';
|
||||
import eleventy from './static';
|
||||
|
||||
export {
|
||||
node,
|
||||
@@ -23,5 +25,7 @@ export {
|
||||
nuxtjs,
|
||||
vuejs,
|
||||
php,
|
||||
rust
|
||||
rust,
|
||||
astro,
|
||||
eleventy
|
||||
};
|
||||
|
||||
@@ -7,6 +7,7 @@ const createDockerfile = async (data, image): Promise<void> => {
|
||||
|
||||
Dockerfile.push(`FROM ${image}`);
|
||||
Dockerfile.push('WORKDIR /usr/src/app');
|
||||
Dockerfile.push(`LABEL coolify.image=true`);
|
||||
Dockerfile.push(
|
||||
`COPY --from=${applicationId}:${tag}-cache /usr/src/app/${baseDirectory || ''} ./`
|
||||
);
|
||||
|
||||
@@ -16,6 +16,7 @@ const createDockerfile = async (data, image): Promise<void> => {
|
||||
|
||||
Dockerfile.push(`FROM ${image}`);
|
||||
Dockerfile.push('WORKDIR /usr/src/app');
|
||||
Dockerfile.push(`LABEL coolify.image=true`);
|
||||
if (secrets.length > 0) {
|
||||
secrets.forEach((secret) => {
|
||||
if (secret.isBuildSecret) {
|
||||
|
||||
@@ -16,6 +16,7 @@ const createDockerfile = async (data, image): Promise<void> => {
|
||||
|
||||
Dockerfile.push(`FROM ${image}`);
|
||||
Dockerfile.push('WORKDIR /usr/src/app');
|
||||
Dockerfile.push(`LABEL coolify.image=true`);
|
||||
if (secrets.length > 0) {
|
||||
secrets.forEach((secret) => {
|
||||
if (secret.isBuildSecret) {
|
||||
|
||||
@@ -16,6 +16,7 @@ const createDockerfile = async (data, image): Promise<void> => {
|
||||
|
||||
Dockerfile.push(`FROM ${image}`);
|
||||
Dockerfile.push('WORKDIR /usr/src/app');
|
||||
Dockerfile.push(`LABEL coolify.image=true`);
|
||||
if (secrets.length > 0) {
|
||||
secrets.forEach((secret) => {
|
||||
if (secret.isBuildSecret) {
|
||||
|
||||
@@ -6,6 +6,7 @@ const createDockerfile = async (data, image): Promise<void> => {
|
||||
const Dockerfile: Array<string> = [];
|
||||
|
||||
Dockerfile.push(`FROM ${image}`);
|
||||
Dockerfile.push(`LABEL coolify.image=true`);
|
||||
Dockerfile.push('RUN a2enmod rewrite');
|
||||
Dockerfile.push('WORKDIR /var/www/html');
|
||||
Dockerfile.push(`COPY ./${baseDirectory || ''} /var/www/html`);
|
||||
|
||||
@@ -6,6 +6,7 @@ const createDockerfile = async (data, image): Promise<void> => {
|
||||
const Dockerfile: Array<string> = [];
|
||||
|
||||
Dockerfile.push(`FROM ${image}`);
|
||||
Dockerfile.push(`LABEL coolify.image=true`);
|
||||
Dockerfile.push('WORKDIR /usr/share/nginx/html');
|
||||
Dockerfile.push(`COPY --from=${applicationId}:${tag}-cache /usr/src/app/${publishDirectory} ./`);
|
||||
Dockerfile.push(`EXPOSE 80`);
|
||||
|
||||
@@ -8,6 +8,7 @@ const createDockerfile = async (data, image, name): Promise<void> => {
|
||||
const Dockerfile: Array<string> = [];
|
||||
Dockerfile.push(`FROM ${image}`);
|
||||
Dockerfile.push('WORKDIR /usr/src/app');
|
||||
Dockerfile.push(`LABEL coolify.image=true`);
|
||||
Dockerfile.push(`COPY --from=${applicationId}:${tag}-cache /usr/src/app/target target`);
|
||||
Dockerfile.push(`COPY --from=${applicationId}:${tag}-cache /usr/local/cargo /usr/local/cargo`);
|
||||
Dockerfile.push(`COPY . .`);
|
||||
|
||||
@@ -16,6 +16,7 @@ const createDockerfile = async (data, image): Promise<void> => {
|
||||
|
||||
Dockerfile.push(`FROM ${image}`);
|
||||
Dockerfile.push('WORKDIR /usr/share/nginx/html');
|
||||
Dockerfile.push(`LABEL coolify.image=true`);
|
||||
if (secrets.length > 0) {
|
||||
secrets.forEach((secret) => {
|
||||
if (secret.isBuildSecret) {
|
||||
|
||||
@@ -7,6 +7,7 @@ const createDockerfile = async (data, image): Promise<void> => {
|
||||
|
||||
Dockerfile.push(`FROM ${image}`);
|
||||
Dockerfile.push('WORKDIR /usr/share/nginx/html');
|
||||
Dockerfile.push(`LABEL coolify.image=true`);
|
||||
Dockerfile.push(`COPY --from=${applicationId}:${tag}-cache /usr/src/app/${publishDirectory} ./`);
|
||||
Dockerfile.push(`EXPOSE 80`);
|
||||
Dockerfile.push('CMD ["nginx", "-g", "daemon off;"]');
|
||||
|
||||
@@ -7,6 +7,7 @@ const createDockerfile = async (data, image): Promise<void> => {
|
||||
|
||||
Dockerfile.push(`FROM ${image}`);
|
||||
Dockerfile.push('WORKDIR /usr/share/nginx/html');
|
||||
Dockerfile.push(`LABEL coolify.image=true`);
|
||||
Dockerfile.push(`COPY --from=${applicationId}:${tag}-cache /usr/src/app/${publishDirectory} ./`);
|
||||
Dockerfile.push(`EXPOSE 80`);
|
||||
Dockerfile.push('CMD ["nginx", "-g", "daemon off;"]');
|
||||
|
||||
@@ -103,9 +103,14 @@ export const getUserDetails = async (event, isAdminRequired = true) => {
|
||||
};
|
||||
|
||||
export function getEngine(engine) {
|
||||
return engine === '/var/run/docker.sock' ? 'unix:///var/run/docker.sock' : `tcp://${engine}:2375`;
|
||||
return engine === '/var/run/docker.sock' ? 'unix:///var/run/docker.sock' : engine;
|
||||
}
|
||||
|
||||
// export async function saveSshKey(destination) {
|
||||
// return await asyncExecShell(
|
||||
// `echo '${destination.sshPrivateKey}' > /tmp/id_rsa_${destination.id} && chmod 600 /tmp/id_rsa_${destination.id}`
|
||||
// );
|
||||
// }
|
||||
export async function removeContainer(id, engine) {
|
||||
const host = getEngine(engine);
|
||||
try {
|
||||
|
||||
@@ -31,6 +31,8 @@
|
||||
<textarea
|
||||
rows="5"
|
||||
class={disabledClass}
|
||||
class:pr-10={true}
|
||||
class:pr-20={value && isHttps}
|
||||
{placeholder}
|
||||
type="text"
|
||||
{id}
|
||||
@@ -44,6 +46,8 @@
|
||||
<input
|
||||
class={disabledClass}
|
||||
type="text"
|
||||
class:pr-10={true}
|
||||
class:pr-20={value && isHttps}
|
||||
{id}
|
||||
{name}
|
||||
{required}
|
||||
@@ -57,6 +61,8 @@
|
||||
{:else}
|
||||
<input
|
||||
class={disabledClass}
|
||||
class:pr-10={true}
|
||||
class:pr-20={value && isHttps}
|
||||
type="password"
|
||||
{id}
|
||||
{name}
|
||||
|
||||
@@ -15,3 +15,6 @@ export const notNodeDeployments = ['php', 'docker', 'rust'];
|
||||
export function getDomain(domain) {
|
||||
return domain?.replace('https://', '').replace('http://', '');
|
||||
}
|
||||
export function generateRemoteEngine(destination) {
|
||||
return `ssh://${destination.user}@${destination.ipAddress}:${destination.port}`;
|
||||
}
|
||||
|
||||
21
src/lib/components/svg/applications/Astro.svelte
Normal file
21
src/lib/components/svg/applications/Astro.svelte
Normal file
@@ -0,0 +1,21 @@
|
||||
<svg
|
||||
class="absolute top-0 left-0 -m-6 h-14 w-14"
|
||||
viewBox="0 0 256 256"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
id="a"
|
||||
fill="#302649"
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="M163.008 18.929c1.944 2.413 2.935 5.67 4.917 12.181l43.309 142.27a180.277 180.277 0 00-51.778-17.53l-28.198-95.29a3.67 3.67 0 00-7.042.01l-27.857 95.232a180.225 180.225 0 00-52.01 17.557l43.52-142.281c1.99-6.502 2.983-9.752 4.927-12.16a15.999 15.999 0 016.484-4.798c2.872-1.154 6.271-1.154 13.07-1.154h31.085c6.807 0 10.211 0 13.086 1.157a16.004 16.004 0 016.487 4.806z"
|
||||
/>
|
||||
<path
|
||||
id="flame"
|
||||
fill="#EF661E"
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="M168.19 180.151c-7.139 6.105-21.39 10.268-37.804 10.268-20.147 0-37.033-6.272-41.513-14.707-1.602 4.835-1.961 10.367-1.961 13.902 0 0-1.056 17.355 11.015 29.426 0-6.268 5.081-11.349 11.349-11.349 10.743 0 10.731 9.373 10.721 16.977v.679c0 11.542 7.054 21.436 17.086 25.606a23.27 23.27 0 01-2.339-10.2c0-11.008 6.463-15.107 13.974-19.87 5.976-3.79 12.616-8.001 17.192-16.449a31.024 31.024 0 003.743-14.82c0-3.299-.513-6.479-1.463-9.463z"
|
||||
/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.1 KiB |
6
src/lib/components/svg/applications/Eleventy.svelte
Normal file
6
src/lib/components/svg/applications/Eleventy.svelte
Normal file
@@ -0,0 +1,6 @@
|
||||
<svg viewBox="0 0 128 128" class="absolute top-0 left-0 -m-8 h-16 w-16">
|
||||
<path fill="transparent" d="M18 0h92v128H18z" /><path
|
||||
d="M55.3 36.3h.4c1.1 0 1.5.9 1.5 2.3v41.8c0 1.8-.4 3-1.6 3l-4.8-.1c-1.2 0-1.6-1-1.6-3V45.5l-2.1.5c-1 0-1.5-.8-1.5-2.2v-3c0-1.2.4-2 1.4-2.2l8.3-2.2zm16 36.1l.1 3 .6 1.3.6.6.8.1h2.2c1 0 1.7.8 1.7 2v1.9c0 1.2-.6 2-1.8 2h-3.2l-2.3-.1c-.7-.2-1.4-.5-2.2-1a5.7 5.7 0 01-2-1.9c-.4-.8-.8-1.9-1-3.2-.4-1.4-.5-3-.5-4.8v-16h-1.5c-1.1 0-1.6-1-1.6-2.4v-1.7c0-1.4.5-2.3 1.6-2.3h1.5v-.1l.6-12.3c0-1.5.5-2.5 1.6-2.5h3.1c1.2 0 1.6 1 1.6 2.5v12.3h3.6c1.1 0 1.6 1 1.6 2.4V54c0 1.4-.5 2.3-1.6 2.3h-3.6v16.2zm9.4 15.7c0-2 .3-3.2 1.5-3.2.2 0 .4 0 1.4.4l1.1.3.2-.1.4-.7c.3-.6.4-1.6.4-3l-.6-3.3L79 52.7v-.9c0-1.2.3-2 1.2-2H84c.5 0 1 .3 1.3.6.3.4.5.9.6 1.6l3.4 18 2.6-17.8c.1-.8.3-1.3.6-1.7.3-.4.8-.6 1.3-.6h2.6c1 0 1.4.8 1.4 2l-.1.8L92 82.2c-.5 2.5-1 4.4-1.5 5.7a6.6 6.6 0 01-2 3c-.9.6-1.9.9-3.1.9h-.3c-2 0-3.3-.6-4.1-1.7-.3-.4-.4-1-.4-2zM31.3 38.8l8.2-2.1h.5c1 0 1.4.8 1.4 2.2v41.9c0 1.8-.4 2.9-1.6 2.9h-4.7c-1.2 0-1.6-1.1-1.6-3v-35l-2 .6c-1.2 0-1.6-.9-1.6-2.2v-3c0-1.2.4-2 1.4-2.3z"
|
||||
fill="#FFF"
|
||||
/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.1 KiB |
27
src/lib/components/svg/services/LanguageTool.svelte
Normal file
27
src/lib/components/svg/services/LanguageTool.svelte
Normal file
@@ -0,0 +1,27 @@
|
||||
<script lang="ts">
|
||||
export let isAbsolute = false;
|
||||
</script>
|
||||
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class={isAbsolute ? 'w-10 h-10 absolute top-0 left-0 -m-5' : 'w-8 mx-auto'}
|
||||
fill="none"
|
||||
viewBox="0 0 140 140"
|
||||
data-lt-extension-installed="true"
|
||||
><g clip-path="url(#clip0)"
|
||||
><path
|
||||
fill="#fff"
|
||||
fill-rule="evenodd"
|
||||
d="M140 43.602c0-1.662.001-3.324-.01-4.987-.008-1.4-.024-2.8-.062-4.2-.082-3.05-.262-6.126-.805-9.142-.55-3.06-1.448-5.907-2.864-8.688A29.227 29.227 0 0 0 123.476 3.81c-2.783-1.416-5.634-2.314-8.697-2.864-3.016-.542-6.094-.722-9.144-.804-1.4-.038-2.801-.054-4.202-.063C99.77.068 98.107.07 96.444.07L77.135 0H62.694L43.726.07c-1.666 0-3.332-.002-4.998.008-1.404.01-2.807.025-4.21.063-3.058.082-6.142.262-9.166.805-3.067.55-5.922 1.447-8.709 2.862a29.293 29.293 0 0 0-7.419 5.377 29.223 29.223 0 0 0-5.389 7.4c-1.42 2.78-2.32 5.63-2.871 8.691-.543 3.016-.723 6.091-.806 9.14-.038 1.4-.054 2.8-.062 4.2C.086 40.277 0 42.342 0 44.004v33.3l.086 19.102c0 1.665 0 3.33.01 4.994a200.6 200.6 0 0 0 .062 4.205c.083 3.054.263 6.135.807 9.155.551 3.064 1.451 5.916 2.87 8.7a29.294 29.294 0 0 0 12.807 12.794c2.788 1.418 5.645 2.317 8.714 2.868 3.022.542 6.105.722 9.162.804 1.403.038 2.806.054 4.21.063 1.666.01 3.332.009 4.998.009l19.14.001h14.477l19.101-.001c1.663 0 3.326.001 4.989-.009a202.92 202.92 0 0 0 4.202-.063c3.052-.082 6.13-.262 9.148-.805 3.061-.551 5.911-1.45 8.692-2.867a29.215 29.215 0 0 0 7.405-5.384 29.22 29.22 0 0 0 5.378-7.409c1.417-2.785 2.315-5.639 2.866-8.704.542-3.02.722-6.099.804-9.152.038-1.402.054-2.804.062-4.205.011-1.665.01-3.33.01-4.993l-.001-19.103V62.694L140 43.602"
|
||||
clip-rule="evenodd"
|
||||
/><path
|
||||
fill="#000"
|
||||
fill-rule="evenodd"
|
||||
d="M39.375 40.188h8.313a6.25 6.25 0 0 1 6.25 6.25v24.25h16.25v8.75h-18.75a6.25 6.25 0 0 1-6.25-6.25v-24.25h-5.813v-8.75zm63.563 6.25v6.5h-8.75v-4h-6.876v30.5h-8.75v-30.5h-6.874v4h-8.75v-6.5a6.25 6.25 0 0 1 6.25-6.25h27.5a6.25 6.25 0 0 1 6.25 6.25z"
|
||||
clip-rule="evenodd"
|
||||
/><path
|
||||
fill="#239AFF"
|
||||
d="M35.319 102.906l-8.138-5.812c2.39-3.347 4.857-5.936 7.452-7.753 2.884-2.018 5.948-3.091 9.117-3.091 2.942 0 5.491.714 7.768 2.08a17.622 17.622 0 0 1 2.615 1.94c.589.518 1.009.926 1.903 1.82 1.355 1.354 1.917 1.851 2.591 2.255.731.439 1.503.655 2.623.655 1.121 0 1.896-.217 2.631-.657.677-.405 1.245-.905 2.6-2.257l.012-.012c.89-.888 1.314-1.299 1.902-1.817a17.643 17.643 0 0 1 2.61-1.933c2.273-1.362 4.814-2.074 7.745-2.074s5.472.712 7.745 2.074c.916.55 1.758 1.183 2.61 1.933.589.518 1.013.929 1.902 1.817l.013.012c1.354 1.352 1.922 1.852 2.599 2.257.735.44 1.51.657 2.631.657.998 0 2.1-.386 3.383-1.284 1.572-1.1 3.272-2.886 5.048-5.372l8.138 5.812c-2.391 3.347-4.857 5.936-7.452 7.753-2.884 2.018-5.948 3.091-9.117 3.091-2.941 0-5.49-.713-7.769-2.078a17.627 17.627 0 0 1-2.619-1.938c-.59-.519-1.015-.93-1.906-1.82l-.013-.013c-1.351-1.348-1.917-1.846-2.59-2.25-.728-.436-1.494-.651-2.603-.651-1.109 0-1.875.215-2.603.651-.673.404-1.239.902-2.59 2.25l-.012.013c-.892.89-1.317 1.301-1.907 1.82-.855.752-1.7 1.388-2.62 1.938C66.74 104.287 64.192 105 61.25 105c-2.942 0-5.49-.714-7.768-2.08a17.654 17.654 0 0 1-2.615-1.939c-.588-.519-1.009-.927-1.902-1.82-1.355-1.355-1.918-1.852-2.592-2.256-.731-.439-1.503-.655-2.623-.655-.998 0-2.1.386-3.383 1.284-1.572 1.1-3.272 2.886-5.048 5.372z"
|
||||
/></g
|
||||
><defs><clipPath id="clip0"><path fill="#fff" d="M0 0h140v140H0z" /></clipPath></defs></svg
|
||||
>
|
||||
@@ -1,7 +1,7 @@
|
||||
function defaultBuildAndDeploy(packageManager) {
|
||||
return {
|
||||
installCommand:
|
||||
packageManager === 'npm' ? `${packageManager} run install` : `${packageManager} install`,
|
||||
packageManager === 'npm' ? `${packageManager} install` : `${packageManager} install`,
|
||||
buildCommand:
|
||||
packageManager === 'npm' ? `${packageManager} run build` : `${packageManager} build`,
|
||||
startCommand:
|
||||
@@ -126,6 +126,26 @@ export function findBuildPack(pack, packageManager = 'npm') {
|
||||
port: 3000
|
||||
};
|
||||
}
|
||||
if (pack === 'astro') {
|
||||
return {
|
||||
...metaData,
|
||||
installCommand: `yarn install`,
|
||||
buildCommand: `yarn build`,
|
||||
startCommand: null,
|
||||
publishDirectory: `dist`,
|
||||
port: 80
|
||||
};
|
||||
}
|
||||
if (pack === 'eleventy') {
|
||||
return {
|
||||
...metaData,
|
||||
installCommand: `yarn install`,
|
||||
buildCommand: `yarn build`,
|
||||
startCommand: null,
|
||||
publishDirectory: `_site`,
|
||||
port: 80
|
||||
};
|
||||
}
|
||||
return {
|
||||
name: 'node',
|
||||
fancyName: 'Node.js',
|
||||
@@ -145,7 +165,6 @@ export const buildPacks = [
|
||||
hoverColor: 'hover:bg-green-700',
|
||||
color: 'bg-green-700'
|
||||
},
|
||||
|
||||
{
|
||||
name: 'static',
|
||||
fancyName: 'Static',
|
||||
@@ -158,36 +177,18 @@ export const buildPacks = [
|
||||
hoverColor: 'hover:bg-sky-700',
|
||||
color: 'bg-sky-700'
|
||||
},
|
||||
{
|
||||
name: 'php',
|
||||
fancyName: 'PHP',
|
||||
hoverColor: 'hover:bg-indigo-700',
|
||||
color: 'bg-indigo-700'
|
||||
},
|
||||
{
|
||||
name: 'svelte',
|
||||
fancyName: 'Svelte',
|
||||
hoverColor: 'hover:bg-orange-700',
|
||||
color: 'bg-orange-700'
|
||||
},
|
||||
{
|
||||
name: 'nestjs',
|
||||
fancyName: 'NestJS',
|
||||
hoverColor: 'hover:bg-red-700',
|
||||
color: 'bg-red-700'
|
||||
},
|
||||
{
|
||||
name: 'react',
|
||||
fancyName: 'React',
|
||||
hoverColor: 'hover:bg-blue-700',
|
||||
color: 'bg-blue-700'
|
||||
},
|
||||
{
|
||||
name: 'nextjs',
|
||||
fancyName: 'NextJS',
|
||||
hoverColor: 'hover:bg-blue-700',
|
||||
color: 'bg-blue-700'
|
||||
},
|
||||
{
|
||||
name: 'gatsby',
|
||||
fancyName: 'Gatsby',
|
||||
hoverColor: 'hover:bg-blue-700',
|
||||
color: 'bg-blue-700'
|
||||
},
|
||||
{
|
||||
name: 'vuejs',
|
||||
fancyName: 'VueJS',
|
||||
@@ -200,6 +201,31 @@ export const buildPacks = [
|
||||
hoverColor: 'hover:bg-green-700',
|
||||
color: 'bg-green-700'
|
||||
},
|
||||
{
|
||||
name: 'gatsby',
|
||||
fancyName: 'Gatsby',
|
||||
hoverColor: 'hover:bg-blue-700',
|
||||
color: 'bg-blue-700'
|
||||
},
|
||||
{
|
||||
name: 'astro',
|
||||
fancyName: 'Astro',
|
||||
hoverColor: 'hover:bg-pink-700',
|
||||
color: 'bg-pink-700'
|
||||
},
|
||||
{
|
||||
name: 'eleventy',
|
||||
fancyName: 'Eleventy',
|
||||
hoverColor: 'hover:bg-red-700',
|
||||
color: 'bg-red-700'
|
||||
},
|
||||
|
||||
{
|
||||
name: 'react',
|
||||
fancyName: 'React',
|
||||
hoverColor: 'hover:bg-blue-700',
|
||||
color: 'bg-blue-700'
|
||||
},
|
||||
{
|
||||
name: 'preact',
|
||||
fancyName: 'Preact',
|
||||
@@ -207,10 +233,16 @@ export const buildPacks = [
|
||||
color: 'bg-blue-700'
|
||||
},
|
||||
{
|
||||
name: 'php',
|
||||
fancyName: 'PHP',
|
||||
hoverColor: 'hover:bg-indigo-700',
|
||||
color: 'bg-indigo-700'
|
||||
name: 'nextjs',
|
||||
fancyName: 'NextJS',
|
||||
hoverColor: 'hover:bg-blue-700',
|
||||
color: 'bg-blue-700'
|
||||
},
|
||||
{
|
||||
name: 'nestjs',
|
||||
fancyName: 'NestJS',
|
||||
hoverColor: 'hover:bg-red-700',
|
||||
color: 'bg-red-700'
|
||||
},
|
||||
{
|
||||
name: 'rust',
|
||||
@@ -220,6 +252,12 @@ export const buildPacks = [
|
||||
}
|
||||
];
|
||||
export const scanningTemplates = {
|
||||
astro: {
|
||||
buildPack: 'astro'
|
||||
},
|
||||
'@11ty/eleventy': {
|
||||
buildPack: 'eleventy'
|
||||
},
|
||||
svelte: {
|
||||
buildPack: 'svelte'
|
||||
},
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { decrypt, encrypt } from '$lib/crypto';
|
||||
import { removeProxyConfiguration } from '$lib/haproxy';
|
||||
import { asyncExecShell, getEngine } from '$lib/common';
|
||||
|
||||
import { getDomain, removeDestinationDocker } from '$lib/common';
|
||||
@@ -119,7 +118,8 @@ export async function getApplicationWebhook({ projectId, branch }) {
|
||||
}
|
||||
export async function getApplicationById({ id }) {
|
||||
const body = await prisma.application.findFirst({
|
||||
where: { id }
|
||||
where: { id },
|
||||
include: { destinationDocker: true }
|
||||
});
|
||||
|
||||
return { ...body };
|
||||
@@ -135,13 +135,13 @@ export async function getApplication({ id, teamId }) {
|
||||
}
|
||||
});
|
||||
|
||||
if (body.gitSource?.githubApp?.clientSecret) {
|
||||
if (body?.gitSource?.githubApp?.clientSecret) {
|
||||
body.gitSource.githubApp.clientSecret = decrypt(body.gitSource.githubApp.clientSecret);
|
||||
}
|
||||
if (body.gitSource?.githubApp?.webhookSecret) {
|
||||
if (body?.gitSource?.githubApp?.webhookSecret) {
|
||||
body.gitSource.githubApp.webhookSecret = decrypt(body.gitSource.githubApp.webhookSecret);
|
||||
}
|
||||
if (body.gitSource?.githubApp?.privateKey) {
|
||||
if (body?.gitSource?.githubApp?.privateKey) {
|
||||
body.gitSource.githubApp.privateKey = decrypt(body.gitSource.githubApp.privateKey);
|
||||
}
|
||||
if (body?.gitSource?.gitlabApp?.appSecret) {
|
||||
|
||||
@@ -156,6 +156,15 @@ export const supportedServiceTypesAndVersions = [
|
||||
ports: {
|
||||
main: 80
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'languagetool',
|
||||
fancyName: 'LanguageTool',
|
||||
baseImage: 'silviof/docker-languagetool',
|
||||
versions: ['latest'],
|
||||
ports: {
|
||||
main: 8010
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { asyncExecShell, getEngine } from '$lib/common';
|
||||
import { decrypt, encrypt } from '$lib/crypto';
|
||||
import { dockerInstance } from '$lib/docker';
|
||||
import { startCoolifyProxy } from '$lib/haproxy';
|
||||
import { getDatabaseImage } from '.';
|
||||
@@ -47,7 +48,36 @@ export async function updateDestination({ id, name, engine, network }) {
|
||||
return await prisma.destinationDocker.update({ where: { id }, data: { name, engine, network } });
|
||||
}
|
||||
|
||||
export async function newDestination({ name, teamId, engine, network, isCoolifyProxyUsed }) {
|
||||
export async function newRemoteDestination({
|
||||
name,
|
||||
teamId,
|
||||
engine,
|
||||
network,
|
||||
isCoolifyProxyUsed,
|
||||
remoteEngine,
|
||||
ipAddress,
|
||||
user,
|
||||
port,
|
||||
sshPrivateKey
|
||||
}) {
|
||||
const encryptedPrivateKey = encrypt(sshPrivateKey);
|
||||
const destination = await prisma.destinationDocker.create({
|
||||
data: {
|
||||
name,
|
||||
teams: { connect: { id: teamId } },
|
||||
engine,
|
||||
network,
|
||||
isCoolifyProxyUsed,
|
||||
remoteEngine,
|
||||
ipAddress,
|
||||
user,
|
||||
port,
|
||||
sshPrivateKey: encryptedPrivateKey
|
||||
}
|
||||
});
|
||||
return destination.id;
|
||||
}
|
||||
export async function newLocalDestination({ name, teamId, engine, network, isCoolifyProxyUsed }) {
|
||||
const host = getEngine(engine);
|
||||
const docker = dockerInstance({ destinationDocker: { engine, network } });
|
||||
const found = await docker.engine.listNetworks({ filters: { name: [`^${network}$`] } });
|
||||
@@ -94,9 +124,13 @@ export async function removeDestination({ id }) {
|
||||
}
|
||||
|
||||
export async function getDestination({ id, teamId }) {
|
||||
return await prisma.destinationDocker.findFirst({
|
||||
let destination = await prisma.destinationDocker.findFirst({
|
||||
where: { id, teams: { some: { id: teamId } } }
|
||||
});
|
||||
if (destination.remoteEngine) {
|
||||
destination.sshPrivateKey = decrypt(destination.sshPrivateKey);
|
||||
}
|
||||
return destination;
|
||||
}
|
||||
export async function getDestinationByApplicationId({ id, teamId }) {
|
||||
return await prisma.destinationDocker.findFirst({
|
||||
|
||||
@@ -105,6 +105,13 @@ export async function configureServiceType({ id, type }) {
|
||||
type
|
||||
}
|
||||
});
|
||||
} else if (type === 'languagetool') {
|
||||
await prisma.service.update({
|
||||
where: { id },
|
||||
data: {
|
||||
type
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
export async function setServiceVersion({ id, version }) {
|
||||
@@ -128,6 +135,9 @@ export async function updatePlausibleAnalyticsService({ id, fqdn, email, usernam
|
||||
export async function updateNocoDbOrMinioService({ id, fqdn, name }) {
|
||||
return await prisma.service.update({ where: { id }, data: { fqdn, name } });
|
||||
}
|
||||
export async function updateLanguageToolService({ id, fqdn, name }) {
|
||||
return await prisma.service.update({ where: { id }, data: { fqdn, name } });
|
||||
}
|
||||
export async function updateVaultWardenService({ id, fqdn, name }) {
|
||||
return await prisma.service.update({ where: { id }, data: { fqdn, name } });
|
||||
}
|
||||
|
||||
@@ -10,13 +10,18 @@ export async function hashPassword(password: string) {
|
||||
const saltRounds = 15;
|
||||
return bcrypt.hash(password, saltRounds);
|
||||
}
|
||||
export async function login({ email, password }) {
|
||||
export async function login({ email, password, isLogin }) {
|
||||
const users = await prisma.user.count();
|
||||
const userFound = await prisma.user.findUnique({
|
||||
where: { email },
|
||||
include: { teams: true, permission: true },
|
||||
rejectOnNotFound: false
|
||||
});
|
||||
if (!userFound && isLogin) {
|
||||
throw {
|
||||
error: 'Wrong password or email address.'
|
||||
};
|
||||
}
|
||||
// Registration disabled if database is not seeded properly
|
||||
const { isRegistrationEnabled, id } = await db.listSettings();
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ export async function buildCacheImageWithNode(data, imageForBuild) {
|
||||
const Dockerfile: Array<string> = [];
|
||||
Dockerfile.push(`FROM ${imageForBuild}`);
|
||||
Dockerfile.push('WORKDIR /usr/src/app');
|
||||
Dockerfile.push(`LABEL coolify.image=true`);
|
||||
if (secrets.length > 0) {
|
||||
secrets.forEach((secret) => {
|
||||
if (secret.isBuildSecret) {
|
||||
|
||||
259
src/lib/haproxy/configuration.ts
Normal file
259
src/lib/haproxy/configuration.ts
Normal file
@@ -0,0 +1,259 @@
|
||||
import { dev } from '$app/env';
|
||||
import got from 'got';
|
||||
import mustache from 'mustache';
|
||||
import crypto from 'crypto';
|
||||
|
||||
import * as db from '$lib/database';
|
||||
import { checkContainer, checkHAProxy } from '.';
|
||||
import { asyncExecShell, getDomain, getEngine } from '$lib/common';
|
||||
|
||||
const url = dev ? 'http://localhost:5555' : 'http://coolify-haproxy:5555';
|
||||
|
||||
let template = `program api
|
||||
command /usr/bin/dataplaneapi -f /usr/local/etc/haproxy/dataplaneapi.hcl --userlist haproxy-dataplaneapi
|
||||
no option start-on-reload
|
||||
|
||||
global
|
||||
stats socket /var/run/api.sock user haproxy group haproxy mode 660 level admin expose-fd listeners
|
||||
log stdout format raw local0 debug
|
||||
|
||||
defaults
|
||||
mode http
|
||||
log global
|
||||
timeout http-request 60s
|
||||
timeout connect 10s
|
||||
timeout client 60s
|
||||
timeout server 60s
|
||||
|
||||
userlist haproxy-dataplaneapi
|
||||
user admin insecure-password "\${HAPROXY_PASSWORD}"
|
||||
|
||||
frontend http
|
||||
mode http
|
||||
bind :80
|
||||
bind :443 ssl crt /usr/local/etc/haproxy/ssl/ alpn h2,http/1.1
|
||||
acl is_certbot path_beg /.well-known/acme-challenge/
|
||||
{{#applications}}
|
||||
{{#isHttps}}
|
||||
http-request redirect scheme https code ${
|
||||
dev ? 302 : 301
|
||||
} if { hdr(host) -i {{domain}} } !{ ssl_fc }
|
||||
{{/isHttps}}
|
||||
http-request redirect location {{{redirectValue}}} code ${
|
||||
dev ? 302 : 301
|
||||
} if { req.hdr(host) -i {{redirectTo}} }
|
||||
{{/applications}}
|
||||
{{#services}}
|
||||
{{#isHttps}}
|
||||
http-request redirect scheme https code ${
|
||||
dev ? 302 : 301
|
||||
} if { hdr(host) -i {{domain}} } !{ ssl_fc }
|
||||
{{/isHttps}}
|
||||
http-request redirect location {{{redirectValue}}} code ${
|
||||
dev ? 302 : 301
|
||||
} if { req.hdr(host) -i {{redirectTo}} }
|
||||
{{/services}}
|
||||
{{#coolify}}
|
||||
{{#isHttps}}
|
||||
http-request redirect scheme https code ${
|
||||
dev ? 302 : 301
|
||||
} if { hdr(host) -i {{domain}} } !{ ssl_fc }
|
||||
{{/isHttps}}
|
||||
http-request redirect location {{{redirectValue}}} code ${
|
||||
dev ? 302 : 301
|
||||
} if { req.hdr(host) -i {{redirectTo}} }
|
||||
{{/coolify}}
|
||||
use_backend backend-certbot if is_certbot
|
||||
use_backend %[req.hdr(host),lower]
|
||||
|
||||
frontend stats
|
||||
bind *:8404
|
||||
stats enable
|
||||
stats uri /
|
||||
stats admin if TRUE
|
||||
stats auth "\${HAPROXY_USERNAME}:\${HAPROXY_PASSWORD}"
|
||||
|
||||
backend backend-certbot
|
||||
mode http
|
||||
server certbot host.docker.internal:9080
|
||||
|
||||
{{#applications}}
|
||||
{{#isRunning}}
|
||||
# updatedAt={{updatedAt}}
|
||||
backend {{domain}}
|
||||
option forwardfor
|
||||
server {{id}} {{id}}:{{port}} check
|
||||
{{/isRunning}}
|
||||
{{/applications}}
|
||||
|
||||
{{#services}}
|
||||
{{#isRunning}}
|
||||
# updatedAt={{updatedAt}}
|
||||
backend {{domain}}
|
||||
option forwardfor
|
||||
server {{id}} {{id}}:{{port}} check
|
||||
{{/isRunning}}
|
||||
{{/services}}
|
||||
|
||||
{{#coolify}}
|
||||
backend {{domain}}
|
||||
option forwardfor
|
||||
option httpchk GET /undead.json
|
||||
server {{id}} {{id}}:{{port}} check fall 10
|
||||
{{/coolify}}
|
||||
`;
|
||||
export async function haproxyInstance() {
|
||||
const { proxyPassword } = await db.listSettings();
|
||||
return got.extend({
|
||||
prefixUrl: url,
|
||||
username: 'admin',
|
||||
password: proxyPassword
|
||||
});
|
||||
}
|
||||
|
||||
export async function configureHAProxy() {
|
||||
try {
|
||||
const haproxy = await haproxyInstance();
|
||||
await checkHAProxy(haproxy);
|
||||
const data = {
|
||||
applications: [],
|
||||
services: [],
|
||||
coolify: []
|
||||
};
|
||||
const applications = await db.prisma.application.findMany({
|
||||
include: { destinationDocker: true, settings: true }
|
||||
});
|
||||
for (const application of applications) {
|
||||
const {
|
||||
fqdn,
|
||||
id,
|
||||
port,
|
||||
destinationDocker,
|
||||
destinationDockerId,
|
||||
settings: { previews },
|
||||
updatedAt
|
||||
} = application;
|
||||
if (destinationDockerId) {
|
||||
const { engine, network } = destinationDocker;
|
||||
const isRunning = await checkContainer(engine, id);
|
||||
if (fqdn) {
|
||||
const domain = getDomain(fqdn);
|
||||
const isHttps = fqdn.startsWith('https://');
|
||||
const isWWW = fqdn.includes('www.');
|
||||
const redirectValue = `${isHttps ? 'https://' : 'http://'}${domain}%[capture.req.uri]`;
|
||||
if (isRunning) {
|
||||
data.applications.push({
|
||||
id,
|
||||
port: port || 3000,
|
||||
domain,
|
||||
isRunning,
|
||||
isHttps,
|
||||
redirectValue,
|
||||
redirectTo: isWWW ? domain : 'www.' + domain,
|
||||
updatedAt: updatedAt.getTime()
|
||||
});
|
||||
}
|
||||
if (previews) {
|
||||
const host = getEngine(engine);
|
||||
const { stdout } = await asyncExecShell(
|
||||
`DOCKER_HOST=${host} docker container ls --filter="status=running" --filter="network=${network}" --filter="name=${id}-" --format="{{json .Names}}"`
|
||||
);
|
||||
const containers = stdout
|
||||
.trim()
|
||||
.split('\n')
|
||||
.filter((a) => a)
|
||||
.map((c) => c.replace(/"/g, ''));
|
||||
if (containers.length > 0) {
|
||||
for (const container of containers) {
|
||||
let previewDomain = `${container.split('-')[1]}.${domain}`;
|
||||
data.applications.push({
|
||||
id: container,
|
||||
port: port || 3000,
|
||||
domain: previewDomain,
|
||||
isRunning,
|
||||
isHttps,
|
||||
redirectValue,
|
||||
redirectTo: isWWW ? previewDomain : 'www.' + previewDomain,
|
||||
updatedAt: updatedAt.getTime()
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
const services = await db.prisma.service.findMany({
|
||||
include: {
|
||||
destinationDocker: true,
|
||||
minio: true,
|
||||
plausibleAnalytics: true,
|
||||
vscodeserver: true,
|
||||
wordpress: true
|
||||
}
|
||||
});
|
||||
|
||||
for (const service of services) {
|
||||
const { fqdn, id, type, destinationDocker, destinationDockerId, updatedAt } = service;
|
||||
if (destinationDockerId) {
|
||||
const { engine } = destinationDocker;
|
||||
const found = db.supportedServiceTypesAndVersions.find((a) => a.name === type);
|
||||
if (found) {
|
||||
const port = found.ports.main;
|
||||
const publicPort = service[type]?.publicPort;
|
||||
const isRunning = await checkContainer(engine, id);
|
||||
if (fqdn) {
|
||||
const domain = getDomain(fqdn);
|
||||
const isHttps = fqdn.startsWith('https://');
|
||||
const isWWW = fqdn.includes('www.');
|
||||
const redirectValue = `${isHttps ? 'https://' : 'http://'}${domain}%[capture.req.uri]`;
|
||||
if (isRunning) {
|
||||
data.services.push({
|
||||
id,
|
||||
port,
|
||||
publicPort,
|
||||
domain,
|
||||
isRunning,
|
||||
isHttps,
|
||||
redirectValue,
|
||||
redirectTo: isWWW ? domain : 'www.' + domain,
|
||||
updatedAt: updatedAt.getTime()
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
const { fqdn } = await db.prisma.setting.findFirst();
|
||||
if (fqdn) {
|
||||
const domain = getDomain(fqdn);
|
||||
const isHttps = fqdn.startsWith('https://');
|
||||
const isWWW = fqdn.includes('www.');
|
||||
const redirectValue = `${isHttps ? 'https://' : 'http://'}${domain}%[capture.req.uri]`;
|
||||
data.coolify.push({
|
||||
id: dev ? 'host.docker.internal' : 'coolify',
|
||||
port: 3000,
|
||||
domain,
|
||||
isHttps,
|
||||
redirectValue,
|
||||
redirectTo: isWWW ? domain : 'www.' + domain
|
||||
});
|
||||
}
|
||||
const output = mustache.render(template, data);
|
||||
const newHash = crypto.createHash('md5').update(output).digest('hex');
|
||||
const { proxyHash, id } = await db.listSettings();
|
||||
if (proxyHash !== newHash) {
|
||||
await db.prisma.setting.update({ where: { id }, data: { proxyHash: newHash } });
|
||||
await haproxy.post(`v2/services/haproxy/configuration/raw`, {
|
||||
searchParams: {
|
||||
skip_version: true
|
||||
},
|
||||
body: output,
|
||||
headers: {
|
||||
'Content-Type': 'text/plain'
|
||||
}
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
import { dev } from '$app/env';
|
||||
import { asyncExecShell, getDomain, getEngine } from '$lib/common';
|
||||
import { asyncExecShell, getEngine } from '$lib/common';
|
||||
import got from 'got';
|
||||
import * as db from '$lib/database';
|
||||
|
||||
@@ -47,113 +47,6 @@ export async function completeTransaction(transactionId) {
|
||||
const haproxy = await haproxyInstance();
|
||||
return await haproxy.put(`v2/services/haproxy/transactions/${transactionId}`);
|
||||
}
|
||||
|
||||
export async function removeProxyConfiguration(fqdn) {
|
||||
const domain = getDomain(fqdn);
|
||||
const haproxy = await haproxyInstance();
|
||||
const backendFound = await haproxy
|
||||
.get(`v2/services/haproxy/configuration/backends/${domain}`)
|
||||
.json();
|
||||
if (backendFound) {
|
||||
const transactionId = await getNextTransactionId();
|
||||
await haproxy
|
||||
.delete(`v2/services/haproxy/configuration/backends/${domain}`, {
|
||||
searchParams: {
|
||||
transaction_id: transactionId
|
||||
}
|
||||
})
|
||||
.json();
|
||||
await completeTransaction(transactionId);
|
||||
}
|
||||
await forceSSLOffApplication(domain);
|
||||
await removeWwwRedirection(fqdn);
|
||||
}
|
||||
export async function forceSSLOffApplication(domain) {
|
||||
const haproxy = await haproxyInstance();
|
||||
await checkHAProxy(haproxy);
|
||||
let transactionId;
|
||||
try {
|
||||
const rules: any = await haproxy
|
||||
.get(`v2/services/haproxy/configuration/http_request_rules`, {
|
||||
searchParams: {
|
||||
parent_name: 'http',
|
||||
parent_type: 'frontend'
|
||||
}
|
||||
})
|
||||
.json();
|
||||
if (rules.data.length > 0) {
|
||||
const rule = rules.data.find((rule) =>
|
||||
rule.cond_test.includes(`{ hdr(host) -i ${domain} } !{ ssl_fc }`)
|
||||
);
|
||||
if (rule) {
|
||||
transactionId = await getNextTransactionId();
|
||||
|
||||
await haproxy
|
||||
.delete(`v2/services/haproxy/configuration/http_request_rules/${rule.index}`, {
|
||||
searchParams: {
|
||||
transaction_id: transactionId,
|
||||
parent_name: 'http',
|
||||
parent_type: 'frontend'
|
||||
}
|
||||
})
|
||||
.json();
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
} finally {
|
||||
if (transactionId) await completeTransaction(transactionId);
|
||||
}
|
||||
}
|
||||
export async function forceSSLOnApplication(domain) {
|
||||
const haproxy = await haproxyInstance();
|
||||
await checkHAProxy(haproxy);
|
||||
let transactionId;
|
||||
try {
|
||||
const rules: any = await haproxy
|
||||
.get(`v2/services/haproxy/configuration/http_request_rules`, {
|
||||
searchParams: {
|
||||
parent_name: 'http',
|
||||
parent_type: 'frontend'
|
||||
}
|
||||
})
|
||||
.json();
|
||||
let nextRule = 0;
|
||||
if (rules.data.length > 0) {
|
||||
const rule = rules.data.find((rule) =>
|
||||
rule.cond_test.includes(`{ hdr(host) -i ${domain} } !{ ssl_fc }`)
|
||||
);
|
||||
if (rule) return;
|
||||
nextRule = rules.data[rules.data.length - 1].index + 1;
|
||||
}
|
||||
transactionId = await getNextTransactionId();
|
||||
|
||||
await haproxy
|
||||
.post(`v2/services/haproxy/configuration/http_request_rules`, {
|
||||
searchParams: {
|
||||
transaction_id: transactionId,
|
||||
parent_name: 'http',
|
||||
parent_type: 'frontend'
|
||||
},
|
||||
json: {
|
||||
index: nextRule,
|
||||
cond: 'if',
|
||||
cond_test: `{ hdr(host) -i ${domain} } !{ ssl_fc }`,
|
||||
type: 'redirect',
|
||||
redir_type: 'scheme',
|
||||
redir_value: 'https',
|
||||
redir_code: dev ? 302 : 301
|
||||
}
|
||||
})
|
||||
.json();
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
throw error;
|
||||
} finally {
|
||||
if (transactionId) await completeTransaction(transactionId);
|
||||
}
|
||||
}
|
||||
|
||||
export async function deleteProxy({ id }) {
|
||||
const haproxy = await haproxyInstance();
|
||||
await checkHAProxy(haproxy);
|
||||
@@ -177,7 +70,7 @@ export async function deleteProxy({ id }) {
|
||||
})
|
||||
.json();
|
||||
} catch (error) {
|
||||
console.log(error.response.body);
|
||||
console.log(error.response?.body || error);
|
||||
} finally {
|
||||
if (transactionId) await completeTransaction(transactionId);
|
||||
}
|
||||
@@ -187,109 +80,6 @@ export async function reloadHaproxy(engine) {
|
||||
const host = getEngine(engine);
|
||||
return await asyncExecShell(`DOCKER_HOST=${host} docker exec coolify-haproxy kill -HUP 1`);
|
||||
}
|
||||
export async function configureProxyForApplication({ domain, imageId, applicationId, port }) {
|
||||
const haproxy = await haproxyInstance();
|
||||
await checkHAProxy(haproxy);
|
||||
|
||||
let serverConfigured = false;
|
||||
let backendAvailable: any = null;
|
||||
|
||||
try {
|
||||
backendAvailable = await haproxy
|
||||
.get(`v2/services/haproxy/configuration/backends/${domain}`)
|
||||
.json();
|
||||
const server: any = await haproxy
|
||||
.get(`v2/services/haproxy/configuration/servers/${imageId}`, {
|
||||
searchParams: {
|
||||
backend: domain
|
||||
}
|
||||
})
|
||||
.json();
|
||||
|
||||
if (backendAvailable && server) {
|
||||
// Very sophisticated way to check if the server is already configured in proxy
|
||||
if (backendAvailable.data.forwardfor.enabled === 'enabled') {
|
||||
if (backendAvailable.data.name === domain) {
|
||||
if (server.data.check === 'enabled') {
|
||||
if (server.data.address === imageId) {
|
||||
if (server.data.port === port) {
|
||||
serverConfigured = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
//console.log('error getting backend or server', error?.response?.body);
|
||||
//
|
||||
}
|
||||
|
||||
if (serverConfigured) return;
|
||||
const transactionId = await getNextTransactionId();
|
||||
if (backendAvailable) {
|
||||
await haproxy
|
||||
.delete(`v2/services/haproxy/configuration/backends/${domain}`, {
|
||||
searchParams: {
|
||||
transaction_id: transactionId
|
||||
}
|
||||
})
|
||||
.json();
|
||||
}
|
||||
try {
|
||||
await haproxy.post('v2/services/haproxy/configuration/backends', {
|
||||
searchParams: {
|
||||
transaction_id: transactionId
|
||||
},
|
||||
json: {
|
||||
'init-addr': 'last,libc,none',
|
||||
forwardfor: { enabled: 'enabled' },
|
||||
name: domain
|
||||
}
|
||||
});
|
||||
|
||||
await haproxy.post('v2/services/haproxy/configuration/servers', {
|
||||
searchParams: {
|
||||
transaction_id: transactionId,
|
||||
backend: domain
|
||||
},
|
||||
json: {
|
||||
address: imageId,
|
||||
check: 'enabled',
|
||||
name: imageId,
|
||||
port: port
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
throw error?.response?.body || error;
|
||||
} finally {
|
||||
await completeTransaction(transactionId);
|
||||
}
|
||||
}
|
||||
|
||||
export async function configureCoolifyProxyOff(fqdn) {
|
||||
const domain = getDomain(fqdn);
|
||||
const isHttps = fqdn.startsWith('https://');
|
||||
const haproxy = await haproxyInstance();
|
||||
await checkHAProxy(haproxy);
|
||||
|
||||
try {
|
||||
await haproxy.get(`v2/services/haproxy/configuration/backends/${domain}`).json();
|
||||
const transactionId = await getNextTransactionId();
|
||||
await haproxy
|
||||
.delete(`v2/services/haproxy/configuration/backends/${domain}`, {
|
||||
searchParams: {
|
||||
transaction_id: transactionId
|
||||
}
|
||||
})
|
||||
.json();
|
||||
await completeTransaction(transactionId);
|
||||
if (isHttps) await forceSSLOffApplication(domain);
|
||||
await removeWwwRedirection(fqdn);
|
||||
} catch (error) {
|
||||
throw error?.response?.body || error;
|
||||
}
|
||||
}
|
||||
export async function checkHAProxy(haproxy?: any) {
|
||||
if (!haproxy) haproxy = await haproxyInstance();
|
||||
try {
|
||||
@@ -301,76 +91,6 @@ export async function checkHAProxy(haproxy?: any) {
|
||||
};
|
||||
}
|
||||
}
|
||||
export async function configureCoolifyProxyOn(fqdn) {
|
||||
const domain = getDomain(fqdn);
|
||||
const haproxy = await haproxyInstance();
|
||||
await checkHAProxy(haproxy);
|
||||
let serverConfigured = false;
|
||||
let backendAvailable: any = null;
|
||||
try {
|
||||
backendAvailable = await haproxy
|
||||
.get(`v2/services/haproxy/configuration/backends/${domain}`)
|
||||
.json();
|
||||
const server: any = await haproxy
|
||||
.get(`v2/services/haproxy/configuration/servers/coolify`, {
|
||||
searchParams: {
|
||||
backend: domain
|
||||
}
|
||||
})
|
||||
.json();
|
||||
if (backendAvailable && server) {
|
||||
// Very sophisticated way to check if the server is already configured in proxy
|
||||
if (backendAvailable.data.forwardfor.enabled === 'enabled') {
|
||||
if (backendAvailable.data.name === domain) {
|
||||
if (server.data.check === 'enabled') {
|
||||
if (server.data.address === dev ? 'host.docker.internal' : 'coolify') {
|
||||
if (server.data.port === 3000) {
|
||||
serverConfigured = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (error) {}
|
||||
if (serverConfigured) return;
|
||||
const transactionId = await getNextTransactionId();
|
||||
try {
|
||||
await haproxy.post('v2/services/haproxy/configuration/backends', {
|
||||
searchParams: {
|
||||
transaction_id: transactionId
|
||||
},
|
||||
json: {
|
||||
adv_check: 'httpchk',
|
||||
httpchk_params: {
|
||||
method: 'GET',
|
||||
uri: '/undead.json'
|
||||
},
|
||||
'init-addr': 'last,libc,none',
|
||||
forwardfor: { enabled: 'enabled' },
|
||||
name: domain
|
||||
}
|
||||
});
|
||||
await haproxy.post('v2/services/haproxy/configuration/servers', {
|
||||
searchParams: {
|
||||
transaction_id: transactionId,
|
||||
backend: domain
|
||||
},
|
||||
json: {
|
||||
address: dev ? 'host.docker.internal' : 'coolify',
|
||||
check: 'enabled',
|
||||
fall: 10,
|
||||
name: 'coolify',
|
||||
port: 3000
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
throw error;
|
||||
} finally {
|
||||
await completeTransaction(transactionId);
|
||||
}
|
||||
}
|
||||
|
||||
export async function stopTcpHttpProxy(destinationDocker, publicPort) {
|
||||
const { engine } = destinationDocker;
|
||||
@@ -434,7 +154,7 @@ export async function startHttpProxy(destinationDocker, id, publicPort, privateP
|
||||
export async function startCoolifyProxy(engine) {
|
||||
const host = getEngine(engine);
|
||||
const found = await checkContainer(engine, 'coolify-haproxy');
|
||||
const { proxyPassword, proxyUser } = await db.listSettings();
|
||||
const { proxyPassword, proxyUser, id } = await db.listSettings();
|
||||
if (!found) {
|
||||
const { stdout: Config } = await asyncExecShell(
|
||||
`DOCKER_HOST="${host}" docker network inspect bridge --format '{{json .IPAM.Config }}'`
|
||||
@@ -443,6 +163,7 @@ export async function startCoolifyProxy(engine) {
|
||||
await asyncExecShell(
|
||||
`DOCKER_HOST="${host}" docker run -e HAPROXY_USERNAME=${proxyUser} -e HAPROXY_PASSWORD=${proxyPassword} --restart always --add-host 'host.docker.internal:host-gateway' --add-host 'host.docker.internal:${ip}' -v coolify-ssl-certs:/usr/local/etc/haproxy/ssl --network coolify-infra -p "80:80" -p "443:443" -p "8404:8404" -p "5555:5555" -p "5000:5000" --name coolify-haproxy -d coollabsio/${defaultProxyImage}`
|
||||
);
|
||||
await db.prisma.setting.update({ where: { id }, data: { proxyHash: null } });
|
||||
}
|
||||
await configureNetworkCoolifyProxy(engine);
|
||||
}
|
||||
@@ -475,6 +196,8 @@ export async function stopCoolifyProxy(engine) {
|
||||
const host = getEngine(engine);
|
||||
const found = await checkContainer(engine, 'coolify-haproxy');
|
||||
await db.setDestinationSettings({ engine, isCoolifyProxyUsed: false });
|
||||
const { id } = await db.prisma.setting.findFirst({});
|
||||
await db.prisma.setting.update({ where: { id }, data: { proxyHash: null } });
|
||||
try {
|
||||
if (found) {
|
||||
await asyncExecShell(
|
||||
@@ -499,168 +222,3 @@ export async function configureNetworkCoolifyProxy(engine) {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export async function configureSimpleServiceProxyOn({ id, domain, port }) {
|
||||
const haproxy = await haproxyInstance();
|
||||
await checkHAProxy(haproxy);
|
||||
let serverConfigured = false;
|
||||
let backendAvailable: any = null;
|
||||
|
||||
try {
|
||||
backendAvailable = await haproxy
|
||||
.get(`v2/services/haproxy/configuration/backends/${domain}`)
|
||||
.json();
|
||||
const server: any = await haproxy
|
||||
.get(`v2/services/haproxy/configuration/servers/${id}`, {
|
||||
searchParams: {
|
||||
backend: domain
|
||||
}
|
||||
})
|
||||
.json();
|
||||
if (backendAvailable && server) {
|
||||
// Very sophisticated way to check if the server is already configured in proxy
|
||||
if (backendAvailable.data.forwardfor.enabled === 'enabled') {
|
||||
if (backendAvailable.data.name === domain) {
|
||||
if (server.data.check === 'enabled') {
|
||||
if (server.data.address === id) {
|
||||
if (server.data.port === port) {
|
||||
serverConfigured = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (error) {}
|
||||
if (serverConfigured) return;
|
||||
const transactionId = await getNextTransactionId();
|
||||
await haproxy.post('v2/services/haproxy/configuration/backends', {
|
||||
searchParams: {
|
||||
transaction_id: transactionId
|
||||
},
|
||||
json: {
|
||||
'init-addr': 'last,libc,none',
|
||||
forwardfor: { enabled: 'enabled' },
|
||||
name: domain
|
||||
}
|
||||
});
|
||||
await haproxy.post('v2/services/haproxy/configuration/servers', {
|
||||
searchParams: {
|
||||
transaction_id: transactionId,
|
||||
backend: domain
|
||||
},
|
||||
json: {
|
||||
address: id,
|
||||
check: 'enabled',
|
||||
name: id,
|
||||
port: port
|
||||
}
|
||||
});
|
||||
await completeTransaction(transactionId);
|
||||
}
|
||||
|
||||
export async function configureSimpleServiceProxyOff(fqdn) {
|
||||
const domain = getDomain(fqdn);
|
||||
const haproxy = await haproxyInstance();
|
||||
await checkHAProxy(haproxy);
|
||||
try {
|
||||
await haproxy.get(`v2/services/haproxy/configuration/backends/${domain}`).json();
|
||||
const transactionId = await getNextTransactionId();
|
||||
await haproxy
|
||||
.delete(`v2/services/haproxy/configuration/backends/${domain}`, {
|
||||
searchParams: {
|
||||
transaction_id: transactionId
|
||||
}
|
||||
})
|
||||
.json();
|
||||
await completeTransaction(transactionId);
|
||||
} catch (error) {}
|
||||
await forceSSLOffApplication(domain);
|
||||
await removeWwwRedirection(fqdn);
|
||||
return;
|
||||
}
|
||||
|
||||
export async function removeWwwRedirection(fqdn) {
|
||||
const domain = getDomain(fqdn);
|
||||
const isHttps = fqdn.startsWith('https://');
|
||||
const redirectValue = `${isHttps ? 'https://' : 'http://'}${domain}%[capture.req.uri]`;
|
||||
|
||||
const haproxy = await haproxyInstance();
|
||||
await checkHAProxy();
|
||||
const rules: any = await haproxy
|
||||
.get(`v2/services/haproxy/configuration/http_request_rules`, {
|
||||
searchParams: {
|
||||
parent_name: 'http',
|
||||
parent_type: 'frontend'
|
||||
}
|
||||
})
|
||||
.json();
|
||||
if (rules.data.length > 0) {
|
||||
const rule = rules.data.find((rule) => rule.redir_value.includes(redirectValue));
|
||||
if (rule) {
|
||||
const transactionId = await getNextTransactionId();
|
||||
await haproxy
|
||||
.delete(`v2/services/haproxy/configuration/http_request_rules/${rule.index}`, {
|
||||
searchParams: {
|
||||
transaction_id: transactionId,
|
||||
parent_name: 'http',
|
||||
parent_type: 'frontend'
|
||||
}
|
||||
})
|
||||
.json();
|
||||
await completeTransaction(transactionId);
|
||||
}
|
||||
}
|
||||
}
|
||||
export async function setWwwRedirection(fqdn) {
|
||||
const haproxy = await haproxyInstance();
|
||||
await checkHAProxy(haproxy);
|
||||
let transactionId;
|
||||
|
||||
try {
|
||||
const domain = getDomain(fqdn);
|
||||
const isHttps = fqdn.startsWith('https://');
|
||||
const isWWW = fqdn.includes('www.');
|
||||
const redirectValue = `${isHttps ? 'https://' : 'http://'}${domain}%[capture.req.uri]`;
|
||||
const contTest = `{ req.hdr(host) -i ${isWWW ? domain.replace('www.', '') : `www.${domain}`} }`;
|
||||
const rules: any = await haproxy
|
||||
.get(`v2/services/haproxy/configuration/http_request_rules`, {
|
||||
searchParams: {
|
||||
parent_name: 'http',
|
||||
parent_type: 'frontend'
|
||||
}
|
||||
})
|
||||
.json();
|
||||
let nextRule = 0;
|
||||
if (rules.data.length > 0) {
|
||||
const rule = rules.data.find((rule) => rule.redir_value.includes(redirectValue));
|
||||
if (rule) return;
|
||||
nextRule = rules.data[rules.data.length - 1].index + 1;
|
||||
}
|
||||
|
||||
transactionId = await getNextTransactionId();
|
||||
await haproxy
|
||||
.post(`v2/services/haproxy/configuration/http_request_rules`, {
|
||||
searchParams: {
|
||||
transaction_id: transactionId,
|
||||
parent_name: 'http',
|
||||
parent_type: 'frontend'
|
||||
},
|
||||
json: {
|
||||
index: nextRule,
|
||||
cond: 'if',
|
||||
cond_test: contTest,
|
||||
type: 'redirect',
|
||||
redir_type: 'location',
|
||||
redir_value: redirectValue,
|
||||
redir_code: dev ? 302 : 301
|
||||
}
|
||||
})
|
||||
.json();
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
throw error;
|
||||
} finally {
|
||||
if (transactionId) await completeTransaction(transactionId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ export default async function ({
|
||||
buildId
|
||||
}): Promise<any> {
|
||||
try {
|
||||
saveBuildLog({ line: 'GitHub importer started', buildId, applicationId });
|
||||
saveBuildLog({ line: 'GitHub importer started.', buildId, applicationId });
|
||||
const { privateKey, appId, installationId } = await db.getUniqueGithubApp({ githubAppId });
|
||||
const githubPrivateKey = privateKey.replace(/\\n/g, '\n').replace(/"/g, '');
|
||||
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { dev } from '$app/env';
|
||||
import { forceSSLOffApplication, forceSSLOnApplication } from '$lib/haproxy';
|
||||
import { asyncExecShell, getEngine } from './common';
|
||||
import { asyncExecShell, getDomain, getEngine } from '$lib/common';
|
||||
import { checkContainer, reloadHaproxy } from '$lib/haproxy';
|
||||
import * as db from '$lib/database';
|
||||
import { dev } from '$app/env';
|
||||
import cuid from 'cuid';
|
||||
import getPort, { portNumbers } from 'get-port';
|
||||
|
||||
export async function letsEncrypt({ domain, isCoolify = false, id = null }) {
|
||||
export async function letsEncrypt(domain, id = null, isCoolify = false) {
|
||||
try {
|
||||
const data = await db.prisma.setting.findFirst();
|
||||
const { minPort, maxPort } = data;
|
||||
@@ -47,7 +47,6 @@ export async function letsEncrypt({ domain, isCoolify = false, id = null }) {
|
||||
}
|
||||
}
|
||||
}
|
||||
await forceSSLOffApplication(domain);
|
||||
if (dualCerts) {
|
||||
await asyncExecShell(
|
||||
`DOCKER_HOST=${host} docker run --rm --name certbot-${randomCuid} -p 9080:${randomPort} -v "coolify-letsencrypt:/etc/letsencrypt" certbot/certbot --logs-dir /etc/letsencrypt/logs certonly --standalone --preferred-challenges http --http-01-address 0.0.0.0 --http-01-port ${randomPort} -d ${nakedDomain} -d ${wwwDomain} --expand --agree-tos --non-interactive --register-unsafely-without-email ${
|
||||
@@ -57,6 +56,7 @@ export async function letsEncrypt({ domain, isCoolify = false, id = null }) {
|
||||
await asyncExecShell(
|
||||
`DOCKER_HOST=${host} docker run --rm -v "coolify-letsencrypt:/etc/letsencrypt" -v "coolify-ssl-certs:/app/ssl" alpine:latest sh -c "test -d /etc/letsencrypt/live/${nakedDomain}/ && cat /etc/letsencrypt/live/${nakedDomain}/fullchain.pem /etc/letsencrypt/live/${nakedDomain}/privkey.pem > /app/ssl/${nakedDomain}.pem || cat /etc/letsencrypt/live/${wwwDomain}/fullchain.pem /etc/letsencrypt/live/${wwwDomain}/privkey.pem > /app/ssl/${wwwDomain}.pem"`
|
||||
);
|
||||
await reloadHaproxy(host);
|
||||
} else {
|
||||
await asyncExecShell(
|
||||
`DOCKER_HOST=${host} docker run --rm --name certbot-${randomCuid} -p 9080:${randomPort} -v "coolify-letsencrypt:/etc/letsencrypt" certbot/certbot --logs-dir /etc/letsencrypt/logs certonly --standalone --preferred-challenges http --http-01-address 0.0.0.0 --http-01-port ${randomPort} -d ${domain} --expand --agree-tos --non-interactive --register-unsafely-without-email ${
|
||||
@@ -66,14 +66,92 @@ export async function letsEncrypt({ domain, isCoolify = false, id = null }) {
|
||||
await asyncExecShell(
|
||||
`DOCKER_HOST=${host} docker run --rm -v "coolify-letsencrypt:/etc/letsencrypt" -v "coolify-ssl-certs:/app/ssl" alpine:latest sh -c "cat /etc/letsencrypt/live/${domain}/fullchain.pem /etc/letsencrypt/live/${domain}/privkey.pem > /app/ssl/${domain}.pem"`
|
||||
);
|
||||
await reloadHaproxy(host);
|
||||
}
|
||||
} catch (error) {
|
||||
if (error.code !== 0) {
|
||||
throw error;
|
||||
}
|
||||
} finally {
|
||||
if (!isCoolify) {
|
||||
await forceSSLOnApplication(domain);
|
||||
}
|
||||
}
|
||||
|
||||
export async function generateSSLCerts() {
|
||||
const ssls = [];
|
||||
const applications = await db.prisma.application.findMany({
|
||||
include: { destinationDocker: true, settings: true }
|
||||
});
|
||||
for (const application of applications) {
|
||||
const {
|
||||
fqdn,
|
||||
id,
|
||||
destinationDocker: { engine, network },
|
||||
settings: { previews }
|
||||
} = application;
|
||||
const isRunning = await checkContainer(engine, id);
|
||||
const domain = getDomain(fqdn);
|
||||
const isHttps = fqdn.startsWith('https://');
|
||||
if (isRunning) {
|
||||
if (isHttps) ssls.push({ domain, id, isCoolify: false });
|
||||
}
|
||||
if (previews) {
|
||||
const host = getEngine(engine);
|
||||
const { stdout } = await asyncExecShell(
|
||||
`DOCKER_HOST=${host} docker container ls --filter="status=running" --filter="network=${network}" --filter="name=${id}-" --format="{{json .Names}}"`
|
||||
);
|
||||
const containers = stdout
|
||||
.trim()
|
||||
.split('\n')
|
||||
.filter((a) => a)
|
||||
.map((c) => c.replace(/"/g, ''));
|
||||
if (containers.length > 0) {
|
||||
for (const container of containers) {
|
||||
let previewDomain = `${container.split('-')[1]}.${domain}`;
|
||||
if (isHttps) ssls.push({ domain: previewDomain, id, isCoolify: false });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
const services = await db.prisma.service.findMany({
|
||||
include: {
|
||||
destinationDocker: true,
|
||||
minio: true,
|
||||
plausibleAnalytics: true,
|
||||
vscodeserver: true,
|
||||
wordpress: true
|
||||
}
|
||||
});
|
||||
|
||||
for (const service of services) {
|
||||
const {
|
||||
fqdn,
|
||||
id,
|
||||
type,
|
||||
destinationDocker: { engine }
|
||||
} = service;
|
||||
const found = db.supportedServiceTypesAndVersions.find((a) => a.name === type);
|
||||
if (found) {
|
||||
const domain = getDomain(fqdn);
|
||||
const isHttps = fqdn.startsWith('https://');
|
||||
const isRunning = await checkContainer(engine, id);
|
||||
if (isRunning) {
|
||||
if (isHttps) ssls.push({ domain, id, isCoolify: false });
|
||||
}
|
||||
}
|
||||
}
|
||||
const { fqdn } = await db.prisma.setting.findFirst();
|
||||
if (fqdn) {
|
||||
const domain = getDomain(fqdn);
|
||||
const isHttps = fqdn.startsWith('https://');
|
||||
if (isHttps) ssls.push({ domain, id: 'coolify', isCoolify: true });
|
||||
}
|
||||
if (ssls.length > 0) {
|
||||
for (const ssl of ssls) {
|
||||
if (!dev) {
|
||||
console.log('Checking SSL for', ssl.domain);
|
||||
await letsEncrypt(ssl.domain, ssl.id, ssl.isCoolify);
|
||||
} else {
|
||||
console.log('Checking SSL for', ssl.domain);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,6 @@ import * as buildpacks from '../buildPacks';
|
||||
import * as importers from '../importers';
|
||||
import { dockerInstance } from '../docker';
|
||||
import { asyncExecShell, createDirectories, getDomain, getEngine, saveBuildLog } from '../common';
|
||||
import { configureProxyForApplication, reloadHaproxy, setWwwRedirection } from '../haproxy';
|
||||
import * as db from '$lib/database';
|
||||
import { decrypt } from '$lib/crypto';
|
||||
import { sentry } from '$lib/common';
|
||||
@@ -234,10 +233,16 @@ export default async function (job) {
|
||||
baseDirectory,
|
||||
publishDirectory
|
||||
});
|
||||
let envFound = false;
|
||||
try {
|
||||
envFound = !!(await fs.stat(`${workdir}/.env`));
|
||||
} catch (error) {
|
||||
//
|
||||
}
|
||||
try {
|
||||
saveBuildLog({ line: 'Deployment started.', buildId, applicationId });
|
||||
const { stderr } = await asyncExecShell(
|
||||
`DOCKER_HOST=${host} docker run --env-file=${workdir}/.env ${labels.join(
|
||||
`DOCKER_HOST=${host} docker run ${envFound && `--env-file=${workdir}/.env`} ${labels.join(
|
||||
' '
|
||||
)} --name ${imageId} --network ${
|
||||
docker.network
|
||||
@@ -250,25 +255,6 @@ export default async function (job) {
|
||||
sentry.captureException(error);
|
||||
throw new Error(error);
|
||||
}
|
||||
try {
|
||||
if (destinationDockerId && destinationDocker.isCoolifyProxyUsed) {
|
||||
saveBuildLog({ line: 'Proxy configuration started!', buildId, applicationId });
|
||||
await configureProxyForApplication({ domain, imageId, applicationId, port });
|
||||
if (isHttps) await letsEncrypt({ domain, id: applicationId });
|
||||
await setWwwRedirection(fqdn);
|
||||
await reloadHaproxy(destinationDocker.engine);
|
||||
saveBuildLog({ line: 'Proxy configuration successful!', buildId, applicationId });
|
||||
} else {
|
||||
saveBuildLog({
|
||||
line: 'Coolify Proxy is not configured for this destination. Nothing else to do.',
|
||||
buildId,
|
||||
applicationId
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
saveBuildLog({ line: error.stdout || error, buildId, applicationId });
|
||||
sentry.captureException(error);
|
||||
throw new Error(error);
|
||||
}
|
||||
saveBuildLog({ line: 'Proxy will be updated shortly.', buildId, applicationId });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,48 +4,57 @@ import { prisma } from '$lib/database';
|
||||
import { defaultProxyImageHttp, defaultProxyImageTcp } from '$lib/haproxy';
|
||||
|
||||
export default async function () {
|
||||
if (!dev) {
|
||||
const destinationDockers = await prisma.destinationDocker.findMany();
|
||||
for (const destinationDocker of destinationDockers) {
|
||||
const host = getEngine(destinationDocker.engine);
|
||||
// Tagging images with labels
|
||||
try {
|
||||
const images = [
|
||||
`coollabsio/${defaultProxyImageTcp}`,
|
||||
`coollabsio/${defaultProxyImageHttp}`,
|
||||
'certbot/certbot:latest',
|
||||
'node:16.14.0-alpine',
|
||||
'alpine:latest',
|
||||
'nginx:stable-alpine',
|
||||
'node:lts',
|
||||
'php:apache',
|
||||
'rust:latest'
|
||||
];
|
||||
for (const image of images) {
|
||||
await asyncExecShell(
|
||||
`DOCKER_HOST=${host} docker pull ${image} && echo "FROM ${image}" | docker build --label coolify.image="true" -t "${image}" -`
|
||||
);
|
||||
}
|
||||
} catch (error) {}
|
||||
try {
|
||||
await asyncExecShell(`DOCKER_HOST=${host} docker container prune -f`);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
// Cleanup images that are not managed by coolify
|
||||
try {
|
||||
await asyncExecShell(
|
||||
`DOCKER_HOST=${host} docker image prune --filter 'label!=coolify.image=true' -a -f`
|
||||
);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
// Cleanup dangling images
|
||||
try {
|
||||
await asyncExecShell(`DOCKER_HOST=${host} docker image prune -f`);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
const destinationDockers = await prisma.destinationDocker.findMany();
|
||||
for (const destinationDocker of destinationDockers) {
|
||||
const host = getEngine(destinationDocker.engine);
|
||||
// Tagging images with labels
|
||||
// try {
|
||||
// const images = [
|
||||
// `coollabsio/${defaultProxyImageTcp}`,
|
||||
// `coollabsio/${defaultProxyImageHttp}`,
|
||||
// 'certbot/certbot:latest',
|
||||
// 'node:16.14.0-alpine',
|
||||
// 'alpine:latest',
|
||||
// 'nginx:stable-alpine',
|
||||
// 'node:lts',
|
||||
// 'php:apache',
|
||||
// 'rust:latest'
|
||||
// ];
|
||||
// for (const image of images) {
|
||||
// try {
|
||||
// await asyncExecShell(`DOCKER_HOST=${host} docker image inspect ${image}`);
|
||||
// } catch (error) {
|
||||
// await asyncExecShell(
|
||||
// `DOCKER_HOST=${host} docker pull ${image} && echo "FROM ${image}" | docker build --label coolify.image="true" -t "${image}" -`
|
||||
// );
|
||||
// }
|
||||
// }
|
||||
// } catch (error) {}
|
||||
try {
|
||||
await asyncExecShell(`DOCKER_HOST=${host} docker container prune -f`);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
try {
|
||||
await asyncExecShell(`DOCKER_HOST=${host} docker image prune -f`);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
// if (!dev) {
|
||||
// // Cleanup images that are not managed by coolify
|
||||
// try {
|
||||
// await asyncExecShell(
|
||||
// `DOCKER_HOST=${host} docker image prune --filter 'label!=coolify.image=true' -a -f`
|
||||
// );
|
||||
// } catch (error) {
|
||||
// console.log(error);
|
||||
// }
|
||||
// // Cleanup old images >3 days
|
||||
// try {
|
||||
// await asyncExecShell(`DOCKER_HOST=${host} docker image prune --filter "until=72h" -a -f`);
|
||||
// } catch (error) {
|
||||
// console.log(error);
|
||||
// }
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,8 +86,8 @@ const cron = async () => {
|
||||
);
|
||||
|
||||
await queue.proxy.add('proxy', {}, { repeat: { every: 10000 } });
|
||||
// await queue.ssl.add('ssl', {}, { repeat: { every: 10000 } });
|
||||
if (!dev) await queue.cleanup.add('cleanup', {}, { repeat: { every: 600000 } });
|
||||
await queue.ssl.add('ssl', {}, { repeat: { every: 60000 } });
|
||||
await queue.cleanup.add('cleanup', {}, { repeat: { every: 600000 } });
|
||||
await queue.sslRenew.add('sslRenew', {}, { repeat: { every: 1800000 } });
|
||||
|
||||
const events = {
|
||||
|
||||
@@ -1,106 +1,12 @@
|
||||
import { getDomain } from '$lib/common';
|
||||
import { getApplicationById, prisma, supportedServiceTypesAndVersions } from '$lib/database';
|
||||
import { dockerInstance } from '$lib/docker';
|
||||
import {
|
||||
checkContainer,
|
||||
configureCoolifyProxyOn,
|
||||
configureProxyForApplication,
|
||||
configureSimpleServiceProxyOn,
|
||||
forceSSLOnApplication,
|
||||
reloadHaproxy,
|
||||
setWwwRedirection,
|
||||
startCoolifyProxy,
|
||||
startHttpProxy
|
||||
} from '$lib/haproxy';
|
||||
import * as db from '$lib/database';
|
||||
import { dev } from '$app/env';
|
||||
import { ErrorHandler } from '$lib/database';
|
||||
import { configureHAProxy } from '$lib/haproxy/configuration';
|
||||
|
||||
export default async function () {
|
||||
try {
|
||||
// Check destination containers and configure proxy if needed
|
||||
const destinationDockers = await prisma.destinationDocker.findMany({});
|
||||
for (const destination of destinationDockers) {
|
||||
if (destination.isCoolifyProxyUsed) {
|
||||
const docker = dockerInstance({ destinationDocker: destination });
|
||||
const containers = await docker.engine.listContainers();
|
||||
const configurations = containers.filter(
|
||||
(container) => container.Labels['coolify.managed']
|
||||
);
|
||||
for (const configuration of configurations) {
|
||||
if (configuration.Labels['coolify.configuration']) {
|
||||
const parsedConfiguration = JSON.parse(
|
||||
Buffer.from(configuration.Labels['coolify.configuration'], 'base64').toString()
|
||||
);
|
||||
if (
|
||||
parsedConfiguration &&
|
||||
configuration.Labels['coolify.type'] === 'standalone-application'
|
||||
) {
|
||||
const { fqdn, applicationId, port, pullmergeRequestId } = parsedConfiguration;
|
||||
if (fqdn) {
|
||||
const found = await getApplicationById({ id: applicationId });
|
||||
if (found) {
|
||||
const domain = getDomain(fqdn);
|
||||
await configureProxyForApplication({
|
||||
domain,
|
||||
imageId: pullmergeRequestId
|
||||
? `${applicationId}-${pullmergeRequestId}`
|
||||
: applicationId,
|
||||
applicationId,
|
||||
port
|
||||
});
|
||||
const isHttps = fqdn.startsWith('https://');
|
||||
if (isHttps) await forceSSLOnApplication(domain);
|
||||
await setWwwRedirection(fqdn);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (const container of containers) {
|
||||
const image = container.Image.split(':')[0];
|
||||
const found = supportedServiceTypesAndVersions.find((a) => a.baseImage === image);
|
||||
if (found) {
|
||||
const type = found.name;
|
||||
const mainPort = found.ports.main;
|
||||
const id = container.Names[0].replace('/', '');
|
||||
const service = await db.prisma.service.findUnique({
|
||||
where: { id },
|
||||
include: {
|
||||
destinationDocker: true,
|
||||
minio: true,
|
||||
plausibleAnalytics: true,
|
||||
vscodeserver: true,
|
||||
wordpress: true
|
||||
}
|
||||
});
|
||||
const { fqdn } = service;
|
||||
const domain = getDomain(fqdn);
|
||||
await configureSimpleServiceProxyOn({ id, domain, port: mainPort });
|
||||
const publicPort = service[type]?.publicPort;
|
||||
if (publicPort) {
|
||||
const containerFound = await checkContainer(
|
||||
destination.engine,
|
||||
`haproxy-for-${publicPort}`
|
||||
);
|
||||
if (!containerFound) {
|
||||
await startHttpProxy(destination, id, publicPort, 9000);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
const services = await prisma.service.findMany({});
|
||||
// Check Coolify FQDN and configure proxy if needed
|
||||
const { fqdn } = await db.listSettings();
|
||||
if (fqdn) {
|
||||
const domain = getDomain(fqdn);
|
||||
await startCoolifyProxy('/var/run/docker.sock');
|
||||
await configureCoolifyProxyOn(fqdn);
|
||||
await setWwwRedirection(fqdn);
|
||||
const isHttps = fqdn.startsWith('https://');
|
||||
if (isHttps) await forceSSLOnApplication(domain);
|
||||
}
|
||||
return await configureHAProxy();
|
||||
} catch (error) {
|
||||
throw error;
|
||||
console.log(error.response?.body || error);
|
||||
return ErrorHandler(error.response?.body || error);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,76 +1,9 @@
|
||||
import { asyncExecShell, getDomain, getEngine } from '$lib/common';
|
||||
import { prisma } from '$lib/database';
|
||||
import { dockerInstance } from '$lib/docker';
|
||||
import { forceSSLOnApplication } from '$lib/haproxy';
|
||||
import * as db from '$lib/database';
|
||||
import { dev } from '$app/env';
|
||||
import getPort, { portNumbers } from 'get-port';
|
||||
import cuid from 'cuid';
|
||||
import { generateSSLCerts } from '$lib/letsencrypt';
|
||||
|
||||
export default async function () {
|
||||
try {
|
||||
const data = await db.prisma.setting.findFirst();
|
||||
const { minPort, maxPort } = data;
|
||||
|
||||
const publicPort = await getPort({ port: portNumbers(minPort, maxPort) });
|
||||
const randomCuid = cuid();
|
||||
const destinationDockers = await prisma.destinationDocker.findMany({});
|
||||
for (const destination of destinationDockers) {
|
||||
if (destination.isCoolifyProxyUsed) {
|
||||
const docker = dockerInstance({ destinationDocker: destination });
|
||||
const containers = await docker.engine.listContainers();
|
||||
const configurations = containers.filter(
|
||||
(container) => container.Labels['coolify.managed']
|
||||
);
|
||||
for (const configuration of configurations) {
|
||||
const parsedConfiguration = JSON.parse(
|
||||
Buffer.from(configuration.Labels['coolify.configuration'], 'base64').toString()
|
||||
);
|
||||
if (configuration.Labels['coolify.type'] === 'standalone-application') {
|
||||
const { fqdn } = parsedConfiguration;
|
||||
if (fqdn) {
|
||||
const domain = getDomain(fqdn);
|
||||
const isHttps = fqdn.startsWith('https://');
|
||||
if (isHttps) {
|
||||
if (dev) {
|
||||
console.log('DEV MODE: SSL is enabled');
|
||||
} else {
|
||||
const host = getEngine(destination.engine);
|
||||
await asyncExecShell(
|
||||
`DOCKER_HOST=${host} docker run --rm --name certbot-${randomCuid} -p 9080:${publicPort} -v "coolify-letsencrypt:/etc/letsencrypt" certbot/certbot --logs-dir /etc/letsencrypt/logs certonly --standalone --preferred-challenges http --http-01-address 0.0.0.0 --http-01-port ${publicPort} -d ${domain} --agree-tos --non-interactive --register-unsafely-without-email`
|
||||
);
|
||||
const { stderr } = await asyncExecShell(
|
||||
`DOCKER_HOST=${host} docker run --rm -v "coolify-letsencrypt:/etc/letsencrypt" -v "coolify-ssl-certs:/app/ssl" alpine:latest cat /etc/letsencrypt/live/${domain}/fullchain.pem /etc/letsencrypt/live/${domain}/privkey.pem > /app/ssl/${domain}.pem`
|
||||
);
|
||||
if (stderr) throw new Error(stderr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
const { fqdn } = await db.listSettings();
|
||||
if (fqdn) {
|
||||
const domain = getDomain(fqdn);
|
||||
const isHttps = fqdn.startsWith('https://');
|
||||
if (isHttps) {
|
||||
if (dev) {
|
||||
console.log('DEV MODE: SSL is enabled');
|
||||
} else {
|
||||
await asyncExecShell(
|
||||
`docker run --rm --name certbot-${randomCuid} -p 9080:${publicPort} -v "coolify-letsencrypt:/etc/letsencrypt" certbot/certbot --logs-dir /etc/letsencrypt/logs certonly --standalone --preferred-challenges http --http-01-address 0.0.0.0 --http-01-port ${publicPort} -d ${domain} --agree-tos --non-interactive --register-unsafely-without-email`
|
||||
);
|
||||
|
||||
const { stderr } = await asyncExecShell(
|
||||
`docker run --rm -v "coolify-letsencrypt:/etc/letsencrypt" -v "coolify-ssl-certs:/app/ssl" alpine:latest cat /etc/letsencrypt/live/${domain}/fullchain.pem /etc/letsencrypt/live/${domain}/privkey.pem > /app/ssl/${domain}.pem`
|
||||
);
|
||||
if (stderr) throw new Error(stderr);
|
||||
}
|
||||
}
|
||||
}
|
||||
return await generateSSLCerts();
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
export const publicPaths = [
|
||||
'/login',
|
||||
'/register',
|
||||
'/reset',
|
||||
'/reset/password',
|
||||
'/webhooks/success',
|
||||
|
||||
@@ -30,7 +30,6 @@
|
||||
<script>
|
||||
export let teams;
|
||||
export let selectedTeamId;
|
||||
import { fade } from 'svelte/transition';
|
||||
|
||||
import '../tailwind.css';
|
||||
import { SvelteToast, toast } from '@zerodevx/svelte-toast';
|
||||
@@ -39,12 +38,13 @@
|
||||
import { errorNotification } from '$lib/form';
|
||||
import { asyncSleep } from '$lib/components/common';
|
||||
import { del, get, post } from '$lib/api';
|
||||
import { browser } from '$app/env';
|
||||
import { browser, dev } from '$app/env';
|
||||
|
||||
let isUpdateAvailable = false;
|
||||
|
||||
let updateStatus = {
|
||||
found: false,
|
||||
loading: false,
|
||||
checking: false,
|
||||
success: null
|
||||
};
|
||||
let latestVersion = 'latest';
|
||||
@@ -59,17 +59,18 @@
|
||||
return errorNotification(error);
|
||||
}
|
||||
if ($session.teamId === '0') {
|
||||
updateStatus.checking = true;
|
||||
try {
|
||||
const data = await get(`/update.json`);
|
||||
if (overrideVersion || data?.isUpdateAvailable) {
|
||||
latestVersion = overrideVersion || data.latestVersion;
|
||||
isUpdateAvailable = overrideVersion ? true : data?.isUpdateAvailable;
|
||||
await post(`/update.json`, { type: 'pull', latestVersion });
|
||||
if (overrideVersion) {
|
||||
isUpdateAvailable = true;
|
||||
} else {
|
||||
isUpdateAvailable = data.isUpdateAvailable;
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
} finally {
|
||||
updateStatus.checking = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -97,26 +98,32 @@
|
||||
async function update() {
|
||||
updateStatus.loading = true;
|
||||
try {
|
||||
await post(`/update.json`, { type: 'update', latestVersion });
|
||||
toast.push('Update completed.<br><br>Waiting for the new version to start...');
|
||||
let reachable = false;
|
||||
let tries = 0;
|
||||
do {
|
||||
if (dev) {
|
||||
console.log(`updating to ${latestVersion}`);
|
||||
await asyncSleep(4000);
|
||||
try {
|
||||
await get(`/undead.json`);
|
||||
reachable = true;
|
||||
} catch (error) {
|
||||
reachable = false;
|
||||
}
|
||||
if (reachable) break;
|
||||
tries++;
|
||||
} while (!reachable || tries < 120);
|
||||
toast.push('New version reachable. Reloading...');
|
||||
updateStatus.loading = false;
|
||||
updateStatus.success = true;
|
||||
await asyncSleep(3000);
|
||||
return window.location.reload();
|
||||
return window.location.reload();
|
||||
} else {
|
||||
await post(`/update.json`, { type: 'update', latestVersion });
|
||||
toast.push('Update completed.<br><br>Waiting for the new version to start...');
|
||||
let reachable = false;
|
||||
let tries = 0;
|
||||
do {
|
||||
await asyncSleep(4000);
|
||||
try {
|
||||
await get(`/undead.json`);
|
||||
reachable = true;
|
||||
} catch (error) {
|
||||
reachable = false;
|
||||
}
|
||||
if (reachable) break;
|
||||
tries++;
|
||||
} while (!reachable || tries < 120);
|
||||
toast.push('New version reachable. Reloading...');
|
||||
updateStatus.loading = false;
|
||||
updateStatus.success = true;
|
||||
await asyncSleep(3000);
|
||||
return window.location.reload();
|
||||
}
|
||||
} catch ({ error }) {
|
||||
updateStatus.success = false;
|
||||
updateStatus.loading = false;
|
||||
@@ -311,42 +318,17 @@
|
||||
|
||||
<div class="flex flex-col space-y-4 py-2">
|
||||
{#if $session.teamId === '0'}
|
||||
{#if updateStatus.checking}
|
||||
<button
|
||||
disabled
|
||||
in:fade={{ duration: 150 }}
|
||||
class="icons tooltip-right bg-gradient-to-r from-purple-500 via-pink-500 to-red-500 text-white duration-75 hover:scale-105"
|
||||
data-tooltip="Checking for updates..."
|
||||
><svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="h-9 w-8 animate-spin"
|
||||
viewBox="0 0 24 24"
|
||||
stroke-width="1.5"
|
||||
stroke="currentColor"
|
||||
fill="none"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
>
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
||||
<path d="M9 4.55a8 8 0 0 1 6 14.9m0 -4.45v5h5" />
|
||||
<line x1="5.63" y1="7.16" x2="5.63" y2="7.17" />
|
||||
<line x1="4.06" y1="11" x2="4.06" y2="11.01" />
|
||||
<line x1="4.63" y1="15.1" x2="4.63" y2="15.11" />
|
||||
<line x1="7.16" y1="18.37" x2="7.16" y2="18.38" />
|
||||
<line x1="11" y1="19.94" x2="11" y2="19.95" />
|
||||
</svg></button
|
||||
>
|
||||
{:else if isUpdateAvailable}
|
||||
{#if isUpdateAvailable}
|
||||
<button
|
||||
disabled={updateStatus.success === false}
|
||||
data-tooltip="Update available"
|
||||
title="Update available"
|
||||
on:click={update}
|
||||
class="icons tooltip-right bg-gradient-to-r from-purple-500 via-pink-500 to-red-500 text-white duration-75 hover:scale-105"
|
||||
>
|
||||
{#if updateStatus.loading}
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="w-8 h-9 lds-heart"
|
||||
class="lds-heart h-9 w-8"
|
||||
viewBox="0 0 24 24"
|
||||
stroke-width="1.5"
|
||||
stroke="currentColor"
|
||||
|
||||
@@ -86,7 +86,7 @@
|
||||
async function handleDeploySubmit() {
|
||||
try {
|
||||
const { buildId } = await post(`/applications/${id}/deploy.json`, { ...application });
|
||||
return await goto(`/applications/${id}/logs/build?buildId=${buildId}`);
|
||||
return window.location.assign(`/applications/${id}/logs/build?buildId=${buildId}`);
|
||||
} catch ({ error }) {
|
||||
return errorNotification(error);
|
||||
}
|
||||
@@ -128,7 +128,7 @@
|
||||
title="Stop application"
|
||||
type="submit"
|
||||
disabled={!$session.isAdmin}
|
||||
class="icons bg-transparent tooltip-bottom text-sm flex items-center space-x-2 hover:bg-green-600 hover:text-white"
|
||||
class="icons bg-transparent tooltip-bottom text-sm flex items-center space-x-2 text-red-500"
|
||||
data-tooltip={$session.isAdmin
|
||||
? 'Stop application'
|
||||
: 'You do not have permission to stop the application.'}
|
||||
@@ -153,7 +153,7 @@
|
||||
title="Rebuild application"
|
||||
type="submit"
|
||||
disabled={!$session.isAdmin}
|
||||
class="icons bg-transparent tooltip-bottom text-sm flex items-center space-x-2 hover:bg-green-600 hover:text-white"
|
||||
class="icons bg-transparent tooltip-bottom text-sm flex items-center space-x-2 hover:text-green-500"
|
||||
data-tooltip={$session.isAdmin
|
||||
? 'Rebuild application'
|
||||
: 'You do not have permission to rebuild application.'}
|
||||
@@ -182,7 +182,7 @@
|
||||
title="Build and start application"
|
||||
type="submit"
|
||||
disabled={!$session.isAdmin}
|
||||
class="icons bg-transparent tooltip-bottom text-sm flex items-center space-x-2 hover:bg-green-600 hover:text-white"
|
||||
class="icons bg-transparent tooltip-bottom text-sm flex items-center space-x-2 text-green-500"
|
||||
data-tooltip={$session.isAdmin
|
||||
? 'Build and start application'
|
||||
: 'You do not have permission to Build and start application.'}
|
||||
|
||||
@@ -35,6 +35,9 @@
|
||||
import { get } from '$lib/api';
|
||||
import { errorNotification } from '$lib/form';
|
||||
import { gitTokens } from '$lib/store';
|
||||
import { browser } from '$app/env';
|
||||
|
||||
const { id } = $page.params;
|
||||
|
||||
let scanning = true;
|
||||
let foundConfig = null;
|
||||
@@ -83,7 +86,7 @@
|
||||
if (pnpmLock) packageManager = 'pnpm';
|
||||
|
||||
if (dockerfile) {
|
||||
foundConfig.buildPack = 'docker';
|
||||
foundConfig = findBuildPack('docker', packageManager);
|
||||
} else if (packageJson) {
|
||||
const path = packageJson.path;
|
||||
const data = await get(
|
||||
@@ -102,6 +105,8 @@
|
||||
foundConfig = findBuildPack('static', packageManager);
|
||||
} else if (indexPHP) {
|
||||
foundConfig = findBuildPack('php');
|
||||
} else {
|
||||
foundConfig = findBuildPack('node', packageManager);
|
||||
}
|
||||
} else if (type === 'github') {
|
||||
const files = await get(`${apiUrl}/repos/${repository}/contents?ref=${branch}`, {
|
||||
@@ -127,7 +132,7 @@
|
||||
if (pnpmLock) packageManager = 'pnpm';
|
||||
|
||||
if (dockerfile) {
|
||||
foundConfig.buildPack = 'docker';
|
||||
foundConfig = findBuildPack('docker', packageManager);
|
||||
} else if (packageJson) {
|
||||
const data = await get(`${packageJson.git_url}`, {
|
||||
Authorization: `Bearer ${$gitTokens.githubToken}`,
|
||||
@@ -143,6 +148,8 @@
|
||||
foundConfig = findBuildPack('static', packageManager);
|
||||
} else if (indexPHP) {
|
||||
foundConfig = findBuildPack('php');
|
||||
} else {
|
||||
foundConfig = findBuildPack('node', packageManager);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
@@ -175,12 +182,15 @@
|
||||
}
|
||||
}
|
||||
if (error.message === 'Bad credentials') {
|
||||
const { token } = await get(`/applications/${id}/configuration/githubToken.json`);
|
||||
$gitTokens.githubToken = token;
|
||||
browser && window.location.reload();
|
||||
}
|
||||
return errorNotification(error);
|
||||
} finally {
|
||||
if (!foundConfig) foundConfig = findBuildPack('node', packageManager);
|
||||
scanning = false;
|
||||
}
|
||||
if (!foundConfig) foundConfig = findBuildPack('node', packageManager);
|
||||
scanning = false;
|
||||
}
|
||||
onMount(async () => {
|
||||
await scanRepository();
|
||||
|
||||
@@ -29,6 +29,7 @@ export const post: RequestHandler = async (event) => {
|
||||
.digest('hex');
|
||||
await db.prisma.application.update({ where: { id }, data: { configHash } });
|
||||
}
|
||||
await db.prisma.application.update({ where: { id }, data: { updatedAt: new Date() } });
|
||||
await buildQueue.add(buildId, { build_id: buildId, type: 'manual', ...applicationFound });
|
||||
return {
|
||||
status: 200,
|
||||
|
||||
@@ -45,6 +45,8 @@
|
||||
import { notNodeDeployments, staticDeployments } from '$lib/components/common';
|
||||
import { toast } from '@zerodevx/svelte-toast';
|
||||
import { post } from '$lib/api';
|
||||
import cuid from 'cuid';
|
||||
import { browser } from '$app/env';
|
||||
const { id } = $page.params;
|
||||
|
||||
let domainEl: HTMLInputElement;
|
||||
@@ -55,6 +57,10 @@
|
||||
let previews = application.settings.previews;
|
||||
let dualCerts = application.settings.dualCerts;
|
||||
|
||||
if (browser && window.location.hostname === 'demo.coolify.io' && !application.fqdn) {
|
||||
application.fqdn = `http://${cuid()}.demo.coolify.io`;
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
domainEl.focus();
|
||||
});
|
||||
@@ -255,6 +261,11 @@
|
||||
<div class="grid grid-cols-2">
|
||||
<div class="flex-col">
|
||||
<label for="fqdn" class="pt-2 text-base font-bold text-stone-100">Domain (FQDN)</label>
|
||||
{#if browser && window.location.hostname === 'demo.coolify.io'}
|
||||
<Explainer
|
||||
text="<span class='text-white font-bold'>You can use the predefined random domain name or enter your own domain name.</span>"
|
||||
/>
|
||||
{/if}
|
||||
<Explainer
|
||||
text="If you specify <span class='text-green-500 font-bold'>https</span>, the application will be accessible only over https. SSL certificate will be generated for you.<br>If you specify <span class='text-green-500 font-bold'>www</span>, the application will be redirected (302) from non-www and vice versa.<br><br>To modify the domain, you must first stop the application.<br><br><span class='text-white font-bold'>You must set your DNS to point to the server IP in advance.</span>"
|
||||
/>
|
||||
|
||||
@@ -51,7 +51,6 @@
|
||||
build.took = data.builds[0].took;
|
||||
build.since = data.builds[0].since;
|
||||
}
|
||||
window.location.reload();
|
||||
return build;
|
||||
});
|
||||
return;
|
||||
|
||||
@@ -43,53 +43,41 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mx-auto max-w-6xl rounded-xl px-6 pt-4">
|
||||
<table class="mx-auto">
|
||||
<thead class=" rounded-xl border-b border-coolgray-500">
|
||||
<tr>
|
||||
<th
|
||||
scope="col"
|
||||
class="px-6 py-3 text-left text-xs font-bold uppercase tracking-wider text-white">Name</th
|
||||
>
|
||||
<th
|
||||
scope="col"
|
||||
class="px-6 py-3 text-left text-xs font-bold uppercase tracking-wider text-white"
|
||||
>Value</th
|
||||
>
|
||||
<th
|
||||
scope="col"
|
||||
class="px-6 py-3 text-left text-xs font-bold uppercase tracking-wider text-white"
|
||||
>Need during buildtime?</th
|
||||
>
|
||||
<th
|
||||
scope="col"
|
||||
class="px-6 py-3 text-left text-xs font-bold uppercase tracking-wider text-white"
|
||||
/>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="">
|
||||
{#each applicationSecrets as secret}
|
||||
{#key secret.id}
|
||||
<tr class="h-20 transition duration-100 hover:bg-coolgray-400">
|
||||
<Secret
|
||||
PRMRSecret={PRMRSecrets.find((s) => s.name === secret.name)}
|
||||
isPRMRSecret
|
||||
name={secret.name}
|
||||
value={secret.value}
|
||||
isBuildSecret={secret.isBuildSecret}
|
||||
on:refresh={refreshSecrets}
|
||||
/>
|
||||
</tr>
|
||||
{/key}
|
||||
{/each}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{#if applicationSecrets.length !== 0}
|
||||
<div class="mx-auto max-w-6xl rounded-xl px-6 pt-4">
|
||||
<table class="mx-auto border-separate text-left">
|
||||
<thead>
|
||||
<tr class="h-12">
|
||||
<th scope="col">Name</th>
|
||||
<th scope="col">Value</th>
|
||||
<th scope="col" class="w-64 text-center">Need during buildtime?</th>
|
||||
<th scope="col" class="w-96 text-center">Action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{#each applicationSecrets as secret}
|
||||
{#key secret.id}
|
||||
<tr>
|
||||
<Secret
|
||||
PRMRSecret={PRMRSecrets.find((s) => s.name === secret.name)}
|
||||
isPRMRSecret
|
||||
name={secret.name}
|
||||
value={secret.value}
|
||||
isBuildSecret={secret.isBuildSecret}
|
||||
on:refresh={refreshSecrets}
|
||||
/>
|
||||
</tr>
|
||||
{/key}
|
||||
{/each}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{/if}
|
||||
<div class="flex justify-center py-4 text-center">
|
||||
<Explainer
|
||||
customClass="w-full"
|
||||
text={applicationSecrets.length === 0
|
||||
? "<span class='font-bold text-white text-xl'>Please add secrets to the application first.</span> <br><br>These values overwrite application secrets in PR/MR deployments. Useful for creating <span class='text-green-500 font-bold'>staging</span> environments."
|
||||
? "You can add secrets to PR/MR deployments. Please add secrets to the application first. <br>Useful for creating <span class='text-green-500 font-bold'>staging</span> environments."
|
||||
: "These values overwrite application secrets in PR/MR deployments. Useful for creating <span class='text-green-500 font-bold'>staging</span> environments."}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import { getDomain, getUserDetails } from '$lib/common';
|
||||
import { asyncExecShell, getEngine, getUserDetails, removeDestinationDocker } from '$lib/common';
|
||||
import * as db from '$lib/database';
|
||||
import { ErrorHandler } from '$lib/database';
|
||||
import { dockerInstance } from '$lib/docker';
|
||||
import { removeProxyConfiguration } from '$lib/haproxy';
|
||||
import { checkContainer } from '$lib/haproxy';
|
||||
import type { RequestHandler } from '@sveltejs/kit';
|
||||
|
||||
export const post: RequestHandler = async (event) => {
|
||||
@@ -17,10 +16,12 @@ export const post: RequestHandler = async (event) => {
|
||||
teamId
|
||||
});
|
||||
if (destinationDockerId) {
|
||||
const docker = dockerInstance({ destinationDocker });
|
||||
await docker.engine.getContainer(id).stop();
|
||||
const { engine } = destinationDocker;
|
||||
const found = await checkContainer(engine, id);
|
||||
if (found) {
|
||||
await removeDestinationDocker({ id, engine });
|
||||
}
|
||||
}
|
||||
await removeProxyConfiguration(fqdn);
|
||||
return {
|
||||
status: 200
|
||||
};
|
||||
|
||||
@@ -13,6 +13,8 @@
|
||||
import Nextjs from '$lib/components/svg/applications/Nextjs.svelte';
|
||||
import Gatsby from '$lib/components/svg/applications/Gatsby.svelte';
|
||||
import Docker from '$lib/components/svg/applications/Docker.svelte';
|
||||
import Astro from '$lib/components/svg/applications/Astro.svelte';
|
||||
import Eleventy from '$lib/components/svg/applications/Eleventy.svelte';
|
||||
|
||||
const buildPack = application?.buildPack?.toLowerCase();
|
||||
</script>
|
||||
@@ -45,6 +47,10 @@
|
||||
<Gatsby />
|
||||
{:else if buildPack === 'docker'}
|
||||
<Docker />
|
||||
{:else if buildPack === 'astro'}
|
||||
<Astro />
|
||||
{:else if buildPack === 'eleventy'}
|
||||
<Eleventy />
|
||||
{/if}
|
||||
|
||||
<div class="truncate text-center text-xl font-bold">{application.name}</div>
|
||||
|
||||
@@ -120,7 +120,7 @@
|
||||
title="Stop database"
|
||||
type="submit"
|
||||
disabled={!$session.isAdmin}
|
||||
class="icons bg-transparent tooltip-bottom text-sm flex items-center space-x-2 hover:bg-purple-600 hover:text-white"
|
||||
class="icons bg-transparent tooltip-bottom text-sm flex items-center space-x-2 text-red-500"
|
||||
data-tooltip={$session.isAdmin
|
||||
? 'Stop database'
|
||||
: 'You do not have permission to stop the database.'}
|
||||
@@ -146,7 +146,7 @@
|
||||
title="Start database"
|
||||
type="submit"
|
||||
disabled={!$session.isAdmin}
|
||||
class="icons bg-transparent tooltip-bottom text-sm flex items-center space-x-2 hover:bg-purple-600 hover:text-white"
|
||||
class="icons bg-transparent tooltip-bottom text-sm flex items-center space-x-2 text-green-500"
|
||||
data-tooltip={$session.isAdmin
|
||||
? 'Start database'
|
||||
: 'You do not have permission to start the database.'}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
export let state;
|
||||
|
||||
import { toast } from '@zerodevx/svelte-toast';
|
||||
import { page } from '$app/stores';
|
||||
import { page, session } from '$app/stores';
|
||||
import Setting from '$lib/components/Setting.svelte';
|
||||
import { errorNotification } from '$lib/form';
|
||||
import { post } from '$lib/api';
|
||||
@@ -117,6 +117,8 @@
|
||||
setTimeout(() => {
|
||||
window.location.reload();
|
||||
}, 5000);
|
||||
} finally {
|
||||
restarting = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -125,27 +127,35 @@
|
||||
<form on:submit|preventDefault={handleSubmit} class="grid grid-flow-row gap-2 py-4">
|
||||
<div class="flex space-x-1 pb-5">
|
||||
<div class="title font-bold">Configuration</div>
|
||||
<button
|
||||
type="submit"
|
||||
class="bg-sky-600 hover:bg-sky-500"
|
||||
class:bg-sky-600={!loading}
|
||||
class:hover:bg-sky-500={!loading}
|
||||
disabled={loading}
|
||||
>{loading ? 'Saving...' : 'Save'}
|
||||
</button>
|
||||
<button
|
||||
class={restarting ? '' : 'bg-red-600 hover:bg-red-500'}
|
||||
disabled={restarting}
|
||||
on:click|preventDefault={forceRestartProxy}
|
||||
>{restarting ? 'Restarting... please wait...' : 'Force restart proxy'}</button
|
||||
>
|
||||
{#if $session.isAdmin}
|
||||
<button
|
||||
type="submit"
|
||||
class="bg-sky-600 hover:bg-sky-500"
|
||||
class:bg-sky-600={!loading}
|
||||
class:hover:bg-sky-500={!loading}
|
||||
disabled={loading}
|
||||
>{loading ? 'Saving...' : 'Save'}
|
||||
</button>
|
||||
<button
|
||||
class={restarting ? '' : 'bg-red-600 hover:bg-red-500'}
|
||||
disabled={restarting}
|
||||
on:click|preventDefault={forceRestartProxy}
|
||||
>{restarting ? 'Restarting... please wait...' : 'Force restart proxy'}</button
|
||||
>
|
||||
{/if}
|
||||
<!-- <button type="button" class="bg-coollabs hover:bg-coollabs-100" on:click={scanApps}
|
||||
>Scan for applications</button
|
||||
> -->
|
||||
</div>
|
||||
<div class="grid grid-cols-2 items-center px-10 ">
|
||||
<label for="name" class="text-base font-bold text-stone-100">Name</label>
|
||||
<input name="name" placeholder="name" bind:value={destination.name} />
|
||||
<input
|
||||
name="name"
|
||||
placeholder="name"
|
||||
disabled={!$session.isAdmin}
|
||||
readonly={!$session.isAdmin}
|
||||
bind:value={destination.name}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-2 items-center px-10">
|
||||
|
||||
225
src/routes/destinations/[id]/_RemoteDocker.svelte
Normal file
225
src/routes/destinations/[id]/_RemoteDocker.svelte
Normal file
@@ -0,0 +1,225 @@
|
||||
<script lang="ts">
|
||||
export let destination;
|
||||
export let settings;
|
||||
export let state;
|
||||
|
||||
import { toast } from '@zerodevx/svelte-toast';
|
||||
import { page, session } from '$app/stores';
|
||||
import Setting from '$lib/components/Setting.svelte';
|
||||
import { errorNotification } from '$lib/form';
|
||||
import { post } from '$lib/api';
|
||||
import CopyPasswordField from '$lib/components/CopyPasswordField.svelte';
|
||||
import { onMount } from 'svelte';
|
||||
import { generateRemoteEngine } from '$lib/components/common';
|
||||
const { id } = $page.params;
|
||||
let cannotDisable = settings.fqdn && destination.engine === '/var/run/docker.sock';
|
||||
// let scannedApps = [];
|
||||
let loading = false;
|
||||
let restarting = false;
|
||||
async function handleSubmit() {
|
||||
loading = true;
|
||||
try {
|
||||
return await post(`/destinations/${id}.json`, { ...destination });
|
||||
} catch ({ error }) {
|
||||
return errorNotification(error);
|
||||
} finally {
|
||||
loading = false;
|
||||
}
|
||||
}
|
||||
// async function scanApps() {
|
||||
// scannedApps = [];
|
||||
// const data = await fetch(`/destinations/${id}/scan.json`);
|
||||
// const { containers } = await data.json();
|
||||
// scannedApps = containers;
|
||||
// }
|
||||
onMount(async () => {
|
||||
if (state === false && destination.isCoolifyProxyUsed === true) {
|
||||
destination.isCoolifyProxyUsed = !destination.isCoolifyProxyUsed;
|
||||
try {
|
||||
await post(`/destinations/${id}/settings.json`, {
|
||||
isCoolifyProxyUsed: destination.isCoolifyProxyUsed,
|
||||
engine: destination.engine
|
||||
});
|
||||
await stopProxy();
|
||||
} catch ({ error }) {
|
||||
return errorNotification(error);
|
||||
}
|
||||
} else if (state === true && destination.isCoolifyProxyUsed === false) {
|
||||
destination.isCoolifyProxyUsed = !destination.isCoolifyProxyUsed;
|
||||
try {
|
||||
await post(`/destinations/${id}/settings.json`, {
|
||||
isCoolifyProxyUsed: destination.isCoolifyProxyUsed,
|
||||
engine: destination.engine
|
||||
});
|
||||
await startProxy();
|
||||
} catch ({ error }) {
|
||||
return errorNotification(error);
|
||||
}
|
||||
}
|
||||
});
|
||||
async function changeProxySetting() {
|
||||
if (!cannotDisable) {
|
||||
const isProxyActivated = destination.isCoolifyProxyUsed;
|
||||
if (isProxyActivated) {
|
||||
const sure = confirm(
|
||||
`Are you sure you want to ${
|
||||
destination.isCoolifyProxyUsed ? 'disable' : 'enable'
|
||||
} Coolify proxy? It will remove the proxy for all configured networks and all deployments on '${
|
||||
destination.engine
|
||||
}'! Nothing will be reachable if you do it!`
|
||||
);
|
||||
if (!sure) return;
|
||||
}
|
||||
destination.isCoolifyProxyUsed = !destination.isCoolifyProxyUsed;
|
||||
try {
|
||||
await post(`/destinations/${id}/settings.json`, {
|
||||
isCoolifyProxyUsed: destination.isCoolifyProxyUsed,
|
||||
engine: destination.engine
|
||||
});
|
||||
if (isProxyActivated) {
|
||||
await stopProxy();
|
||||
} else {
|
||||
await startProxy();
|
||||
}
|
||||
} catch ({ error }) {
|
||||
return errorNotification(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
async function stopProxy() {
|
||||
try {
|
||||
const engine = generateRemoteEngine(destination);
|
||||
await post(`/destinations/${id}/stop.json`, { engine });
|
||||
return toast.push('Coolify Proxy stopped!');
|
||||
} catch ({ error }) {
|
||||
return errorNotification(error);
|
||||
}
|
||||
}
|
||||
async function startProxy() {
|
||||
try {
|
||||
const engine = generateRemoteEngine(destination);
|
||||
await post(`/destinations/${id}/start.json`, { engine });
|
||||
return toast.push('Coolify Proxy started!');
|
||||
} catch ({ error }) {
|
||||
return errorNotification(error);
|
||||
}
|
||||
}
|
||||
async function forceRestartProxy() {
|
||||
const sure = confirm(
|
||||
'Are you sure you want to restart the proxy? Everyting will be reconfigured in ~10 sec.'
|
||||
);
|
||||
if (sure) {
|
||||
try {
|
||||
restarting = true;
|
||||
toast.push('Coolify Proxy restarting...');
|
||||
await post(`/destinations/${id}/restart.json`, {
|
||||
engine: destination.engine,
|
||||
fqdn: settings.fqdn
|
||||
});
|
||||
} catch ({ error }) {
|
||||
setTimeout(() => {
|
||||
window.location.reload();
|
||||
}, 5000);
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<form on:submit|preventDefault={handleSubmit} class="grid grid-flow-row gap-2 py-4">
|
||||
<div class="flex space-x-1 pb-5">
|
||||
<div class="title font-bold">Configuration</div>
|
||||
{#if $session.isAdmin}
|
||||
<button
|
||||
type="submit"
|
||||
class="bg-sky-600 hover:bg-sky-500"
|
||||
class:bg-sky-600={!loading}
|
||||
class:hover:bg-sky-500={!loading}
|
||||
disabled={loading}
|
||||
>{loading ? 'Saving...' : 'Save'}
|
||||
</button>
|
||||
<button
|
||||
class={restarting ? '' : 'bg-red-600 hover:bg-red-500'}
|
||||
disabled={restarting}
|
||||
on:click|preventDefault={forceRestartProxy}
|
||||
>{restarting ? 'Restarting... please wait...' : 'Force restart proxy'}</button
|
||||
>
|
||||
{/if}
|
||||
<!-- <button type="button" class="bg-coollabs hover:bg-coollabs-100" on:click={scanApps}
|
||||
>Scan for applications</button
|
||||
> -->
|
||||
</div>
|
||||
<div class="grid grid-cols-2 items-center px-10 ">
|
||||
<label for="name" class="text-base font-bold text-stone-100">Name</label>
|
||||
<input
|
||||
name="name"
|
||||
placeholder="name"
|
||||
disabled={!$session.isAdmin}
|
||||
readonly={!$session.isAdmin}
|
||||
bind:value={destination.name}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-2 items-center px-10">
|
||||
<label for="engine" class="text-base font-bold text-stone-100">Engine</label>
|
||||
<CopyPasswordField
|
||||
id="engine"
|
||||
readonly
|
||||
disabled
|
||||
name="engine"
|
||||
placeholder="eg: /var/run/docker.sock"
|
||||
value={destination.engine}
|
||||
/>
|
||||
</div>
|
||||
<!-- <div class="flex items-center">
|
||||
<label for="remoteEngine">Remote Engine?</label>
|
||||
<input name="remoteEngine" type="checkbox" bind:checked={payload.remoteEngine} />
|
||||
</div> -->
|
||||
<div class="grid grid-cols-2 items-center px-10">
|
||||
<label for="network" class="text-base font-bold text-stone-100">Network</label>
|
||||
<CopyPasswordField
|
||||
id="network"
|
||||
readonly
|
||||
disabled
|
||||
name="network"
|
||||
placeholder="default: coolify"
|
||||
value={destination.network}
|
||||
/>
|
||||
</div>
|
||||
<div class="grid grid-cols-2 items-center">
|
||||
<Setting
|
||||
disabled={cannotDisable}
|
||||
bind:setting={destination.isCoolifyProxyUsed}
|
||||
on:click={changeProxySetting}
|
||||
title="Use Coolify Proxy?"
|
||||
description={`This will install a proxy on the destination to allow you to access your applications and services without any manual configuration. Databases will have their own proxy. <br><br>${
|
||||
cannotDisable
|
||||
? '<span class="font-bold text-white">You cannot disable this proxy as FQDN is configured for Coolify.</span>'
|
||||
: ''
|
||||
}`}
|
||||
/>
|
||||
</div>
|
||||
</form>
|
||||
<!-- <div class="flex justify-center">
|
||||
{#if payload.isCoolifyProxyUsed}
|
||||
{#if state}
|
||||
<button on:click={stopProxy}>Stop proxy</button>
|
||||
{:else}
|
||||
<button on:click={startProxy}>Start proxy</button>
|
||||
{/if}
|
||||
{/if}
|
||||
</div> -->
|
||||
|
||||
<!-- {#if scannedApps.length > 0}
|
||||
<div class="flex justify-center px-6 pb-10">
|
||||
<div class="flex space-x-2 h-8 items-center">
|
||||
<div class="font-bold text-xl text-white">Found applications</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="max-w-4xl mx-auto px-6">
|
||||
<div class="flex space-x-2 justify-center">
|
||||
{#each scannedApps as app}
|
||||
<FoundApp {app} />
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
{/if} -->
|
||||
@@ -1,4 +1,5 @@
|
||||
import { asyncExecShell, getEngine, getTeam, getUserDetails } from '$lib/common';
|
||||
import { asyncExecShell, getUserDetails } from '$lib/common';
|
||||
import { generateRemoteEngine } from '$lib/components/common';
|
||||
import * as db from '$lib/database';
|
||||
import { ErrorHandler } from '$lib/database';
|
||||
import { checkContainer } from '$lib/haproxy';
|
||||
@@ -12,15 +13,26 @@ export const get: RequestHandler = async (event) => {
|
||||
try {
|
||||
const destination = await db.getDestination({ id, teamId });
|
||||
const settings = await db.listSettings();
|
||||
const state =
|
||||
destination?.engine && (await checkContainer(destination.engine, 'coolify-haproxy'));
|
||||
let payload = {
|
||||
destination,
|
||||
settings,
|
||||
state: false
|
||||
};
|
||||
if (destination.remoteEngine) {
|
||||
// const { stdout } = await asyncExecShell(
|
||||
// `ssh -p ${destination.port} ${destination.user}@${destination.ipAddress} "docker ps -a"`
|
||||
// );
|
||||
// console.log(stdout)
|
||||
// const engine = await generateRemoteEngine(destination);
|
||||
// // await saveSshKey(destination);
|
||||
// payload.state = await checkContainer(engine, 'coolify-haproxy');
|
||||
} else {
|
||||
payload.state =
|
||||
destination?.engine && (await checkContainer(destination.engine, 'coolify-haproxy'));
|
||||
}
|
||||
return {
|
||||
status: 200,
|
||||
body: {
|
||||
destination,
|
||||
settings,
|
||||
state
|
||||
}
|
||||
body: { ...payload }
|
||||
};
|
||||
} catch (error) {
|
||||
return ErrorHandler(error);
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
|
||||
import type Prisma from '@prisma/client';
|
||||
import LocalDocker from './_LocalDocker.svelte';
|
||||
import RemoteDocker from './_RemoteDocker.svelte';
|
||||
</script>
|
||||
|
||||
<div class="flex space-x-1 p-6 text-2xl font-bold">
|
||||
@@ -42,6 +43,11 @@
|
||||
<span class="arrow-right-applications px-1">></span>
|
||||
<span class="pr-2">{destination.name}</span>
|
||||
</div>
|
||||
|
||||
<div class="mx-auto max-w-4xl px-6">
|
||||
<LocalDocker bind:destination {settings} {state} />
|
||||
{#if destination.remoteEngine}
|
||||
<RemoteDocker bind:destination {settings} {state} />
|
||||
{:else}
|
||||
<LocalDocker bind:destination {settings} {state} />
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
@@ -1,30 +1,19 @@
|
||||
import { getDomain, getUserDetails } from '$lib/common';
|
||||
import { getUserDetails } from '$lib/common';
|
||||
import { ErrorHandler } from '$lib/database';
|
||||
import * as db from '$lib/database';
|
||||
import {
|
||||
configureCoolifyProxyOn,
|
||||
forceSSLOnApplication,
|
||||
setWwwRedirection,
|
||||
startCoolifyProxy,
|
||||
stopCoolifyProxy
|
||||
} from '$lib/haproxy';
|
||||
import { startCoolifyProxy, stopCoolifyProxy } from '$lib/haproxy';
|
||||
import type { RequestHandler } from '@sveltejs/kit';
|
||||
|
||||
export const post: RequestHandler = async (event) => {
|
||||
const { teamId, status, body } = await getUserDetails(event);
|
||||
if (status === 401) return { status, body };
|
||||
|
||||
const { engine, fqdn } = await event.request.json();
|
||||
const { engine } = await event.request.json();
|
||||
|
||||
try {
|
||||
const domain = getDomain(fqdn);
|
||||
await stopCoolifyProxy(engine);
|
||||
await startCoolifyProxy(engine);
|
||||
await db.setDestinationSettings({ engine, isCoolifyProxyUsed: true });
|
||||
await configureCoolifyProxyOn(fqdn);
|
||||
await setWwwRedirection(fqdn);
|
||||
const isHttps = fqdn.startsWith('https://');
|
||||
if (isHttps) await forceSSLOnApplication(domain);
|
||||
return {
|
||||
status: 200
|
||||
};
|
||||
|
||||
@@ -4,10 +4,10 @@ import { ErrorHandler } from '$lib/database';
|
||||
import type { RequestHandler } from '@sveltejs/kit';
|
||||
|
||||
export const post: RequestHandler = async (event) => {
|
||||
const { email, password } = await event.request.json();
|
||||
const { email, password, isLogin } = await event.request.json();
|
||||
|
||||
try {
|
||||
const { body } = await db.login({ email, password });
|
||||
const { body } = await db.login({ email, password, isLogin });
|
||||
event.locals.session.data = body;
|
||||
return {
|
||||
status: 200
|
||||
|
||||
@@ -18,7 +18,11 @@
|
||||
async function handleSubmit() {
|
||||
loading = true;
|
||||
try {
|
||||
const { teamId } = await post(`/login.json`, { email: email.toLowerCase(), password });
|
||||
const { teamId } = await post(`/login.json`, {
|
||||
email: email.toLowerCase(),
|
||||
password,
|
||||
isLogin: true
|
||||
});
|
||||
if (teamId === '0') {
|
||||
window.location.replace('/settings');
|
||||
} else {
|
||||
@@ -67,7 +71,15 @@
|
||||
class:text-stone-600={loading}
|
||||
class:bg-coollabs={!loading}>{loading ? 'Authenticating...' : 'Login'}</button
|
||||
>
|
||||
<button on:click|preventDefault={() => goto('/reset')}>Reset password</button>
|
||||
|
||||
<button
|
||||
on:click|preventDefault={() => goto('/register')}
|
||||
class="bg-transparent hover:bg-coolgray-300 text-white ">Register</button
|
||||
>
|
||||
<button
|
||||
class="bg-transparent hover:bg-coolgray-300"
|
||||
on:click|preventDefault={() => goto('/reset')}>Reset password</button
|
||||
>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
@@ -51,26 +51,7 @@
|
||||
placeholder="eg: /var/run/docker.sock"
|
||||
bind:value={payload.engine}
|
||||
/>
|
||||
<!-- <Explainer text="You can use remote Docker Engine with over SSH." /> -->
|
||||
</div>
|
||||
<!-- <div class="flex items-center">
|
||||
<label for="remoteEngine">Remote Docker Engine?</label>
|
||||
<input name="remoteEngine" type="checkbox" bind:checked={payload.remoteEngine} />
|
||||
</div>
|
||||
{#if payload.remoteEngine}
|
||||
<div class="grid grid-cols-3 items-center">
|
||||
<label for="user">User</label>
|
||||
<div class="col-span-2">
|
||||
<input required name="user" placeholder="eg: root" bind:value={payload.user} />
|
||||
</div>
|
||||
</div>
|
||||
<div class="grid grid-cols-3 items-center">
|
||||
<label for="port">Port</label>
|
||||
<div class="col-span-2">
|
||||
<input required name="port" placeholder="eg: 22" bind:value={payload.port} />
|
||||
</div>
|
||||
</div>
|
||||
{/if} -->
|
||||
<div class="grid grid-cols-2 items-center px-10">
|
||||
<label for="network" class="text-base font-bold text-stone-100">Network</label>
|
||||
<input required name="network" placeholder="default: coolify" bind:value={payload.network} />
|
||||
90
src/routes/new/destination/_RemoteDocker.svelte
Normal file
90
src/routes/new/destination/_RemoteDocker.svelte
Normal file
@@ -0,0 +1,90 @@
|
||||
<script lang="ts">
|
||||
import { goto } from '$app/navigation';
|
||||
|
||||
export let payload;
|
||||
|
||||
import { post } from '$lib/api';
|
||||
import Explainer from '$lib/components/Explainer.svelte';
|
||||
import Setting from '$lib/components/Setting.svelte';
|
||||
import { errorNotification } from '$lib/form';
|
||||
|
||||
let loading = false;
|
||||
|
||||
async function handleSubmit() {
|
||||
try {
|
||||
const { id } = await post('/new/destination/docker.json', {
|
||||
...payload
|
||||
});
|
||||
return await goto(`/destinations/${id}`);
|
||||
} catch ({ error }) {
|
||||
return errorNotification(error);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="flex justify-center px-6 pb-8">
|
||||
<form on:submit|preventDefault={handleSubmit} class="grid grid-flow-row gap-2 py-4">
|
||||
<div class="flex items-center space-x-2 pb-5">
|
||||
<div class="title font-bold">Configuration</div>
|
||||
<button
|
||||
type="submit"
|
||||
class:bg-sky-600={!loading}
|
||||
class:hover:bg-sky-500={!loading}
|
||||
disabled={loading}
|
||||
>{loading
|
||||
? payload.isCoolifyProxyUsed
|
||||
? 'Saving and configuring proxy...'
|
||||
: 'Saving...'
|
||||
: 'Save'}</button
|
||||
>
|
||||
</div>
|
||||
<div class="mt-2 grid grid-cols-2 items-center px-10">
|
||||
<label for="name" class="text-base font-bold text-stone-100">Name</label>
|
||||
<input required name="name" placeholder="name" bind:value={payload.name} />
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-2 items-center px-10">
|
||||
<label for="ipAddress" class="text-base font-bold text-stone-100">IP Address</label>
|
||||
<input
|
||||
required
|
||||
name="ipAddress"
|
||||
placeholder="eg: 192.168..."
|
||||
bind:value={payload.ipAddress}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-2 items-center px-10">
|
||||
<label for="user" class="text-base font-bold text-stone-100">User</label>
|
||||
<input required name="user" placeholder="eg: root" bind:value={payload.user} />
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-2 items-center px-10">
|
||||
<label for="port" class="text-base font-bold text-stone-100">Port</label>
|
||||
<input required name="port" placeholder="eg: 22" bind:value={payload.port} />
|
||||
</div>
|
||||
<div class="grid grid-cols-2 items-center px-10">
|
||||
<label for="sshPrivateKey" class="text-base font-bold text-stone-100">SSH Private Key</label>
|
||||
<textarea
|
||||
rows="10"
|
||||
class="resize-none"
|
||||
required
|
||||
name="sshPrivateKey"
|
||||
placeholder="eg: -----BEGIN...."
|
||||
bind:value={payload.sshPrivateKey}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-2 items-center px-10">
|
||||
<label for="network" class="text-base font-bold text-stone-100">Network</label>
|
||||
<input required name="network" placeholder="default: coolify" bind:value={payload.network} />
|
||||
</div>
|
||||
<div class="grid grid-cols-2 items-center">
|
||||
<Setting
|
||||
bind:setting={payload.isCoolifyProxyUsed}
|
||||
on:click={() => (payload.isCoolifyProxyUsed = !payload.isCoolifyProxyUsed)}
|
||||
title="Use Coolify Proxy?"
|
||||
description="This will install a proxy on the destination to allow you to access your applications and services without any manual configuration (recommended for Docker).<br><br>Databases will have their own proxy."
|
||||
/>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
@@ -8,10 +8,36 @@ export const post: RequestHandler = async (event) => {
|
||||
const { teamId, status, body } = await getUserDetails(event);
|
||||
if (status === 401) return { status, body };
|
||||
|
||||
const { name, engine, network, isCoolifyProxyUsed } = await event.request.json();
|
||||
const {
|
||||
name,
|
||||
engine,
|
||||
network,
|
||||
isCoolifyProxyUsed,
|
||||
remoteEngine,
|
||||
ipAddress,
|
||||
user,
|
||||
port,
|
||||
sshPrivateKey
|
||||
} = await event.request.json();
|
||||
|
||||
try {
|
||||
const id = await db.newDestination({ name, teamId, engine, network, isCoolifyProxyUsed });
|
||||
let id = null;
|
||||
if (remoteEngine) {
|
||||
id = await db.newRemoteDestination({
|
||||
name,
|
||||
teamId,
|
||||
engine,
|
||||
network,
|
||||
isCoolifyProxyUsed,
|
||||
remoteEngine,
|
||||
ipAddress,
|
||||
user,
|
||||
port,
|
||||
sshPrivateKey
|
||||
});
|
||||
} else {
|
||||
id = await db.newLocalDestination({ name, teamId, engine, network, isCoolifyProxyUsed });
|
||||
}
|
||||
return { status: 200, body: { id } };
|
||||
} catch (error) {
|
||||
return ErrorHandler(error);
|
||||
|
||||
@@ -1,25 +1,34 @@
|
||||
<script>
|
||||
import Docker from './_Docker.svelte';
|
||||
import LocalDocker from './_LocalDocker.svelte';
|
||||
import cuid from 'cuid';
|
||||
import RemoteDocker from './_RemoteDocker.svelte';
|
||||
let payload = {};
|
||||
let selected = 'docker';
|
||||
let selected = 'localDocker';
|
||||
|
||||
function setPredefined(type) {
|
||||
selected = type;
|
||||
switch (type) {
|
||||
case 'docker':
|
||||
case 'localDocker':
|
||||
payload = {
|
||||
name: 'Local Docker',
|
||||
engine: '/var/run/docker.sock',
|
||||
remoteEngine: false,
|
||||
user: 'root',
|
||||
port: 22,
|
||||
privateKey: null,
|
||||
network: cuid(),
|
||||
isCoolifyProxyUsed: true
|
||||
};
|
||||
break;
|
||||
|
||||
case 'remoteDocker':
|
||||
payload = {
|
||||
name: 'Remote Docker',
|
||||
remoteEngine: true,
|
||||
ipAddress: null,
|
||||
user: 'root',
|
||||
port: 22,
|
||||
sshPrivateKey: null,
|
||||
network: cuid(),
|
||||
isCoolifyProxyUsed: true
|
||||
};
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -32,12 +41,15 @@
|
||||
<div class="flex-col space-y-2 pb-10 text-center">
|
||||
<div class="text-xl font-bold text-white">Predefined destinations</div>
|
||||
<div class="flex justify-center space-x-2">
|
||||
<button class="w-32" on:click={() => setPredefined('docker')}>Docker</button>
|
||||
<button class="w-32" on:click={() => setPredefined('localDocker')}>Local Docker</button>
|
||||
<!-- <button class="w-32" on:click={() => setPredefined('remoteDocker')}>Remote Docker</button> -->
|
||||
<button class="w-32" on:click={() => setPredefined('kubernetes')}>Kubernetes</button>
|
||||
</div>
|
||||
</div>
|
||||
{#if selected === 'docker'}
|
||||
<Docker {payload} />
|
||||
{#if selected === 'localDocker'}
|
||||
<LocalDocker {payload} />
|
||||
{:else if selected === 'remoteDocker'}
|
||||
<RemoteDocker {payload} />
|
||||
{:else}
|
||||
<div class="text-center font-bold text-4xl py-10">Not implemented yet</div>
|
||||
{/if}
|
||||
|
||||
103
src/routes/register/index.svelte
Normal file
103
src/routes/register/index.svelte
Normal file
@@ -0,0 +1,103 @@
|
||||
<script lang="ts">
|
||||
export let userCount: number;
|
||||
|
||||
import { browser } from '$app/env';
|
||||
import { goto } from '$app/navigation';
|
||||
import { session } from '$app/stores';
|
||||
import { post } from '$lib/api';
|
||||
import { errorNotification } from '$lib/form';
|
||||
import { onMount } from 'svelte';
|
||||
|
||||
let loading = false;
|
||||
let emailEl;
|
||||
let email, password, passwordCheck;
|
||||
|
||||
if (browser && $session.userId) {
|
||||
goto('/');
|
||||
}
|
||||
onMount(() => {
|
||||
emailEl.focus();
|
||||
});
|
||||
async function handleSubmit() {
|
||||
if (password !== passwordCheck) {
|
||||
return errorNotification('Passwords do not match.');
|
||||
}
|
||||
loading = true;
|
||||
try {
|
||||
await post(`/login.json`, {
|
||||
email: email.toLowerCase(),
|
||||
password,
|
||||
isLogin: false
|
||||
});
|
||||
return window.location.replace('/');
|
||||
} catch ({ error }) {
|
||||
return errorNotification(error);
|
||||
} finally {
|
||||
loading = false;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="icons fixed top-0 left-0 m-3 cursor-pointer" on:click={() => goto('/')}>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="h-6 w-6"
|
||||
viewBox="0 0 24 24"
|
||||
stroke-width="1.5"
|
||||
stroke="currentColor"
|
||||
fill="none"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
>
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
||||
<line x1="5" y1="12" x2="19" y2="12" />
|
||||
<line x1="5" y1="12" x2="11" y2="18" />
|
||||
<line x1="5" y1="12" x2="11" y2="6" />
|
||||
</svg>
|
||||
</div>
|
||||
<div class="flex h-screen flex-col items-center justify-center">
|
||||
{#if $session.userId}
|
||||
<div class="flex justify-center px-4 text-xl font-bold">Already logged in...</div>
|
||||
{:else}
|
||||
<div class="flex justify-center px-4">
|
||||
<form on:submit|preventDefault={handleSubmit} class="flex flex-col py-4 space-y-2">
|
||||
<div class="text-6xl font-bold border-gradient w-48 mx-auto border-b-4">Coolify</div>
|
||||
<div class="text-xs text-center font-bold pb-10">v{$session.version}</div>
|
||||
<input
|
||||
type="email"
|
||||
name="email"
|
||||
placeholder="Email"
|
||||
autocomplete="off"
|
||||
required
|
||||
bind:this={emailEl}
|
||||
bind:value={email}
|
||||
/>
|
||||
<input
|
||||
type="password"
|
||||
name="password"
|
||||
placeholder="Password"
|
||||
bind:value={password}
|
||||
required
|
||||
/>
|
||||
<input
|
||||
type="password"
|
||||
name="passwordCheck"
|
||||
placeholder="Password again"
|
||||
bind:value={passwordCheck}
|
||||
required
|
||||
/>
|
||||
|
||||
<div class="flex space-x-2 h-8 items-center justify-center pt-8">
|
||||
<button type="submit" class="hover:bg-coollabs-100 text-white bg-coollabs"
|
||||
>Register</button
|
||||
>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
{#if userCount === 0}
|
||||
<div class="pt-5">
|
||||
You are registering the first user. It will be the administrator of your Coolify instance.
|
||||
</div>
|
||||
{/if}
|
||||
{/if}
|
||||
</div>
|
||||
11
src/routes/register/index.ts
Normal file
11
src/routes/register/index.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import * as db from '$lib/database';
|
||||
import { ErrorHandler } from '$lib/database';
|
||||
import type { RequestHandler } from '@sveltejs/kit';
|
||||
|
||||
export const get: RequestHandler = async () => {
|
||||
try {
|
||||
return { status: 200, body: { userCount: await db.prisma.user.count() } };
|
||||
} catch (error) {
|
||||
return ErrorHandler(error);
|
||||
}
|
||||
};
|
||||
@@ -110,23 +110,6 @@
|
||||
loading = false;
|
||||
}
|
||||
}
|
||||
// onMount(async () => {
|
||||
// if (
|
||||
// service.type &&
|
||||
// service.destinationDockerId &&
|
||||
// service.version &&
|
||||
// service.fqdn &&
|
||||
// !isRunning
|
||||
// ) {
|
||||
// try {
|
||||
// await post(`/services/${service.id}/${service.type}/stop.json`, {});
|
||||
// } catch ({ error }) {
|
||||
// return errorNotification(error);
|
||||
// } finally {
|
||||
// loading = false;
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
</script>
|
||||
|
||||
<nav class="nav-side">
|
||||
@@ -140,7 +123,7 @@
|
||||
title="Stop Service"
|
||||
type="submit"
|
||||
disabled={!$session.isAdmin}
|
||||
class="icons bg-transparent tooltip-bottom text-sm flex items-center space-x-2 hover:bg-pink-600 hover:text-white"
|
||||
class="icons bg-transparent tooltip-bottom text-sm flex items-center space-x-2 text-red-500"
|
||||
data-tooltip={$session.isAdmin
|
||||
? 'Stop Service'
|
||||
: 'You do not have permission to stop the service.'}
|
||||
@@ -166,7 +149,7 @@
|
||||
title="Start Service"
|
||||
type="submit"
|
||||
disabled={!$session.isAdmin}
|
||||
class="icons bg-transparent tooltip-bottom text-sm flex items-center space-x-2 hover:bg-pink-600 hover:text-white"
|
||||
class="icons bg-transparent tooltip-bottom text-sm flex items-center space-x-2 text-green-500"
|
||||
data-tooltip={$session.isAdmin
|
||||
? 'Start Service'
|
||||
: 'You do not have permission to start the service.'}
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
import { goto } from '$app/navigation';
|
||||
import { post } from '$lib/api';
|
||||
import VaultWarden from '$lib/components/svg/services/VaultWarden.svelte';
|
||||
import LanguageTool from '$lib/components/svg/services/LanguageTool.svelte';
|
||||
|
||||
const { id } = $page.params;
|
||||
const from = $page.url.searchParams.get('from');
|
||||
@@ -74,6 +75,8 @@
|
||||
<Wordpress isAbsolute />
|
||||
{:else if type.name === 'vaultwarden'}
|
||||
<VaultWarden isAbsolute />
|
||||
{:else if type.name === 'languagetool'}
|
||||
<LanguageTool isAbsolute />
|
||||
{/if}{type.fancyName}
|
||||
</button>
|
||||
</form>
|
||||
|
||||
@@ -35,12 +35,18 @@
|
||||
import VsCodeServer from '$lib/components/svg/services/VSCodeServer.svelte';
|
||||
import Wordpress from '$lib/components/svg/services/Wordpress.svelte';
|
||||
import Services from './_Services/_Services.svelte';
|
||||
import { getDomain } from '$lib/components/common';
|
||||
import VaultWarden from '$lib/components/svg/services/VaultWarden.svelte';
|
||||
import cuid from 'cuid';
|
||||
import { browser } from '$app/env';
|
||||
import LanguageTool from '$lib/components/svg/services/LanguageTool.svelte';
|
||||
|
||||
export let service;
|
||||
export let isRunning;
|
||||
export let readOnly;
|
||||
|
||||
if (browser && window.location.hostname === 'demo.coolify.io' && !service.fqdn) {
|
||||
service.fqdn = `http://${cuid()}.demo.coolify.io`;
|
||||
}
|
||||
</script>
|
||||
|
||||
<div
|
||||
@@ -99,6 +105,10 @@
|
||||
<a href="https://github.com/dani-garcia/vaultwarden" target="_blank">
|
||||
<VaultWarden />
|
||||
</a>
|
||||
{:else if service.type === 'languagetool'}
|
||||
<a href="https://languagetool.org/dev" target="_blank">
|
||||
<LanguageTool />
|
||||
</a>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
21
src/routes/services/[id]/languagetool/index.json.ts
Normal file
21
src/routes/services/[id]/languagetool/index.json.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
import { getUserDetails } from '$lib/common';
|
||||
import * as db from '$lib/database';
|
||||
import { ErrorHandler } from '$lib/database';
|
||||
import type { RequestHandler } from '@sveltejs/kit';
|
||||
|
||||
export const post: RequestHandler = async (event) => {
|
||||
const { status, body } = await getUserDetails(event);
|
||||
if (status === 401) return { status, body };
|
||||
|
||||
const { id } = event.params;
|
||||
|
||||
let { name, fqdn } = await event.request.json();
|
||||
if (fqdn) fqdn = fqdn.toLowerCase();
|
||||
|
||||
try {
|
||||
await db.updateLanguageToolService({ id, fqdn, name });
|
||||
return { status: 201 };
|
||||
} catch (error) {
|
||||
return ErrorHandler(error);
|
||||
}
|
||||
};
|
||||
65
src/routes/services/[id]/languagetool/start.json.ts
Normal file
65
src/routes/services/[id]/languagetool/start.json.ts
Normal file
@@ -0,0 +1,65 @@
|
||||
import { asyncExecShell, createDirectories, getEngine, getUserDetails } from '$lib/common';
|
||||
import * as db from '$lib/database';
|
||||
import { promises as fs } from 'fs';
|
||||
import yaml from 'js-yaml';
|
||||
import type { RequestHandler } from '@sveltejs/kit';
|
||||
import { ErrorHandler, getServiceImage } from '$lib/database';
|
||||
import { makeLabelForServices } from '$lib/buildPacks/common';
|
||||
|
||||
export const post: RequestHandler = async (event) => {
|
||||
const { teamId, status, body } = await getUserDetails(event);
|
||||
if (status === 401) return { status, body };
|
||||
|
||||
const { id } = event.params;
|
||||
|
||||
try {
|
||||
const service = await db.getService({ id, teamId });
|
||||
const { type, version, destinationDockerId, destinationDocker } = service;
|
||||
const network = destinationDockerId && destinationDocker.network;
|
||||
const host = getEngine(destinationDocker.engine);
|
||||
|
||||
const { workdir } = await createDirectories({ repository: type, buildId: id });
|
||||
const image = getServiceImage(type);
|
||||
const composeFile = {
|
||||
version: '3.8',
|
||||
services: {
|
||||
[id]: {
|
||||
container_name: id,
|
||||
image: `${image}:${version}`,
|
||||
networks: [network],
|
||||
restart: 'always',
|
||||
volumes: [`${id}-ngrams:/ngrams`],
|
||||
labels: makeLabelForServices('languagetool')
|
||||
}
|
||||
},
|
||||
networks: {
|
||||
[network]: {
|
||||
external: true
|
||||
}
|
||||
},
|
||||
volumes: {
|
||||
[`${id}-ngrams`]: {
|
||||
external: true
|
||||
}
|
||||
}
|
||||
};
|
||||
const composeFileDestination = `${workdir}/docker-compose.yaml`;
|
||||
await fs.writeFile(composeFileDestination, yaml.dump(composeFile));
|
||||
try {
|
||||
await asyncExecShell(`DOCKER_HOST=${host} docker volume create ${id}-ngrams`);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
|
||||
try {
|
||||
await asyncExecShell(`DOCKER_HOST=${host} docker compose -f ${composeFileDestination} up -d`);
|
||||
return {
|
||||
status: 200
|
||||
};
|
||||
} catch (error) {
|
||||
return ErrorHandler(error);
|
||||
}
|
||||
} catch (error) {
|
||||
return ErrorHandler(error);
|
||||
}
|
||||
};
|
||||
35
src/routes/services/[id]/languagetool/stop.json.ts
Normal file
35
src/routes/services/[id]/languagetool/stop.json.ts
Normal file
@@ -0,0 +1,35 @@
|
||||
import { getUserDetails, removeDestinationDocker } from '$lib/common';
|
||||
import * as db from '$lib/database';
|
||||
import { ErrorHandler } from '$lib/database';
|
||||
import { checkContainer } from '$lib/haproxy';
|
||||
import type { RequestHandler } from '@sveltejs/kit';
|
||||
|
||||
export const post: RequestHandler = async (event) => {
|
||||
const { teamId, status, body } = await getUserDetails(event);
|
||||
if (status === 401) return { status, body };
|
||||
|
||||
const { id } = event.params;
|
||||
|
||||
try {
|
||||
const service = await db.getService({ id, teamId });
|
||||
const { destinationDockerId, destinationDocker, fqdn } = service;
|
||||
if (destinationDockerId) {
|
||||
const engine = destinationDocker.engine;
|
||||
|
||||
try {
|
||||
const found = await checkContainer(engine, id);
|
||||
if (found) {
|
||||
await removeDestinationDocker({ id, engine });
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
status: 200
|
||||
};
|
||||
} catch (error) {
|
||||
return ErrorHandler(error);
|
||||
}
|
||||
};
|
||||
@@ -3,14 +3,7 @@ import * as db from '$lib/database';
|
||||
import { promises as fs } from 'fs';
|
||||
import yaml from 'js-yaml';
|
||||
import type { RequestHandler } from '@sveltejs/kit';
|
||||
import { letsEncrypt } from '$lib/letsencrypt';
|
||||
import {
|
||||
checkHAProxy,
|
||||
configureSimpleServiceProxyOn,
|
||||
reloadHaproxy,
|
||||
setWwwRedirection,
|
||||
startHttpProxy
|
||||
} from '$lib/haproxy';
|
||||
import { startHttpProxy } from '$lib/haproxy';
|
||||
import getPort, { portNumbers } from 'get-port';
|
||||
import { getDomain } from '$lib/components/common';
|
||||
import { ErrorHandler } from '$lib/database';
|
||||
@@ -23,7 +16,6 @@ export const post: RequestHandler = async (event) => {
|
||||
const { id } = event.params;
|
||||
|
||||
try {
|
||||
await checkHAProxy();
|
||||
const service = await db.getService({ id, teamId });
|
||||
const {
|
||||
type,
|
||||
@@ -37,9 +29,6 @@ export const post: RequestHandler = async (event) => {
|
||||
const data = await db.prisma.setting.findFirst();
|
||||
const { minPort, maxPort } = data;
|
||||
|
||||
const domain = getDomain(fqdn);
|
||||
const isHttps = fqdn.startsWith('https://');
|
||||
|
||||
const network = destinationDockerId && destinationDocker.network;
|
||||
const host = getEngine(destinationDocker.engine);
|
||||
|
||||
@@ -95,15 +84,8 @@ export const post: RequestHandler = async (event) => {
|
||||
}
|
||||
try {
|
||||
await asyncExecShell(`DOCKER_HOST=${host} docker compose -f ${composeFileDestination} up -d`);
|
||||
await configureSimpleServiceProxyOn({ id, domain, port: consolePort });
|
||||
await db.updateMinioService({ id, publicPort });
|
||||
await startHttpProxy(destinationDocker, id, publicPort, apiPort);
|
||||
|
||||
if (isHttps) {
|
||||
await letsEncrypt({ domain, id });
|
||||
}
|
||||
await setWwwRedirection(fqdn);
|
||||
await reloadHaproxy(destinationDocker.engine);
|
||||
return {
|
||||
status: 200
|
||||
};
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
import { getEngine, getUserDetails, removeDestinationDocker } from '$lib/common';
|
||||
import { getDomain } from '$lib/components/common';
|
||||
import { getUserDetails, removeDestinationDocker } from '$lib/common';
|
||||
import * as db from '$lib/database';
|
||||
import { ErrorHandler } from '$lib/database';
|
||||
import { dockerInstance } from '$lib/docker';
|
||||
import { checkContainer, configureSimpleServiceProxyOff, stopTcpHttpProxy } from '$lib/haproxy';
|
||||
import { checkContainer, stopTcpHttpProxy } from '$lib/haproxy';
|
||||
import type { RequestHandler } from '@sveltejs/kit';
|
||||
|
||||
export const post: RequestHandler = async (event) => {
|
||||
@@ -21,7 +19,6 @@ export const post: RequestHandler = async (event) => {
|
||||
minio: { publicPort }
|
||||
} = service;
|
||||
await db.updateMinioService({ id, publicPort: null });
|
||||
const domain = getDomain(fqdn);
|
||||
if (destinationDockerId) {
|
||||
const engine = destinationDocker.engine;
|
||||
|
||||
@@ -35,7 +32,6 @@ export const post: RequestHandler = async (event) => {
|
||||
}
|
||||
try {
|
||||
await stopTcpHttpProxy(destinationDocker, publicPort);
|
||||
await configureSimpleServiceProxyOff(fqdn);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
|
||||
@@ -3,14 +3,6 @@ import * as db from '$lib/database';
|
||||
import { promises as fs } from 'fs';
|
||||
import yaml from 'js-yaml';
|
||||
import type { RequestHandler } from '@sveltejs/kit';
|
||||
import { letsEncrypt } from '$lib/letsencrypt';
|
||||
import {
|
||||
checkHAProxy,
|
||||
configureSimpleServiceProxyOn,
|
||||
reloadHaproxy,
|
||||
setWwwRedirection
|
||||
} from '$lib/haproxy';
|
||||
import { getDomain } from '$lib/components/common';
|
||||
import { ErrorHandler } from '$lib/database';
|
||||
import { makeLabelForServices } from '$lib/buildPacks/common';
|
||||
|
||||
@@ -21,13 +13,8 @@ export const post: RequestHandler = async (event) => {
|
||||
const { id } = event.params;
|
||||
|
||||
try {
|
||||
await checkHAProxy();
|
||||
const service = await db.getService({ id, teamId });
|
||||
const { type, version, fqdn, destinationDockerId, destinationDocker } = service;
|
||||
|
||||
const domain = getDomain(fqdn);
|
||||
const isHttps = fqdn.startsWith('https://');
|
||||
|
||||
const { type, version, destinationDockerId, destinationDocker } = service;
|
||||
const network = destinationDockerId && destinationDocker.network;
|
||||
const host = getEngine(destinationDocker.engine);
|
||||
|
||||
@@ -55,13 +42,6 @@ export const post: RequestHandler = async (event) => {
|
||||
|
||||
try {
|
||||
await asyncExecShell(`DOCKER_HOST=${host} docker compose -f ${composeFileDestination} up -d`);
|
||||
await configureSimpleServiceProxyOn({ id, domain, port: 8080 });
|
||||
|
||||
if (isHttps) {
|
||||
await letsEncrypt({ domain, id });
|
||||
}
|
||||
await setWwwRedirection(fqdn);
|
||||
await reloadHaproxy(destinationDocker.engine);
|
||||
return {
|
||||
status: 200
|
||||
};
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
import { getUserDetails, removeDestinationDocker } from '$lib/common';
|
||||
import { getDomain } from '$lib/components/common';
|
||||
import * as db from '$lib/database';
|
||||
import { ErrorHandler } from '$lib/database';
|
||||
import { dockerInstance } from '$lib/docker';
|
||||
import { checkContainer, configureSimpleServiceProxyOff } from '$lib/haproxy';
|
||||
import { checkContainer } from '$lib/haproxy';
|
||||
import type { RequestHandler } from '@sveltejs/kit';
|
||||
|
||||
export const post: RequestHandler = async (event) => {
|
||||
@@ -15,7 +13,6 @@ export const post: RequestHandler = async (event) => {
|
||||
try {
|
||||
const service = await db.getService({ id, teamId });
|
||||
const { destinationDockerId, destinationDocker, fqdn } = service;
|
||||
const domain = getDomain(fqdn);
|
||||
if (destinationDockerId) {
|
||||
const engine = destinationDocker.engine;
|
||||
|
||||
@@ -27,11 +24,6 @@ export const post: RequestHandler = async (event) => {
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
try {
|
||||
await configureSimpleServiceProxyOff(fqdn);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
|
||||
@@ -3,14 +3,6 @@ import * as db from '$lib/database';
|
||||
import { promises as fs } from 'fs';
|
||||
import yaml from 'js-yaml';
|
||||
import type { RequestHandler } from '@sveltejs/kit';
|
||||
import { letsEncrypt } from '$lib/letsencrypt';
|
||||
import {
|
||||
checkHAProxy,
|
||||
configureSimpleServiceProxyOn,
|
||||
reloadHaproxy,
|
||||
setWwwRedirection
|
||||
} from '$lib/haproxy';
|
||||
import { getDomain } from '$lib/components/common';
|
||||
import { ErrorHandler } from '$lib/database';
|
||||
import { makeLabelForServices } from '$lib/buildPacks/common';
|
||||
|
||||
@@ -21,7 +13,6 @@ export const post: RequestHandler = async (event) => {
|
||||
const { id } = event.params;
|
||||
|
||||
try {
|
||||
await checkHAProxy();
|
||||
const service = await db.getService({ id, teamId });
|
||||
const {
|
||||
type,
|
||||
@@ -41,9 +32,6 @@ export const post: RequestHandler = async (event) => {
|
||||
}
|
||||
} = service;
|
||||
|
||||
const domain = getDomain(fqdn);
|
||||
const isHttps = fqdn.startsWith('https://');
|
||||
|
||||
const config = {
|
||||
plausibleAnalytics: {
|
||||
image: `plausible/analytics:${version}`,
|
||||
@@ -82,7 +70,6 @@ export const post: RequestHandler = async (event) => {
|
||||
};
|
||||
const network = destinationDockerId && destinationDocker.network;
|
||||
const host = getEngine(destinationDocker.engine);
|
||||
const engine = destinationDocker.engine;
|
||||
|
||||
const { workdir } = await createDirectories({ repository: type, buildId: id });
|
||||
|
||||
@@ -186,13 +173,7 @@ COPY ./init-db.sh /docker-entrypoint-initdb.d/init-db.sh`;
|
||||
await asyncExecShell(
|
||||
`DOCKER_HOST=${host} docker compose -f ${composeFileDestination} up --build -d`
|
||||
);
|
||||
await configureSimpleServiceProxyOn({ id, domain, port: 8000 });
|
||||
|
||||
if (isHttps) {
|
||||
await letsEncrypt({ domain, id });
|
||||
}
|
||||
await setWwwRedirection(fqdn);
|
||||
await reloadHaproxy(destinationDocker.engine);
|
||||
return {
|
||||
status: 200
|
||||
};
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
import { getUserDetails, removeDestinationDocker } from '$lib/common';
|
||||
import { getDomain } from '$lib/components/common';
|
||||
import * as db from '$lib/database';
|
||||
import { ErrorHandler } from '$lib/database';
|
||||
import { dockerInstance } from '$lib/docker';
|
||||
import { checkContainer, configureSimpleServiceProxyOff } from '$lib/haproxy';
|
||||
import { checkContainer } from '$lib/haproxy';
|
||||
import type { RequestHandler } from '@sveltejs/kit';
|
||||
|
||||
export const post: RequestHandler = async (event) => {
|
||||
@@ -15,7 +13,6 @@ export const post: RequestHandler = async (event) => {
|
||||
try {
|
||||
const service = await db.getService({ id, teamId });
|
||||
const { destinationDockerId, destinationDocker, fqdn } = service;
|
||||
const domain = getDomain(fqdn);
|
||||
|
||||
if (destinationDockerId) {
|
||||
const engine = destinationDocker.engine;
|
||||
@@ -36,12 +33,6 @@ export const post: RequestHandler = async (event) => {
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
|
||||
try {
|
||||
await configureSimpleServiceProxyOff(fqdn);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
|
||||
@@ -3,14 +3,6 @@ import * as db from '$lib/database';
|
||||
import { promises as fs } from 'fs';
|
||||
import yaml from 'js-yaml';
|
||||
import type { RequestHandler } from '@sveltejs/kit';
|
||||
import { letsEncrypt } from '$lib/letsencrypt';
|
||||
import {
|
||||
checkHAProxy,
|
||||
configureSimpleServiceProxyOn,
|
||||
reloadHaproxy,
|
||||
setWwwRedirection
|
||||
} from '$lib/haproxy';
|
||||
import { getDomain } from '$lib/components/common';
|
||||
import { getServiceImage, ErrorHandler } from '$lib/database';
|
||||
import { makeLabelForServices } from '$lib/buildPacks/common';
|
||||
|
||||
@@ -21,12 +13,8 @@ export const post: RequestHandler = async (event) => {
|
||||
const { id } = event.params;
|
||||
|
||||
try {
|
||||
await checkHAProxy();
|
||||
const service = await db.getService({ id, teamId });
|
||||
const { type, version, fqdn, destinationDockerId, destinationDocker } = service;
|
||||
|
||||
const domain = getDomain(fqdn);
|
||||
const isHttps = fqdn.startsWith('https://');
|
||||
const { type, version, destinationDockerId, destinationDocker } = service;
|
||||
|
||||
const network = destinationDockerId && destinationDocker.network;
|
||||
const host = getEngine(destinationDocker.engine);
|
||||
@@ -73,13 +61,6 @@ export const post: RequestHandler = async (event) => {
|
||||
}
|
||||
try {
|
||||
await asyncExecShell(`DOCKER_HOST=${host} docker compose -f ${composeFileDestination} up -d`);
|
||||
await configureSimpleServiceProxyOn({ id, domain, port: 80 });
|
||||
|
||||
if (isHttps) {
|
||||
await letsEncrypt({ domain, id });
|
||||
}
|
||||
await setWwwRedirection(fqdn);
|
||||
await reloadHaproxy(destinationDocker.engine);
|
||||
return {
|
||||
status: 200
|
||||
};
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
import { getUserDetails, removeDestinationDocker } from '$lib/common';
|
||||
import { getDomain } from '$lib/components/common';
|
||||
import * as db from '$lib/database';
|
||||
import { ErrorHandler } from '$lib/database';
|
||||
import { dockerInstance } from '$lib/docker';
|
||||
import { checkContainer, configureSimpleServiceProxyOff } from '$lib/haproxy';
|
||||
import { checkContainer } from '$lib/haproxy';
|
||||
import type { RequestHandler } from '@sveltejs/kit';
|
||||
|
||||
export const post: RequestHandler = async (event) => {
|
||||
@@ -15,7 +13,6 @@ export const post: RequestHandler = async (event) => {
|
||||
try {
|
||||
const service = await db.getService({ id, teamId });
|
||||
const { destinationDockerId, destinationDocker, fqdn } = service;
|
||||
const domain = getDomain(fqdn);
|
||||
if (destinationDockerId) {
|
||||
const engine = destinationDocker.engine;
|
||||
|
||||
@@ -27,13 +24,7 @@ export const post: RequestHandler = async (event) => {
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
try {
|
||||
await configureSimpleServiceProxyOff(fqdn);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
status: 200
|
||||
};
|
||||
|
||||
@@ -3,14 +3,6 @@ import * as db from '$lib/database';
|
||||
import { promises as fs } from 'fs';
|
||||
import yaml from 'js-yaml';
|
||||
import type { RequestHandler } from '@sveltejs/kit';
|
||||
import { letsEncrypt } from '$lib/letsencrypt';
|
||||
import {
|
||||
checkHAProxy,
|
||||
configureSimpleServiceProxyOn,
|
||||
reloadHaproxy,
|
||||
setWwwRedirection
|
||||
} from '$lib/haproxy';
|
||||
import { getDomain } from '$lib/components/common';
|
||||
import { ErrorHandler } from '$lib/database';
|
||||
import { makeLabelForServices } from '$lib/buildPacks/common';
|
||||
|
||||
@@ -21,20 +13,15 @@ export const post: RequestHandler = async (event) => {
|
||||
const { id } = event.params;
|
||||
|
||||
try {
|
||||
await checkHAProxy();
|
||||
const service = await db.getService({ id, teamId });
|
||||
const {
|
||||
type,
|
||||
version,
|
||||
fqdn,
|
||||
destinationDockerId,
|
||||
destinationDocker,
|
||||
vscodeserver: { password }
|
||||
} = service;
|
||||
|
||||
const domain = getDomain(fqdn);
|
||||
const isHttps = fqdn.startsWith('https://');
|
||||
|
||||
const network = destinationDockerId && destinationDocker.network;
|
||||
const host = getEngine(destinationDocker.engine);
|
||||
|
||||
@@ -83,13 +70,6 @@ export const post: RequestHandler = async (event) => {
|
||||
|
||||
try {
|
||||
await asyncExecShell(`DOCKER_HOST=${host} docker compose -f ${composeFileDestination} up -d`);
|
||||
await configureSimpleServiceProxyOn({ id, domain, port: 8080 });
|
||||
|
||||
if (isHttps) {
|
||||
await letsEncrypt({ domain, id });
|
||||
}
|
||||
await setWwwRedirection(fqdn);
|
||||
await reloadHaproxy(destinationDocker.engine);
|
||||
return {
|
||||
status: 200
|
||||
};
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
import { getUserDetails, removeDestinationDocker } from '$lib/common';
|
||||
import { getDomain } from '$lib/components/common';
|
||||
import * as db from '$lib/database';
|
||||
import { ErrorHandler } from '$lib/database';
|
||||
import { dockerInstance } from '$lib/docker';
|
||||
import { checkContainer, configureSimpleServiceProxyOff } from '$lib/haproxy';
|
||||
import { checkContainer } from '$lib/haproxy';
|
||||
import type { RequestHandler } from '@sveltejs/kit';
|
||||
|
||||
export const post: RequestHandler = async (event) => {
|
||||
@@ -15,7 +13,6 @@ export const post: RequestHandler = async (event) => {
|
||||
try {
|
||||
const service = await db.getService({ id, teamId });
|
||||
const { destinationDockerId, destinationDocker, fqdn } = service;
|
||||
const domain = getDomain(fqdn);
|
||||
if (destinationDockerId) {
|
||||
const engine = destinationDocker.engine;
|
||||
|
||||
@@ -27,11 +24,6 @@ export const post: RequestHandler = async (event) => {
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
try {
|
||||
await configureSimpleServiceProxyOff(fqdn);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
return {
|
||||
status: 200
|
||||
|
||||
@@ -3,14 +3,6 @@ import * as db from '$lib/database';
|
||||
import { promises as fs } from 'fs';
|
||||
import yaml from 'js-yaml';
|
||||
import type { RequestHandler } from '@sveltejs/kit';
|
||||
import { letsEncrypt } from '$lib/letsencrypt';
|
||||
import {
|
||||
checkHAProxy,
|
||||
configureSimpleServiceProxyOn,
|
||||
reloadHaproxy,
|
||||
setWwwRedirection
|
||||
} from '$lib/haproxy';
|
||||
import { getDomain } from '$lib/components/common';
|
||||
import { ErrorHandler } from '$lib/database';
|
||||
import { makeLabelForServices } from '$lib/buildPacks/common';
|
||||
|
||||
@@ -21,7 +13,6 @@ export const post: RequestHandler = async (event) => {
|
||||
const { id } = event.params;
|
||||
|
||||
try {
|
||||
await checkHAProxy();
|
||||
const service = await db.getService({ id, teamId });
|
||||
const {
|
||||
type,
|
||||
@@ -39,9 +30,6 @@ export const post: RequestHandler = async (event) => {
|
||||
}
|
||||
} = service;
|
||||
|
||||
const domain = getDomain(fqdn);
|
||||
const isHttps = fqdn.startsWith('https://');
|
||||
|
||||
const network = destinationDockerId && destinationDocker.network;
|
||||
const host = getEngine(destinationDocker.engine);
|
||||
|
||||
@@ -120,13 +108,6 @@ export const post: RequestHandler = async (event) => {
|
||||
|
||||
try {
|
||||
await asyncExecShell(`DOCKER_HOST=${host} docker compose -f ${composeFileDestination} up -d`);
|
||||
await configureSimpleServiceProxyOn({ id, domain, port: 80 });
|
||||
|
||||
if (isHttps) {
|
||||
await letsEncrypt({ domain, id });
|
||||
}
|
||||
await setWwwRedirection(fqdn);
|
||||
await reloadHaproxy(destinationDocker.engine);
|
||||
return {
|
||||
status: 200
|
||||
};
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
import { getUserDetails, removeDestinationDocker } from '$lib/common';
|
||||
import { getDomain } from '$lib/components/common';
|
||||
import * as db from '$lib/database';
|
||||
import { ErrorHandler } from '$lib/database';
|
||||
import { dockerInstance } from '$lib/docker';
|
||||
import { checkContainer, configureSimpleServiceProxyOff } from '$lib/haproxy';
|
||||
import { checkContainer } from '$lib/haproxy';
|
||||
import type { RequestHandler } from '@sveltejs/kit';
|
||||
|
||||
export const post: RequestHandler = async (event) => {
|
||||
@@ -15,7 +13,6 @@ export const post: RequestHandler = async (event) => {
|
||||
try {
|
||||
const service = await db.getService({ id, teamId });
|
||||
const { destinationDockerId, destinationDocker, fqdn } = service;
|
||||
const domain = getDomain(fqdn);
|
||||
if (destinationDockerId) {
|
||||
const engine = destinationDocker.engine;
|
||||
try {
|
||||
@@ -30,11 +27,6 @@ export const post: RequestHandler = async (event) => {
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
try {
|
||||
await configureSimpleServiceProxyOff(fqdn);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
import VsCodeServer from '$lib/components/svg/services/VSCodeServer.svelte';
|
||||
import Wordpress from '$lib/components/svg/services/Wordpress.svelte';
|
||||
import VaultWarden from '$lib/components/svg/services/VaultWarden.svelte';
|
||||
import LanguageTool from '$lib/components/svg/services/LanguageTool.svelte';
|
||||
|
||||
export let services;
|
||||
</script>
|
||||
@@ -70,6 +71,8 @@
|
||||
<Wordpress isAbsolute />
|
||||
{:else if service.type === 'vaultwarden'}
|
||||
<VaultWarden isAbsolute />
|
||||
{:else if service.type === 'languagetool'}
|
||||
<LanguageTool isAbsolute />
|
||||
{/if}
|
||||
<div class="font-bold text-xl text-center truncate">
|
||||
{service.name}
|
||||
|
||||
@@ -1,17 +1,6 @@
|
||||
import { dev } from '$app/env';
|
||||
import { getDomain, getUserDetails } from '$lib/common';
|
||||
import { getUserDetails } from '$lib/common';
|
||||
import * as db from '$lib/database';
|
||||
import { listSettings, ErrorHandler } from '$lib/database';
|
||||
import {
|
||||
configureCoolifyProxyOff,
|
||||
configureCoolifyProxyOn,
|
||||
forceSSLOnApplication,
|
||||
reloadHaproxy,
|
||||
removeWwwRedirection,
|
||||
setWwwRedirection,
|
||||
startCoolifyProxy
|
||||
} from '$lib/haproxy';
|
||||
import { letsEncrypt } from '$lib/letsencrypt';
|
||||
import type { RequestHandler } from '@sveltejs/kit';
|
||||
import { promises as dns } from 'dns';
|
||||
|
||||
@@ -51,10 +40,7 @@ export const del: RequestHandler = async (event) => {
|
||||
// Do not care.
|
||||
}
|
||||
try {
|
||||
const domain = getDomain(fqdn);
|
||||
await db.prisma.setting.update({ where: { fqdn }, data: { fqdn: null } });
|
||||
await configureCoolifyProxyOff(fqdn);
|
||||
await removeWwwRedirection(domain);
|
||||
return {
|
||||
status: 200,
|
||||
body: {
|
||||
@@ -79,49 +65,19 @@ export const post: RequestHandler = async (event) => {
|
||||
|
||||
const { fqdn, isRegistrationEnabled, dualCerts, minPort, maxPort } = await event.request.json();
|
||||
try {
|
||||
const {
|
||||
id,
|
||||
fqdn: oldFqdn,
|
||||
isRegistrationEnabled: oldIsRegistrationEnabled,
|
||||
dualCerts: oldDualCerts
|
||||
} = await db.listSettings();
|
||||
if (oldIsRegistrationEnabled !== isRegistrationEnabled) {
|
||||
const { id } = await db.listSettings();
|
||||
if (isRegistrationEnabled) {
|
||||
await db.prisma.setting.update({ where: { id }, data: { isRegistrationEnabled } });
|
||||
}
|
||||
if (oldDualCerts !== dualCerts) {
|
||||
await db.prisma.setting.update({ where: { id }, data: { dualCerts } });
|
||||
}
|
||||
if (oldFqdn && oldFqdn !== fqdn) {
|
||||
if (oldFqdn) {
|
||||
const oldDomain = getDomain(oldFqdn);
|
||||
await configureCoolifyProxyOff(oldFqdn);
|
||||
await removeWwwRedirection(oldDomain);
|
||||
}
|
||||
}
|
||||
if (fqdn) {
|
||||
await startCoolifyProxy('/var/run/docker.sock');
|
||||
const domain = getDomain(fqdn);
|
||||
const isHttps = fqdn.startsWith('https://');
|
||||
if (domain) {
|
||||
await configureCoolifyProxyOn(fqdn);
|
||||
await setWwwRedirection(fqdn);
|
||||
if (isHttps) {
|
||||
await letsEncrypt({ domain, isCoolify: true });
|
||||
await forceSSLOnApplication(domain);
|
||||
await reloadHaproxy('/var/run/docker.sock');
|
||||
}
|
||||
}
|
||||
|
||||
await db.prisma.setting.update({ where: { id }, data: { fqdn } });
|
||||
await db.prisma.destinationDocker.updateMany({
|
||||
where: { engine: '/var/run/docker.sock' },
|
||||
data: { isCoolifyProxyUsed: true }
|
||||
});
|
||||
}
|
||||
if (dualCerts) {
|
||||
await db.prisma.setting.update({ where: { id }, data: { dualCerts } });
|
||||
}
|
||||
if (minPort && maxPort) {
|
||||
await db.prisma.setting.update({ where: { id }, data: { minPort, maxPort } });
|
||||
}
|
||||
|
||||
return {
|
||||
status: 201
|
||||
};
|
||||
|
||||
@@ -78,6 +78,7 @@
|
||||
if (fqdn !== settings.fqdn) {
|
||||
await post(`/settings/check.json`, { fqdn });
|
||||
await post(`/settings.json`, { fqdn });
|
||||
return window.location.reload();
|
||||
}
|
||||
if (minPort !== settings.minPort || maxPort !== settings.maxPort) {
|
||||
await post(`/settings.json`, { minPort, maxPort });
|
||||
@@ -98,7 +99,7 @@
|
||||
{#if $session.teamId === '0'}
|
||||
<div class="mx-auto max-w-4xl px-6">
|
||||
<form on:submit|preventDefault={handleSubmit} class="grid grid-flow-row gap-2 py-4">
|
||||
<div class="flex space-x-1 py-6">
|
||||
<div class="flex space-x-1 pb-6">
|
||||
<div class="title font-bold">Global Settings</div>
|
||||
<button
|
||||
type="submit"
|
||||
|
||||
@@ -6,13 +6,16 @@ import type { RequestHandler } from '@sveltejs/kit';
|
||||
import compare from 'compare-versions';
|
||||
import got from 'got';
|
||||
|
||||
export const get: RequestHandler = async () => {
|
||||
export const get: RequestHandler = async (request) => {
|
||||
try {
|
||||
const currentVersion = version;
|
||||
const versions = await got
|
||||
.get(`https://get.coollabs.io/versions.json?appId=${process.env['COOLIFY_APP_ID']}`)
|
||||
.json();
|
||||
const latestVersion = dev ? '10.0.0' : versions['coolify'].main.version;
|
||||
const latestVersion =
|
||||
request.url.hostname === 'staging.coolify.io'
|
||||
? versions['coolify'].next.version
|
||||
: versions['coolify'].main.version;
|
||||
const isUpdateAvailable = compare(latestVersion, currentVersion);
|
||||
return {
|
||||
body: {
|
||||
@@ -21,32 +24,17 @@ export const get: RequestHandler = async () => {
|
||||
}
|
||||
};
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
return ErrorHandler(error);
|
||||
}
|
||||
};
|
||||
|
||||
export const post: RequestHandler = async (event) => {
|
||||
const { type, latestVersion } = await event.request.json();
|
||||
if (type === 'pull') {
|
||||
if (type === 'update') {
|
||||
try {
|
||||
if (!dev) {
|
||||
await asyncExecShell(`docker pull coollabsio/coolify:${latestVersion}`);
|
||||
return {
|
||||
status: 200,
|
||||
body: {}
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
status: 200,
|
||||
body: {}
|
||||
};
|
||||
}
|
||||
} catch (error) {
|
||||
return ErrorHandler(error);
|
||||
}
|
||||
} else if (type === 'update') {
|
||||
try {
|
||||
if (!dev) {
|
||||
await asyncExecShell(`env | grep COOLIFY > .env`);
|
||||
await asyncExecShell(
|
||||
`docker run --rm -tid --env-file .env -v /var/run/docker.sock:/var/run/docker.sock -v coolify-db coollabsio/coolify:${latestVersion} /bin/sh -c "env | grep COOLIFY > .env && echo 'TAG=${latestVersion}' >> .env && docker stop -t 0 coolify coolify-redis && docker rm coolify coolify-redis && docker compose up -d --force-recreate"`
|
||||
|
||||
@@ -4,7 +4,7 @@ import type { RequestHandler } from '@sveltejs/kit';
|
||||
import cuid from 'cuid';
|
||||
import crypto from 'crypto';
|
||||
import { buildQueue } from '$lib/queues';
|
||||
import { checkContainer, removeProxyConfiguration } from '$lib/haproxy';
|
||||
import { checkContainer } from '$lib/haproxy';
|
||||
import { dev } from '$app/env';
|
||||
|
||||
export const options: RequestHandler = async () => {
|
||||
@@ -84,6 +84,10 @@ export const post: RequestHandler = async (event) => {
|
||||
data: { configHash }
|
||||
});
|
||||
}
|
||||
await db.prisma.application.update({
|
||||
where: { id: applicationFound.id },
|
||||
data: { updatedAt: new Date() }
|
||||
});
|
||||
await buildQueue.add(buildId, {
|
||||
build_id: buildId,
|
||||
type: 'webhook_commit',
|
||||
@@ -128,6 +132,10 @@ export const post: RequestHandler = async (event) => {
|
||||
pullmergeRequestAction === 'reopened' ||
|
||||
pullmergeRequestAction === 'synchronize'
|
||||
) {
|
||||
await db.prisma.application.update({
|
||||
where: { id: applicationFound.id },
|
||||
data: { updatedAt: new Date() }
|
||||
});
|
||||
await buildQueue.add(buildId, {
|
||||
build_id: buildId,
|
||||
type: 'webhook_pr',
|
||||
@@ -143,18 +151,9 @@ export const post: RequestHandler = async (event) => {
|
||||
};
|
||||
} else if (pullmergeRequestAction === 'closed') {
|
||||
if (applicationFound.destinationDockerId) {
|
||||
const domain = getDomain(applicationFound.fqdn);
|
||||
const isHttps = applicationFound.fqdn.startsWith('https://');
|
||||
const isWWW = applicationFound.fqdn.includes('www.');
|
||||
const fqdn = `${isHttps ? 'https://' : 'http://'}${
|
||||
isWWW ? 'www.' : ''
|
||||
}${pullmergeRequestId}.${domain}`;
|
||||
|
||||
const id = `${applicationFound.id}-${pullmergeRequestId}`;
|
||||
const engine = applicationFound.destinationDocker.engine;
|
||||
|
||||
await removeDestinationDocker({ id, engine });
|
||||
await removeProxyConfiguration(fqdn);
|
||||
}
|
||||
return {
|
||||
status: 200,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { getTeam, getUserDetails, getDomain, removeDestinationDocker } from '$lib/common';
|
||||
import { checkContainer, removeProxyConfiguration } from '$lib/haproxy';
|
||||
import { checkContainer } from '$lib/haproxy';
|
||||
import * as db from '$lib/database';
|
||||
import type { RequestHandler } from '@sveltejs/kit';
|
||||
import cuid from 'cuid';
|
||||
@@ -48,6 +48,10 @@ export const post: RequestHandler = async (event) => {
|
||||
data: { configHash }
|
||||
});
|
||||
}
|
||||
await db.prisma.application.update({
|
||||
where: { id: applicationFound.id },
|
||||
data: { updatedAt: new Date() }
|
||||
});
|
||||
await buildQueue.add(buildId, {
|
||||
build_id: buildId,
|
||||
type: 'webhook_commit',
|
||||
@@ -125,6 +129,10 @@ export const post: RequestHandler = async (event) => {
|
||||
action === 'open' ||
|
||||
action === 'update'
|
||||
) {
|
||||
await db.prisma.application.update({
|
||||
where: { id: applicationFound.id },
|
||||
data: { updatedAt: new Date() }
|
||||
});
|
||||
await buildQueue.add(buildId, {
|
||||
build_id: buildId,
|
||||
type: 'webhook_mr',
|
||||
@@ -140,18 +148,9 @@ export const post: RequestHandler = async (event) => {
|
||||
};
|
||||
} else if (action === 'close') {
|
||||
if (applicationFound.destinationDockerId) {
|
||||
const domain = getDomain(applicationFound.fqdn);
|
||||
const isHttps = applicationFound.fqdn.startsWith('https://');
|
||||
const isWWW = applicationFound.fqdn.includes('www.');
|
||||
const fqdn = `${isHttps ? 'https://' : 'http://'}${
|
||||
isWWW ? 'www.' : ''
|
||||
}${pullmergeRequestId}.${domain}`;
|
||||
|
||||
const id = `${applicationFound.id}-${pullmergeRequestId}`;
|
||||
const engine = applicationFound.destinationDocker.engine;
|
||||
|
||||
await removeDestinationDocker({ id, engine });
|
||||
await removeProxyConfiguration(fqdn);
|
||||
}
|
||||
|
||||
return {
|
||||
|
||||
@@ -35,10 +35,10 @@ main,
|
||||
}
|
||||
|
||||
input {
|
||||
@apply h-12 w-96 rounded border border-transparent bg-transparent bg-coolgray-200 p-2 pr-20 text-xs tracking-tight text-white placeholder-stone-600 outline-none transition duration-150 hover:bg-coolgray-500 focus:bg-coolgray-500 disabled:border disabled:border-dashed disabled:border-coolgray-300 disabled:bg-transparent md:text-sm;
|
||||
@apply h-12 w-96 rounded border border-transparent bg-transparent bg-coolgray-200 p-2 text-xs tracking-tight text-white placeholder-stone-600 outline-none transition duration-150 hover:bg-coolgray-500 focus:bg-coolgray-500 disabled:border disabled:border-dashed disabled:border-coolgray-300 disabled:bg-transparent md:text-sm;
|
||||
}
|
||||
textarea {
|
||||
@apply min-w-[24rem] rounded border border-transparent bg-transparent bg-coolgray-200 p-2 pr-20 text-xs tracking-tight text-white placeholder-stone-600 outline-none transition duration-150 hover:bg-coolgray-500 focus:bg-coolgray-500 disabled:border disabled:border-dashed disabled:border-coolgray-300 disabled:bg-transparent md:text-sm;
|
||||
@apply min-w-[24rem] rounded border border-transparent bg-transparent bg-coolgray-200 p-2 text-xs tracking-tight text-white placeholder-stone-600 outline-none transition duration-150 hover:bg-coolgray-500 focus:bg-coolgray-500 disabled:border disabled:border-dashed disabled:border-coolgray-300 disabled:bg-transparent md:text-sm;
|
||||
}
|
||||
|
||||
select {
|
||||
|
||||
Reference in New Issue
Block a user