Compare commits

...

805 Commits

Author SHA1 Message Date
Andras Bacsai
742df4f5df fix: select server view 2024-10-08 17:08:35 +02:00
Andras Bacsai
2522ecf832 chore: Update version to 4.0.0-beta.357 2024-10-08 17:08:26 +02:00
Andras Bacsai
40f2c7a1f9 Merge pull request #3714 from coollabsio/next
v4.0.0-beta.356
2024-10-07 14:08:08 +02:00
Andras Bacsai
3f8324d09e chore: Refactor loadServices2 method and remove unused code 2024-10-07 14:03:04 +02:00
Andras Bacsai
eee292b02f fix: directus 2024-10-07 13:45:02 +02:00
Andras Bacsai
2b4dc1f9c8 Merge pull request #3752 from peaklabs-dev/fix-directus
Fix: Directus template
2024-10-07 13:44:00 +02:00
Andras Bacsai
dd29827a14 Merge pull request #3749 from mkilinskidev/mki
Fix subtitle typo in server navbar
2024-10-07 13:23:40 +02:00
Andras Bacsai
dfe290b546 Merge pull request #3741 from coollabsio/dependabot/npm_and_yarn/cookie-0.7.0
chore(deps): bump cookie from 0.6.0 to 0.7.0
2024-10-07 13:15:16 +02:00
Andras Bacsai
4eeb7ee7c6 Merge pull request #3570 from katywings/nitropage
chore: add Nitropage service template and logo
2024-10-07 12:43:25 +02:00
Andras Bacsai
51813463b8 fix: chatwoot service 2024-10-07 12:36:33 +02:00
Andras Bacsai
da8a45391c Merge branch 'next' of github.com:coollabsio/coolify into next 2024-10-07 12:22:09 +02:00
Andras Bacsai
673081ffb3 chore: Update select.blade.php with improved search functionality 2024-10-07 12:22:00 +02:00
peaklabs-dev
8f6c01ba49 Update service-templates.json 2024-10-07 12:14:07 +02:00
peaklabs-dev
40852995b4 Merge branch 'next' of https://github.com/coollabsio/coolify into next 2024-10-07 12:13:53 +02:00
peaklabs-dev
e6bb1deaa9 Update getoutline.yaml 2024-10-07 12:13:52 +02:00
Andras Bacsai
2dc3177a7a feat: Refactor setType method to use slug value for type 2024-10-07 12:12:32 +02:00
Andras Bacsai
facbd9a50d Merge branch 'next' of github.com:coollabsio/coolify into next 2024-10-07 12:12:22 +02:00
Andras Bacsai
a0532afb24 feat: Refactor setType method to use slug value for type 2024-10-07 12:12:05 +02:00
Andras Bacsai
a725a6eaf2 feat: update setType method to use slug value for type 2024-10-07 12:11:56 +02:00
peaklabs-dev
3fd3660960 Update service-templates.json 2024-10-07 12:07:37 +02:00
peaklabs-dev
5898e0ac4a Merge branch 'next' of https://github.com/coollabsio/coolify into next 2024-10-07 12:07:18 +02:00
peaklabs-dev
4f4743cc7f Fix: Outline 2024-10-07 12:07:14 +02:00
Andras Bacsai
3b3362daf0 Merge pull request #3722 from danielalves96/add_ollama_with_web_ui
feat: add ollama service with open-webui and logo
2024-10-07 11:56:28 +02:00
Andras Bacsai
cd199ed81d Merge branch 'next' of github.com:coollabsio/coolify into next 2024-10-07 11:54:59 +02:00
Andras Bacsai
7e32a37729 fix: new services 2024-10-07 11:54:54 +02:00
🏔️ Peak
58c3cea0c0 Merge pull request #3127 from peaklabs-dev/service-getoutline
Feat: getoutline service
2024-10-07 11:29:57 +02:00
Andras Bacsai
1c10a43321 fix: new resource selection view
fix: new services
2024-10-07 11:19:14 +02:00
Andras Bacsai
370a0b1eec fix: use local service-templates in dev 2024-10-07 11:02:01 +02:00
peaklabs-dev
282ff4e670 Update service-templates.json 2024-10-07 10:39:21 +02:00
peaklabs-dev
af09472679 Update labelstudio.yaml 2024-10-07 10:36:08 +02:00
🏔️ Peak
053ee63606 Merge pull request #3729 from rennokki/service/labelstudio
Service: Label Studio
2024-10-07 10:21:03 +02:00
peaklabs-dev
a8d8df7d8b Fix: Directus 2024-10-06 19:42:09 +02:00
Andras Bacsai
283fe47f5c Merge pull request #3750 from coollabsio/helper-1.0.2
chore: Bump coolify-helper version to 1.0.2
2024-10-06 18:04:26 +02:00
Andras Bacsai
88367d8af1 chore: Bump coolify-helper version to 1.0.2 2024-10-06 18:04:03 +02:00
Andras Bacsai
506f733632 Merge pull request #3748 from peaklabs-dev/fix-helper-manifest
Fix: Broken helper manifests (for a short period a few hours)
2024-10-06 18:00:00 +02:00
Mateusz Kilinski
9f2e7851f7 Fix subtitle typo in server navbar 2024-10-06 17:43:22 +02:00
peaklabs-dev
8269e9d29d Fix: Update helper version 2024-10-06 17:39:16 +02:00
dependabot[bot]
8803cae54c chore(deps): bump cookie from 0.6.0 to 0.7.0
Bumps [cookie](https://github.com/jshttp/cookie) from 0.6.0 to 0.7.0.
- [Release notes](https://github.com/jshttp/cookie/releases)
- [Commits](https://github.com/jshttp/cookie/compare/v0.6.0...v0.7.0)

---
updated-dependencies:
- dependency-name: cookie
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-10-06 08:13:20 +00:00
peaklabs-dev
c1930e3dfc Revert "Update coolify-helper.yml"
This reverts commit c717b6859b.
2024-10-06 00:51:54 +02:00
🏔️ Peak
c717b6859b Update coolify-helper.yml 2024-10-06 00:51:28 +02:00
Andras Bacsai
4624a381b1 new search input on "new resource" view 2024-10-05 20:55:23 +02:00
Andras Bacsai
6928b0a2c8 chore: Update project query to order by name in lowercase 2024-10-05 15:04:47 +02:00
Andras Bacsai
2da6f66e85 chore: Update project query to order by name in uppercase 2024-10-05 15:04:31 +02:00
Andras Bacsai
a1124a885d feat: project search on frontend 2024-10-05 15:03:40 +02:00
Andras Bacsai
9448d0f0d2 feat: Add Invoice Ninja service configuration to Service model 2024-10-05 14:16:53 +02:00
Alex Renoki
e446354d97 Added Label Studio 2024-10-05 06:27:16 +03:00
Daniel Alves
c8aa09359f fix: remove not used extra host 2024-10-04 16:15:18 -03:00
Andras Bacsai
128d732438 fix: one-click services 2024-10-04 20:17:08 +02:00
Andras Bacsai
3b97bb1341 feat: Add Argilla service configuration to Service model 2024-10-04 20:16:58 +02:00
Andras Bacsai
a4c8f83d17 chore: Update password form submission in modal-confirmation component 2024-10-04 20:10:40 +02:00
Daniel Alves
0ca9885ddf feat: add ollama service with open webui and logo 2024-10-04 11:51:45 -03:00
Andras Bacsai
4f4453b17c chore: Update proxy configuration paths for Caddy and Nginx in dev 2024-10-04 13:46:33 +02:00
Andras Bacsai
d60d90de92 chore: Update anythingllm.yaml volumes configuration 2024-10-04 13:41:14 +02:00
Andras Bacsai
ce49f4806d fix: proxy conf in dev 2024-10-04 13:25:17 +02:00
Andras Bacsai
82daf6c420 Merge pull request #2980 from rennokki/feature/ai-templates
New services: LLM & AI-related one-click services
2024-10-04 13:24:34 +02:00
Andras Bacsai
f1eb43815e Merge branch 'next' into feature/ai-templates 2024-10-04 12:44:15 +02:00
Andras Bacsai
be9041d592 chore: Update MariaDB image to version 11 and fix service environment variable orders 2024-10-04 12:20:35 +02:00
Andras Bacsai
c2c0afa0ba fix: service env orders, application env orders 2024-10-04 12:08:57 +02:00
Andras Bacsai
611f70d79f chore: Remove commented code for shared variable type validation 2024-10-04 12:08:06 +02:00
Alexander G.
59c54b8aec Merge branch 'next' into feature/ai-templates 2024-10-04 12:29:30 +03:00
Alex Renoki
f0f685b78a Added anythingllm 2024-10-04 12:29:08 +03:00
Alex Renoki
c54d77515b Added unstructured 2024-10-04 11:54:32 +03:00
Alex Renoki
9435be7cce Added Argilla 2024-10-04 11:49:04 +03:00
Alex Renoki
f2ccc4059d Added prefect 2024-10-04 11:33:01 +03:00
Alex Renoki
21c6510e9d Improved healthchecks and generations 2024-10-04 11:26:45 +03:00
Andras Bacsai
2ca73695b3 fix: tag mass redeployments 2024-10-04 10:22:58 +02:00
Alex Renoki
31193a9f66 Fixed postgres healthchecks 2024-10-04 08:49:02 +03:00
Alex Renoki
9f5257bf8a Added infisical 2024-10-04 08:48:49 +03:00
Alex Renoki
78a34dbef1 Fixed langfuse 2024-10-04 07:21:20 +03:00
Alex Renoki
f4d650b03f Fixed litellm 2024-10-04 07:09:58 +03:00
Alex Renoki
97ee34f1a1 Added searxng 2024-10-04 06:53:14 +03:00
Alex Renoki
9014062b48 Added weaviate 2024-10-04 06:43:59 +03:00
Alex Renoki
a8f230b5eb Added qdrant 2024-10-04 06:36:25 +03:00
Alex Renoki
94ee525e0a Merge branch 'feature/ai-templates' of github.com:rennokki/coolify into feature/ai-templates 2024-10-04 05:46:26 +03:00
Alex Renoki
d4ace01633 Added litellm 2024-10-04 05:40:08 +03:00
Alex Renoki
49bcd7b8e6 Bump to v2 2024-10-04 05:40:08 +03:00
Alex Renoki
5f613df4e0 Added langfuse 2024-10-04 05:40:07 +03:00
Andras Bacsai
65aeebd9fa fix: Reset description and subject fields after submitting feedback 2024-10-03 23:27:23 +02:00
Andras Bacsai
f26d2e1d0b chore: Update version to 4.0.0-beta.356 2024-10-03 23:26:32 +02:00
Andras Bacsai
a1d395ff0c Merge pull request #3708 from coollabsio/next
v4.0.0-beta.355
2024-10-03 23:04:54 +02:00
Andras Bacsai
4e9126887f Merge pull request #3707 from coollabsio/custom-traefik-middlewares
fix: parser, espacing container labels
2024-10-03 23:00:17 +02:00
Andras Bacsai
5fa650122d Merge pull request #3637 from MarioZet23/custom-traefik-middlewares
feat: Allow custom traefik middlewares
2024-10-03 22:59:46 +02:00
Andras Bacsai
ee7f8200ac fix: parser, espacing container labels 2024-10-03 22:58:06 +02:00
Andras Bacsai
d2a8f31a1c Merge branch 'next' into custom-traefik-middlewares 2024-10-03 22:44:22 +02:00
Andras Bacsai
2468d0044b chore: Update version to 4.0.0-beta.355 2024-10-03 22:39:44 +02:00
Andras Bacsai
81b8a58415 fix: scheduled backup for services view 2024-10-03 22:38:37 +02:00
Andras Bacsai
7442d19611 Merge pull request #3705 from coollabsio/next
v4.0.0-beta.354
2024-10-03 22:04:36 +02:00
Andras Bacsai
8c024ddb57 chore: Update homarr service template and remove unnecessary code 2024-10-03 22:02:18 +02:00
Andras Bacsai
d990a5691d chore: Update homarr service template and remove unnecessary code 2024-10-03 21:47:06 +02:00
Andras Bacsai
2181ef381b Merge pull request #3697 from danielalves96/add_homarr_template
feat: add homarr service tamplate and logo
2024-10-03 21:39:14 +02:00
Andras Bacsai
c80f5be974 chore: Update it-tools service template and port configuration 2024-10-03 21:38:13 +02:00
Andras Bacsai
358f6575f8 chore: Refactor modal-confirmation component 2024-10-03 21:38:08 +02:00
Andras Bacsai
de0f34734b Merge pull request #3702 from danielalves96/add-it-tools
feat: add it-tools service template and logo
2024-10-03 21:33:33 +02:00
Andras Bacsai
33cb2d150d chore: Fix application deployment queue filter logic 2024-10-03 21:32:02 +02:00
Andras Bacsai
5f07b473e9 fix: parse proxy config and check the set ports usage 2024-10-03 21:29:55 +02:00
Andras Bacsai
5bcd813792 chore: Remove commented code in Server model 2024-10-03 21:29:04 +02:00
Andras Bacsai
a0bb523507 chore: Remove debug statement in Service model 2024-10-03 21:11:14 +02:00
Andras Bacsai
0b4fc38d6b chore: Update version to 4.0.0-beta.354 2024-10-03 21:10:52 +02:00
Andras Bacsai
82c834915d Merge pull request #3703 from coollabsio/next
v4.0.0-beta.353
2024-10-03 21:03:16 +02:00
Andras Bacsai
d637675ce3 chore: Update service application view 2024-10-03 21:02:42 +02:00
Andras Bacsai
e71c04a0c7 chore: Update version to 4.0.0-beta.353 2024-10-03 20:59:10 +02:00
Andras Bacsai
885b3bdea7 Merge pull request #3701 from coollabsio/next
v4.0.0-beta.352
2024-10-03 20:53:17 +02:00
Daniel Alves
9d6757aeb7 feat: add it-tools service template and logo 2024-10-03 15:52:33 -03:00
Andras Bacsai
d84d0a816b chore: Refactor DatabaseBackupJob to handle missing team 2024-10-03 20:51:18 +02:00
Andras Bacsai
0da31c34b5 fix: add new supported database images 2024-10-03 20:47:22 +02:00
Andras Bacsai
ccdaf59ecb fix: service application view 2024-10-03 20:47:02 +02:00
Andras Bacsai
3fc9cf90ab chore: update version to 4.0.0-beta.352 2024-10-03 20:46:45 +02:00
Daniel Alves
c4be720b20 fix: update FQDN 2024-10-03 15:00:52 -03:00
Daniel Alves
aabe27efd1 feat: add homarr service tamplate and logo 2024-10-03 12:58:35 -03:00
Andras Bacsai
a8982379c9 Merge pull request #3683 from coollabsio/next
v4.0.0-beta.351
2024-10-03 15:15:21 +02:00
Andras Bacsai
6dd0bd0742 fix: api useBuildServer 2024-10-03 15:09:56 +02:00
Andras Bacsai
1d3494a6ba fix: network handling
fix: environment variable handling
2024-10-03 15:04:40 +02:00
Andras Bacsai
ee5eb427c9 fix: bitcoin core template 2024-10-03 14:07:58 +02:00
Andras Bacsai
ad7b5e6e1c Merge pull request #3689 from ALsJourney/bitcoin_core_service
Basic Bitcoin Core node service
2024-10-03 14:00:52 +02:00
Andras Bacsai
73bd344147 fix: strapi template 2024-10-03 13:49:50 +02:00
Andras Bacsai
ef448280d8 fix: able to support more database dynamically from Coolify's UI 2024-10-03 13:49:43 +02:00
Andras Bacsai
5282248cb4 Merge pull request #3685 from statickidz/add-strapi-template
Add Strapi template
2024-10-03 13:18:40 +02:00
Andras Bacsai
14c9f25c57 feat: restart service without pulling the latest image 2024-10-03 13:17:35 +02:00
ALsJourney
44b3d08d86 Finished basic bitcoin core service 2024-10-03 13:13:25 +02:00
Andras Bacsai
5da1f48ae1 fix typo 2024-10-03 12:43:41 +02:00
Andras Bacsai
2bc1b9027c Merge pull request #3679 from alepouna/typo-fix
Update docker-registry.yaml
2024-10-03 12:43:46 +02:00
Andras Bacsai
1c7ca56756 feat: backup all databases for mysql,mariadb,postgresql 2024-10-03 12:39:45 +02:00
Adrian Barrio
d70faea845 Merge remote-tracking branch 'origin/next' into add-strapi-template 2024-10-03 11:33:35 +02:00
Adrian Barrio
fdb5cab875 feat: add strapi template 2024-10-03 11:28:27 +02:00
Andras Bacsai
bb6cb8edc9 improvement: show backup button on supported db service stacks 2024-10-03 10:48:25 +02:00
Andras Bacsai
a6ec2b92fb version++ 2024-10-03 10:23:38 +02:00
Andras Bacsai
436a1d945f Merge pull request #3663 from coollabsio/next
v4.0.0-beta.350
2024-10-03 10:09:05 +02:00
Andras Bacsai
a6a3abc273 chore: Update soketi service image to version 1.0.3 2024-10-03 10:05:54 +02:00
Andras Bacsai
c4e702f096 fix: able to select root permission easier 2024-10-03 09:57:37 +02:00
alepouna
31df222798 Update docker-registry.yaml 2024-10-03 04:04:37 +03:00
Andras Bacsai
e91939a4ea refactor: Remove unnecessary watch command from soketi service entrypoint 2024-10-02 21:24:09 +02:00
Andras Bacsai
ceccd093d2 refactor: Improve socket reconnection interval in terminal.js 2024-10-02 21:24:05 +02:00
Andras Bacsai
66bb4e0fc1 refactor: Remove inactivity timer in terminal-server.js 2024-10-02 21:23:59 +02:00
Andras Bacsai
dd3ff38df7 refactor: Encode delimiter in SshMultiplexingHelper 2024-10-02 21:23:46 +02:00
Andras Bacsai
69553ec314 refactor: Improve popup component styling and button behavior 2024-10-02 18:26:51 +02:00
Andras Bacsai
7bb1bf0ae3 refactor: Improve parsing of commands for sudo in parseCommandsByLineForSudo 2024-10-02 18:26:40 +02:00
Andras Bacsai
a1a8f1336a refactor: Fix indentation in modal-confirmation.blade.php 2024-10-02 17:35:48 +02:00
Andras Bacsai
207fe1d709 wtf wtf wtf 2024-10-02 17:27:02 +02:00
Andras Bacsai
059535a676 chore: Remove commented out code for uploading to S3 in DatabaseBackupJob 2024-10-02 16:43:01 +02:00
Andras Bacsai
765a74ca4f handle errors in databasebackupjob 2024-10-02 15:33:14 +02:00
Andras Bacsai
e03e4f2e91 refactor: Improve SSH command generation in Terminal.php and terminal-server.js 2024-10-02 15:16:55 +02:00
Andras Bacsai
0ab432d5e6 chore: Remove unnecessary command from SshMultiplexingHelper 2024-10-02 14:54:48 +02:00
Andras Bacsai
6f25b548c7 fix: realtime watch in development mode 2024-10-02 14:18:52 +02:00
Andras Bacsai
d55e4bf381 feat: Handle HTTPS domain in ConfigureCloudflareTunnels 2024-10-02 13:36:25 +02:00
Andras Bacsai
ec216254b5 chore: Update modal input in server form to prevent closing on outside click 2024-10-02 13:36:09 +02:00
Andras Bacsai
fbb36bfe8e revert modal-confirmation in dev 2024-10-02 12:01:12 +02:00
Andras Bacsai
dd782e75f5 fix: local dev s3 uploads
fix: hetzner s3 uploads (mc alias instead of mc host)
2024-10-02 11:45:30 +02:00
Andras Bacsai
2be2f0ac79 feat: support Hetzner S3 2024-10-02 10:25:45 +02:00
Andras Bacsai
97943db5f4 chore: Add missing import for Attribute class in ApplicationDeploymentQueue model 2024-10-02 09:21:54 +02:00
Andras Bacsai
bbd2748ad7 chore: Update command signature and description for cleanup application deployment queue 2024-10-02 09:21:50 +02:00
Andras Bacsai
a530804a71 feat: Add command to check application deployment queue 2024-10-02 09:21:28 +02:00
Andras Bacsai
8ca8ab82b0 refactor: Remove deployment queue when deleting an application 2024-10-02 09:20:49 +02:00
Andras Bacsai
024ad8e943 fix: cleanup stucked applicationdeploymentqueue 2024-10-02 09:20:08 +02:00
Andras Bacsai
4d86b556a4 fix: ipv6 scp should use -6 flag 2024-10-02 08:15:03 +02:00
Andras Bacsai
73e38ff951 chore: Update version numbers to 4.0.0-beta.350 in configuration files 2024-10-02 08:13:49 +02:00
Andras Bacsai
5354561c39 Merge pull request #3659 from coollabsio/next
v4.0.0-beta.349
2024-10-01 21:36:50 +02:00
Andras Bacsai
223cd37031 fix: remove autofocuses 2024-10-01 21:36:16 +02:00
Andras Bacsai
93a0725a4e Merge pull request #3613 from nfnot/main
refactor: Update search input placeholder in resource index view
2024-10-01 21:32:21 +02:00
Andras Bacsai
4d1d4598b6 chore: Update version numbers to 4.0.0-beta.349 and 4.0.0-beta.350 2024-10-01 21:31:54 +02:00
Norman
888e96448c Merge branch 'main' into main 2024-10-01 13:33:02 +03:00
Andras Bacsai
0eea31544e Merge pull request #3636 from coollabsio/next
v4.0.0-beta.348
2024-10-01 12:04:39 +02:00
Andras Bacsai
8065da9fa0 Refactor input fields to include autocomplete="off" 2024-10-01 11:55:01 +02:00
Andras Bacsai
5cd81fe255 wip: server storage check 2024-10-01 11:52:36 +02:00
Andras Bacsai
b00828d4aa chore: Refactor instanceSettings() function and improve code readability 2024-10-01 11:36:37 +02:00
Andras Bacsai
5a770f9ddb fix: Handle deletion of 'hello' in confirmation modal for dev environment 2024-10-01 11:16:16 +02:00
Andras Bacsai
903d84e0dd fix: confirmation text could be empty, then skip that part
fix: confirmation modal should not be closed by clicking away
2024-10-01 10:53:20 +02:00
Andras Bacsai
16ccc87fbe chore: Add "Not Usable" indicator for storage items 2024-10-01 10:45:03 +02:00
Andras Bacsai
e4108863a8 chore: Remove unnecessary code in DatabaseBackupJob.php 2024-10-01 10:43:04 +02:00
Andras Bacsai
83549965ca Refactor instanceSettings() function for improved code readability 2024-10-01 10:37:40 +02:00
Andras Bacsai
4d9dcfb84c chore: Update Coolify Realtime image to version 1.0.2 2024-10-01 10:34:11 +02:00
Andras Bacsai
4db50bd025 chore: Refactor instanceSettings() function to improve code readability 2024-10-01 10:33:56 +02:00
Andras Bacsai
817bd9c35d chore: Update Coolify Realtime workflow to only trigger on the main branch 2024-10-01 10:09:38 +02:00
Andras Bacsai
2e10d670be Merge pull request #3647 from derpoho/next
fixes coollabsio#3645, incorrect adding of sudo if non-root user
2024-10-01 10:00:48 +02:00
Andras Bacsai
cec0d7d1f7 Merge pull request #3651 from LEstradioto/fix-enhance-terminal-2
Fix Terminal: no more exit fallback
2024-10-01 09:52:38 +02:00
Andras Bacsai
1f45532477 fix: mixpost 2024-10-01 09:35:54 +02:00
Andras Bacsai
bcc92e1f32 fix: in dev mode do not ask confirmation on delete 2024-10-01 09:31:01 +02:00
Andras Bacsai
31cf3294bf Update UUID description in API controller and OpenAPI specification 2024-10-01 09:04:01 +02:00
Andras Bacsai
26307334a4 feat: Add query parameters for deleting configurations, volumes, docker cleanup, and connected networks 2024-10-01 09:02:29 +02:00
Andras Bacsai
9212f3b24c feat: Update resource deletion job to allow configurable options through API 2024-10-01 09:02:16 +02:00
Andras Bacsai
31b2196ad9 Merge pull request #3650 from ImBIOS/patch-1
chore: fix docs link in running state
2024-10-01 07:40:59 +02:00
Luan Estradioto
2c38af1df0 - fixes: no more exit fallback to server 2024-10-01 01:42:09 -03:00
Imamuzzaki Abu Salam
89e84c5b48 chore: fix docs link in running state 2024-10-01 10:16:16 +07:00
Marcus Pohorely
39d2fdc08b Merge branch 'main' into next 2024-09-30 23:24:42 +02:00
Marcus Pohorely
ac9f817b9f fixes #3645, incorrect adding of sudo if non-root user 2024-09-30 23:21:58 +02:00
Andras Bacsai
852e881805 Merge pull request #2351 from AlejandroAkbal/main
feat: add Mixpost template
2024-09-30 16:35:55 +02:00
Andras Bacsai
001dec6604 chore: Update Mailpit logo to use SVG format 2024-09-30 16:31:36 +02:00
Andras Bacsai
cf9c62cbf0 Merge pull request #3202 from FranckKe/add_mailpit_template
feat: add Mailpit template
2024-09-30 16:16:05 +02:00
Andras Bacsai
99a4f721f1 Merge pull request #2904 from LEstradioto/add-storage-link-to-dev-environment
add storage:link to dev environment
2024-09-30 15:48:10 +02:00
Andras Bacsai
505be9dc97 add debugbar config 2024-09-30 15:44:07 +02:00
Andras Bacsai
cfec5b3a70 feat: Add support for use_build_server in API endpoints for creating/updating applications 2024-09-30 14:18:41 +02:00
Andras Bacsai
95483f1464 Merge pull request #3615 from liberocks/feature/api-use-build-server
feat: allow specify use_build_server when creating/updating an application through API
2024-09-30 14:17:59 +02:00
Andras Bacsai
987b90ead2 fix: new dev volumes and service files
fix: new parser version (4) that will fix data layout (applications goes to /applications, services goes to /services)
2024-09-30 14:16:37 +02:00
Andras Bacsai
68f541ded3 fix: filebrowser template 2024-09-30 14:16:37 +02:00
Andras Bacsai
afdf4cd5a8 service restart does no cleanup docker 2024-09-30 14:16:37 +02:00
Andras Bacsai
11dbce1471 Merge pull request #3630 from jordanamr/fix/filebrowser-template
fix(templates): filebrowser FQDN env variable
2024-09-30 14:16:14 +02:00
Andras Bacsai
e1037ac031 Merge branch 'next' into fix/filebrowser-template 2024-09-30 14:16:01 +02:00
Andras Bacsai
88c2b1e841 Merge pull request #3609 from peaklabs-dev/fix-2185
Fix: Remove memlock from dragonfly DB as it caused problems for some users
2024-09-30 12:18:38 +02:00
Andras Bacsai
f46fd8872a Merge pull request #3608 from peaklabs-dev/add-debugbar
Feat: Add debug bar for better debugging
2024-09-30 12:15:04 +02:00
Andras Bacsai
b6b4d93658 fix: compose based terminal 2024-09-30 11:58:28 +02:00
Andras Bacsai
8385b7dfe8 fix: handle edge case when build variables and env variables are in different format 2024-09-30 11:15:23 +02:00
Andras Bacsai
a660117015 use latest helper in dev 2024-09-30 11:14:53 +02:00
Andras Bacsai
6fe31c26a3 refactor: remove unnecessary code 2024-09-30 11:14:40 +02:00
Andras Bacsai
cccd05f322 chore: Refactor code to improve SSH key handling and storage 2024-09-29 20:12:30 +02:00
MarioZet
1b0e2e1257 Feat. Apply all middlewares from labels to coolify router, instead of only basicauth and redirect 2024-09-29 20:08:39 +02:00
Andras Bacsai
795af8de52 Make sure key is not created with wrong private_key 2024-09-29 20:05:02 +02:00
Jordan Rey
606d46eef0 fix(templates): filebrowser FQDN env variable 2024-09-29 15:36:41 +02:00
Andras Bacsai
56ec0a3004 chore: Update version numbers to 4.0.0-beta.348 2024-09-29 13:27:45 +02:00
Norman
b84576ce87 Merge branch 'main' into main 2024-09-28 18:18:47 +03:00
Andras Bacsai
019a8bfaa6 Merge pull request #3606 from coollabsio/next
v4.0.0-beta.347
2024-09-28 11:14:33 +02:00
Andras Bacsai
fe20480fdc fix: proxy 2024-09-28 11:14:14 +02:00
Andras Bacsai
71e4b0f9d6 Refactor server form blade template 2024-09-28 11:12:03 +02:00
Andras Bacsai
bc46b0371d Add private key storage for server validation 2024-09-28 10:20:32 +02:00
liberocks
f5785b1f17 fix: save settings after assigning value 2024-09-28 11:28:48 +07:00
liberocks
2219219906 fix: edit is_build_server_enabled upon creating application on other application type 2024-09-28 11:25:00 +07:00
liberocks
9ec3233c0c feat: allow specify use_build_server when creating/updating an application 2024-09-28 11:11:43 +07:00
Norman
f2a9a04461 refactor: Update search input placeholder in resource index view 2024-09-28 01:14:54 +00:00
Andras Bacsai
7c269bd0bf chore: custom vite envs 2024-09-27 21:07:56 +02:00
peaklabs-dev
b99474ac73 Fix: Remove memlock as it caused problems for some users 2024-09-27 17:38:34 +02:00
Andras Bacsai
fcadb20d58 chore: Update database startup heading title 2024-09-27 17:32:37 +02:00
Andras Bacsai
24733d0670 Merge pull request #3572 from ejscheepers/main
Fixed NEXT_PUBLIC_API_URI in plunk.yaml
2024-09-27 17:32:18 +02:00
Andras Bacsai
d3898ee320 chore: Update database startup heading title 2024-09-27 17:31:48 +02:00
Andras Bacsai
09cd087cd0 chore: Update backup deletion labels to use language files 2024-09-27 17:29:36 +02:00
Andras Bacsai
d75e55111a chore: Update web.php to cast server port as integer 2024-09-27 17:26:27 +02:00
Andras Bacsai
8e6c7eaeda chore: Update API Tokens view to include link to Settings menu 2024-09-27 17:23:36 +02:00
Andras Bacsai
9489a0881f Merge pull request #3542 from peaklabs-dev/fix-dev-volumes
Fix: Volume issues in development
2024-09-27 17:15:39 +02:00
Andras Bacsai
691f606fa0 Merge branch 'next' into fix-dev-volumes 2024-09-27 17:13:02 +02:00
Andras Bacsai
ac60b8cb22 chore: Remove unused .env.development.example file 2024-09-27 17:11:55 +02:00
Andras Bacsai
46ae2a4ae1 update service-template 2024-09-27 17:08:32 +02:00
Andras Bacsai
f0981078ce chore: Update versions.json file 2024-09-27 17:08:04 +02:00
Andras Bacsai
0816169cb6 Merge pull request #3591 from clho40/next
Next
2024-09-27 17:07:45 +02:00
Andras Bacsai
df8c5c6bf2 Merge branch 'next' into next 2024-09-27 17:06:52 +02:00
Andras Bacsai
ea1be05c17 Merge pull request #3594 from peaklabs-dev/lock-closed-issues-and-prs
Feat: GitHub action that locks closed issues, discussions, and PRs
2024-09-27 17:05:37 +02:00
Andras Bacsai
eafba5d115 fix typo 2024-09-27 17:04:36 +02:00
Andras Bacsai
40eec96a1e Merge pull request #3568 from tiennm99/main
[Twenty] (Fix) typo
2024-09-27 17:04:04 +02:00
Andras Bacsai
46268f915f Merge pull request #3585 from peaklabs-dev/close-stale-issues-prs
Feat: GH Action that close stale issues and PRs
2024-09-27 17:03:34 +02:00
peaklabs-dev
c237cea280 Merge branch 'coollabsio:main' into add-debugbar 2024-09-27 16:59:21 +02:00
peaklabs-dev
26f18e25aa Create .gitignore 2024-09-27 16:54:24 +02:00
Andras Bacsai
8d02fb9254 chore: Refactor API Tokens component to use isApiEnabled flag 2024-09-27 16:48:17 +02:00
Andras Bacsai
c52fe571f5 Merge pull request #3576 from peaklabs-dev/fix-api-enabeled
Fix: Disable API by default and do not allow API key creation when API is disabled
2024-09-27 16:46:21 +02:00
Andras Bacsai
4995675745 Merge pull request #3564 from peaklabs-dev/remove-pr-build-gh-action
Fix: Removed some GH Actions and ordered issue templates
2024-09-27 16:44:00 +02:00
Andras Bacsai
65356e9bae fixes 2024-09-27 16:43:07 +02:00
Andras Bacsai
6726964f18 Merge pull request #3545 from peaklabs-dev/improve-cleanup
Feat: Improve Docker cleanup
2024-09-27 16:41:03 +02:00
Andras Bacsai
9a766aedc1 Merge branch 'next' into improve-cleanup 2024-09-27 16:40:48 +02:00
Andras Bacsai
96b8ddf664 chore: Add autocomplete attribute to input fields 2024-09-27 16:32:03 +02:00
Andras Bacsai
8adf4051fd refactor: Update delete server confirmation modal buttons 2024-09-27 15:45:59 +02:00
Andras Bacsai
dedf2cf87b fix: proxy fixes 2024-09-27 15:36:51 +02:00
Andras Bacsai
72e12aaf5c feat: Add ContainerStatusTypes enum for managing container status 2024-09-27 15:27:09 +02:00
Andras Bacsai
6c78580f1f refactor: Improve start proxy script to handle existing containers gracefully 2024-09-27 15:27:05 +02:00
Andras Bacsai
75c8f6c94a Update version numbers to 4.0.0-beta.347 2024-09-27 14:45:07 +02:00
Andras Bacsai
55847d90c0 Merge pull request #3518 from coollabsio/improve-seeders
Refactor: Improve seeders
2024-09-27 14:43:56 +02:00
Andras Bacsai
b374addc37 Merge pull request #3490 from peaklabs-dev/improve-release.md
Feat: Improve release.md
2024-09-27 14:40:08 +02:00
peaklabs-dev
5541c737b7 Remove all deleted seeders 2024-09-27 12:24:58 +02:00
peaklabs-dev
39015e7d6d Fix: Typo in install script 2024-09-27 12:17:54 +02:00
Andras Bacsai
4c3beb6715 Merge pull request #3586 from coollabsio/next
v4.0.0-beta.346
2024-09-27 09:53:25 +02:00
Andras Bacsai
a807016cab Merge pull request #3574 from LEstradioto/fix-enhance-terminal
Terminal fixes
2024-09-27 09:49:31 +02:00
Andras Bacsai
2c2173e773 refactor: Update environment variable name for uptime-kuma service 2024-09-27 08:48:17 +02:00
peaklabs-dev
2364fac240 Update lock-closed-issues-discussions-and-prs.yml 2024-09-26 19:10:40 +02:00
Ho Chia Leung
68c065baa0 Merge pull request #1 from clho40/clho40-logto-entrypoint-fixes
Clho40 logto entrypoint fixes
2024-09-26 16:43:29 +02:00
Ho Chia Leung
bfc4474815 merged the latest entrypoint configuration from Logto's source
The previous entrypoint configuration throws error error: type "application_type" does not exist
2024-09-26 16:41:38 +02:00
peaklabs-dev
0e31c02f9e Update lock-closed-issues-discussions-and-prs.yml 2024-09-26 14:27:58 +02:00
peaklabs-dev
6ee80c3ea7 Update lock-closed-issues-discussions-and-prs.yml 2024-09-26 14:20:21 +02:00
peaklabs-dev
b9d24913e8 Create lock-closed-issues-discussions-and-prs.yml 2024-09-26 14:10:16 +02:00
Andras Bacsai
9a1c9124ae refactor: Add support for IPv6 addresses in sslip function 2024-09-26 13:47:13 +02:00
Andras Bacsai
306c4dcbc5 chore: Update version numbers to 4.0.0-beta.346 2024-09-26 13:47:07 +02:00
peaklabs-dev
ed7e4360c8 Merge branch 'close-stale-issues-prs' of https://github.com/peaklabs-dev/coolify into close-stale-issues-prs 2024-09-26 13:39:42 +02:00
peaklabs-dev
f02db282ca Update manage-stale-issues-and-prs.yml 2024-09-26 13:39:36 +02:00
Andras Bacsai
3535dbb98f Merge pull request #3583 from coollabsio/next
v4.0.0-beta.345
2024-09-26 13:21:16 +02:00
Andras Bacsai
84b2af53d8 refactor: Fix modal input closeOutside prop in configuration.blade.php 2024-09-26 13:20:06 +02:00
Andras Bacsai
ba70451765 refactor: Update install.sh script to remove redirection of upgrade output to /dev/null 2024-09-26 13:07:06 +02:00
Andras Bacsai
f3ec4ca4a3 refactor: Improve modal confirmation titles and button labels 2024-09-26 13:07:01 +02:00
Andras Bacsai
174923de98 refactor: Update ProductionSeeder to fix issue with coolify_key assignment 2024-09-26 13:06:56 +02:00
Andras Bacsai
68ab8dc14c refactor: Add localhost as Server if it doesn't exist and not in cloud environment 2024-09-26 12:31:39 +02:00
Andras Bacsai
b218356f2d chore: Update version numbers to 4.0.0-beta.345 2024-09-26 12:31:36 +02:00
Andras Bacsai
e83aecebc3 Merge pull request #3559 from coollabsio/next
v4.0.0-beta.344
2024-09-26 12:22:48 +02:00
Andras Bacsai
0bb1f57ea7 fix: deploy key based deployments 2024-09-26 12:19:49 +02:00
peaklabs-dev
49144552b3 Merge branch 'coollabsio:main' into close-stale-issues-prs 2024-09-26 11:47:40 +02:00
peaklabs-dev
111e9ba3a3 Fix: Disable API by default 2024-09-26 10:45:18 +02:00
Andras Bacsai
d006edc485 refactor: Add localhost as Server if it doesn't exist and not in cloud environment 2024-09-26 10:37:02 +02:00
Andras Bacsai
aa28c99827 refactor: Update OS_TYPE for Asahi Linux in install.sh script 2024-09-26 10:36:59 +02:00
peaklabs-dev
47920f1191 Feat: If API is disabeled do not show API token creation stuff 2024-09-26 10:32:12 +02:00
Luan Estradioto
6bd8583eab - resize check to int
- modularize, tree-shake terminal, idempotency on navigations
2024-09-25 22:14:05 -03:00
EJS00102
92dbd44c8c Fixed NEXT_PUBLIC_API_URI in plunk.yaml 2024-09-26 00:01:38 +02:00
Katja Lutz
2cf0f4facc chore: add Nitropage service template and logo 2024-09-25 21:23:23 +02:00
tiennm99
be6caf8d76 [Twenty] (Fix) typo 2024-09-25 23:41:04 +07:00
peaklabs-dev
6cf5a2802b ordered the issue templates 2024-09-25 13:28:33 +02:00
peaklabs-dev
9c756ad6c5 Delete docker-image.yml 2024-09-25 13:28:17 +02:00
peaklabs-dev
20de0c56a4 Delete fix-php-code-style-issues 2024-09-25 13:28:13 +02:00
peaklabs-dev
0058f9aa13 Delete pr-build.yml 2024-09-25 13:28:08 +02:00
Andras Bacsai
567bbe9d0b chore: Update version numbers to 4.0.0-beta.344 2024-09-25 10:27:51 +02:00
Andras Bacsai
59d2c9748a fix: make sure to reload window if app status changes 2024-09-25 10:27:23 +02:00
Andras Bacsai
bd2e1ad9fe refactor: Fix typo in execute-container-command.blade.php 2024-09-25 10:25:35 +02:00
Andras Bacsai
43df918e43 Merge pull request #3550 from coollabsio/next
v4.0.0-beta.343
2024-09-25 09:29:54 +02:00
Andras Bacsai
1a8d15390d refactor: Update confirmation label in danger.blade.php template 2024-09-25 09:27:17 +02:00
Andras Bacsai
4af6caa79c refactor: Update checkbox component to support full width option 2024-09-25 09:16:28 +02:00
peaklabs-dev
dfd6fdf0a8 Merge pull request #3554 from coollabsio/next
Next
2024-09-25 00:00:49 +02:00
peaklabs-dev
b0635327a1 Revert "Fix: Typo"
This reverts commit ca21545d7b.
2024-09-25 00:00:26 +02:00
Andras Bacsai
8e91d958be refactor: Improve layout and add checkbox for task enablement in scheduled task form 2024-09-24 21:29:55 +02:00
Andras Bacsai
17d55630d5 refactor: Group and sort fields in StackForm by service name and password status 2024-09-24 21:17:07 +02:00
Andras Bacsai
70dfa101ef refactor: Improve label positioning in input and checkbox components 2024-09-24 21:04:04 +02:00
Andras Bacsai
d6b4e33db3 fix: exited services statuses 2024-09-24 20:40:41 +02:00
Andras Bacsai
a9670bd6eb refactor: Remove commented out code and improve environment variable handling in newParser function 2024-09-24 18:38:35 +02:00
Andras Bacsai
02165c2b9f chore: Update version numbers to 4.0.0-beta.343 2024-09-24 18:22:06 +02:00
Andras Bacsai
afbdd2eb06 fix: parser 2024-09-24 18:21:31 +02:00
Andras Bacsai
b0e6014e8f Merge pull request #3546 from coollabsio/dependabot/npm_and_yarn/rollup-3.29.5
chore(deps): bump rollup from 3.29.4 to 3.29.5
2024-09-24 14:34:17 +02:00
dependabot[bot]
0f13af2eca chore(deps): bump rollup from 3.29.4 to 3.29.5
Bumps [rollup](https://github.com/rollup/rollup) from 3.29.4 to 3.29.5.
- [Release notes](https://github.com/rollup/rollup/releases)
- [Changelog](https://github.com/rollup/rollup/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rollup/rollup/compare/v3.29.4...v3.29.5)

---
updated-dependencies:
- dependency-name: rollup
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-09-24 12:27:43 +00:00
Andras Bacsai
d4d9268f12 Merge pull request #3506 from coollabsio/next
v4.0.0-beta.342
2024-09-24 14:26:04 +02:00
peaklabs-dev
f9dbc30812 Feat: Use the new confirmation flow 2024-09-24 13:06:03 +02:00
Andras Bacsai
62459f9a95 refactor: Remove unused code in DatabaseBackupStatusJob and PopulateSshKeysDirectorySeeder 2024-09-24 11:57:13 +02:00
Andras Bacsai
eb80a7e2f7 chore: Update Docker commands to start proxy 2024-09-24 10:53:12 +02:00
Andras Bacsai
57d8930f9e chore: Update cleanup command to use Redis instead of queue 2024-09-23 23:48:12 +02:00
Andras Bacsai
688c27c901 fix: cloudflare tunnel configuration, ui, etc 2024-09-23 23:18:23 +02:00
Andras Bacsai
480ae3de8a Refactor Server.php to improve default 404 redirect setup 2024-09-23 22:57:24 +02:00
Andras Bacsai
21a5b4ce80 chore: Refactor pre-commit hook to improve performance and readability 2024-09-23 22:16:28 +02:00
Andras Bacsai
12a0d71e47 Merge pull request #3543 from peaklabs-dev/cf-production-ready
Feat: Make cloudflare production ready
2024-09-23 21:53:23 +02:00
peaklabs-dev
5ed7ae3d3e remove ray 2024-09-23 21:45:59 +02:00
Andras Bacsai
6dd3adba4d refactor: Simplify SSH key synchronization logic 2024-09-23 21:16:25 +02:00
Andras Bacsai
08d58eb8f8 chore: Update CONTRIBUTING.md with troubleshooting note about database migrations 2024-09-23 20:55:20 +02:00
Andras Bacsai
46a7937761 test 2024-09-23 20:54:56 +02:00
Andras Bacsai
13a5536cff test 2024-09-23 20:54:18 +02:00
Andras Bacsai
2381706465 chore: Refactor pre-commit hook to improve performance and readability 2024-09-23 20:52:13 +02:00
Andras Bacsai
7a0f054f1a test 2024-09-23 20:49:26 +02:00
Andras Bacsai
00e1464185 chore: Add modified files to the commit 2024-09-23 20:48:57 +02:00
Andras Bacsai
fac4a8aaf9 hooks? 2024-09-23 20:45:42 +02:00
Andras Bacsai
2841675691 refactor 2024-09-23 20:31:50 +02:00
Andras Bacsai
573e5c4913 refactor 2024-09-23 20:29:22 +02:00
peaklabs-dev
6934a746f7 Fix: Make helper text more clean to use a FQDN and not an URL 2024-09-23 19:57:42 +02:00
Andras Bacsai
b570ccd7d3 format 2024-09-23 19:51:31 +02:00
Andras Bacsai
68efd4b553 fix: migrations 2024-09-23 19:50:26 +02:00
Andras Bacsai
e00ec2f75b chore: Remove unused migration file for populating SSH keys and clearing mux directory 2024-09-23 19:46:45 +02:00
peaklabs-dev
1bb192f3e2 Fix: Cloudflare tunnel 2024-09-23 19:23:46 +02:00
peaklabs-dev
e039f183da Merge pull request #16 from coollabsio/next
Next
2024-09-23 18:50:19 +02:00
peaklabs-dev
7aab44645f Merge branch 'cf-production-ready' into next 2024-09-23 18:50:08 +02:00
peaklabs-dev
7c52d7ef9e Update CONTRIBUTING.md 2024-09-23 17:33:06 +02:00
peaklabs-dev
83c6dcb063 Fix: Persist DBs, services and so on stored in data/coolify 2024-09-23 17:31:20 +02:00
peaklabs-dev
6bb21da9f3 Update CONTRIBUTING.md 2024-09-23 17:20:31 +02:00
peaklabs-dev
5a46ef42c8 Feat: clean new volume name for dev volumes 2024-09-23 17:03:10 +02:00
Andras Bacsai
04e504bb8b chore: Refactor DockerCleanupJob to remove unused middleware and uniqueId method 2024-09-23 12:10:46 +02:00
Andras Bacsai
960f970822 chore: Remove unused middleware and uniqueId method in DockerCleanupJob 2024-09-23 12:03:14 +02:00
Andras Bacsai
ae62781c6a fix: cloudflared service 2024-09-23 11:36:57 +02:00
Andras Bacsai
b42c15b2e5 Merge pull request #3483 from djsisson/update-CF-Tunnel-template
Update cloudflared.yaml
2024-09-23 11:36:52 +02:00
Andras Bacsai
c77cc45e0d fix: Logto service 2024-09-23 11:33:53 +02:00
Andras Bacsai
310708f1b6 Merge pull request #3480 from JustMrMendez/patch-1
FIXES: #3322 deploy DB alterations before starting the service
2024-09-23 11:33:55 +02:00
Andras Bacsai
8386aaf95b Merge pull request #3481 from peaklabs-dev/new-pull-request-template
Feat: New pull request template
2024-09-23 11:32:24 +02:00
Andras Bacsai
6d8d91802b chore: Update install.sh version to 1.6 2024-09-23 11:30:57 +02:00
Andras Bacsai
c0a1f15d34 Merge pull request #3472 from disjukr/asahi-linux
Add support to install.sh for Asahi Linux
2024-09-23 11:29:26 +02:00
Andras Bacsai
0222aa137d feat(api): add endpoint to execute a command 2024-09-23 11:09:14 +02:00
Andras Bacsai
4d36bc4742 Merge pull request #3535 from Luca-Sordetti/main
feat(api): add an endpoint to execute a command
2024-09-23 10:53:28 +02:00
Andras Bacsai
6639379ba6 Merge pull request #3522 from InfiniBrains/main
Add hint to "build variable" check in the enviroment variable tab. Remember the user what should be doing in order to make it work.
2024-09-23 10:49:59 +02:00
Andras Bacsai
d60ff107c4 Merge pull request #3539 from peaklabs-dev/fix-dev-error
Fix: Ray error on development
2024-09-23 10:49:39 +02:00
Andras Bacsai
a468ce77f0 refactor: Update shared.php to include predefined ports for services 2024-09-23 10:46:34 +02:00
Andras Bacsai
1fb0ee0db5 refactor: Add Postiz service to compose file (disabled for now) 2024-09-23 10:46:30 +02:00
Andras Bacsai
9281dda03f refactor: Fix typo in subscription URLs 2024-09-23 10:46:19 +02:00
peaklabs-dev
d3485cea8d Update pull_request_template.md 2024-09-23 10:27:48 +02:00
peaklabs-dev
92772f9132 Merge branch 'next' into fix-dev-error 2024-09-23 10:20:26 +02:00
Andras Bacsai
6f8c4a4ce4 refactor: Update select.blade.php to improve trademarks policy display 2024-09-23 09:44:33 +02:00
Andras Bacsai
85ab772acd refactor: Update select.blade.php to improve trademarks policy display 2024-09-23 09:43:17 +02:00
Andras Bacsai
6336125ca2 Merge pull request #3516 from nathanialhenniges/main
Added link for more services to the coolfiy docs
2024-09-23 09:42:49 +02:00
Andras Bacsai
341c7e3598 refactor: Update environment variables for services in compose files 2024-09-23 09:26:53 +02:00
Andras Bacsai
ff9b68b450 refactor: Remove unnecessary code in shared.php file 2024-09-23 09:26:49 +02:00
Andras Bacsai
a072a00926 Merge pull request #3525 from gabrielcossette/fix_ghost_template_domain
Fix Ghost Template domain generation
2024-09-23 09:05:34 +02:00
Andras Bacsai
b84d39ba56 refactor: Update confirmation button text for deletion actions 2024-09-23 08:58:04 +02:00
peaklabs-dev
164a213ab1 Fix: force helper image removal 2024-09-22 20:36:41 +02:00
peaklabs-dev
696acb71fe Improve helper text for all cleanup settings 2024-09-22 20:26:45 +02:00
peaklabs-dev
ff5e445b43 Feat: Manual cleanup button and unused volumes and network deletion 2024-09-22 20:02:51 +02:00
Luca-Sordetti
4e167dc539 feat(api): add an endpoint to execute a command 2024-09-22 12:38:25 +02:00
peaklabs-dev
76655a7c7d Remove dev .env form nightly as there is also no dev compose in nightly 2024-09-21 01:31:17 +02:00
peaklabs-dev
a26c1f0052 Update CONTRIBUTING.md 2024-09-21 01:11:03 +02:00
peaklabs-dev
cb4f7755c3 Update CONTRIBUTING.md 2024-09-21 01:08:28 +02:00
peaklabs-dev
b7139f8af8 remove clockwork 2024-09-21 00:20:16 +02:00
peaklabs-dev
a5b3fef1d8 Fix: ray error because port is not uncommented 2024-09-21 00:20:01 +02:00
peaklabs-dev
fca64d6726 Fix: volumes on development environment 2024-09-20 23:12:08 +02:00
Gabriel Cossette
b9a026b488 Fix Ghost Template domain generation
Signed-off-by: Gabriel Cossette <gabriel.cossette@mapgears.com>
2024-09-20 14:29:11 -06:00
Alexandre Tolstenko Nogueira
a4d0f1da9e Add hint to "build variable" check in the enviroment variable tab. remember the user what should be doing in order to make it work. #3477 2024-09-20 14:12:15 -04:00
Andras Bacsai
eb9bbf3eda refactor: Improve attribute sanitization in Server model 2024-09-20 18:14:52 +02:00
Andras Bacsai
be42f15711 refactor: Update ServerSeeder and PopulateSshKeysDirectorySeeder 2024-09-20 17:28:55 +02:00
peaklabs-dev
768b39dd25 Revert "remove team seeders"
This reverts commit 000a348c90.
2024-09-20 15:45:18 +02:00
peaklabs-dev
000a348c90 remove team seeders 2024-09-20 15:42:24 +02:00
peaklabs-dev
56f7eb769d Remove commented out seeders 2024-09-20 15:42:06 +02:00
peaklabs-dev
cc77775f20 Remove not needed seeders to make management simpler 2024-09-20 15:32:56 +02:00
peaklabs-dev
ca21545d7b Fix: Typo 2024-09-20 15:01:34 +02:00
Andras Bacsai
fa375e2fd8 refactor: Update install.sh script to check if coolify-db volume exists before generating SSH key 2024-09-20 14:39:58 +02:00
Andras Bacsai
760cf8aeb5 refactor: Update PrivateKey model to use ownedByCurrentTeam() scope for cleanupUnusedKeys() 2024-09-20 13:05:51 +02:00
Andras Bacsai
f9238ce263 Merge pull request #3509 from coollabsio/delete-unused-ssh-keys
Feat: Delete unused ssh keys button
2024-09-20 13:00:54 +02:00
Andras Bacsai
c0898f0568 refactor: Remove unnecessary code in PrivateKey model 2024-09-20 12:51:02 +02:00
Andras Bacsai
5b00b66f24 refactor: Update PrivateKey model to improve code readability and maintainability 2024-09-20 12:27:55 +02:00
Andras Bacsai
b81f9114d9 chore: Update ProductionSeeder to call OauthSettingSeeder and PopulateSshKeysDirectorySeeder 2024-09-20 11:34:13 +02:00
Andras Bacsai
be8573c828 chore: Update SSH key generation in install.sh script 2024-09-20 11:04:26 +02:00
Andras Bacsai
f1881d5c35 refactor: Update CleanupHelperContainersJob to use more efficient Docker command 2024-09-20 10:08:37 +02:00
Nathanial Henniges
699e76637b Added link for more services to the coolfiy docs 2024-09-20 03:02:31 -05:00
peaklabs-dev
dbc723089b Feat: Delete unused private keys button 2024-09-19 19:27:25 +02:00
Andras Bacsai
fc6f5d82db chore: Add SSH key for localhost in ProductionSeeder 2024-09-19 17:26:59 +02:00
Andras Bacsai
1815c9dccf fix: store original root key in the original location 2024-09-19 16:35:10 +02:00
Andras Bacsai
7d54fe9c18 chore: Update remove-labels-and-assignees-on-close.yml 2024-09-19 13:26:27 +02:00
Andras Bacsai
e9fbb7d2b0 fix: coolify-db should not be in the managed resources 2024-09-19 13:23:48 +02:00
Andras Bacsai
2d94ebf7f1 Merge branch 'next' of github.com:coollabsio/coolify into next 2024-09-19 13:16:10 +02:00
Andras Bacsai
c874261c5b feat: Add nullable constraint to 'fingerprint' column in private_keys table 2024-09-19 13:16:08 +02:00
Andras Bacsai
1c5fd8d668 refactor: Update getAJoke function to use HTTPS for API request 2024-09-19 13:16:05 +02:00
Andras Bacsai
874e04e844 Merge pull request #3505 from peaklabs-dev/main
Fix: Update remove-labels-and-assignees-on-close.yml for PRs
2024-09-19 13:01:40 +02:00
peaklabs-dev
c46715db3c Merge branch 'main' of https://github.com/peaklabs-dev/coolify 2024-09-19 13:01:19 +02:00
peaklabs-dev
aa0fe922ea Update remove-labels-and-assignees-on-close.yml 2024-09-19 13:01:07 +02:00
peaklabs-dev
60e9fcc202 Update remove-labels-and-assignees-on-close.yml 2024-09-19 12:55:20 +02:00
Andras Bacsai
91485b5d4d refactor: Update getAJoke function to exclude offensive jokes 2024-09-19 12:50:51 +02:00
Andras Bacsai
6ec1b9b3f5 disable remove labels for issues 2024-09-19 12:47:35 +02:00
Andras Bacsai
240352f4b2 Merge pull request #3504 from coollabsio/fix-ssh-keys
Fix ssh keys
2024-09-19 12:44:56 +02:00
Andras Bacsai
cfd9ae9817 Merge pull request #3454 from peaklabs-dev/fix-ssh-keys
Fix: SSH Keys, Multiplexing issues and a lot of other small things for dev and prod
2024-09-19 12:44:23 +02:00
Andras Bacsai
f65789bdbb fix: proxy status 2024-09-19 12:32:56 +02:00
Andras Bacsai
9518040d23 refactor: Remove CleanupSshKeysJob from schedule in Kernel.php 2024-09-19 12:06:56 +02:00
Andras Bacsai
631b4e6438 Merge branch 'next' into fix-ssh-keys 2024-09-19 11:45:12 +02:00
Andras Bacsai
d47bd047bf fixes 2024-09-19 11:24:21 +02:00
Andras Bacsai
a65b62332b refactor: Remove commented out code in Navbar.php 2024-09-19 10:57:34 +02:00
Andras Bacsai
eb10bbb888 Merge pull request #3502 from coollabsio/fix-#2546-deletion-issues
Fixes
2024-09-19 10:41:57 +02:00
Andras Bacsai
4b02debf97 Merge pull request #3024 from peaklabs-dev/fix-#2546-deletion-issues
Feat: Fix all deletion issues, add graceful shutdown to everything, new delete confirmation process
2024-09-19 10:40:27 +02:00
Andras Bacsai
430fdcf2e9 chore: Update version numbers to 4.0.0-beta.342 2024-09-19 10:35:54 +02:00
Andras Bacsai
636de24b6c Merge pull request #3501 from coollabsio/#2546
refactor: Update Docker cleanup label in Heading.php and Navbar.php
2024-09-19 10:32:09 +02:00
Andras Bacsai
2e3267ee94 Merge branch 'fix-#2546-deletion-issues' into #2546 2024-09-19 10:32:02 +02:00
Andras Bacsai
98e744e808 refactor: Update Docker cleanup label in Heading.php and Navbar.php 2024-09-19 10:27:44 +02:00
Andras Bacsai
532f5e351e fixes 2024-09-18 21:24:42 +02:00
Andras Bacsai
182087cf1b a few changes here and there 2024-09-18 21:18:47 +02:00
peaklabs-dev
0494f9a7e5 Merge branch 'coollabsio:main' into service-getoutline 2024-09-18 20:44:53 +02:00
peaklabs-dev
6676c6bd64 Merge branch 'coollabsio:main' into new-pull-request-template 2024-09-18 20:44:42 +02:00
peaklabs-dev
22326ec0b4 Merge branch 'coollabsio:main' into improve-release.md 2024-09-18 20:44:24 +02:00
peaklabs-dev
8153e2f63b Merge branch 'coollabsio:main' into fix-ssh-keys 2024-09-18 20:43:59 +02:00
peaklabs-dev
b0793c879a Merge branch 'coollabsio:main' into close-stale-issues-prs 2024-09-18 20:43:01 +02:00
peaklabs-dev
dce8555aa7 Merge branch 'coollabsio:main' into add-debugbar 2024-09-18 20:42:29 +02:00
peaklabs-dev
35857de697 Merge branch 'coollabsio:main' into cf-production-ready 2024-09-18 20:42:18 +02:00
peaklabs-dev
cb177dae58 Update RELEASE.md 2024-09-18 18:36:04 +02:00
peaklabs-dev
4e8708051d Update RELEASE.md 2024-09-18 18:34:54 +02:00
peaklabs-dev
5b27eef984 Update RELEASE.md 2024-09-18 18:28:21 +02:00
peaklabs-dev
d1f28b42e5 Update RELEASE.md 2024-09-18 18:21:08 +02:00
peaklabs-dev
513ca6f57d Update RELEASE.md 2024-09-18 18:09:03 +02:00
Andras Bacsai
5ec45d547a Merge branch 'next' into fix-#2546-deletion-issues 2024-09-18 18:05:06 +02:00
peaklabs-dev
4aed40fb65 Update RELEASE.md 2024-09-18 17:15:39 +02:00
Darren Sisson
d2cf53578a Update cloudflared.yaml
add network mode host to template, otherwise cloudflared has no access to localhost
2024-09-18 16:09:24 +01:00
Mr. Mendez
1fa42ec82d FIXES: #3322 deploy DB alterations before updating
FIXES: #3322 

[Bug]: logto stop working after pulling latest image #3322
2024-09-18 08:59:02 -04:00
Andras Bacsai
e42c7e258c Merge pull request #3479 from coollabsio/next
v4.0.0-beta.341
2024-09-18 14:45:00 +02:00
Andras Bacsai
2c210abf57 Merge pull request #3478 from dennisblume/caddy-terminal-fix
Fix WebSocket connection for Terminal page when using Caddy
2024-09-18 14:36:48 +02:00
Dennis Blume
98ba7ac28c Fix WebSocket connection for Terminal page when using Caddy 2024-09-18 13:33:38 +02:00
Andras Bacsai
5772f2c3d9 feat: Add buddy logo 2024-09-18 13:18:31 +02:00
Andras Bacsai
cb9c569d4b Merge pull request #3470 from Skeyelab/add-buddy-svg
featu update: adding budge logo
2024-09-18 13:18:10 +02:00
Andras Bacsai
5616e588e9 Merge pull request #3473 from coollabsio/dependabot/npm_and_yarn/vite-4.5.5
chore(deps-dev): bump vite from 4.5.3 to 4.5.5
2024-09-18 12:56:34 +02:00
Andras Bacsai
40e844fab4 refactor: Remove unnecessary console.log statements in terminal.blade.php 2024-09-18 12:54:31 +02:00
Andras Bacsai
2e56edd939 refactor: Update WebSocket connection initialization in terminal.blade.php 2024-09-18 09:51:20 +02:00
Andras Bacsai
8179a5c6a3 feat: custom terminal host 2024-09-18 09:43:47 +02:00
Andras Bacsai
d0518153fb fix: generated fqdn for SERVICE_FQDN_APP_3000 magic envs 2024-09-18 09:21:57 +02:00
dependabot[bot]
29236bf101 chore(deps-dev): bump vite from 4.5.3 to 4.5.5
Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) from 4.5.3 to 4.5.5.
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/v4.5.5/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/v4.5.5/packages/vite)

---
updated-dependencies:
- dependency-name: vite
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-09-18 07:13:17 +00:00
Andras Bacsai
2d306d56ab chore: Update version numbers to 4.0.0-beta.341 2024-09-18 09:13:04 +02:00
JongChan Choi
e5768999e4 chore: Update install.sh to support Asahi Linux 2024-09-18 13:22:07 +09:00
Eric Dahl
b076db2eed update 2024-09-17 18:45:41 -04:00
Eric Dahl
3534424dc8 adding budge logo 2024-09-17 18:41:26 -04:00
peaklabs-dev
d6f498e6bb Update RELEASE.md 2024-09-17 23:05:03 +02:00
peaklabs-dev
3e0a5191b9 Update RELEASE.md 2024-09-17 23:01:56 +02:00
peaklabs-dev
28cde9fd50 Update RELEASE.md 2024-09-17 22:52:47 +02:00
peaklabs-dev
e415a99f71 Update RELEASE.md 2024-09-17 22:28:00 +02:00
peaklabs-dev
3b6c3609c3 Update pull_request_template.md 2024-09-17 22:11:30 +02:00
peaklabs-dev
95a97cf9cd Update pull_request_template.md 2024-09-17 22:09:00 +02:00
peaklabs-dev
7b33ef705b Update pull_request_template.md 2024-09-17 22:07:19 +02:00
peaklabs-dev
39449584ac Update pull_request_template.md 2024-09-17 22:04:19 +02:00
peaklabs-dev
19458e7445 Update pull_request_template.md 2024-09-17 21:47:19 +02:00
Andras Bacsai
2d9c728a64 Merge pull request #3468 from coollabsio/next
v4.0.0-beta.340
2024-09-17 17:31:39 +02:00
Andras Bacsai
12a8e9b0e1 fix: only update helper image in DB 2024-09-17 17:29:42 +02:00
Andras Bacsai
649cc2dac2 chore: Update version numbers to 4.0.0-beta.340 2024-09-17 17:25:38 +02:00
Andras Bacsai
c169f1f64b Merge pull request #3467 from coollabsio/next
v4.0.0-beta.339
2024-09-17 17:20:27 +02:00
Andras Bacsai
5ecf31d1fc refactor: Remove unnecessary code in Terminal.blade.php 2024-09-17 17:20:03 +02:00
Andras Bacsai
e937d30545 fix: move terminal to separate view on services 2024-09-17 17:15:34 +02:00
peaklabs-dev
bf48b33e64 Update pull_request_template.md 2024-09-17 17:14:15 +02:00
Andras Bacsai
595a2414b1 fix: if you exit a container manually, it should close the underlying tty as well 2024-09-17 16:48:58 +02:00
Andras Bacsai
07ed726c88 refactor: Remove unnecessary code in Terminal.php 2024-09-17 16:48:30 +02:00
Andras Bacsai
d373815f98 refactor: Add authorization check in ExecuteContainerCommand mount method 2024-09-17 16:28:28 +02:00
peaklabs-dev
d9181bd00b Fix: Multiplexing do not write file manually 2024-09-17 16:22:53 +02:00
peaklabs-dev
d13e2c0865 Fix: Clear mux directory 2024-09-17 15:57:57 +02:00
peaklabs-dev
42ff7b19a4 Fix: Few multiplexing things 2024-09-17 15:54:22 +02:00
peaklabs-dev
283fcc87a5 Fix: SSH algorhytm text 2024-09-17 15:31:44 +02:00
peaklabs-dev
ea3501ada6 Fix: SSH Multiplexing for Jobs 2024-09-17 15:31:05 +02:00
peaklabs-dev
175f4b9ae1 use shared functions when possible 2024-09-17 14:47:02 +02:00
peaklabs-dev
2bc74c75e1 Remove duplicated code 2024-09-17 14:43:02 +02:00
peaklabs-dev
4ac2758d70 Update .env.development.example 2024-09-17 14:35:08 +02:00
peaklabs-dev
bdc0fc87f0 Fix: UI bug, do not write ssh key to disk in server dialog 2024-09-17 14:33:24 +02:00
peaklabs-dev
845d32c94c Fix: Do not delete SSH Key from disk during server validation error 2024-09-17 14:33:04 +02:00
peaklabs-dev
6a6b947fba Fix: Make sure in use private keys are not deleted 2024-09-17 14:32:44 +02:00
peaklabs-dev
2ec66fd146 FIx: Server ID 0 2024-09-17 14:08:34 +02:00
peaklabs-dev
ccbbfd8908 Fix: ID issues on dev seeders 2024-09-17 14:03:31 +02:00
peaklabs-dev
43895419ff Remove unused code 2024-09-17 13:45:05 +02:00
peaklabs-dev
1c78067386 Feat: Add ssh key fingerprint and generate one for existing keys 2024-09-17 13:20:48 +02:00
peaklabs-dev
871d09bd96 Feat: Move more functions to the PrivateKey Model 2024-09-17 13:20:27 +02:00
peaklabs-dev
2d8bda4fa6 Fix: Private key with ID 2 on dev 2024-09-17 13:06:50 +02:00
peaklabs-dev
95070ab48d Feat: SSH Key cleanup job 2024-09-17 12:57:06 +02:00
Andras Bacsai
8bb8a7faa3 Merge pull request #3464 from peaklabs-dev/remove-labels-assinges-on-close
Feat: GitHub action that removes labels and assignees on close
2024-09-17 12:54:36 +02:00
Andras Bacsai
428c40aab5 chore: Update version numbers to 4.0.0-beta.339 2024-09-17 12:54:23 +02:00
peaklabs-dev
52c4994d44 Feat: remove unused code form multiplexing 2024-09-17 12:44:59 +02:00
Andras Bacsai
6f578855a0 Merge pull request #3463 from coollabsio/next
v4.0.0-beta.388
2024-09-17 12:38:50 +02:00
Andras Bacsai
8967315c49 refactor: terminal / run command 2024-09-17 12:29:36 +02:00
Andras Bacsai
162fb7bfc5 fix: refactor run-command 2024-09-17 12:27:20 +02:00
peaklabs-dev
144508218e Fix: SSH multiplexing 2024-09-17 12:26:11 +02:00
Andras Bacsai
4bdb5c9030 chore: nightly - Update soketi image to version 1.0.1 and versions.json to reflect latest version of realtime container 2024-09-17 12:08:09 +02:00
Andras Bacsai
a2ea8814cf chore: Update soketi image to version 1.0.1 2024-09-17 12:00:57 +02:00
Andras Bacsai
cbc2f1f015 chore: Update versions.json to reflect latest version of realtime container 2024-09-17 11:58:28 +02:00
Andras Bacsai
35b9b7fdf2 fix/feat: able to open terminal to any containers 2024-09-17 11:54:25 +02:00
Andras Bacsai
d92819ab60 fix: Handle WebSocket connection close in terminal.blade.php 2024-09-17 11:30:46 +02:00
Andras Bacsai
ea877f3623 Update version numbers to 4.0.0-beta.338 2024-09-17 11:30:37 +02:00
Andras Bacsai
5818c9cf6b chore: Add validation to prevent selecting 'default' server or container in RunCommand.php 2024-09-17 11:30:29 +02:00
peaklabs-dev
f9375f91ec Feat: Create a Multiplexing Helper 2024-09-16 22:33:43 +02:00
peaklabs-dev
86722939cd Fix. Remove write to SSH key on every remote command execution 2024-09-16 21:34:27 +02:00
peaklabs-dev
70b757df5b remove old function 2024-09-16 19:53:45 +02:00
peaklabs-dev
451272bf11 Fix: Use new function names and logic everywhere 2024-09-16 19:52:55 +02:00
peaklabs-dev
a68fbefadb Fix: Populate SSH keys in dev 2024-09-16 19:34:46 +02:00
peaklabs-dev
b79b4015d7 Feat: Populate SSH key folder 2024-09-16 19:08:15 +02:00
peaklabs-dev
0bfdc1c531 Feat: Store all keys on disk by default 2024-09-16 18:45:08 +02:00
peaklabs-dev
b09017ea46 Feat: new ssh key file name on disk 2024-09-16 18:11:37 +02:00
peaklabs-dev
95fcf38d45 Feat: Add is_sftp and is_server_ssh_key coloums 2024-09-16 18:11:16 +02:00
peaklabs-dev
54c03fae41 Remove ssh key fingerprint as we can just us uuid 2024-09-16 18:10:46 +02:00
Andras Bacsai
b2bab451d3 Merge pull request #3457 from coollabsio/next
v4.0.0-beta.337
2024-09-16 17:29:14 +02:00
Andras Bacsai
7b4559c5e6 fix: install script 2024-09-16 17:28:31 +02:00
peaklabs-dev
ba636a95dc Refactor SSH Keys 2024-09-16 17:24:42 +02:00
Andras Bacsai
682b45a2b5 refactor: Improve Docker network connection command in StartService.php 2024-09-16 16:39:16 +02:00
Andras Bacsai
d44e3a1091 chore: Update docker network connection command in ApplicationDeploymentJob.php 2024-09-16 16:38:34 +02:00
Andras Bacsai
d2d56f136b chore: Update Coolify installer and scripts to include a function for fetching programming jokes 2024-09-16 16:35:52 +02:00
Andras Bacsai
9b48a99798 fix: generate https for minio 2024-09-16 16:35:47 +02:00
Andras Bacsai
1322dc9c23 refactor: Remove unnecessary code in ExecuteContainerCommand.php 2024-09-16 15:43:24 +02:00
Andras Bacsai
f71fb7266d fix: terminal 2024-09-16 15:35:44 +02:00
Andras Bacsai
35f23cfb96 chore: Update version numbers to 4.0.0-beta.337 2024-09-16 15:35:38 +02:00
Andras Bacsai
0c4ce55a15 Merge pull request #3456 from coollabsio/next
chore: Fix syntax error in versions.json
2024-09-16 14:44:08 +02:00
Andras Bacsai
77ee80b562 chore: Fix syntax error in versions.json 2024-09-16 14:43:51 +02:00
Andras Bacsai
2621292dc1 Merge pull request #3425 from coollabsio/next
v4.0.0-beta.336
2024-09-16 14:41:39 +02:00
Andras Bacsai
62a4d7055a fix: update Coolify installer 2024-09-16 14:37:19 +02:00
Andras Bacsai
3fd41c0a92 chore: Update helper version to 1.0.1 2024-09-16 14:30:47 +02:00
Andras Bacsai
0e8291cd86 chore: Update coolify nightly version to 4.0.0-beta.335 2024-09-16 14:30:41 +02:00
Andras Bacsai
175b89ced2 revert: databasebackup 2024-09-16 14:15:06 +02:00
peaklabs-dev
3aee8e030e Fix: Encrypt private SSH keys in the DB 2024-09-16 13:17:39 +02:00
peaklabs-dev
02017334e5 Fix: Make sure invalid private keys can not be added 2024-09-16 13:02:48 +02:00
peaklabs-dev
f9b7841572 Feat: Add a fingerprint to every private key on save, create... 2024-09-16 12:54:48 +02:00
peaklabs-dev
7d39a5089c Feat: Add SSH Key fingerprint to DB 2024-09-16 11:53:26 +02:00
Andras Bacsai
2313fed546 fix: add build.sh to debug logs 2024-09-16 11:50:03 +02:00
Andras Bacsai
e1a6c3e776 chore: Refactor terminal component and select form layout 2024-09-16 11:25:20 +02:00
peaklabs-dev
b41a19d94d Update manage-stale-issues-and-prs.yml 2024-09-16 11:20:46 +02:00
peaklabs-dev
7037c779e2 Update remove-labels-and-assignees-on-close.yml 2024-09-16 11:13:56 +02:00
Andras Bacsai
f124a1e60d chore: Update terminal button text and layout in application heading view 2024-09-16 10:56:11 +02:00
peaklabs-dev
4450ee382f Update manage-stale-issues-and-prs.yml 2024-09-16 10:43:31 +02:00
Andras Bacsai
7ebb0a4579 Merge pull request #3444 from Vahor/trigger-helper-update-in-manual-upgrade
Trigger pull helper image job when upgrading coolify
2024-09-16 10:37:40 +02:00
Andras Bacsai
4962c606bc Merge pull request #3452 from peaklabs-dev/new-issue-onboarding
Feat: New issue onboarding
2024-09-16 10:35:39 +02:00
Andras Bacsai
b728d69ab0 Merge pull request #3451 from peaklabs-dev/add-bounty-issues
Feat: Add Bounty issue type
2024-09-16 10:35:18 +02:00
Andras Bacsai
3d6e53602c Merge pull request #3443 from danielqba/main
Fix tooltip
2024-09-16 10:33:42 +02:00
peaklabs-dev
1c6450da24 Feat: Make sure this action is also triggered on PR issue close 2024-09-16 10:23:05 +02:00
Andras Bacsai
15fe5bd864 chore: Update branch restriction for push event in coolify-helper.yml 2024-09-16 10:22:02 +02:00
Andras Bacsai
08e4afbbc4 fix: keep-alive ws connections 2024-09-16 10:20:57 +02:00
peaklabs-dev
06fd7286da Update ENHANCEMENT_BOUNTY.yml 2024-09-16 09:45:49 +02:00
peaklabs-dev
fce1e34fc8 Update BUG_REPORT.yml 2024-09-16 09:34:31 +02:00
Vahor
0739e0f5e7 trigger pull helper image job when upgrading coolify 2024-09-15 14:23:57 +02:00
Luis Daniel
faf7ba50e6 Fix tootip
Fix the tooltip from the Server Docker cleanup frequency. Previous value was every 10 minutes. New value is every night at midnight according to changes https://github.com/coollabsio/coolify/releases/tag/v4.0.0-beta.332
2024-09-15 07:19:23 -04:00
peaklabs-dev
e8179ec519 Update ENHANCEMENT_BOUNTY.yml 2024-09-13 20:53:31 +02:00
peaklabs-dev
220f77e737 Create manage-stale-issues-and-prs.yml 2024-09-13 19:14:15 +02:00
peaklabs-dev
7948a0309f Feat: remove labels and assignees on issue close 2024-09-13 18:42:38 +02:00
peaklabs-dev
47277a68ec Create remove-labels-assignees-on-close.yml 2024-09-13 18:24:37 +02:00
peaklabs-dev
60f75f9deb Update config.yml 2024-09-13 18:06:16 +02:00
peaklabs-dev
e90d1af884 Update ENHANCEMENT_BOUNTY.yml 2024-09-13 17:49:30 +02:00
peaklabs-dev
e3046698a5 Create ENHANCEMENT_BOUNTY.yml 2024-09-13 17:42:19 +02:00
peaklabs-dev
bb773e1118 Update BUG_REPORT.yml 2024-09-13 17:01:31 +02:00
Andras Bacsai
dcf91cc034 Update WebSocket URL in terminal.blade.php to include /ws for consistency with the server configuration. 2024-09-13 16:58:16 +02:00
peaklabs-dev
cddf8476de Update BUG_REPORT.yml 2024-09-13 15:31:14 +02:00
Andras Bacsai
51c43e7457 chore: Rename Command Center to Terminal in code and views 2024-09-13 15:18:00 +02:00
Andras Bacsai
7cac243589 chore: Update Dockerfile and workflow for Coolify Realtime (v4) 2024-09-13 14:05:37 +02:00
Andras Bacsai
0cfd8ed5f0 chore: Update Dockerfile and workflow for Coolify Realtime (v4) 2024-09-13 13:46:10 +02:00
Andras Bacsai
8318598cb5 chore: Update Dockerfile and workflow for Coolify Realtime (v4) 2024-09-13 13:17:19 +02:00
Andras Bacsai
2f692da1c9 chore: Update WebSocket URL in terminal.blade.php 2024-09-13 13:16:14 +02:00
Andras Bacsai
ecd98bfcd5 chore: Update APP_NAME environment variable in docker-compose.prod.yml 2024-09-13 13:13:23 +02:00
Andras Bacsai
ba860398f3 chore: Update .env file and docker-compose configuration 2024-09-13 12:47:46 +02:00
Andras Bacsai
1f9af39fa7 chore: Remove unused entrypoint script and update volume mapping 2024-09-13 12:45:59 +02:00
Andras Bacsai
62b995d26c chore: Update Dockerfile and workflow for Coolify Realtime (v4) 2024-09-13 12:40:17 +02:00
Andras Bacsai
b28d118609 Merge branch 'next' of github.com:coollabsio/coolify into next 2024-09-13 12:37:34 +02:00
Andras Bacsai
81d0589c55 Merge pull request #3427 from peaklabs-dev/new-issue-template
Feat: New issue template
2024-09-13 12:37:35 +02:00
Andras Bacsai
07893b432b chore: Update button text for container connection form 2024-09-13 12:37:32 +02:00
Andras Bacsai
568d47d1dd Merge pull request #3417 from lassejlv/patch-1
Fix spell error
2024-09-13 12:35:07 +02:00
Andras Bacsai
85cce4e453 Merge branch 'next' of github.com:coollabsio/coolify into next 2024-09-13 12:22:01 +02:00
Andras Bacsai
888c1f7697 update files 2024-09-13 12:21:02 +02:00
Andras Bacsai
79c8ce7572 Merge pull request #3429 from coollabsio/feat--terminal-pty
fixes for the new terminal
2024-09-13 12:20:53 +02:00
Andras Bacsai
121afaa18c Merge pull request #2586 from LEstradioto/feat--terminal-pty
[FEAT] fully functioning terminal
2024-09-13 12:20:10 +02:00
Andras Bacsai
e48ad87cdb chore: Update terminal styling for better readability 2024-09-13 12:19:13 +02:00
peaklabs-dev
a587cae251 Update BUG_REPORT.yml 2024-09-13 11:44:07 +02:00
peaklabs-dev
c04c1530f5 Update BUG_REPORT.yml 2024-09-13 11:43:24 +02:00
peaklabs-dev
f4ee61fc6a Update BUG_REPORT.yml 2024-09-13 11:40:00 +02:00
Andras Bacsai
b6080c2c8e Merge branch 'next' into feat--terminal-pty 2024-09-13 11:25:47 +02:00
Andras Bacsai
1738286983 chore: Update shared.php to fix issues with source and network variables 2024-09-13 11:12:28 +02:00
peaklabs-dev
703bf51705 Update BUG_REPORT.yml 2024-09-13 11:00:00 +02:00
Andras Bacsai
aa4980289d feat: make coolify full width by default 2024-09-13 10:51:51 +02:00
Andras Bacsai
dd8a2dd3c1 chore: Update coolify environment variable assignment with double quotes 2024-09-13 08:23:05 +02:00
lasse
3086ef1462 Update actions.blade.php 2024-09-12 21:34:52 +02:00
Andras Bacsai
0b33315991 Merge pull request #3410 from peaklabs-dev/desing-contributing.md
Feat: Redesigned contributing.md
2024-09-12 18:08:59 +02:00
Andras Bacsai
b6b9179bb3 Merge branch 'next' into desing-contributing.md 2024-09-12 18:08:35 +02:00
Andras Bacsai
9122983f22 Merge pull request #3411 from peaklabs-dev/fix-pr-build-gh-actions
Fix: PR Build GitHub Action
2024-09-12 18:07:59 +02:00
peaklabs-dev
b9b33c831c Fix: Made help text more clear 2024-09-12 17:17:19 +02:00
peaklabs-dev
ccdcea665d Update pr-build.yml 2024-09-12 17:09:00 +02:00
peaklabs-dev
7b5aa78557 Update pr-build.yml 2024-09-12 17:03:04 +02:00
peaklabs-dev
9310af0301 Feat: New cf tunnel install flow 2024-09-12 15:50:22 +02:00
Andras Bacsai
e38b29d833 chore: Update release version to 4.0.0-beta.336 2024-09-12 15:04:24 +02:00
peaklabs-dev
0d3d5f40fd Fix: Css issue with advanced settings and remove cf tunnel in onboarding 2024-09-12 14:58:52 +02:00
peaklabs-dev
c402d7f543 Merge branch 'coollabsio:main' into service-getoutline 2024-09-12 13:05:27 +02:00
peaklabs-dev
894f2c66d3 Merge branch 'coollabsio:main' into add-debugbar 2024-09-12 13:03:56 +02:00
peaklabs-dev
d4679a8be1 Merge branch 'coollabsio:main' into desing-contributing.md 2024-09-12 13:03:39 +02:00
Andras Bacsai
7ac45aa706 Merge pull request #3406 from coollabsio/next
v4.0.0-beta.335
2024-09-12 12:43:32 +02:00
Andras Bacsai
8862b50c98 chore: Remove unnecessary SSH command execution time logging 2024-09-12 12:42:47 +02:00
Andras Bacsai
b5a56892fd chore: Remove unnecessary null check for proxy_type in generate_default_proxy_configuration 2024-09-12 12:39:34 +02:00
Andras Bacsai
664a990c60 chore: Update listeners and proxy settings in server form and new server components 2024-09-12 12:34:09 +02:00
Andras Bacsai
16e472da19 chore: Update constants.ssh.mux_enabled in remoteProcess.php 2024-09-12 12:16:20 +02:00
Andras Bacsai
7dd0588bfe Merge pull request #3405 from peaklabs-dev/fix-ssh-multiplexing-docker-desktop-windows
Fix: SSH-Multiplexing on docker desktop for windows
2024-09-12 12:14:39 +02:00
Andras Bacsai
a95ebb4d56 Merge branch 'next' into fix-ssh-multiplexing-docker-desktop-windows 2024-09-12 12:14:24 +02:00
Andras Bacsai
75f266fa9f fix: cloudflare tunnel with new multiplexing feature 2024-09-12 12:07:50 +02:00
Andras Bacsai
90fd0ebf12 chore: Update release version to 4.0.0-beta.335 2024-09-12 10:51:14 +02:00
peaklabs-dev
4aeb8ff02b Fix: SSH Multiplexing on docker desktop on Windows 2024-09-12 10:40:06 +02:00
Andras Bacsai
8bc22e185b Merge pull request #3404 from coollabsio/next
fixes for 334
2024-09-12 10:34:51 +02:00
Andras Bacsai
5244ef60bd chore: Update 'key' value of gitlab in Service.php to use environment variable 2024-09-12 10:29:45 +02:00
Andras Bacsai
f3748fc294 update lock file 2024-09-12 10:25:46 +02:00
Andras Bacsai
03d419e591 chore: Remove itsgoingd/clockwork from require-dev in composer.json 2024-09-12 10:20:55 +02:00
Andras Bacsai
9e90daf414 Merge pull request #3393 from coollabsio/next
v4.0.0-beta.334
2024-09-12 10:12:01 +02:00
Andras Bacsai
420f1df998 Merge pull request #3391 from peaklabs-dev/install-clokwork
Feat: Install Clockwork
2024-09-12 10:03:03 +02:00
Andras Bacsai
f672a08afb chore: Add minio/mc command to Dockerfile 2024-09-12 09:56:48 +02:00
Andras Bacsai
67d44713e7 Merge pull request #3399 from dimaaan21/next
fix: keydb. add `:` delimiter for connection string
2024-09-12 09:49:56 +02:00
Andras Bacsai
0b950f444a Merge pull request #3396 from peaklabs-dev/add-release.md
Feat: Add RELEASE.md
2024-09-12 09:46:44 +02:00
Andras Bacsai
8712af7379 fix: move mc command to coolify image from helper 2024-09-12 09:42:28 +02:00
Luan Estradioto
35dfb1b0f8 fix: grouped process and docker execs are killed with ssh process
fix: run clear command only if exists
fix: link terminal js on dev compose better dx
fix: add error on terminal ux
2024-09-12 01:58:56 -03:00
Luan Estradioto
2edcd01493 Merge remote-tracking branch 'upstream/feat--terminal-pty' into feat--terminal-pty 2024-09-11 20:41:30 -03:00
Dmitry
72c08e4496 fix: keydb. add : delimiter for connection string 2024-09-11 22:44:35 +03:00
peaklabs-dev
baa236f934 Feat: Add debug bar 2024-09-11 16:46:14 +02:00
Andras Bacsai
1a40bebaae chore: Update permissions in pr-build.yml and version numbers 2024-09-11 15:47:54 +02:00
peaklabs-dev
25f5060333 move clockwork to dev only 2024-09-11 15:25:51 +02:00
peaklabs-dev
6e48c94c6e Install Clockwork 2024-09-11 15:10:25 +02:00
peaklabs-dev
410b55cf03 Update CONTRIBUTING.md 2024-09-11 14:39:24 +02:00
peaklabs-dev
0881d001d6 Update CONTRIBUTING.md 2024-09-11 14:34:37 +02:00
peaklabs-dev
483b4f8eb7 Update CONTRIBUTING.md 2024-09-11 14:31:35 +02:00
Andras Bacsai
c9a52c552b Merge pull request #3389 from coollabsio/next
v4.0.0-beta.333
2024-09-11 14:26:58 +02:00
Andras Bacsai
72f0118506 chore: Add reminder to backup .env file during installation script 2024-09-11 14:26:10 +02:00
Andras Bacsai
bc13ad6b82 chore: Copy .env file to backup location during installation script 2024-09-11 14:25:40 +02:00
Andras Bacsai
b145691e1e chore: Add reminder to backup .env file before running install script again 2024-09-11 14:25:16 +02:00
Andras Bacsai
5d476e3924 chore: Update server check job middleware to use server ID instead of UUID 2024-09-11 14:23:19 +02:00
peaklabs-dev
3f3bf075fa Update RELEASE.md 2024-09-11 14:18:10 +02:00
peaklabs-dev
6498e5b6f0 Update RELEASE.md 2024-09-11 14:16:25 +02:00
peaklabs-dev
a3caad239c Feat: release.md file 2024-09-11 14:09:15 +02:00
Andras Bacsai
117fbeb07c fixes for terminal 2024-09-11 12:19:27 +02:00
Andras Bacsai
33e9c9b0f9 Merge branch 'next' into feat--terminal-pty 2024-09-11 10:41:33 +02:00
Andras Bacsai
577927a20b Merge pull request #3386 from coollabsio/fix-#3343
fix: Disable mux_enabled during server validation
2024-09-11 10:23:33 +02:00
Andras Bacsai
409d5ef60e Merge pull request #3379 from peaklabs-dev/fix-#3343
Fix: Onboarding fails if SSH server uses other port than 22 and other onboarding improvements
2024-09-11 10:22:32 +02:00
Andras Bacsai
f1a1deff26 fix: Disable mux_enabled during server validation 2024-09-11 10:21:18 +02:00
Andras Bacsai
9d42a7f146 Merge pull request #3384 from fizikiukas/patch-1
Update Hostinger link in README
2024-09-11 08:50:46 +02:00
Valentinas Čirba
826b64d056 Update README.md 2024-09-11 07:57:16 +03:00
peaklabs-dev
2c9491d81c Fix: Do not change localhost server name on revalidation 2024-09-10 17:43:16 +02:00
peaklabs-dev
d378bb94be Fix: remote servers with port and user 2024-09-10 17:29:53 +02:00
peaklabs-dev
d74cfd09ce Fixes 2024-09-10 17:18:00 +02:00
peaklabs-dev
91c845732e fix set custom port or user during boarding 2024-09-10 16:55:34 +02:00
peaklabs-dev
83698ac8f2 Merge branch 'coollabsio:main' into fix-#3343 2024-09-10 16:35:23 +02:00
Andras Bacsai
f718604ac4 chore: Update .env file with new values 2024-09-10 14:58:26 +02:00
Andras Bacsai
3e188bf947 chore: Copy .env file to .env-{DATE} if it exists 2024-09-10 14:54:22 +02:00
Andras Bacsai
f70160a17c chore: Update version numbers to 4.0.0-beta.333 2024-09-10 14:52:47 +02:00
Andras Bacsai
5722d1a220 Merge pull request #3352 from KalvadTech/alpine_support
Implement support for Alpine Linux
2024-09-10 14:52:25 +02:00
Andras Bacsai
bae9ea79de Merge pull request #3366 from coollabsio/next
v4.0.0-beta.332
2024-09-10 14:41:41 +02:00
peaklabs-dev
f3845ce30a New onboarding error UI and advanced menu 2024-09-10 13:55:58 +02:00
Andras Bacsai
d57c9d8aa0 feat: add elixir finetunes to the deployment job 2024-09-10 12:44:16 +02:00
Andras Bacsai
c7c2924990 fix: Update remoteProcess.php to handle null values in logItem properties 2024-09-10 12:05:10 +02:00
Andras Bacsai
aa30e83f4a fix: delete older versions of the helper image other than the latest one 2024-09-10 11:33:52 +02:00
Andras Bacsai
77455cd444 fix: scp through cloudflare 2024-09-10 10:19:13 +02:00
Andras Bacsai
2777fbc0ec fix: Remove debug statement in shared.php 2024-09-10 08:52:25 +02:00
Andras Bacsai
2c929b300a feat: Expose project description in API response 2024-09-10 08:49:25 +02:00
Andras Bacsai
27ad4441ee formatting 2024-09-10 08:49:20 +02:00
Andras Bacsai
63729c7bbf Merge pull request #3373 from mattstein/api-project-description
feat: Expose project description in API response
2024-09-10 08:49:08 +02:00
Andras Bacsai
1e68444f10 Merge pull request #3374 from Vahor/host-network
fix: don't add `networks` key if `network_mode` is used
2024-09-10 08:42:17 +02:00
Andras Bacsai
f8dfe643f4 chore: Update appwrite.yaml to include OpenSSL key variable assignment 2024-09-10 08:37:57 +02:00
Vahor
66cf6df4b3 skip docker network creation 2024-09-09 23:46:29 +02:00
Vahor
29acc4ee25 fix: don't add networks key if network_mode is used 2024-09-09 23:30:47 +02:00
Matt Stein
f73983e3dd Include project’s description in API response. 2024-09-09 09:44:43 -07:00
Matt Stein
44d417c07e Fix user-facing string case. 2024-09-09 09:38:40 -07:00
Andras Bacsai
1d72f76072 fix: appwrite template + parser 2024-09-09 15:04:51 +02:00
peaklabs-dev
565cb54dba Merge branch 'coollabsio:main' into service-getoutline 2024-09-09 12:07:00 +02:00
Andras Bacsai
c2f7e85022 Merge pull request #3364 from peaklabs-dev/improve-persist-ssh-sessions
Feat: Implement SSH multiplexing to reduce the number of SSH authentications in remote processes
2024-09-09 11:23:24 +02:00
Andras Bacsai
9e6486fa66 Merge pull request #3367 from peaklabs-dev/default-timezone
Fix: Set a default server timezone
2024-09-09 11:20:10 +02:00
peaklabs-dev
28bcd0023c remove cache 2024-09-09 10:33:57 +02:00
Andras Bacsai
84093afaf6 refactor: Improve environment variable handling in shared.php 2024-09-09 10:16:12 +02:00
Andras Bacsai
40347744e0 chore: Set timeout for ServerCheckJob to 60 seconds 2024-09-09 09:08:43 +02:00
Andras Bacsai
060988d923 fix: reenable overlapping servercheckjob 2024-09-09 09:05:40 +02:00
Andras Bacsai
b093c9757c Merge branch 'next' into improve-persist-ssh-sessions 2024-09-09 08:30:04 +02:00
Loïc Tosser
25976a4870 Merge branch 'next' into alpine_support 2024-09-09 08:48:36 +04:00
peaklabs-dev
4f9e1a3e5e Feat: Cleanup stale multiplexing connections 2024-09-08 19:37:00 +02:00
peaklabs-dev
c8218e6901 Fix: Enabel mux 2024-09-08 19:15:37 +02:00
peaklabs-dev
cc10d08a7c Feat: Implement SSH Multiplexing 2024-09-08 18:13:00 +02:00
peaklabs-dev
e5a980d544 Merge pull request #3361 from coollabsio/main
merge main into next
2024-09-08 15:33:59 +02:00
peaklabs-dev
59c7f2cb56 Fix: Set a default server timezone 2024-09-08 15:24:27 +02:00
Andras Bacsai
d2a306dab9 refactor: Skip returning volume if driver type is cifs or nfs 2024-09-08 13:53:20 +02:00
Andras Bacsai
681a745fc7 chore: Update coolify-helper.yml to include "next" branch in push trigger 2024-09-08 13:09:14 +02:00
Andras Bacsai
abb6655fef chore: Update versions.json to version 1.0.1 2024-09-08 12:42:46 +02:00
Andras Bacsai
aa586a5677 chore: Update docker cleanup schedule to run daily at midnight 2024-09-08 12:40:53 +02:00
Andras Bacsai
87ee3c511c chore: Update docker image pruning command to exclude managed images 2024-09-08 12:38:22 +02:00
Andras Bacsai
a17daf96be chore: Add coolify.managed=true label to Docker image builds 2024-09-08 12:38:16 +02:00
Andras Bacsai
a419496066 testing label 2024-09-08 12:35:11 +02:00
Andras Bacsai
c668d2d1ff chore: Update DATABASE_URL in plunk.yaml to use plunk database 2024-09-07 20:59:51 +02:00
Andras Bacsai
4611332a8f newparser parser parsing parser parse 2024-09-07 20:57:56 +02:00
Andras Bacsai
8b3eed5895 chore: Update version to 4.0.0-beta.332 2024-09-07 20:56:56 +02:00
Andras Bacsai
9861ad4045 refactor: Update cleanup schedule to run daily at midnight 2024-09-07 20:56:52 +02:00
Andras Bacsai
5fb560dbbf chore: Update versions.json and sentry.php to 4.0.0-beta.332 2024-09-07 20:56:26 +02:00
Loïc Tosser
6b475cc1bf refactor: Improve handling of environment variable merging in upgrade script 2024-09-07 11:00:42 +04:00
Loïc Tosser
5ef2d476a4 Implementing support for Alpine Linux 2024-09-07 10:35:26 +04:00
peaklabs-dev
eb5765979f Merge branch 'coollabsio:main' into service-getoutline 2024-09-05 18:05:58 +02:00
ayntk-ai
fc3c69f687 Feat: more conformations and fixes 2024-09-05 17:54:32 +02:00
ayntk-ai
08df814408 Feat: delete volume confirmation 2024-09-04 22:33:47 +02:00
ayntk-ai
a7b78dcf41 Feat: Backup job confirmation 2024-09-04 21:29:32 +02:00
ayntk-ai
2b5df8d2fd Feat: Team deletion confirmation 2024-09-04 21:15:46 +02:00
ayntk-ai
f4263ee022 Feat: User deletion confirmation 2024-09-04 21:14:18 +02:00
ayntk-ai
44f3f6001e Feat: Redeploy all confirmation 2024-09-04 21:04:43 +02:00
ayntk-ai
9105c1aa51 Feat: GH app deletion confirmation 2024-09-04 21:00:58 +02:00
ayntk-ai
3e04a7958e Feat/Fix: Proxy stop and restart confirmation 2024-09-04 20:41:17 +02:00
ayntk-ai
505127dae5 Feat: confirm server settings 2024-09-04 20:11:04 +02:00
ayntk-ai
371fe53911 Feat: confirm server deletion 2024-09-04 20:06:22 +02:00
ayntk-ai
9515bc6162 Feat: confirm private key 2024-09-04 20:02:01 +02:00
ayntk-ai
93a4a3e09c Feat: confirm API token 2024-09-04 19:58:36 +02:00
ayntk-ai
bbbd5cbaa1 Feat: confirm scheduled tasks 2024-09-04 19:44:10 +02:00
ayntk-ai
7fe3b78d45 Feat: Environment variabel deletion 2024-09-04 19:41:10 +02:00
ayntk-ai
a29353c1ae Feat: confirm ressource operation 2024-09-04 19:34:47 +02:00
ayntk-ai
c16e914be4 Fix: DB image cleanup 2024-09-04 14:59:44 +02:00
ayntk-ai
bec974dca4 Fix application image cleanup 2024-09-04 14:54:43 +02:00
ayntk-ai
b314b08f25 Feat: stop service confirm 2024-09-04 14:34:46 +02:00
ayntk-ai
9a2d5be354 Feat: confirm file storage 2024-09-03 18:31:06 +02:00
ayntk-ai
d94e39ccc7 Feat: service confirmation 2024-09-03 16:59:51 +02:00
ayntk-ai
d5b7e9ed83 Feat: preview deployments and typos 2024-09-03 16:43:50 +02:00
ayntk-ai
f29bc52fa5 Feat: general confirm 2024-09-03 15:59:30 +02:00
ayntk-ai
3d21f1a2a4 fix checkbox hide label 2024-09-03 14:59:01 +02:00
ayntk-ai
20558d438a remove ray 2024-09-03 00:30:15 +02:00
ayntk-ai
792f6bc163 made wording more clear 2024-09-03 00:01:24 +02:00
ayntk-ai
3d1c730703 Feat: del init script 2024-09-02 23:58:48 +02:00
ayntk-ai
c3188958b4 Feat: DB start, stop confirm 2024-09-02 23:54:16 +02:00
ayntk-ai
c24fec9c45 fix step and password error 2024-09-02 23:48:05 +02:00
ayntk-ai
70043c24cf 100000000x Speed improvement first toast then submit in the background 2024-09-02 23:30:47 +02:00
ayntk-ai
ff1e08cf8b add toast dispatching 2024-09-02 23:25:18 +02:00
ayntk-ai
a4d1ae1341 Feat: ability to hide labels 2024-09-02 21:54:21 +02:00
ayntk-ai
5944ee5524 fix close modal on submit 2024-09-02 21:22:31 +02:00
ayntk-ai
1b0c5f8d69 css fix for long text 2024-09-02 19:49:57 +02:00
ayntk-ai
dfd218ec06 fixes here and there 2024-09-02 19:27:21 +02:00
ayntk-ai
843e3fb599 fix checkboxes in danger 2024-08-31 21:10:44 +02:00
ayntk-ai
a97ccd206c confirm init script 2024-08-31 20:55:56 +02:00
ayntk-ai
776d41613d Fix 3 risk levels 2024-08-31 20:55:43 +02:00
ayntk-ai
f857bbc437 fix submit action 2024-08-31 19:31:23 +02:00
ayntk-ai
f8226cf892 confirm backup deletion 2024-08-31 19:31:01 +02:00
ayntk-ai
d2a0621f93 delete backup folder if empty 2024-08-31 18:38:57 +02:00
ayntk-ai
38845d7eb0 confirm backup and delete all backups of the job 2024-08-31 18:29:19 +02:00
ayntk-ai
3b3bc6c33b fix default checkbox state false or true 2024-08-31 16:19:39 +02:00
ayntk-ai
2adac01034 confirm danger 2024-08-31 16:12:08 +02:00
ayntk-ai
b656cabb33 delete project confirmation 2024-08-31 15:07:50 +02:00
ayntk-ai
830c047ccf delete environment confirmation 2024-08-31 15:06:07 +02:00
ayntk-ai
a3dd48de1d destination and dashboard confirmation 2024-08-31 14:51:59 +02:00
ayntk-ai
b118a627d0 fix password validation and password error 2024-08-31 13:41:08 +02:00
ayntk-ai
bcfca40f3a rest checkboxes on close 2024-08-31 13:10:45 +02:00
ayntk-ai
76cb473db8 fix default checkbox state 2024-08-31 13:06:55 +02:00
ayntk-ai
73dfdb83a7 fix rendering bug, more props 2024-08-31 12:55:17 +02:00
ayntk-ai
bff6964d4a scheduled task deletion 2024-08-30 20:33:12 +02:00
ayntk-ai
b807601d19 delete user confirm 2024-08-30 20:08:14 +02:00
ayntk-ai
9136d7acdc WIP more delete confirmations 2024-08-30 20:00:04 +02:00
ayntk-ai
da0398f35d remove unused code 2024-08-29 21:47:17 +02:00
ayntk-ai
6820fcc084 Fix name for services and DBs 2024-08-29 18:53:49 +02:00
ayntk-ai
d984bec175 Ajust text 2024-08-29 18:08:58 +02:00
ayntk-ai
182af1ec18 Fix application delete 2024-08-29 18:01:16 +02:00
ayntk-ai
a22e757ab7 fix execute action on the last button 2024-08-29 15:19:19 +02:00
ayntk-ai
354c74e920 fix 2024-08-29 12:37:19 +02:00
ayntk-ai
62b7900855 more props and more fixes 2024-08-28 15:40:39 +02:00
ayntk-ai
c92659994d improve button text 2024-08-28 13:41:24 +02:00
ayntk-ai
a2651ab3c1 reset modal on cancel, fix back button when there is no prior step 2024-08-28 13:38:37 +02:00
ayntk-ai
1b51d46b3d more props, nav button fixes 2024-08-28 13:31:09 +02:00
ayntk-ai
141752b9ad fix checkbox actions default display 2024-08-28 13:11:42 +02:00
ayntk-ai
73068aaa75 Refactor: Integrate tow step process in the modal component WIP 2024-08-28 12:52:04 +02:00
ayntk-ai
8d2a02dc3c change title of confirmation popup 2024-08-27 14:29:47 +02:00
ayntk-ai
4726676248 make things more clear 2024-08-27 14:19:37 +02:00
ayntk-ai
9040f5d2a1 confirm with password 2024-08-27 13:44:12 +02:00
ayntk-ai
ac50d8b4d8 fix styling 2024-08-27 12:57:03 +02:00
ayntk-ai
2a581147aa new confirm delete dialog 2024-08-27 12:43:59 +02:00
Franck Kerbiriou
7e154ba3c3 Add Mailpit template 2024-08-22 22:52:20 +02:00
ayntk-ai
1e46b63041 Feat getoutline service 2024-08-20 18:32:35 +02:00
Alex Renoki
71bb1f5e17 Added litellm 2024-08-17 06:20:42 +03:00
Alex Renoki
ce926afdaa Bump to v2 2024-08-17 06:16:38 +03:00
Luan Estradioto
2b8c9920d8 removed extra container and added new process to soketi container 2024-08-15 20:52:50 -03:00
Luan Estradioto
548fc21e40 added ws authentication 2024-08-15 11:17:18 -03:00
Luan Estradioto
c2ea8996ee feat: fully functional terminal for command center 2024-08-15 11:17:18 -03:00
ayntk-ai
5b54dc8792 Revert "improve CleanupDocker.php"
This reverts commit b5360e5e75.
2024-08-09 23:25:57 +02:00
ayntk-ai
b5360e5e75 improve CleanupDocker.php 2024-08-09 23:12:30 +02:00
ayntk-ai
840e225aa8 formatting and waring text 2024-08-09 22:43:18 +02:00
ayntk-ai
7d1179e7c8 fix cleanup images for databases 2024-08-09 22:25:39 +02:00
ayntk-ai
16a5c601e3 graceful db stop and db deletion fixes 2024-08-09 22:15:45 +02:00
ayntk-ai
c566152f37 improve graceful_shutdown_container 2024-08-09 20:28:57 +02:00
ayntk-ai
2ca6ffb84e fix public function service.php 2024-08-09 19:57:53 +02:00
ayntk-ai
41be1f7666 use public function 2024-08-09 19:39:43 +02:00
ayntk-ai
450351921e added public functions 2024-08-09 19:39:21 +02:00
ayntk-ai
a4bb87d13b simplify DeleteService.php 2024-08-09 19:22:14 +02:00
ayntk-ai
1cfddfd529 fix stop large amount of containers 2024-08-09 19:17:58 +02:00
ayntk-ai
72bcf03cbb graceful service container stop 2024-08-09 18:59:41 +02:00
ayntk-ai
d177e49e62 updated warning message and formating 2024-08-09 18:43:13 +02:00
ayntk-ai
5595853379 WIP database network, image removal 2024-08-09 03:03:40 +02:00
ayntk-ai
97c2bedda2 add delete_connected_networks function to services.php 2024-08-09 03:00:30 +02:00
ayntk-ai
d980c7a425 only run network removal on stop service if it is not a deletion operation 2024-08-09 02:59:41 +02:00
ayntk-ai
53dff4ca4f simplify uuid variabel 2024-08-09 02:58:59 +02:00
ayntk-ai
7722809c52 typo 2024-08-09 02:20:32 +02:00
ayntk-ai
e67e03f73f added comments and removed temp ones 2024-08-09 02:15:40 +02:00
ayntk-ai
86a087056e fix volume deletion for services 2024-08-09 02:11:42 +02:00
ayntk-ai
51071da700 fix order 2024-08-09 01:00:07 +02:00
ayntk-ai
70aa05bde9 order in importance 2024-08-09 00:42:23 +02:00
ayntk-ai
0135e2b5c0 add logic 2024-08-09 00:30:11 +02:00
ayntk-ai
2f95349888 Merge branch 'coollabsio:main' into fix-#2546-deletion-issues 2024-08-08 15:40:13 +02:00
ayntk-ai
4d0acee95c UI options for deletion WIP 2024-08-08 12:31:37 +02:00
ayntk-ai
74bea37b43 Merge branch 'coollabsio:main' into fix-#2546-deletion-issues 2024-08-08 11:50:57 +02:00
ayntk-ai
070daee28e remove networks and cleanup unused images when stoping dockercompose build pack containers 2024-08-08 01:19:17 +02:00
ayntk-ai
df796dffa2 fix delte networks and unused images of services when deleted 2024-08-08 01:02:48 +02:00
Alex Renoki
18ae29ba99 Added langfuse 2024-07-31 07:11:08 +03:00
Luan Estradioto
1138ec0dea add storage:link to dev environment 2024-07-21 13:30:28 -03:00
Alejandro Akbal
21fc8efb86 feat: add Mixpost template 2024-06-04 13:13:37 +01:00
413 changed files with 11037 additions and 5248 deletions

View File

@@ -6,13 +6,7 @@ APP_KEY=
APP_URL=http://localhost
APP_PORT=8000
APP_DEBUG=true
MUX_ENABLED=false
# Enable Laravel Telescope for debugging
TELESCOPE_ENABLED=false
# Selenium Driver URL for Dusk
DUSK_DRIVER_URL=http://selenium:4444
SSH_MUX_ENABLED=true
# PostgreSQL Database Configuration
DB_DATABASE=coolify
@@ -25,7 +19,13 @@ DB_PORT=5432
# Set to true to enable Ray
RAY_ENABLED=false
# Set custom ray port
RAY_PORT=
# RAY_PORT=
# Enable Laravel Telescope for debugging
TELESCOPE_ENABLED=false
# Selenium Driver URL for Dusk
DUSK_DRIVER_URL=http://selenium:4444
# Special Keys for Andras
# For cache purging

View File

@@ -0,0 +1,65 @@
name: 🐞 Bug Report
description: "File a new bug report."
title: "[Bug]: "
labels: ["🐛 Bug", "🔍 Triage"]
body:
- type: markdown
attributes:
value: |
> [!IMPORTANT]
> **Please ensure you are using the latest version of Coolify before submitting an issue, as the bug may have already been fixed in a recent update.** (Of course, if you're experiencing an issue on the latest version that wasn't present in a previous version, please let us know.)
# 💎 Bounty Program (with [algora.io](https://console.algora.io/org/coollabsio/bounties/new))
- If you would like to prioritize the issue resolution, consider adding a bounty to this issue through our [Bounty Program](https://console.algora.io/org/coollabsio/bounties/new).
- type: textarea
attributes:
label: Error Message and Logs
description: Provide a detailed description of the error or exception you encountered, along with any relevant log output.
validations:
required: true
- type: textarea
attributes:
label: Steps to Reproduce
description: Please provide a step-by-step guide to reproduce the issue. Be as detailed as possible, otherwise we may not be able to assist you.
value: |
1.
2.
3.
4.
validations:
required: true
- type: input
attributes:
label: Example Repository URL
description: If applicable, provide a URL to a repository demonstrating the issue.
- type: input
attributes:
label: Coolify Version
description: Please provide the Coolify version you are using. This can be found in the top left corner of your Coolify dashboard.
placeholder: "v4.0.0-beta.335"
validations:
required: true
- type: dropdown
attributes:
label: Are you using Coolify Cloud?
options:
- "No (self-hosted)"
- "Yes (Coolify Cloud)"
validations:
required: true
- type: input
attributes:
label: Operating System and Version (self-hosted)
description: Run `cat /etc/os-release` or `lsb_release -a` in your terminal and provide the operating system and version.
placeholder: "Ubuntu 22.04"
- type: textarea
attributes:
label: Additional Information
description: Any other relevant details about the issue.

View File

@@ -0,0 +1,31 @@
name: 💎 Enhancement Bounty
description: "Propose a new feature, service, or improvement with an attached bounty."
title: "[Enhancement]: "
labels: ["✨ Enhancement", "🔍 Triage"]
body:
- type: markdown
attributes:
value: |
> [!IMPORTANT]
> **This issue template is exclusively for proposing new features, services, or improvements with an attached bounty.** Enhancements without a bounty can be discussed in the appropriate category of [Github Discussions](https://github.com/coollabsio/coolify/discussions).
# 💎 Add a Bounty (with [algora.io](https://console.algora.io/org/coollabsio/bounties/new))
- [Click here to add the required bounty](https://console.algora.io/org/coollabsio/bounties/new)
- type: dropdown
attributes:
label: Request Type
description: Select the type of request you are making.
options:
- New Feature
- New Service
- Improvement
validations:
required: true
- type: textarea
attributes:
label: Description
description: Provide a detailed description of the feature, improvement, or service you are proposing.
validations:
required: true

View File

@@ -1,46 +0,0 @@
name: Bug report
description: "Create a new bug report."
title: "[Bug]: "
body:
- type: markdown
attributes:
value: >-
# 💎 Bounty program (with
[algora.io](https://console.algora.io/org/coollabsio/bounties/new))
If you would like to prioritize the issue resolution, you can add bounty
to this issue.
Click [here](https://console.algora.io/org/coollabsio/bounties/new) to
get started.
- type: textarea
attributes:
label: Description
description: A clear and concise description of the problem
- type: textarea
attributes:
label: Minimal Reproduction (if possible, example repository)
description: Please provide a step by step guide to reproduce the issue.
validations:
required: true
- type: textarea
attributes:
label: Exception or Error
description: Please provide error logs if possible.
- type: input
attributes:
label: Version
description: Coolify's version (see top of your screen).
validations:
required: true
- type: checkboxes
attributes:
label: Cloud?
description: "Are you using the cloud version of Coolify?"
options:
- label: 'Yes'
required: false
- label: 'No'
required: false

View File

@@ -1,8 +1,18 @@
blank_issues_enabled: false
contact_links:
- name: 🤔 Community Support (Chat)
- name: 🤔 Questions and Community Support
url: https://coollabs.io/discord
about: Reach out to us on Discord.
- name: 🙋‍♂️ Feature Requests
url: https://github.com/coollabsio/coolify/discussions/categories/new-features
about: All feature requests will be discussed here.
about: If you have any questions, reach out to us on Discord inside the "#support" channel.
- name: 💡 Feature Request
url: https://github.com/coollabsio/coolify/discussions/categories/feature-requests
about: Suggest a new feature for Coolify.
- name: ⚙️ Service Request
url: https://github.com/coollabsio/coolify/discussions/categories/service-requests
about: Request a new service integration for Coolify.
- name: 🔧 Improvements
url: https://github.com/coollabsio/coolify/discussions/categories/improvements
about: Suggest improvements to existing features for Coolify.

View File

@@ -1 +1,13 @@
> Always use `next` branch as destination branch for PRs, not `main`
## Submit Checklist (REMOVE THIS SECTION BEFORE SUBMITTING)
- [ ] I have selected the `next` branch as the destination for my PR, not `main`.
- [ ] I have listed all changes in the `Changes` section.
- [ ] I have filled out the `Issues` section with the issue/discussion link(s) (if applicable).
- [ ] I have tested my changes.
- [ ] I have considered backwards compatibility.
- [ ] I have removed this checklist and any unused sections.
## Changes
-
## Issues
- fix #

View File

@@ -38,6 +38,8 @@ jobs:
platforms: linux/amd64
push: true
tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-next
labels: |
coolify.managed=true
aarch64:
runs-on: [ self-hosted, arm64 ]
permissions:
@@ -64,6 +66,8 @@ jobs:
platforms: linux/aarch64
push: true
tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-next-aarch64
labels: |
coolify.managed=true
merge-manifest:
runs-on: ubuntu-latest
permissions:
@@ -94,3 +98,4 @@ jobs:
if: always()
with:
webhook: ${{ secrets.DISCORD_WEBHOOK_DEV_RELEASE_CHANNEL }}

View File

@@ -38,6 +38,8 @@ jobs:
platforms: linux/amd64
push: true
tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}
labels: |
coolify.managed=true
aarch64:
runs-on: [ self-hosted, arm64 ]
permissions:
@@ -64,6 +66,8 @@ jobs:
platforms: linux/aarch64
push: true
tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-aarch64
labels: |
coolify.managed=true
merge-manifest:
runs-on: ubuntu-latest
permissions:
@@ -94,3 +98,4 @@ jobs:
if: always()
with:
webhook: ${{ secrets.DISCORD_WEBHOOK_PROD_RELEASE_CHANNEL }}

View File

@@ -0,0 +1,103 @@
name: Coolify Realtime Development (v4)
on:
push:
branches: [ "next" ]
paths:
- .github/workflows/coolify-realtime.yml
- docker/coolify-realtime/Dockerfile
- docker/coolify-realtime/terminal-server.js
- docker/coolify-realtime/package.json
- docker/coolify-realtime/soketi-entrypoint.sh
env:
REGISTRY: ghcr.io
IMAGE_NAME: "coollabsio/coolify-realtime"
jobs:
amd64:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- uses: actions/checkout@v4
- name: Login to ghcr.io
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Get Version
id: version
run: |
echo "VERSION=$(docker run --rm -v "$(pwd):/app" -w /app ghcr.io/jqlang/jq:latest '.coolify.realtime.version' versions.json)"|xargs >> $GITHUB_OUTPUT
- name: Build image and push to registry
uses: docker/build-push-action@v5
with:
no-cache: true
context: .
file: docker/coolify-realtime/Dockerfile
platforms: linux/amd64
push: true
tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-next
labels: |
coolify.managed=true
aarch64:
runs-on: [ self-hosted, arm64 ]
permissions:
contents: read
packages: write
steps:
- uses: actions/checkout@v4
- name: Login to ghcr.io
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Get Version
id: version
run: |
echo "VERSION=$(docker run --rm -v "$(pwd):/app" -w /app ghcr.io/jqlang/jq:latest '.coolify.realtime.version' versions.json)"|xargs >> $GITHUB_OUTPUT
- name: Build image and push to registry
uses: docker/build-push-action@v5
with:
no-cache: true
context: .
file: docker/coolify-realtime/Dockerfile
platforms: linux/aarch64
push: true
tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-next-aarch64
labels: |
coolify.managed=true
merge-manifest:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
needs: [ amd64, aarch64 ]
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to ghcr.io
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Get Version
id: version
run: |
echo "VERSION=$(docker run --rm -v "$(pwd):/app" -w /app ghcr.io/jqlang/jq:latest '.coolify.realtime.version' versions.json)"|xargs >> $GITHUB_OUTPUT
- name: Create & publish manifest
run: |
docker buildx imagetools create --append ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-next-aarch64 --tag ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-next
- uses: sarisia/actions-status-discord@v1
if: always()
with:
webhook: ${{ secrets.DISCORD_WEBHOOK_PROD_RELEASE_CHANNEL }}

103
.github/workflows/coolify-realtime.yml vendored Normal file
View File

@@ -0,0 +1,103 @@
name: Coolify Realtime (v4)
on:
push:
branches: [ "main" ]
paths:
- .github/workflows/coolify-realtime.yml
- docker/coolify-realtime/Dockerfile
- docker/coolify-realtime/terminal-server.js
- docker/coolify-realtime/package.json
- docker/coolify-realtime/soketi-entrypoint.sh
env:
REGISTRY: ghcr.io
IMAGE_NAME: "coollabsio/coolify-realtime"
jobs:
amd64:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- uses: actions/checkout@v4
- name: Login to ghcr.io
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Get Version
id: version
run: |
echo "VERSION=$(docker run --rm -v "$(pwd):/app" -w /app ghcr.io/jqlang/jq:latest '.coolify.realtime.version' versions.json)"|xargs >> $GITHUB_OUTPUT
- name: Build image and push to registry
uses: docker/build-push-action@v5
with:
no-cache: true
context: .
file: docker/coolify-realtime/Dockerfile
platforms: linux/amd64
push: true
tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}
labels: |
coolify.managed=true
aarch64:
runs-on: [ self-hosted, arm64 ]
permissions:
contents: read
packages: write
steps:
- uses: actions/checkout@v4
- name: Login to ghcr.io
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Get Version
id: version
run: |
echo "VERSION=$(docker run --rm -v "$(pwd):/app" -w /app ghcr.io/jqlang/jq:latest '.coolify.realtime.version' versions.json)"|xargs >> $GITHUB_OUTPUT
- name: Build image and push to registry
uses: docker/build-push-action@v5
with:
no-cache: true
context: .
file: docker/coolify-realtime/Dockerfile
platforms: linux/aarch64
push: true
tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-aarch64
labels: |
coolify.managed=true
merge-manifest:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
needs: [ amd64, aarch64 ]
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to ghcr.io
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Get Version
id: version
run: |
echo "VERSION=$(docker run --rm -v "$(pwd):/app" -w /app ghcr.io/jqlang/jq:latest '.coolify.realtime.version' versions.json)"|xargs >> $GITHUB_OUTPUT
- name: Create & publish manifest
run: |
docker buildx imagetools create --append ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-aarch64 --tag ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }} --tag ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest
- uses: sarisia/actions-status-discord@v1
if: always()
with:
webhook: ${{ secrets.DISCORD_WEBHOOK_PROD_RELEASE_CHANNEL }}

View File

@@ -1,44 +0,0 @@
name: Docker Image CI
on:
# push:
# branches: [ "main" ]
# pull_request:
# branches: [ "*" ]
push:
branches: ["this-does-not-exist"]
pull_request:
branches: ["this-does-not-exist"]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Cache Docker layers
uses: actions/cache@v2
with:
path: |
/usr/local/share/ca-certificates
/var/cache/apt/archives
/var/lib/apt/lists
~/.cache
key: ${{ runner.os }}-docker-${{ hashFiles('**/Dockerfile') }}
restore-keys: |
${{ runner.os }}-docker-
- name: Build the Docker image
run: |
cp .env.example .env
docker run --rm -u "$(id -u):$(id -g)" \
-v "$(pwd):/app" \
-w /app composer:2 \
composer install --ignore-platform-reqs
./vendor/bin/spin build
- name: Start the stack
run: |
./vendor/bin/spin up -d
./vendor/bin/spin exec coolify php artisan key:generate
./vendor/bin/spin exec coolify php artisan migrate:fresh --seed
- name: Test (missing E2E tests)
run: |
./vendor/bin/spin exec coolify php artisan test

View File

@@ -1,25 +0,0 @@
name: Fix PHP code style issues
on: [push]
permissions:
contents: write
jobs:
php-code-styling:
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
ref: ${{ github.head_ref }}
- name: Fix PHP code style issues
uses: aglipanci/laravel-pint-action@2.4
- name: Commit changes
uses: stefanzweifel/git-auto-commit-action@v5
with:
commit_message: Fix styling

View File

@@ -0,0 +1,17 @@
name: Lock closed Issues, Discussions, and PRs
on:
schedule:
- cron: '0 1 * * *'
jobs:
lock-threads:
runs-on: ubuntu-latest
steps:
- name: Lock threads after 30 days of inactivity
uses: dessant/lock-threads@v5
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
issue-inactive-days: '30'
pr-inactive-days: '30'
discussion-inactive-days: '30'

View File

@@ -0,0 +1,28 @@
name: Manage Stale Issues and PRs
on:
schedule:
- cron: '0 2 * * *'
jobs:
manage-stale:
runs-on: ubuntu-latest
steps:
- name: Manage stale issues and PRs
uses: actions/stale@v9
id: stale
with:
stale-issue-message: 'This issue will be automatically closed in a few days if no response is received. Please provide an update with the requested information.'
stale-pr-message: 'This pull request will be automatically closed in a few days if no response is received. Please update your PR or comment if you would like to continue working on it.'
close-issue-message: 'This issue has been automatically closed due to inactivity.'
close-pr-message: 'This pull request has been automatically closed due to inactivity.'
days-before-stale: 14
days-before-close: 7
stale-issue-label: '⏱︎ Stale'
stale-pr-label: '⏱︎ Stale'
only-labels: '💤 Waiting for feedback'
remove-stale-when-updated: true
operations-per-run: 100
labels-to-remove-when-unstale: '⏱︎ Stale, 💤 Waiting for feedback'
close-issue-reason: 'not_planned'
exempt-all-milestones: false

View File

@@ -1,81 +0,0 @@
name: PR Build (v4)
on:
pull_request:
types:
- opened
branches-ignore: ["main", "v3"]
paths-ignore:
- .github/workflows/coolify-helper.yml
- docker/coolify-helper/Dockerfile
env:
REGISTRY: ghcr.io
IMAGE_NAME: "coollabsio/coolify"
jobs:
amd64:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Login to ghcr.io
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build image and push to registry
uses: docker/build-push-action@v5
with:
context: .
file: docker/prod/Dockerfile
platforms: linux/amd64
push: true
tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.event.number }}
aarch64:
runs-on: [self-hosted, arm64]
permissions:
contents: read
packages: write
steps:
- uses: actions/checkout@v4
- name: Login to ghcr.io
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build image and push to registry
uses: docker/build-push-action@v5
with:
context: .
file: docker/prod/Dockerfile
platforms: linux/aarch64
push: true
tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.event.number }}-aarch64
merge-manifest:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
needs: [amd64, aarch64]
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to ghcr.io
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Create & publish manifest
run: |
docker buildx imagetools create --append ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.event.number }}-aarch64 --tag ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.event.number }}
- uses: sarisia/actions-status-discord@v1
if: always()
with:
webhook: ${{ secrets.DISCORD_WEBHOOK_DEV_RELEASE_CHANNEL }}

View File

@@ -0,0 +1,78 @@
name: Remove Labels and Assignees on Issue Close
on:
issues:
types: [closed]
pull_request:
types: [closed]
pull_request_target:
types: [closed]
jobs:
remove-labels-and-assignees:
runs-on: ubuntu-latest
steps:
- name: Remove labels and assignees
uses: actions/github-script@v7
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const { owner, repo } = context.repo;
async function processIssue(issueNumber) {
try {
const { data: currentLabels } = await github.rest.issues.listLabelsOnIssue({
owner,
repo,
issue_number: issueNumber
});
const labelsToKeep = currentLabels
.filter(label => label.name === '⏱︎ Stale')
.map(label => label.name);
await github.rest.issues.setLabels({
owner,
repo,
issue_number: issueNumber,
labels: labelsToKeep
});
const { data: issue } = await github.rest.issues.get({
owner,
repo,
issue_number: issueNumber
});
if (issue.assignees && issue.assignees.length > 0) {
await github.rest.issues.removeAssignees({
owner,
repo,
issue_number: issueNumber,
assignees: issue.assignees.map(assignee => assignee.login)
});
}
} catch (error) {
if (error.status !== 404) {
console.error(`Error processing issue ${issueNumber}:`, error);
}
}
}
if (context.eventName === 'issues' || context.eventName === 'pull_request' || context.eventName === 'pull_request_target') {
const issue = context.payload.issue || context.payload.pull_request;
await processIssue(issue.number);
}
if (context.eventName === 'pull_request' || context.eventName === 'pull_request_target') {
const pr = context.payload.pull_request;
if (pr.body) {
const issueReferences = pr.body.match(/#(\d+)/g);
if (issueReferences) {
for (const reference of issueReferences) {
const issueNumber = parseInt(reference.substring(1));
await processIssue(issueNumber);
}
}
}
}

View File

@@ -1,54 +1,72 @@
# Contributing
# Contributing to Coolify
> "First, thanks for considering contributing to my project. It really means a lot!" - [@andrasbacsai](https://github.com/andrasbacsai)
You can ask for guidance anytime on our [Discord server](https://coollabs.io/discord) in the `#contribute` channel.
## Table of Contents
## Code Contribution
1. [Setup Development Environment](#1-setup-development-environment)
2. [Verify Installation](#2-verify-installation-optional)
3. [Fork and Setup Local Repository](#3-fork-and-setup-local-repository)
4. [Set up Environment Variables](#4-set-up-environment-variables)
5. [Start Coolify](#5-start-coolify)
6. [Start Development](#6-start-development)
7. [Create a Pull Request](#7-create-a-pull-request)
8. [Development Notes](#development-notes)
9. [Resetting Development Environment](#resetting-development-environment)
10. [Additional Contribution Guidelines](#additional-contribution-guidelines)
## 1. Setup your development environment
## 1. Setup Development Environment
Follow the steps below for your operating system:
### Windows
<details>
<summary><strong>Windows</strong></summary>
1. Install `docker-ce`, Docker Desktop (or similar):
- Docker CE (recommended):
- Install Windows Subsystem for Linux v2 (WSL2) by following this guide: [Install WSL](https://learn.microsoft.com/en-us/windows/wsl/install)
- After installing WSL2, install Docker CE for your Linux distribution by following this guide: [Install Docker Engine](https://docs.docker.com/engine/install/)
- Install Windows Subsystem for Linux v2 (WSL2) by following this guide: [Install WSL](https://learn.microsoft.com/en-us/windows/wsl/install?ref=coolify)
- After installing WSL2, install Docker CE for your Linux distribution by following this guide: [Install Docker Engine](https://docs.docker.com/engine/install/?ref=coolify)
- Make sure to choose the appropriate Linux distribution (e.g., Ubuntu) when following the Docker installation guide
- Install Docker Desktop (easier):
- Download and install [Docker Desktop for Windows](https://docs.docker.com/desktop/install/windows-install/)
- Download and install [Docker Desktop for Windows](https://docs.docker.com/desktop/install/windows-install/?ref=coolify)
- Ensure WSL2 backend is enabled in Docker Desktop settings
2. Install Spin:
- Follow the instructions to install Spin on Windows from the [Spin documentation](https://serversideup.net/open-source/spin/docs/installation/install-windows#download-and-install-spin-into-wsl2)
- Follow the instructions to install Spin on Windows from the [Spin documentation](https://serversideup.net/open-source/spin/docs/installation/install-windows#download-and-install-spin-into-wsl2?ref=coolify)
### MacOS
</details>
<details>
<summary><strong>MacOS</strong></summary>
1. Install Orbstack, Docker Desktop (or similar):
- Orbstack (recommended, as it is a faster and lighter alternative to Docker Desktop):
- Download and install [Orbstack](https://docs.orbstack.dev/quick-start#installation)
- Download and install [Orbstack](https://docs.orbstack.dev/quick-start#installation?ref=coolify)
- Docker Desktop:
- Download and install [Docker Desktop for Mac](https://docs.docker.com/desktop/install/mac-install/)
- Download and install [Docker Desktop for Mac](https://docs.docker.com/desktop/install/mac-install/?ref=coolify)
2. Install Spin:
- Follow the instructions to install Spin on MacOS from the [Spin documentation](https://serversideup.net/open-source/spin/docs/installation/install-macos/#download-and-install-spin)
- Follow the instructions to install Spin on MacOS from the [Spin documentation](https://serversideup.net/open-source/spin/docs/installation/install-macos/#download-and-install-spin?ref=coolify)
### Linux
</details>
<details>
<summary><strong>Linux</strong></summary>
1. Install Docker Engine, Docker Desktop (or similar):
- Docker Engine (recommended, as there is no VM overhead):
- Follow the official [Docker Engine installation guide](https://docs.docker.com/engine/install/) for your Linux distribution
- Follow the official [Docker Engine installation guide](https://docs.docker.com/engine/install/?ref=coolify) for your Linux distribution
- Docker Desktop:
- If you want a GUI, you can use [Docker Desktop for Linux](https://docs.docker.com/desktop/install/linux-install/)
- If you want a GUI, you can use [Docker Desktop for Linux](https://docs.docker.com/desktop/install/linux-install/?ref=coolify)
2. Install Spin:
- Follow the instructions to install Spin on Linux from the [Spin documentation](https://serversideup.net/open-source/spin/docs/installation/install-linux#configure-docker-permissions)
- Follow the instructions to install Spin on Linux from the [Spin documentation](https://serversideup.net/open-source/spin/docs/installation/install-linux#configure-docker-permissions?ref=coolify)
</details>
## 2. Verify installation (optional)
## 2. Verify Installation (Optional)
After installing Docker (or Orbstack) and Spin, verify the installation:
@@ -60,63 +78,53 @@ After installing Docker (or Orbstack) and Spin, verify the installation:
```
You should see version information for both Docker and Spin.
## 3. Fork the Coolify repository and setup your local repository
## 3. Fork and Setup Local Repository
1. Fork the [Coolify](https://github.com/coollabsio/coolify) repository to your GitHub account.
2. Install a code editor on your machine (below are some popular choices, choose one):
2. Install a code editor on your machine (choose one):
- Visual Studio Code (recommended free):
- Windows/macOS/Linux: Download and install from [https://code.visualstudio.com/download](https://code.visualstudio.com/download)
- Cursor (recommended but paid for getting the full benefits):
- Windows/macOS/Linux: Download and install from [https://www.cursor.com/](https://www.cursor.com/)
- Zed (very fast code editor):
- macOS/Linux: Download and install from [https://zed.dev/download](https://zed.dev/download)
- Windows: Not available yet
| Editor | Platform | Download Link |
|--------|----------|---------------|
| Visual Studio Code (recommended free) | Windows/macOS/Linux | [Download](https://code.visualstudio.com/download?ref=coolify) |
| Cursor (recommended but paid) | Windows/macOS/Linux | [Download](https://www.cursor.com/?ref=coolify) |
| Zed (very fast) | macOS/Linux | [Download](https://zed.dev/download?ref=coolify) |
3. Clone the Coolify Repository from your fork to your local machine
- Use `git clone` in the command line
- Use `git clone` in the command line, or
- Use GitHub Desktop (recommended):
- Download and install from [https://desktop.github.com/](https://desktop.github.com/)
- Download and install from [https://desktop.github.com/](https://desktop.github.com/?ref=coolify)
- Open GitHub Desktop and login with your GitHub account
- Click on `File` -> `Clone Repository` select `github.com` as the repository location, then select your forked Coolify repository, choose the local path and then click `Clone`
4. Open the cloned Coolify Repository in your chosen code editor.
## 4. Set up Environment Variables
1. In the Code Editor, locate the `.env.development.example` file in the root directory of your local Coolify repository.
2. Duplicate the `.env.development.example` file and rename the copy to `.env`.
3. Open the new `.env` file and review its contents. Adjust any environment variables as needed for your development setup.
4. If you encounter errors during database migrations, update the database connection settings in your `.env` file. Use the IP address or hostname of your PostgreSQL database container. You can find this information by running `docker ps` after executing `spin up`.
5. Save the changes to your `.env` file.
## 5. Start Coolify
1. Open a terminal in the local Coolify directory.
2. Run the following command in the terminal (leave that terminal open):
```
```bash
spin up
```
Note: You may see some errors, but don't worry; this is expected.
> [!NOTE]
> You may see some errors, but don't worry; this is expected.
3. If you encounter permission errors, especially on macOS, use:
```
```bash
sudo spin up
```
Note: If you change environment variables afterwards or anything seems broken, press Ctrl + C to stop the process and run `spin up` again.
> [!NOTE]
> If you change environment variables afterwards or anything seems broken, press Ctrl + C to stop the process and run `spin up` again.
## 6. Start Development
@@ -126,42 +134,19 @@ Note: If you change environment variables afterwards or anything seems broken, p
- Password: `password`
2. Additional development tools:
- Laravel Horizon (scheduler): `http://localhost:8000/horizon`
Note: Only accessible when logged in as root user
- Mailpit (email catcher): `http://localhost:8025`
- Telescope (debugging tool): `http://localhost:8000/telescope`
Note: Disabled by default (so the database is not overloaded), enable by adding the following environment variable to your `.env` file:
```env
TELESCOPE_ENABLED=true
```
| Tool | URL | Note |
|------|-----|------|
| Laravel Horizon (scheduler) | `http://localhost:8000/horizon` | Only accessible when logged in as root user |
| Mailpit (email catcher) | `http://localhost:8025` | |
| Telescope (debugging tool) | `http://localhost:8000/telescope` | Disabled by default |
> [!NOTE]
> To enable Telescope, add the following to your `.env` file:
> ```env
> TELESCOPE_ENABLED=true
> ```
## 7. Development Notes
When working on Coolify, keep the following in mind:
1. **Database Migrations**: After switching branches or making changes to the database structure, always run migrations:
```bash
docker exec -it coolify php artisan migrate
```
2. **Resetting Development Setup**: To reset your development setup to a clean database with default values:
```bash
docker exec -it coolify php artisan migrate:fresh --seed
```
3. **Troubleshooting**: If you encounter unexpected behavior, ensure your database is up-to-date with the latest migrations and if possible reset the development setup to eliminate any envrionement specific issues.
Remember, forgetting to migrate the database can cause problems, so make it a habit to run migrations after pulling changes or switching branches.
## 8. Contributing a New Service
To add a new service to Coolify, please refer to our documentation:
[Adding a New Service](https://coolify.io/docs/knowledge-base/add-a-service)
## 9. Create a Pull Request
## 7. Create a Pull Request
1. After making changes or adding a new service:
- Commit your changes to your forked repository.
@@ -176,14 +161,83 @@ To add a new service to Coolify, please refer to our documentation:
3. Filling out the PR details:
- Give your PR a descriptive title.
- In the description, explain the changes you've made.
- Reference any related issues by using keywords like "Fixes #123" or "Closes #456".
- Use the Pull Request Template provided and fill in the details.
4. Important note:
Always set the base branch for your PR to the `next` branch of the Coolify repository, not the `main` branch.
> [!IMPORTANT]
> Always set the base branch for your PR to the `next` branch of the Coolify repository, not the `main` branch.
5. Submit your PR:
4. Submit your PR:
- Review your changes one last time.
- Click "Create pull request" to submit.
> [!NOTE]
> Make sure your PR is out of draft mode as soon as it's ready for review. PRs that are in draft mode for a long time may be closed by maintainers.
After submission, maintainers will review your PR and may request changes or provide feedback.
## Development Notes
When working on Coolify, keep the following in mind:
1. **Database Migrations**: After switching branches or making changes to the database structure, always run migrations:
```bash
docker exec -it coolify php artisan migrate
```
2. **Resetting Development Setup**: To reset your development setup to a clean database with default values:
```bash
docker exec -it coolify php artisan migrate:fresh --seed
```
3. **Troubleshooting**: If you encounter unexpected behavior, ensure your database is up-to-date with the latest migrations and if possible reset the development setup to eliminate any environment-specific issues.
> [!IMPORTANT]
> Forgetting to migrate the database can cause problems, so make it a habit to run migrations after pulling changes or switching branches.
## Resetting Development Environment
If you encounter issues or break your database or something else, follow these steps to start from a clean slate (works since `v4.0.0-beta.342`):
1. Stop all running containers `ctrl + c`.
2. Remove all Coolify containers:
```bash
docker rm coolify coolify-db coolify-redis coolify-realtime coolify-testing-host coolify-minio coolify-vite-1 coolify-mail
```
3. Remove Coolify volumes (it is possible that the volumes have no `coolify` prefix on your machine, in that case remove the prefix from the command):
```bash
docker volume rm coolify_dev_backups_data coolify_dev_postgres_data coolify_dev_redis_data coolify_dev_coolify_data coolify_dev_minio_data
```
4. Remove unused images:
```bash
docker image prune -a
```
5. Start Coolify again:
```bash
spin up
```
6. Run database migrations and seeders:
```bash
docker exec -it coolify php artisan migrate:fresh --seed
```
After completing these steps, you'll have a fresh development setup.
> [!IMPORTANT]
> Always run database migrations and seeders after switching branches or pulling updates to ensure your local database structure matches the current codebase and includes necessary seed data.
## Additional Contribution Guidelines
### Contributing a New Service
To add a new service to Coolify, please refer to our documentation:
[Adding a New Service](https://coolify.io/docs/knowledge-base/contribute/service)
### Contributing to Documentation
To contribute to the Coolify documentation, please refer to this guide:
[Contributing to the Coolify Documentation](https://github.com/coollabsio/documentation-coolify/blob/main/CONTRIBUTING.md)

View File

@@ -54,7 +54,7 @@ Special thanks to our biggest sponsors!
* [Latitude](https://latitude.sh/?ref=coolify.io) - A cloud computing platform offering bare metal servers and cloud instances for developers and businesses.
* [Brand Dev](https://brand.dev/?ref=coolify.io) - A web development agency specializing in creating custom digital experiences and brand identities.
* [Jobscollider](https://jobscollider.com/remote-jobs?ref=coolify.io) - A job search platform connecting professionals with remote work opportunities across various industries.
* [Hostinger](https://hostinger.com?ref=coolify.io) - A web hosting provider offering affordable hosting solutions, domain registration, and website building tools.
* [Hostinger](https://www.hostinger.com/vps/coolify-hosting?ref=coolify.io) - A web hosting provider offering affordable hosting solutions, domain registration, and website building tools.
* [Glueops](https://www.glueops.dev/?ref=coolify.io) - A DevOps consulting company providing infrastructure automation and cloud optimization services.
* [Ubicloud](https://ubicloud.com/?ref=coolify.io) - An open-source alternative to hyperscale cloud providers, offering high-performance cloud computing services.
* [Juxtdigital](https://juxtdigital.dev/?ref=coolify.io) - A digital agency offering web development, design, and digital marketing services for businesses.

130
RELEASE.md Normal file
View File

@@ -0,0 +1,130 @@
# Coolify Release Guide
This guide outlines the release process for Coolify, intended for developers and those interested in understanding how releases are managed and deployed.
## Table of Contents
- [Release Process](#release-process)
- [Version Types](#version-types)
- [Stable](#stable)
- [Nightly](#nightly)
- [Beta](#beta)
- [Version Availability](#version-availability)
- [Self-Hosted](#self-hosted)
- [Cloud](#cloud)
- [Manually Update to Specific Versions](#manually-update-to-specific-versions)
## Release Process
1. **Development on `next` or Feature Branches**
- Improvements, fixes, and new features are developed on the `next` branch or separate feature branches.
2. **Merging to `main`**
- Once ready, changes are merged from the `next` branch into the `main` branch.
3. **Building the Release**
- After merging to `main`, GitHub Actions automatically builds release images for all architectures and pushes them to the GitHub Container Registry with the version tag and the `latest` tag.
4. **Creating a GitHub Release**
- A new GitHub release is manually created with details of the changes made in the version.
5. **Updating the CDN**
- To make a new version publicly available, the version information on the CDN needs to be updated: [https://cdn.coollabs.io/coolify/versions.json](https://cdn.coollabs.io/coolify/versions.json)
> [!NOTE]
> The CDN update may not occur immediately after the GitHub release. It can take hours or even days due to additional testing, stability checks, or potential hotfixes. **The update becomes available only after the CDN is updated.**
## Version Types
<details>
<summary><strong>Stable (coming soon)</strong></summary>
- **Stable**
- The production version suitable for stable, production environments (generally recommended).
- **Update Frequency:** Every 2 to 4 weeks, with more frequent possible hotfixes.
- **Release Size:** Larger but less frequent releases. Multiple nightly versions are consolidated into a single stable release.
- **Versioning Scheme:** Follows semantic versioning (e.g., `v4.0.0`).
- **Installation Command:**
```bash
curl -fsSL https://cdn.coollabs.io/coolify/install.sh | bash
```
</details>
<details>
<summary><strong>Nightly</strong></summary>
- **Nightly**
- The latest development version, suitable for testing the latest changes and experimenting with new features.
- **Update Frequency:** Daily or bi-weekly updates.
- **Release Size:** Smaller, more frequent releases.
- **Versioning Scheme:** TO BE DETERMINED
- **Installation Command:**
```bash
curl -fsSL https://cdn.coollabs.io/coolify-nightly/install.sh | bash -s next
```
</details>
<details>
<summary><strong>Beta</strong></summary>
- **Beta**
- Test releases for the upcoming stable version.
- **Purpose:** Allows users to test and provide feedback on new features and changes before they become stable.
- **Update Frequency:** Available if we think beta testing is necessary.
- **Release Size:** Same size as stable release as it will become the next stabe release after some time.
- **Versioning Scheme:** Follows semantic versioning (e.g., `4.1.0-beta.1`).
- **Installation Command:**
```bash
curl -fsSL https://cdn.coollabs.io/coolify/install.sh | bash
```
</details>
> [!WARNING]
> Do not use nightly/beta builds in production as there is no guarantee of stability.
## Version Availability
When a new version is released and a new GitHub release is created, it doesn't immediately become available for your instance. Here's how version availability works for different instance types.
### Self-Hosted
- **Update Frequency:** More frequent updates, especially on the nightly release channel.
- **Update Availability:** New versions are available once the CDN has been updated.
- **Update Methods:**
1. **Manual Update in Instance Settings:**
- Go to `Settings > Update Check Frequency` and click the `Check Manually` button.
- If an update is available, an upgrade button will appear on the sidebar.
2. **Automatic Update:**
- If enabled, the instance will update automatically at the time set in the settings.
3. **Re-run Installation Script:**
- Run the installation script again to upgrade to the latest version available on the CDN:
```bash
curl -fsSL https://cdn.coollabs.io/coolify/install.sh | bash
```
> [!IMPORTANT]
> If a new release is available on GitHub but your instance hasn't updated yet or no upgrade button is shown in the UI, the CDN might not have been updated yet. This intentional delay ensures stability and allows for hotfixes before official release.
### Cloud
- **Update Frequency:** Less frequent as it's a managed service.
- **Update Availability:** New versions are available once Andras has updated the cloud version manually.
- **Update Method:**
- Updates are managed by Andras, who ensures each cloud version is thoroughly tested and stable before releasing it.
> [!IMPORTANT]
> The cloud version of Coolify may be several versions behind the latest GitHub releases even if the CDN is updated. This is intentional to ensure stability and reliability for cloud users and Andras will manully update the cloud version when the update is ready.
## Manually Update to Specific Versions
> [!CAUTION]
> Updating to unreleased versions is not recommended and may cause issues. Use at your own risk!
To update your Coolify instance to a specific (unreleased) version, use the following command:
```bash
curl -fsSL https://cdn.coollabs.io/coolify/install.sh | bash -s <version>
```
Replace `<version>` with the version you want to update to (for example `4.0.0-beta.332`).

View File

@@ -2,6 +2,7 @@
namespace App\Actions\Application;
use App\Actions\Server\CleanupDocker;
use App\Models\Application;
use Lorisleiva\Actions\Concerns\AsAction;
@@ -9,44 +10,35 @@ class StopApplication
{
use AsAction;
public function handle(Application $application, bool $previewDeployments = false)
public function handle(Application $application, bool $previewDeployments = false, bool $dockerCleanup = true)
{
if ($application->destination->server->isSwarm()) {
instant_remote_process(["docker stack rm {$application->uuid}"], $application->destination->server);
return;
}
$servers = collect([]);
$servers->push($application->destination->server);
$application->additional_servers->map(function ($server) use ($servers) {
$servers->push($server);
});
foreach ($servers as $server) {
try {
$server = $application->destination->server;
if (! $server->isFunctional()) {
return 'Server is not functional';
}
if ($previewDeployments) {
$containers = getCurrentApplicationContainerStatus($server, $application->id, includePullrequests: true);
} else {
$containers = getCurrentApplicationContainerStatus($server, $application->id, 0);
}
if ($containers->count() > 0) {
foreach ($containers as $container) {
$containerName = data_get($container, 'Names');
if ($containerName) {
instant_remote_process(command: ["docker stop --time=30 $containerName"], server: $server, throwError: false);
instant_remote_process(command: ["docker rm $containerName"], server: $server, throwError: false);
instant_remote_process(command: ["docker rm -f {$containerName}"], server: $server, throwError: false);
}
}
ray('Stopping application: '.$application->name);
if ($server->isSwarm()) {
instant_remote_process(["docker stack rm {$application->uuid}"], $server);
return;
}
$containersToStop = $application->getContainersToStop($previewDeployments);
$application->stopContainers($containersToStop, $server);
if ($application->build_pack === 'dockercompose') {
// remove network
$uuid = $application->uuid;
instant_remote_process(["docker network disconnect {$uuid} coolify-proxy"], $server, false);
instant_remote_process(["docker network rm {$uuid}"], $server, false);
$application->delete_connected_networks($application->uuid);
}
if ($dockerCleanup) {
CleanupDocker::dispatch($server, true);
}
} catch (\Exception $e) {
ray($e->getMessage());
return $e->getMessage();
}
}
}

View File

@@ -4,6 +4,7 @@ namespace App\Actions\CoolifyTask;
use App\Enums\ActivityTypes;
use App\Enums\ProcessStatus;
use App\Helpers\SshMultiplexingHelper;
use App\Jobs\ApplicationDeploymentJob;
use App\Models\Server;
use Illuminate\Process\ProcessResult;
@@ -137,7 +138,7 @@ class RunRemoteProcess
$command = $this->activity->getExtraProperty('command');
$server = Server::whereUuid($server_uuid)->firstOrFail();
return generateSshCommand($server, $command);
return SshMultiplexingHelper::generateSshCommand($server, $command);
}
protected function handleOutput(string $type, string $output)

View File

@@ -23,7 +23,7 @@ class StartDragonfly
$startCommand = "dragonfly --requirepass {$this->database->dragonfly_password}";
$container_name = $this->database->uuid;
$this->configuration_dir = database_configuration_dir() . '/' . $container_name;
$this->configuration_dir = database_configuration_dir().'/'.$container_name;
$this->commands = [
"echo 'Starting {$database->name}.'",
@@ -46,9 +46,6 @@ class StartDragonfly
'networks' => [
$this->database->destination->network,
],
'ulimits' => [
'memlock' => '-1',
],
'labels' => [
'coolify.managed' => 'true',
],
@@ -75,7 +72,7 @@ class StartDragonfly
],
],
];
if (!is_null($this->database->limits_cpuset)) {
if (! is_null($this->database->limits_cpuset)) {
data_set($docker_compose, "services.{$container_name}.cpuset", $this->database->limits_cpuset);
}
if ($this->database->destination->server->isLogDrainEnabled() && $this->database->isLogDrainEnabled()) {
@@ -118,10 +115,10 @@ class StartDragonfly
$local_persistent_volumes = [];
foreach ($this->database->persistentStorages as $persistentStorage) {
if ($persistentStorage->host_path !== '' && $persistentStorage->host_path !== null) {
$local_persistent_volumes[] = $persistentStorage->host_path . ':' . $persistentStorage->mount_path;
$local_persistent_volumes[] = $persistentStorage->host_path.':'.$persistentStorage->mount_path;
} else {
$volume_name = $persistentStorage->name;
$local_persistent_volumes[] = $volume_name . ':' . $persistentStorage->mount_path;
$local_persistent_volumes[] = $volume_name.':'.$persistentStorage->mount_path;
}
}
@@ -152,7 +149,7 @@ class StartDragonfly
$environment_variables->push("$env->key=$env->real_value");
}
if ($environment_variables->filter(fn($env) => str($env)->contains('REDIS_PASSWORD'))->isEmpty()) {
if ($environment_variables->filter(fn ($env) => str($env)->contains('REDIS_PASSWORD'))->isEmpty()) {
$environment_variables->push("REDIS_PASSWORD={$this->database->dragonfly_password}");
}

View File

@@ -24,7 +24,7 @@ class StartKeydb
$startCommand = "keydb-server --requirepass {$this->database->keydb_password} --appendonly yes";
$container_name = $this->database->uuid;
$this->configuration_dir = database_configuration_dir() . '/' . $container_name;
$this->configuration_dir = database_configuration_dir().'/'.$container_name;
$this->commands = [
"echo 'Starting {$database->name}.'",
@@ -74,7 +74,7 @@ class StartKeydb
],
],
];
if (!is_null($this->database->limits_cpuset)) {
if (! is_null($this->database->limits_cpuset)) {
data_set($docker_compose, "services.{$container_name}.cpuset", $this->database->limits_cpuset);
}
if ($this->database->destination->server->isLogDrainEnabled() && $this->database->isLogDrainEnabled()) {
@@ -94,10 +94,10 @@ class StartKeydb
if (count($volume_names) > 0) {
$docker_compose['volumes'] = $volume_names;
}
if (!is_null($this->database->keydb_conf) || !empty($this->database->keydb_conf)) {
if (! is_null($this->database->keydb_conf) || ! empty($this->database->keydb_conf)) {
$docker_compose['services'][$container_name]['volumes'][] = [
'type' => 'bind',
'source' => $this->configuration_dir . '/keydb.conf',
'source' => $this->configuration_dir.'/keydb.conf',
'target' => '/etc/keydb/keydb.conf',
'read_only' => true,
];
@@ -125,10 +125,10 @@ class StartKeydb
$local_persistent_volumes = [];
foreach ($this->database->persistentStorages as $persistentStorage) {
if ($persistentStorage->host_path !== '' && $persistentStorage->host_path !== null) {
$local_persistent_volumes[] = $persistentStorage->host_path . ':' . $persistentStorage->mount_path;
$local_persistent_volumes[] = $persistentStorage->host_path.':'.$persistentStorage->mount_path;
} else {
$volume_name = $persistentStorage->name;
$local_persistent_volumes[] = $volume_name . ':' . $persistentStorage->mount_path;
$local_persistent_volumes[] = $volume_name.':'.$persistentStorage->mount_path;
}
}
@@ -159,7 +159,7 @@ class StartKeydb
$environment_variables->push("$env->key=$env->real_value");
}
if ($environment_variables->filter(fn($env) => str($env)->contains('REDIS_PASSWORD'))->isEmpty()) {
if ($environment_variables->filter(fn ($env) => str($env)->contains('REDIS_PASSWORD'))->isEmpty()) {
$environment_variables->push("REDIS_PASSWORD={$this->database->keydb_password}");
}

View File

@@ -21,7 +21,7 @@ class StartMariadb
$this->database = $database;
$container_name = $this->database->uuid;
$this->configuration_dir = database_configuration_dir() . '/' . $container_name;
$this->configuration_dir = database_configuration_dir().'/'.$container_name;
$this->commands = [
"echo 'Starting {$database->name}.'",
@@ -69,7 +69,7 @@ class StartMariadb
],
],
];
if (!is_null($this->database->limits_cpuset)) {
if (! is_null($this->database->limits_cpuset)) {
data_set($docker_compose, "services.{$container_name}.cpuset", $this->database->limits_cpuset);
}
if ($this->database->destination->server->isLogDrainEnabled() && $this->database->isLogDrainEnabled()) {
@@ -89,10 +89,10 @@ class StartMariadb
if (count($volume_names) > 0) {
$docker_compose['volumes'] = $volume_names;
}
if (!is_null($this->database->mariadb_conf) || !empty($this->database->mariadb_conf)) {
if (! is_null($this->database->mariadb_conf) || ! empty($this->database->mariadb_conf)) {
$docker_compose['services'][$container_name]['volumes'][] = [
'type' => 'bind',
'source' => $this->configuration_dir . '/custom-config.cnf',
'source' => $this->configuration_dir.'/custom-config.cnf',
'target' => '/etc/mysql/conf.d/custom-config.cnf',
'read_only' => true,
];
@@ -120,10 +120,10 @@ class StartMariadb
$local_persistent_volumes = [];
foreach ($this->database->persistentStorages as $persistentStorage) {
if ($persistentStorage->host_path !== '' && $persistentStorage->host_path !== null) {
$local_persistent_volumes[] = $persistentStorage->host_path . ':' . $persistentStorage->mount_path;
$local_persistent_volumes[] = $persistentStorage->host_path.':'.$persistentStorage->mount_path;
} else {
$volume_name = $persistentStorage->name;
$local_persistent_volumes[] = $volume_name . ':' . $persistentStorage->mount_path;
$local_persistent_volumes[] = $volume_name.':'.$persistentStorage->mount_path;
}
}
@@ -154,18 +154,18 @@ class StartMariadb
$environment_variables->push("$env->key=$env->real_value");
}
if ($environment_variables->filter(fn($env) => str($env)->contains('MARIADB_ROOT_PASSWORD'))->isEmpty()) {
if ($environment_variables->filter(fn ($env) => str($env)->contains('MARIADB_ROOT_PASSWORD'))->isEmpty()) {
$environment_variables->push("MARIADB_ROOT_PASSWORD={$this->database->mariadb_root_password}");
}
if ($environment_variables->filter(fn($env) => str($env)->contains('MARIADB_DATABASE'))->isEmpty()) {
if ($environment_variables->filter(fn ($env) => str($env)->contains('MARIADB_DATABASE'))->isEmpty()) {
$environment_variables->push("MARIADB_DATABASE={$this->database->mariadb_database}");
}
if ($environment_variables->filter(fn($env) => str($env)->contains('MARIADB_USER'))->isEmpty()) {
if ($environment_variables->filter(fn ($env) => str($env)->contains('MARIADB_USER'))->isEmpty()) {
$environment_variables->push("MARIADB_USER={$this->database->mariadb_user}");
}
if ($environment_variables->filter(fn($env) => str($env)->contains('MARIADB_PASSWORD'))->isEmpty()) {
if ($environment_variables->filter(fn ($env) => str($env)->contains('MARIADB_PASSWORD'))->isEmpty()) {
$environment_variables->push("MARIADB_PASSWORD={$this->database->mariadb_password}");
}

View File

@@ -23,7 +23,7 @@ class StartMongodb
$startCommand = 'mongod';
$container_name = $this->database->uuid;
$this->configuration_dir = database_configuration_dir() . '/' . $container_name;
$this->configuration_dir = database_configuration_dir().'/'.$container_name;
$this->commands = [
"echo 'Starting {$database->name}.'",
@@ -77,7 +77,7 @@ class StartMongodb
],
],
];
if (!is_null($this->database->limits_cpuset)) {
if (! is_null($this->database->limits_cpuset)) {
data_set($docker_compose, "services.{$container_name}.cpuset", $this->database->limits_cpuset);
}
if ($this->database->destination->server->isLogDrainEnabled() && $this->database->isLogDrainEnabled()) {
@@ -97,19 +97,19 @@ class StartMongodb
if (count($volume_names) > 0) {
$docker_compose['volumes'] = $volume_names;
}
if (!is_null($this->database->mongo_conf) || !empty($this->database->mongo_conf)) {
if (! is_null($this->database->mongo_conf) || ! empty($this->database->mongo_conf)) {
$docker_compose['services'][$container_name]['volumes'][] = [
'type' => 'bind',
'source' => $this->configuration_dir . '/mongod.conf',
'source' => $this->configuration_dir.'/mongod.conf',
'target' => '/etc/mongo/mongod.conf',
'read_only' => true,
];
$docker_compose['services'][$container_name]['command'] = $startCommand . ' --config /etc/mongo/mongod.conf';
$docker_compose['services'][$container_name]['command'] = $startCommand.' --config /etc/mongo/mongod.conf';
}
$this->add_default_database();
$docker_compose['services'][$container_name]['volumes'][] = [
'type' => 'bind',
'source' => $this->configuration_dir . '/docker-entrypoint-initdb.d',
'source' => $this->configuration_dir.'/docker-entrypoint-initdb.d',
'target' => '/docker-entrypoint-initdb.d',
'read_only' => true,
];
@@ -136,10 +136,10 @@ class StartMongodb
$local_persistent_volumes = [];
foreach ($this->database->persistentStorages as $persistentStorage) {
if ($persistentStorage->host_path !== '' && $persistentStorage->host_path !== null) {
$local_persistent_volumes[] = $persistentStorage->host_path . ':' . $persistentStorage->mount_path;
$local_persistent_volumes[] = $persistentStorage->host_path.':'.$persistentStorage->mount_path;
} else {
$volume_name = $persistentStorage->name;
$local_persistent_volumes[] = $volume_name . ':' . $persistentStorage->mount_path;
$local_persistent_volumes[] = $volume_name.':'.$persistentStorage->mount_path;
}
}
@@ -170,15 +170,15 @@ class StartMongodb
$environment_variables->push("$env->key=$env->real_value");
}
if ($environment_variables->filter(fn($env) => str($env)->contains('MONGO_INITDB_ROOT_USERNAME'))->isEmpty()) {
if ($environment_variables->filter(fn ($env) => str($env)->contains('MONGO_INITDB_ROOT_USERNAME'))->isEmpty()) {
$environment_variables->push("MONGO_INITDB_ROOT_USERNAME={$this->database->mongo_initdb_root_username}");
}
if ($environment_variables->filter(fn($env) => str($env)->contains('MONGO_INITDB_ROOT_PASSWORD'))->isEmpty()) {
if ($environment_variables->filter(fn ($env) => str($env)->contains('MONGO_INITDB_ROOT_PASSWORD'))->isEmpty()) {
$environment_variables->push("MONGO_INITDB_ROOT_PASSWORD={$this->database->mongo_initdb_root_password}");
}
if ($environment_variables->filter(fn($env) => str($env)->contains('MONGO_INITDB_DATABASE'))->isEmpty()) {
if ($environment_variables->filter(fn ($env) => str($env)->contains('MONGO_INITDB_DATABASE'))->isEmpty()) {
$environment_variables->push("MONGO_INITDB_DATABASE={$this->database->mongo_initdb_database}");
}

View File

@@ -21,7 +21,7 @@ class StartMysql
$this->database = $database;
$container_name = $this->database->uuid;
$this->configuration_dir = database_configuration_dir() . '/' . $container_name;
$this->configuration_dir = database_configuration_dir().'/'.$container_name;
$this->commands = [
"echo 'Starting {$database->name}.'",
@@ -69,7 +69,7 @@ class StartMysql
],
],
];
if (!is_null($this->database->limits_cpuset)) {
if (! is_null($this->database->limits_cpuset)) {
data_set($docker_compose, "services.{$container_name}.cpuset", $this->database->limits_cpuset);
}
if ($this->database->destination->server->isLogDrainEnabled() && $this->database->isLogDrainEnabled()) {
@@ -89,10 +89,10 @@ class StartMysql
if (count($volume_names) > 0) {
$docker_compose['volumes'] = $volume_names;
}
if (!is_null($this->database->mysql_conf) || !empty($this->database->mysql_conf)) {
if (! is_null($this->database->mysql_conf) || ! empty($this->database->mysql_conf)) {
$docker_compose['services'][$container_name]['volumes'][] = [
'type' => 'bind',
'source' => $this->configuration_dir . '/custom-config.cnf',
'source' => $this->configuration_dir.'/custom-config.cnf',
'target' => '/etc/mysql/conf.d/custom-config.cnf',
'read_only' => true,
];
@@ -120,10 +120,10 @@ class StartMysql
$local_persistent_volumes = [];
foreach ($this->database->persistentStorages as $persistentStorage) {
if ($persistentStorage->host_path !== '' && $persistentStorage->host_path !== null) {
$local_persistent_volumes[] = $persistentStorage->host_path . ':' . $persistentStorage->mount_path;
$local_persistent_volumes[] = $persistentStorage->host_path.':'.$persistentStorage->mount_path;
} else {
$volume_name = $persistentStorage->name;
$local_persistent_volumes[] = $volume_name . ':' . $persistentStorage->mount_path;
$local_persistent_volumes[] = $volume_name.':'.$persistentStorage->mount_path;
}
}
@@ -154,18 +154,18 @@ class StartMysql
$environment_variables->push("$env->key=$env->real_value");
}
if ($environment_variables->filter(fn($env) => str($env)->contains('MYSQL_ROOT_PASSWORD'))->isEmpty()) {
if ($environment_variables->filter(fn ($env) => str($env)->contains('MYSQL_ROOT_PASSWORD'))->isEmpty()) {
$environment_variables->push("MYSQL_ROOT_PASSWORD={$this->database->mysql_root_password}");
}
if ($environment_variables->filter(fn($env) => str($env)->contains('MYSQL_DATABASE'))->isEmpty()) {
if ($environment_variables->filter(fn ($env) => str($env)->contains('MYSQL_DATABASE'))->isEmpty()) {
$environment_variables->push("MYSQL_DATABASE={$this->database->mysql_database}");
}
if ($environment_variables->filter(fn($env) => str($env)->contains('MYSQL_USER'))->isEmpty()) {
if ($environment_variables->filter(fn ($env) => str($env)->contains('MYSQL_USER'))->isEmpty()) {
$environment_variables->push("MYSQL_USER={$this->database->mysql_user}");
}
if ($environment_variables->filter(fn($env) => str($env)->contains('MYSQL_PASSWORD'))->isEmpty()) {
if ($environment_variables->filter(fn ($env) => str($env)->contains('MYSQL_PASSWORD'))->isEmpty()) {
$environment_variables->push("MYSQL_PASSWORD={$this->database->mysql_password}");
}

View File

@@ -37,7 +37,6 @@ class StartPostgresql
$this->generate_init_scripts();
$this->add_custom_conf();
$docker_compose = [
'services' => [
$container_name => [

View File

@@ -24,7 +24,7 @@ class StartRedis
$startCommand = "redis-server --requirepass {$this->database->redis_password} --appendonly yes";
$container_name = $this->database->uuid;
$this->configuration_dir = database_configuration_dir() . '/' . $container_name;
$this->configuration_dir = database_configuration_dir().'/'.$container_name;
$this->commands = [
"echo 'Starting {$database->name}.'",
@@ -78,7 +78,7 @@ class StartRedis
],
],
];
if (!is_null($this->database->limits_cpuset)) {
if (! is_null($this->database->limits_cpuset)) {
data_set($docker_compose, "services.{$container_name}.cpuset", $this->database->limits_cpuset);
}
if ($this->database->destination->server->isLogDrainEnabled() && $this->database->isLogDrainEnabled()) {
@@ -98,10 +98,10 @@ class StartRedis
if (count($volume_names) > 0) {
$docker_compose['volumes'] = $volume_names;
}
if (!is_null($this->database->redis_conf) || !empty($this->database->redis_conf)) {
if (! is_null($this->database->redis_conf) || ! empty($this->database->redis_conf)) {
$docker_compose['services'][$container_name]['volumes'][] = [
'type' => 'bind',
'source' => $this->configuration_dir . '/redis.conf',
'source' => $this->configuration_dir.'/redis.conf',
'target' => '/usr/local/etc/redis/redis.conf',
'read_only' => true,
];
@@ -130,10 +130,10 @@ class StartRedis
$local_persistent_volumes = [];
foreach ($this->database->persistentStorages as $persistentStorage) {
if ($persistentStorage->host_path !== '' && $persistentStorage->host_path !== null) {
$local_persistent_volumes[] = $persistentStorage->host_path . ':' . $persistentStorage->mount_path;
$local_persistent_volumes[] = $persistentStorage->host_path.':'.$persistentStorage->mount_path;
} else {
$volume_name = $persistentStorage->name;
$local_persistent_volumes[] = $volume_name . ':' . $persistentStorage->mount_path;
$local_persistent_volumes[] = $volume_name.':'.$persistentStorage->mount_path;
}
}
@@ -164,7 +164,7 @@ class StartRedis
$environment_variables->push("$env->key=$env->real_value");
}
if ($environment_variables->filter(fn($env) => str($env)->contains('REDIS_PASSWORD'))->isEmpty()) {
if ($environment_variables->filter(fn ($env) => str($env)->contains('REDIS_PASSWORD'))->isEmpty()) {
$environment_variables->push("REDIS_PASSWORD={$this->database->redis_password}");
}

View File

@@ -2,6 +2,7 @@
namespace App\Actions\Database;
use App\Actions\Server\CleanupDocker;
use App\Models\StandaloneClickhouse;
use App\Models\StandaloneDragonfly;
use App\Models\StandaloneKeydb;
@@ -10,25 +11,65 @@ use App\Models\StandaloneMongodb;
use App\Models\StandaloneMysql;
use App\Models\StandalonePostgresql;
use App\Models\StandaloneRedis;
use Illuminate\Support\Facades\Process;
use Lorisleiva\Actions\Concerns\AsAction;
class StopDatabase
{
use AsAction;
public function handle(StandaloneRedis|StandalonePostgresql|StandaloneMongodb|StandaloneMysql|StandaloneMariadb|StandaloneKeydb|StandaloneDragonfly|StandaloneClickhouse $database)
public function handle(StandaloneRedis|StandalonePostgresql|StandaloneMongodb|StandaloneMysql|StandaloneMariadb|StandaloneKeydb|StandaloneDragonfly|StandaloneClickhouse $database, bool $isDeleteOperation = false, bool $dockerCleanup = true)
{
$server = $database->destination->server;
if (! $server->isFunctional()) {
return 'Server is not functional';
}
instant_remote_process(command: ["docker stop --time=30 $database->uuid"], server: $server, throwError: false);
instant_remote_process(command: ["docker rm $database->uuid"], server: $server, throwError: false);
instant_remote_process(command: ["docker rm -f $database->uuid"], server: $server, throwError: false);
$this->stopContainer($database, $database->uuid, 300);
if (! $isDeleteOperation) {
if ($dockerCleanup) {
CleanupDocker::dispatch($server, true);
}
}
if ($database->is_public) {
StopDatabaseProxy::run($database);
}
return 'Database stopped successfully';
}
private function stopContainer($database, string $containerName, int $timeout = 300): void
{
$server = $database->destination->server;
$process = Process::timeout($timeout)->start("docker stop --time=$timeout $containerName");
$startTime = time();
while ($process->running()) {
if (time() - $startTime >= $timeout) {
$this->forceStopContainer($containerName, $server);
break;
}
usleep(100000);
}
$this->removeContainer($containerName, $server);
}
private function forceStopContainer(string $containerName, $server): void
{
instant_remote_process(command: ["docker kill $containerName"], server: $server, throwError: false);
}
private function removeContainer(string $containerName, $server): void
{
instant_remote_process(command: ["docker rm -f $containerName"], server: $server, throwError: false);
}
private function deleteConnectedNetworks($uuid, $server)
{
instant_remote_process(["docker network disconnect {$uuid} coolify-proxy"], $server, false);
instant_remote_process(["docker network rm {$uuid}"], $server, false);
}
}

View File

@@ -543,7 +543,7 @@ class GetContainersStatus
}
}
}
$exitedServices = $exitedServices->unique('id');
$exitedServices = $exitedServices->unique('uuid');
foreach ($exitedServices as $exitedService) {
if (str($exitedService->status)->startsWith('exited')) {
continue;
@@ -651,8 +651,9 @@ class GetContainersStatus
// $this->server->team?->notify(new ContainerStopped($containerName, $this->server, $url));
}
// Check if proxy is running
$this->server->proxyType();
if (! $this->server->proxySet() || $this->server->proxy->force_stop) {
return;
}
$foundProxyContainer = $this->containers->filter(function ($value, $key) {
if ($this->server->isSwarm()) {
return data_get($value, 'Spec.Name') === 'coolify-proxy_traefik';

View File

@@ -2,7 +2,6 @@
namespace App\Actions\Fortify;
use App\Models\InstanceSettings;
use App\Models\User;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Validator;
@@ -20,7 +19,7 @@ class CreateNewUser implements CreatesNewUsers
*/
public function create(array $input): User
{
$settings = InstanceSettings::get();
$settings = instanceSettings();
if (! $settings->is_registration_enabled) {
abort(403);
}
@@ -48,7 +47,7 @@ class CreateNewUser implements CreatesNewUsers
$team = $user->teams()->first();
// Disable registration after first user is created
$settings = InstanceSettings::get();
$settings = instanceSettings();
$settings->is_registration_enabled = false;
$settings->save();
} else {

View File

@@ -2,7 +2,6 @@
namespace App\Actions\License;
use App\Models\InstanceSettings;
use Illuminate\Support\Facades\Http;
use Lorisleiva\Actions\Concerns\AsAction;
@@ -13,7 +12,7 @@ class CheckResaleLicense
public function handle()
{
try {
$settings = InstanceSettings::get();
$settings = instanceSettings();
if (isDev()) {
$settings->update([
'is_resale_license_active' => true,

View File

@@ -22,7 +22,7 @@ class CheckConfiguration
];
$proxy_configuration = instant_remote_process($payload, $server, false);
if ($reset || ! $proxy_configuration || is_null($proxy_configuration)) {
$proxy_configuration = str(generate_default_proxy_configuration($server))->trim()->value;
$proxy_configuration = str(generate_default_proxy_configuration($server))->trim()->value();
}
if (! $proxy_configuration || is_null($proxy_configuration)) {
throw new \Exception('Could not generate proxy configuration');

View File

@@ -2,14 +2,17 @@
namespace App\Actions\Proxy;
use App\Enums\ProxyTypes;
use App\Models\Server;
use Lorisleiva\Actions\Concerns\AsAction;
use Symfony\Component\Yaml\Yaml;
class CheckProxy
{
use AsAction;
public function handle(Server $server, $fromUI = false)
// It should return if the proxy should be started (true) or not (false)
public function handle(Server $server, $fromUI = false): bool
{
if (! $server->isFunctional()) {
return false;
@@ -26,7 +29,7 @@ class CheckProxy
if (is_null($proxyType) || $proxyType === 'NONE' || $server->proxy->force_stop) {
return false;
}
['uptime' => $uptime, 'error' => $error] = $server->validateConnection();
['uptime' => $uptime, 'error' => $error] = $server->validateConnection(false);
if (! $uptime) {
throw new \Exception($error);
}
@@ -62,22 +65,42 @@ class CheckProxy
$ip = 'host.docker.internal';
}
$connection80 = @fsockopen($ip, '80');
$connection443 = @fsockopen($ip, '443');
$port80 = is_resource($connection80) && fclose($connection80);
$port443 = is_resource($connection443) && fclose($connection443);
if ($port80) {
if ($fromUI) {
throw new \Exception("Port 80 is in use.<br>You must stop the process using this port.<br>Docs: <a target='_blank' href='https://coolify.io/docs'>https://coolify.io/docs</a><br>Discord: <a target='_blank' href='https://coollabs.io/discord'>https://coollabs.io/discord</a>");
$portsToCheck = ['80', '443'];
try {
if ($server->proxyType() !== ProxyTypes::NONE->value) {
$proxyCompose = CheckConfiguration::run($server);
if (isset($proxyCompose)) {
$yaml = Yaml::parse($proxyCompose);
$portsToCheck = [];
if ($server->proxyType() === ProxyTypes::TRAEFIK->value) {
$ports = data_get($yaml, 'services.traefik.ports');
} elseif ($server->proxyType() === ProxyTypes::CADDY->value) {
$ports = data_get($yaml, 'services.caddy.ports');
}
if (isset($ports)) {
foreach ($ports as $port) {
$portsToCheck[] = str($port)->before(':')->value();
}
}
}
} else {
return false;
$portsToCheck = [];
}
} catch (\Exception $e) {
ray($e->getMessage());
}
if ($port443) {
if ($fromUI) {
throw new \Exception("Port 443 is in use.<br>You must stop the process using this port.<br>Docs: <a target='_blank' href='https://coolify.io/docs'>https://coolify.io/docs</a><br>Discord: <a target='_blank' href='https://coollabs.io/discord'>https://coollabs.io/discord</a>");
} else {
return false;
if (count($portsToCheck) === 0) {
return false;
}
foreach ($portsToCheck as $port) {
$connection = @fsockopen($ip, $port);
if (is_resource($connection) && fclose($connection)) {
if ($fromUI) {
throw new \Exception("Port $port is in use.<br>You must stop the process using this port.<br>Docs: <a target='_blank' href='https://coolify.io/docs'>https://coolify.io/docs</a><br>Discord: <a target='_blank' href='https://coollabs.io/discord'>https://coollabs.io/discord</a>");
} else {
return false;
}
}
}

View File

@@ -26,7 +26,7 @@ class StartProxy
}
SaveConfiguration::run($server, $configuration);
$docker_compose_yml_base64 = base64_encode($configuration);
$server->proxy->last_applied_settings = str($docker_compose_yml_base64)->pipe('md5')->value;
$server->proxy->last_applied_settings = str($docker_compose_yml_base64)->pipe('md5')->value();
$server->save();
if ($server->isSwarm()) {
$commands = $commands->merge([
@@ -35,7 +35,7 @@ class StartProxy
"echo 'Creating required Docker Compose file.'",
"echo 'Starting coolify-proxy.'",
'docker stack deploy -c docker-compose.yml coolify-proxy',
"echo 'Proxy started successfully.'",
"echo 'Successfully started coolify-proxy.'",
]);
} else {
$caddfile = 'import /dynamic/*.caddy';
@@ -46,11 +46,14 @@ class StartProxy
"echo 'Creating required Docker Compose file.'",
"echo 'Pulling docker image.'",
'docker compose pull',
"echo 'Stopping existing coolify-proxy.'",
'docker compose down -v --remove-orphans > /dev/null 2>&1',
'if docker ps -a --format "{{.Names}}" | grep -q "^coolify-proxy$"; then',
" echo 'Stopping and removing existing coolify-proxy.'",
' docker rm -f coolify-proxy || true',
" echo 'Successfully stopped and removed existing coolify-proxy.'",
'fi',
"echo 'Starting coolify-proxy.'",
'docker compose up -d --remove-orphans',
"echo 'Proxy started successfully.'",
"echo 'Successfully started coolify-proxy.'",
]);
$commands = $commands->merge(connectProxyToNetworks($server));
}

View File

@@ -11,22 +11,29 @@ class CleanupDocker
public function handle(Server $server)
{
$settings = instanceSettings();
$helperImageVersion = data_get($settings, 'helper_version');
$helperImage = config('coolify.helper_image');
$helperImageWithVersion = "$helperImage:$helperImageVersion";
$commands = $this->getCommands();
$commands = [
'docker container prune -f --filter "label=coolify.managed=true" --filter "label!=coolify.proxy=true"',
'docker image prune -af --filter "label!=coolify.managed=true"',
'docker builder prune -af',
"docker images --filter before=$helperImageWithVersion --filter reference=$helperImage | grep $helperImage | awk '{print $3}' | xargs -r docker rmi -f",
];
$serverSettings = $server->settings;
if ($serverSettings->delete_unused_volumes) {
$commands[] = 'docker volume prune -af';
}
if ($serverSettings->delete_unused_networks) {
$commands[] = 'docker network prune -f';
}
foreach ($commands as $command) {
instant_remote_process([$command], $server, false);
}
}
private function getCommands(): array
{
$commonCommands = [
'docker container prune -f --filter "label=coolify.managed=true"',
'docker image prune -af',
'docker builder prune -af',
];
return $commonCommands;
}
}

View File

@@ -2,6 +2,7 @@
namespace App\Actions\Server;
use App\Events\CloudflareTunnelConfigured;
use App\Models\Server;
use Lorisleiva\Actions\Concerns\AsAction;
use Symfony\Component\Yaml\Yaml;
@@ -40,12 +41,17 @@ class ConfigureCloudflared
instant_remote_process($commands, $server);
} catch (\Throwable $e) {
ray($e);
$server->settings->is_cloudflare_tunnel = false;
$server->settings->save();
throw $e;
} finally {
CloudflareTunnelConfigured::dispatch($server->team_id);
$commands = collect([
'rm -fr /tmp/cloudflared',
]);
instant_remote_process($commands, $server);
}
}
}

View File

@@ -2,7 +2,7 @@
namespace App\Actions\Server;
use App\Models\InstanceSettings;
use App\Jobs\PullHelperImageJob;
use App\Models\Server;
use Lorisleiva\Actions\Concerns\AsAction;
@@ -19,7 +19,7 @@ class UpdateCoolify
public function handle($manual_update = false)
{
try {
$settings = InstanceSettings::get();
$settings = instanceSettings();
$this->server = Server::find(0);
if (! $this->server) {
return;
@@ -55,6 +55,13 @@ class UpdateCoolify
return;
}
$all_servers = Server::all();
$servers = $all_servers->where('settings.is_usable', true)->where('settings.is_reachable', true)->where('ip', '!=', '1.2.3.4');
foreach ($servers as $server) {
PullHelperImageJob::dispatch($server);
}
instant_remote_process(["docker pull -q ghcr.io/coollabsio/coolify:{$this->latestVersion}"], $this->server, false);
remote_process([

View File

@@ -2,6 +2,7 @@
namespace App\Actions\Service;
use App\Actions\Server\CleanupDocker;
use App\Models\Service;
use Lorisleiva\Actions\Concerns\AsAction;
@@ -9,11 +10,11 @@ class DeleteService
{
use AsAction;
public function handle(Service $service)
public function handle(Service $service, bool $deleteConfigurations, bool $deleteVolumes, bool $dockerCleanup, bool $deleteConnectedNetworks)
{
try {
$server = data_get($service, 'server');
if ($server->isFunctional()) {
if ($deleteVolumes && $server->isFunctional()) {
$storagesToDelete = collect([]);
$service->environment_variables()->delete();
@@ -33,13 +34,29 @@ class DeleteService
foreach ($storagesToDelete as $storage) {
$commands[] = "docker volume rm -f $storage->name";
}
$commands[] = "docker rm -f $service->uuid";
instant_remote_process($commands, $server, false);
// Execute volume deletion first, this must be done first otherwise volumes will not be deleted.
if (! empty($commands)) {
foreach ($commands as $command) {
$result = instant_remote_process([$command], $server, false);
if ($result !== 0) {
ray("Failed to execute: $command");
}
}
}
}
if ($deleteConnectedNetworks) {
$service->delete_connected_networks($service->uuid);
}
instant_remote_process(["docker rm -f $service->uuid"], $server, throwError: false);
} catch (\Exception $e) {
throw new \Exception($e->getMessage());
} finally {
if ($deleteConfigurations) {
$service->delete_configurations();
}
foreach ($service->applications()->get() as $application) {
$application->forceDelete();
}
@@ -50,6 +67,11 @@ class DeleteService
$task->delete();
}
$service->tags()->detach();
$service->forceDelete();
if ($dockerCleanup) {
CleanupDocker::dispatch($server, true);
}
}
}
}

View File

@@ -16,8 +16,10 @@ class StartService
$service->saveComposeConfigs();
$commands[] = 'cd '.$service->workdir();
$commands[] = "echo 'Saved configuration files to {$service->workdir()}.'";
$commands[] = "echo 'Creating Docker network.'";
$commands[] = "docker network inspect $service->uuid >/dev/null 2>&1 || docker network create --attachable $service->uuid";
if ($service->networks()->count() > 0) {
$commands[] = "echo 'Creating Docker network.'";
$commands[] = "docker network inspect $service->uuid >/dev/null 2>&1 || docker network create --attachable $service->uuid";
}
$commands[] = 'echo Starting service.';
$commands[] = "echo 'Pulling images.'";
$commands[] = 'docker compose pull';
@@ -29,7 +31,7 @@ class StartService
$network = $service->destination->network;
$serviceNames = data_get(Yaml::parse($compose), 'services', []);
foreach ($serviceNames as $serviceName => $serviceConfig) {
$commands[] = "docker network connect --alias {$serviceName}-{$service->uuid} $network {$serviceName}-{$service->uuid} || true";
$commands[] = "docker network connect --alias {$serviceName}-{$service->uuid} $network {$serviceName}-{$service->uuid} >/dev/null 2>&1 || true";
}
}
$activity = remote_process($commands, $service->server, type_uuid: $service->uuid, callEventOnFinish: 'ServiceStatusChanged');

View File

@@ -2,6 +2,7 @@
namespace App\Actions\Service;
use App\Actions\Server\CleanupDocker;
use App\Models\Service;
use Lorisleiva\Actions\Concerns\AsAction;
@@ -9,40 +10,27 @@ class StopService
{
use AsAction;
public function handle(Service $service)
public function handle(Service $service, bool $isDeleteOperation = false, bool $dockerCleanup = true)
{
try {
$server = $service->destination->server;
if (! $server->isFunctional()) {
return 'Server is not functional';
}
ray('Stopping service: '.$service->name);
$applications = $service->applications()->get();
foreach ($applications as $application) {
if ($applications->count() < 6) {
instant_remote_process(command: ["docker stop --time=10 {$application->name}-{$service->uuid}"], server: $server, throwError: false);
}
instant_remote_process(command: ["docker rm {$application->name}-{$service->uuid}"], server: $server, throwError: false);
instant_remote_process(command: ["docker rm -f {$application->name}-{$service->uuid}"], server: $server, throwError: false);
$application->update(['status' => 'exited']);
}
$dbs = $service->databases()->get();
foreach ($dbs as $db) {
if ($dbs->count() < 6) {
instant_remote_process(command: ["docker stop --time=10 {$db->name}-{$service->uuid}"], server: $server, throwError: false);
$containersToStop = $service->getContainersToStop();
$service->stopContainers($containersToStop, $server);
if (! $isDeleteOperation) {
$service->delete_connected_networks($service->uuid);
if ($dockerCleanup) {
CleanupDocker::dispatch($server, true);
}
instant_remote_process(command: ["docker rm {$db->name}-{$service->uuid}"], server: $server, throwError: false);
instant_remote_process(command: ["docker rm -f {$db->name}-{$service->uuid}"], server: $server, throwError: false);
$db->update(['status' => 'exited']);
}
instant_remote_process(["docker network disconnect {$service->uuid} coolify-proxy"], $service->server);
instant_remote_process(["docker network rm {$service->uuid}"], $service->server);
} catch (\Exception $e) {
ray($e->getMessage());
return $e->getMessage();
}
}
}

View File

@@ -0,0 +1,50 @@
<?php
namespace App\Console\Commands;
use App\Enums\ApplicationDeploymentStatus;
use App\Models\ApplicationDeploymentQueue;
use Illuminate\Console\Command;
class CheckApplicationDeploymentQueue extends Command
{
protected $signature = 'check:deployment-queue {--force} {--seconds=3600}';
protected $description = 'Check application deployment queue.';
public function handle()
{
$seconds = $this->option('seconds');
$deployments = ApplicationDeploymentQueue::whereIn('status', [
ApplicationDeploymentStatus::IN_PROGRESS,
ApplicationDeploymentStatus::QUEUED,
])->where('created_at', '<=', now()->subSeconds($seconds))->get();
if ($deployments->isEmpty()) {
$this->info('No deployments found in the last '.$seconds.' seconds.');
return;
}
$this->info('Found '.$deployments->count().' deployments created in the last '.$seconds.' seconds.');
foreach ($deployments as $deployment) {
if ($this->option('force')) {
$this->info('Deployment '.$deployment->id.' created at '.$deployment->created_at.' is older than '.$seconds.' seconds. Setting status to failed.');
$this->cancelDeployment($deployment);
} else {
$this->info('Deployment '.$deployment->id.' created at '.$deployment->created_at.' is older than '.$seconds.' seconds. Setting status to failed.');
if ($this->confirm('Do you want to cancel this deployment?', true)) {
$this->cancelDeployment($deployment);
}
}
}
}
private function cancelDeployment(ApplicationDeploymentQueue $deployment)
{
$deployment->update(['status' => ApplicationDeploymentStatus::FAILED]);
if ($deployment->server?->isFunctional()) {
remote_process(['docker rm -f '.$deployment->deployment_uuid], $deployment->server, false);
}
}
}

View File

@@ -7,9 +7,9 @@ use Illuminate\Console\Command;
class CleanupApplicationDeploymentQueue extends Command
{
protected $signature = 'cleanup:application-deployment-queue {--team-id=}';
protected $signature = 'cleanup:deployment-queue {--team-id=}';
protected $description = 'CleanupApplicationDeploymentQueue';
protected $description = 'Cleanup application deployment queue.';
public function handle()
{

View File

@@ -1,24 +0,0 @@
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Redis;
class CleanupQueue extends Command
{
protected $signature = 'cleanup:queue';
protected $description = 'Cleanup Queue';
public function handle()
{
echo "Running queue cleanup...\n";
$prefix = config('database.redis.options.prefix');
$keys = Redis::connection()->keys('*:laravel*');
foreach ($keys as $key) {
$keyWithoutPrefix = str_replace($prefix, '', $key);
Redis::connection()->del($keyWithoutPrefix);
}
}
}

View File

@@ -0,0 +1,31 @@
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Redis;
class CleanupRedis extends Command
{
protected $signature = 'cleanup:redis';
protected $description = 'Cleanup Redis';
public function handle()
{
echo "Cleanup Redis keys.\n";
$prefix = config('database.redis.options.prefix');
$keys = Redis::connection()->keys('*:laravel*');
collect($keys)->each(function ($key) use ($prefix) {
$keyWithoutPrefix = str_replace($prefix, '', $key);
Redis::connection()->del($keyWithoutPrefix);
});
$queueOverlaps = Redis::connection()->keys('*laravel-queue-overlap*');
collect($queueOverlaps)->each(function ($key) {
Redis::connection()->del($key);
});
}
}

View File

@@ -2,10 +2,13 @@
namespace App\Console\Commands;
use App\Jobs\CleanupHelperContainersJob;
use App\Models\Application;
use App\Models\ApplicationDeploymentQueue;
use App\Models\ApplicationPreview;
use App\Models\ScheduledDatabaseBackup;
use App\Models\ScheduledTask;
use App\Models\Server;
use App\Models\Service;
use App\Models\ServiceApplication;
use App\Models\ServiceDatabase;
@@ -35,6 +38,27 @@ class CleanupStuckedResources extends Command
private function cleanup_stucked_resources()
{
try {
$servers = Server::all()->filter(function ($server) {
return $server->isFunctional();
});
foreach ($servers as $server) {
CleanupHelperContainersJob::dispatch($server);
}
} catch (\Throwable $e) {
echo "Error in cleaning stucked resources: {$e->getMessage()}\n";
}
try {
$applicationsDeploymentQueue = ApplicationDeploymentQueue::get();
foreach ($applicationsDeploymentQueue as $applicationDeploymentQueue) {
if (is_null($applicationDeploymentQueue->application)) {
echo "Deleting stuck application deployment queue: {$applicationDeploymentQueue->id}\n";
$applicationDeploymentQueue->delete();
}
}
} catch (\Throwable $e) {
echo "Error in cleaning stuck application deployment queue: {$e->getMessage()}\n";
}
try {
$applications = Application::withTrashed()->whereNotNull('deleted_at')->get();
foreach ($applications as $application) {

View File

@@ -48,6 +48,13 @@ class Dev extends Command
echo "Generating APP_KEY.\n";
Artisan::call('key:generate');
}
// Generate STORAGE link if not exists
if (! file_exists(public_path('storage'))) {
echo "Generating STORAGE link.\n";
Artisan::call('storage:link');
}
// Seed database if it's empty
$settings = InstanceSettings::find(0);
if (! $settings) {

View File

@@ -5,10 +5,8 @@ namespace App\Console\Commands;
use App\Actions\Server\StopSentinel;
use App\Enums\ActivityTypes;
use App\Enums\ApplicationDeploymentStatus;
use App\Jobs\CleanupHelperContainersJob;
use App\Models\ApplicationDeploymentQueue;
use App\Models\Environment;
use App\Models\InstanceSettings;
use App\Models\ScheduledDatabaseBackup;
use App\Models\Server;
use App\Models\StandalonePostgresql;
@@ -18,7 +16,7 @@ use Illuminate\Support\Facades\Http;
class Init extends Command
{
protected $signature = 'app:init {--full-cleanup} {--cleanup-deployments} {--cleanup-proxy-networks}';
protected $signature = 'app:init {--force-cloud}';
protected $description = 'Cleanup instance related stuffs';
@@ -26,9 +24,63 @@ class Init extends Command
public function handle()
{
if (isCloud() && ! $this->option('force-cloud')) {
echo "Skipping init as we are on cloud and --force-cloud option is not set\n";
return;
}
$this->servers = Server::all();
$this->alive();
get_public_ips();
if (isCloud()) {
} else {
$this->send_alive_signal();
get_public_ips();
}
// Backward compatibility
$this->disable_metrics();
$this->replace_slash_in_environment_name();
$this->restore_coolify_db_backup();
//
$this->update_traefik_labels();
if (! isCloud() || $this->option('force-cloud')) {
$this->cleanup_unused_network_from_coolify_proxy();
}
if (isCloud()) {
$this->cleanup_unnecessary_dynamic_proxy_configuration();
} else {
$this->cleanup_in_progress_application_deployments();
}
$this->call('cleanup:redis');
$this->call('cleanup:stucked-resources');
if (isCloud()) {
$response = Http::retry(3, 1000)->get(config('constants.services.official'));
if ($response->successful()) {
$services = $response->json();
File::put(base_path('templates/service-templates.json'), json_encode($services));
}
} else {
try {
$localhost = $this->servers->where('id', 0)->first();
$localhost->setupDynamicProxyConfiguration();
} catch (\Throwable $e) {
echo "Could not setup dynamic configuration: {$e->getMessage()}\n";
}
$settings = instanceSettings();
if (! is_null(env('AUTOUPDATE', null))) {
if (env('AUTOUPDATE') == true) {
$settings->update(['is_auto_update_enabled' => true]);
} else {
$settings->update(['is_auto_update_enabled' => false]);
}
}
}
}
private function disable_metrics()
{
if (version_compare('4.0.0-beta.312', config('version'), '<=')) {
foreach ($this->servers as $server) {
if ($server->settings->is_metrics_enabled === true) {
@@ -39,62 +91,6 @@ class Init extends Command
}
}
}
$full_cleanup = $this->option('full-cleanup');
$cleanup_deployments = $this->option('cleanup-deployments');
$cleanup_proxy_networks = $this->option('cleanup-proxy-networks');
$this->replace_slash_in_environment_name();
if ($cleanup_deployments) {
echo "Running cleanup deployments.\n";
$this->cleanup_in_progress_application_deployments();
return;
}
if ($cleanup_proxy_networks) {
echo "Running cleanup proxy networks.\n";
$this->cleanup_unused_network_from_coolify_proxy();
return;
}
if ($full_cleanup) {
// Required for falsely deleted coolify db
$this->restore_coolify_db_backup();
$this->update_traefik_labels();
$this->cleanup_unused_network_from_coolify_proxy();
$this->cleanup_unnecessary_dynamic_proxy_configuration();
$this->cleanup_in_progress_application_deployments();
$this->cleanup_stucked_helper_containers();
$this->call('cleanup:queue');
$this->call('cleanup:stucked-resources');
if (! isCloud()) {
try {
$localhost = $this->servers->where('id', 0)->first();
$localhost->setupDynamicProxyConfiguration();
} catch (\Throwable $e) {
echo "Could not setup dynamic configuration: {$e->getMessage()}\n";
}
}
$settings = InstanceSettings::get();
if (! is_null(env('AUTOUPDATE', null))) {
if (env('AUTOUPDATE') == true) {
$settings->update(['is_auto_update_enabled' => true]);
} else {
$settings->update(['is_auto_update_enabled' => false]);
}
}
if (isCloud()) {
$response = Http::retry(3, 1000)->get(config('constants.services.official'));
if ($response->successful()) {
$services = $response->json();
File::put(base_path('templates/service-templates.json'), json_encode($services));
}
}
return;
}
$this->cleanup_stucked_helper_containers();
$this->call('cleanup:stucked-resources');
}
private function update_traefik_labels()
@@ -108,33 +104,28 @@ class Init extends Command
private function cleanup_unnecessary_dynamic_proxy_configuration()
{
if (isCloud()) {
foreach ($this->servers as $server) {
try {
if (! $server->isFunctional()) {
continue;
}
if ($server->id === 0) {
continue;
}
$file = $server->proxyPath().'/dynamic/coolify.yaml';
return instant_remote_process([
"rm -f $file",
], $server, false);
} catch (\Throwable $e) {
echo "Error in cleaning up unnecessary dynamic proxy configuration: {$e->getMessage()}\n";
foreach ($this->servers as $server) {
try {
if (! $server->isFunctional()) {
continue;
}
if ($server->id === 0) {
continue;
}
$file = $server->proxyPath().'/dynamic/coolify.yaml';
return instant_remote_process([
"rm -f $file",
], $server, false);
} catch (\Throwable $e) {
echo "Error in cleaning up unnecessary dynamic proxy configuration: {$e->getMessage()}\n";
}
}
}
private function cleanup_unused_network_from_coolify_proxy()
{
if (isCloud()) {
return;
}
foreach ($this->servers as $server) {
if (! $server->isFunctional()) {
continue;
@@ -175,43 +166,36 @@ class Init extends Command
private function restore_coolify_db_backup()
{
try {
$database = StandalonePostgresql::withTrashed()->find(0);
if ($database && $database->trashed()) {
echo "Restoring coolify db backup\n";
$database->restore();
$scheduledBackup = ScheduledDatabaseBackup::find(0);
if (! $scheduledBackup) {
ScheduledDatabaseBackup::create([
'id' => 0,
'enabled' => true,
'save_s3' => false,
'frequency' => '0 0 * * *',
'database_id' => $database->id,
'database_type' => 'App\Models\StandalonePostgresql',
'team_id' => 0,
]);
if (version_compare('4.0.0-beta.179', config('version'), '<=')) {
try {
$database = StandalonePostgresql::withTrashed()->find(0);
if ($database && $database->trashed()) {
echo "Restoring coolify db backup\n";
$database->restore();
$scheduledBackup = ScheduledDatabaseBackup::find(0);
if (! $scheduledBackup) {
ScheduledDatabaseBackup::create([
'id' => 0,
'enabled' => true,
'save_s3' => false,
'frequency' => '0 0 * * *',
'database_id' => $database->id,
'database_type' => 'App\Models\StandalonePostgresql',
'team_id' => 0,
]);
}
}
}
} catch (\Throwable $e) {
echo "Error in restoring coolify db backup: {$e->getMessage()}\n";
}
}
private function cleanup_stucked_helper_containers()
{
foreach ($this->servers as $server) {
if ($server->isFunctional()) {
CleanupHelperContainersJob::dispatch($server);
} catch (\Throwable $e) {
echo "Error in restoring coolify db backup: {$e->getMessage()}\n";
}
}
}
private function alive()
private function send_alive_signal()
{
$id = config('app.id');
$version = config('version');
$settings = InstanceSettings::get();
$settings = instanceSettings();
$do_not_track = data_get($settings, 'do_not_track');
if ($do_not_track == true) {
echo "Skipping alive as do_not_track is enabled\n";
@@ -225,23 +209,7 @@ class Init extends Command
echo "Error in alive: {$e->getMessage()}\n";
}
}
// private function cleanup_ssh()
// {
// TODO: it will cleanup id.root@host.docker.internal
// try {
// $files = Storage::allFiles('ssh/keys');
// foreach ($files as $file) {
// Storage::delete($file);
// }
// $files = Storage::allFiles('ssh/mux');
// foreach ($files as $file) {
// Storage::delete($file);
// }
// } catch (\Throwable $e) {
// echo "Error in cleaning ssh: {$e->getMessage()}\n";
// }
// }
private function cleanup_in_progress_application_deployments()
{
// Cleanup any failed deployments
@@ -263,11 +231,13 @@ class Init extends Command
private function replace_slash_in_environment_name()
{
$environments = Environment::all();
foreach ($environments as $environment) {
if (str_contains($environment->name, '/')) {
$environment->name = str_replace('/', '-', $environment->name);
$environment->save();
if (version_compare('4.0.0-beta.298', config('version'), '<=')) {
$environments = Environment::all();
foreach ($environments as $environment) {
if (str_contains($environment->name, '/')) {
$environment->name = str_replace('/', '-', $environment->name);
$environment->save();
}
}
}
}

View File

@@ -78,7 +78,7 @@ class ServicesGenerate extends Command
if ($logo->count() > 0) {
$logo = str($logo[0])->after('# logo:')->trim()->value();
} else {
$logo = 'svgs/unknown.svg';
$logo = 'svgs/coolify.png';
}
$minversion = collect(preg_grep('/^# minversion:/', explode("\n", $content)))->values();
if ($minversion->count() > 0) {

View File

@@ -4,6 +4,7 @@ namespace App\Console;
use App\Jobs\CheckForUpdatesJob;
use App\Jobs\CleanupInstanceStuffsJob;
use App\Jobs\CleanupStaleMultiplexedConnections;
use App\Jobs\DatabaseBackupJob;
use App\Jobs\DockerCleanupJob;
use App\Jobs\PullHelperImageJob;
@@ -11,8 +12,8 @@ use App\Jobs\PullSentinelImageJob;
use App\Jobs\PullTemplatesFromCDN;
use App\Jobs\ScheduledTaskJob;
use App\Jobs\ServerCheckJob;
use App\Jobs\ServerStorageCheckJob;
use App\Jobs\UpdateCoolifyJob;
use App\Models\InstanceSettings;
use App\Models\ScheduledDatabaseBackup;
use App\Models\ScheduledTask;
use App\Models\Server;
@@ -27,9 +28,10 @@ class Kernel extends ConsoleKernel
protected function schedule(Schedule $schedule): void
{
$this->all_servers = Server::all();
$settings = InstanceSettings::get();
$settings = instanceSettings();
$schedule->job(new CleanupStaleMultiplexedConnections)->hourly();
$schedule->command('telescope:prune')->daily();
if (isDev()) {
// Instance Jobs
$schedule->command('horizon:snapshot')->everyMinute();
@@ -39,6 +41,10 @@ class Kernel extends ConsoleKernel
$this->check_resources($schedule);
$this->check_scheduled_tasks($schedule);
$schedule->command('uploads:clear')->everyTwoMinutes();
$schedule->command('telescope:prune')->daily();
$schedule->job(new PullHelperImageJob)->everyFiveMinutes()->onOneServer();
} else {
// Instance Jobs
$schedule->command('horizon:snapshot')->everyFiveMinutes();
@@ -60,7 +66,7 @@ class Kernel extends ConsoleKernel
private function pull_images($schedule)
{
$settings = InstanceSettings::get();
$settings = instanceSettings();
$servers = $this->all_servers->where('settings.is_usable', true)->where('settings.is_reachable', true)->where('ip', '!=', '1.2.3.4');
foreach ($servers as $server) {
if ($server->isSentinelEnabled()) {
@@ -73,16 +79,16 @@ class Kernel extends ConsoleKernel
}
})->cron($settings->update_check_frequency)->timezone($settings->instance_timezone)->onOneServer();
}
$schedule->job(new PullHelperImageJob($server))
->cron($settings->update_check_frequency)
->timezone($settings->instance_timezone)
->onOneServer();
}
$schedule->job(new PullHelperImageJob)
->cron($settings->update_check_frequency)
->timezone($settings->instance_timezone)
->onOneServer();
}
private function schedule_updates($schedule)
{
$settings = InstanceSettings::get();
$settings = instanceSettings();
$updateCheckFrequency = $settings->update_check_frequency;
$schedule->job(new CheckForUpdatesJob)
@@ -110,6 +116,7 @@ class Kernel extends ConsoleKernel
}
foreach ($servers as $server) {
$schedule->job(new ServerCheckJob($server))->everyMinute()->onOneServer();
// $schedule->job(new ServerStorageCheckJob($server))->everyMinute()->onOneServer();
$serverTimezone = $server->settings->server_timezone;
if ($server->settings->force_docker_cleanup) {
$schedule->job(new DockerCleanupJob($server))->cron($server->settings->docker_cleanup_frequency)->timezone($serverTimezone)->onOneServer();

View File

@@ -0,0 +1,14 @@
<?php
namespace App\Enums;
enum ContainerStatusTypes: string
{
case PAUSED = 'paused';
case RESTARTING = 'restarting';
case REMOVING = 'removing';
case RUNNING = 'running';
case DEAD = 'dead';
case CREATED = 'created';
case EXITED = 'exited';
}

View File

@@ -0,0 +1,34 @@
<?php
namespace App\Events;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
class CloudflareTunnelConfigured implements ShouldBroadcast
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public $teamId;
public function __construct($teamId = null)
{
if (is_null($teamId)) {
$teamId = auth()->user()->currentTeam()->id ?? null;
}
if (is_null($teamId)) {
throw new \Exception('Team id is null');
}
$this->teamId = $teamId;
}
public function broadcastOn(): array
{
return [
new PrivateChannel("team.{$this->teamId}"),
];
}
}

View File

@@ -65,7 +65,7 @@ class Handler extends ExceptionHandler
if ($e instanceof RuntimeException) {
return;
}
$this->settings = \App\Models\InstanceSettings::get();
$this->settings = instanceSettings();
if ($this->settings->do_not_track) {
return;
}

View File

@@ -0,0 +1,186 @@
<?php
namespace App\Helpers;
use App\Models\PrivateKey;
use App\Models\Server;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Process;
class SshMultiplexingHelper
{
public static function serverSshConfiguration(Server $server)
{
$privateKey = PrivateKey::findOrFail($server->private_key_id);
$sshKeyLocation = $privateKey->getKeyLocation();
$muxFilename = '/var/www/html/storage/app/ssh/mux/mux_'.$server->uuid;
return [
'sshKeyLocation' => $sshKeyLocation,
'muxFilename' => $muxFilename,
];
}
public static function ensureMultiplexedConnection(Server $server)
{
if (! self::isMultiplexingEnabled()) {
return;
}
$sshConfig = self::serverSshConfiguration($server);
$muxSocket = $sshConfig['muxFilename'];
$sshKeyLocation = $sshConfig['sshKeyLocation'];
self::validateSshKey($sshKeyLocation);
$checkCommand = "ssh -O check -o ControlPath=$muxSocket ";
if (data_get($server, 'settings.is_cloudflare_tunnel')) {
$checkCommand .= '-o ProxyCommand="cloudflared access ssh --hostname %h" ';
}
$checkCommand .= "{$server->user}@{$server->ip}";
$process = Process::run($checkCommand);
if ($process->exitCode() !== 0) {
self::establishNewMultiplexedConnection($server);
}
}
public static function establishNewMultiplexedConnection(Server $server)
{
$sshConfig = self::serverSshConfiguration($server);
$sshKeyLocation = $sshConfig['sshKeyLocation'];
$muxSocket = $sshConfig['muxFilename'];
$connectionTimeout = config('constants.ssh.connection_timeout');
$serverInterval = config('constants.ssh.server_interval');
$muxPersistTime = config('constants.ssh.mux_persist_time');
$establishCommand = "ssh -fNM -o ControlMaster=auto -o ControlPath=$muxSocket -o ControlPersist={$muxPersistTime} ";
if (data_get($server, 'settings.is_cloudflare_tunnel')) {
$establishCommand .= ' -o ProxyCommand="cloudflared access ssh --hostname %h" ';
}
$establishCommand .= self::getCommonSshOptions($server, $sshKeyLocation, $connectionTimeout, $serverInterval);
$establishCommand .= "{$server->user}@{$server->ip}";
$establishProcess = Process::run($establishCommand);
if ($establishProcess->exitCode() !== 0) {
throw new \RuntimeException('Failed to establish multiplexed connection: '.$establishProcess->errorOutput());
}
}
public static function removeMuxFile(Server $server)
{
$sshConfig = self::serverSshConfiguration($server);
$muxSocket = $sshConfig['muxFilename'];
$closeCommand = "ssh -O exit -o ControlPath=$muxSocket ";
if (data_get($server, 'settings.is_cloudflare_tunnel')) {
$closeCommand .= '-o ProxyCommand="cloudflared access ssh --hostname %h" ';
}
$closeCommand .= "{$server->user}@{$server->ip}";
Process::run($closeCommand);
}
public static function generateScpCommand(Server $server, string $source, string $dest)
{
$sshConfig = self::serverSshConfiguration($server);
$sshKeyLocation = $sshConfig['sshKeyLocation'];
$muxSocket = $sshConfig['muxFilename'];
$timeout = config('constants.ssh.command_timeout');
$muxPersistTime = config('constants.ssh.mux_persist_time');
$scp_command = "timeout $timeout scp ";
if ($server->isIpv6()) {
$scp_command .= '-6 ';
}
if (self::isMultiplexingEnabled()) {
$scp_command .= "-o ControlMaster=auto -o ControlPath=$muxSocket -o ControlPersist={$muxPersistTime} ";
self::ensureMultiplexedConnection($server);
}
if (data_get($server, 'settings.is_cloudflare_tunnel')) {
$scp_command .= '-o ProxyCommand="cloudflared access ssh --hostname %h" ';
}
$scp_command .= self::getCommonSshOptions($server, $sshKeyLocation, config('constants.ssh.connection_timeout'), config('constants.ssh.server_interval'), isScp: true);
$scp_command .= "{$source} {$server->user}@{$server->ip}:{$dest}";
return $scp_command;
}
public static function generateSshCommand(Server $server, string $command)
{
if ($server->settings->force_disabled) {
throw new \RuntimeException('Server is disabled.');
}
$sshConfig = self::serverSshConfiguration($server);
$sshKeyLocation = $sshConfig['sshKeyLocation'];
$muxSocket = $sshConfig['muxFilename'];
$timeout = config('constants.ssh.command_timeout');
$muxPersistTime = config('constants.ssh.mux_persist_time');
$ssh_command = "timeout $timeout ssh ";
if (self::isMultiplexingEnabled()) {
$ssh_command .= "-o ControlMaster=auto -o ControlPath=$muxSocket -o ControlPersist={$muxPersistTime} ";
self::ensureMultiplexedConnection($server);
}
if (data_get($server, 'settings.is_cloudflare_tunnel')) {
$ssh_command .= "-o ProxyCommand='cloudflared access ssh --hostname %h' ";
}
$ssh_command .= self::getCommonSshOptions($server, $sshKeyLocation, config('constants.ssh.connection_timeout'), config('constants.ssh.server_interval'));
$delimiter = Hash::make($command);
$delimiter = base64_encode($delimiter);
$command = str_replace($delimiter, '', $command);
$ssh_command .= "{$server->user}@{$server->ip} 'bash -se' << \\$delimiter".PHP_EOL
.$command.PHP_EOL
.$delimiter;
return $ssh_command;
}
private static function isMultiplexingEnabled(): bool
{
return config('constants.ssh.mux_enabled') && ! config('coolify.is_windows_docker_desktop');
}
private static function validateSshKey(string $sshKeyLocation): void
{
$checkKeyCommand = "ls $sshKeyLocation 2>/dev/null";
$keyCheckProcess = Process::run($checkKeyCommand);
if ($keyCheckProcess->exitCode() !== 0) {
throw new \RuntimeException("SSH key file not accessible: $sshKeyLocation");
}
}
private static function getCommonSshOptions(Server $server, string $sshKeyLocation, int $connectionTimeout, int $serverInterval, bool $isScp = false): string
{
$options = "-i {$sshKeyLocation} "
.'-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null '
.'-o PasswordAuthentication=no '
."-o ConnectTimeout=$connectionTimeout "
."-o ServerAliveInterval=$serverInterval "
.'-o RequestTTY=no '
.'-o LogLevel=ERROR ';
// Bruh
if ($isScp) {
$options .= "-P {$server->port} ";
} else {
$options .= "-p {$server->port} ";
}
return $options;
}
}

View File

@@ -177,6 +177,7 @@ class ApplicationsController extends Controller
'docker_compose_custom_build_command' => ['type' => 'string', 'description' => 'The Docker Compose custom build command.'],
'docker_compose_domains' => ['type' => 'array', 'description' => 'The Docker Compose domains.'],
'watch_paths' => ['type' => 'string', 'description' => 'The watch paths.'],
'use_build_server' => ['type' => 'boolean', 'nullable' => true, 'description' => 'Use build server.'],
],
)),
]),
@@ -279,6 +280,7 @@ class ApplicationsController extends Controller
'docker_compose_custom_build_command' => ['type' => 'string', 'description' => 'The Docker Compose custom build command.'],
'docker_compose_domains' => ['type' => 'array', 'description' => 'The Docker Compose domains.'],
'watch_paths' => ['type' => 'string', 'description' => 'The watch paths.'],
'use_build_server' => ['type' => 'boolean', 'nullable' => true, 'description' => 'Use build server.'],
],
)),
]),
@@ -381,6 +383,7 @@ class ApplicationsController extends Controller
'docker_compose_custom_build_command' => ['type' => 'string', 'description' => 'The Docker Compose custom build command.'],
'docker_compose_domains' => ['type' => 'array', 'description' => 'The Docker Compose domains.'],
'watch_paths' => ['type' => 'string', 'description' => 'The watch paths.'],
'use_build_server' => ['type' => 'boolean', 'nullable' => true, 'description' => 'Use build server.'],
],
)),
]),
@@ -468,6 +471,7 @@ class ApplicationsController extends Controller
'manual_webhook_secret_gitea' => ['type' => 'string', 'description' => 'Manual webhook secret for Gitea.'],
'redirect' => ['type' => 'string', 'nullable' => true, 'description' => 'How to set redirect with Traefik / Caddy. www<->non-www.', 'enum' => ['www', 'non-www', 'both']],
'instant_deploy' => ['type' => 'boolean', 'description' => 'The flag to indicate if the application should be deployed instantly.'],
'use_build_server' => ['type' => 'boolean', 'nullable' => true, 'description' => 'Use build server.'],
],
)),
]),
@@ -552,6 +556,7 @@ class ApplicationsController extends Controller
'manual_webhook_secret_gitea' => ['type' => 'string', 'description' => 'Manual webhook secret for Gitea.'],
'redirect' => ['type' => 'string', 'nullable' => true, 'description' => 'How to set redirect with Traefik / Caddy. www<->non-www.', 'enum' => ['www', 'non-www', 'both']],
'instant_deploy' => ['type' => 'boolean', 'description' => 'The flag to indicate if the application should be deployed instantly.'],
'use_build_server' => ['type' => 'boolean', 'nullable' => true, 'description' => 'Use build server.'],
],
)),
]),
@@ -602,6 +607,7 @@ class ApplicationsController extends Controller
'name' => ['type' => 'string', 'description' => 'The application name.'],
'description' => ['type' => 'string', 'description' => 'The application description.'],
'instant_deploy' => ['type' => 'boolean', 'description' => 'The flag to indicate if the application should be deployed instantly.'],
'use_build_server' => ['type' => 'boolean', 'nullable' => true, 'description' => 'Use build server.'],
],
)),
]),
@@ -627,7 +633,7 @@ class ApplicationsController extends Controller
private function create_application(Request $request, $type)
{
$allowedFields = ['project_uuid', 'environment_name', 'server_uuid', 'destination_uuid', 'type', 'name', 'description', 'is_static', 'domains', 'git_repository', 'git_branch', 'git_commit_sha', 'private_key_uuid', 'docker_registry_image_name', 'docker_registry_image_tag', 'build_pack', 'install_command', 'build_command', 'start_command', 'ports_exposes', 'ports_mappings', 'base_directory', 'publish_directory', 'health_check_enabled', 'health_check_path', 'health_check_port', 'health_check_host', 'health_check_method', 'health_check_return_code', 'health_check_scheme', 'health_check_response_text', 'health_check_interval', 'health_check_timeout', 'health_check_retries', 'health_check_start_period', 'limits_memory', 'limits_memory_swap', 'limits_memory_swappiness', 'limits_memory_reservation', 'limits_cpus', 'limits_cpuset', 'limits_cpu_shares', 'custom_labels', 'custom_docker_run_options', 'post_deployment_command', 'post_deployment_command_container', 'pre_deployment_command', 'pre_deployment_command_container', 'manual_webhook_secret_github', 'manual_webhook_secret_gitlab', 'manual_webhook_secret_bitbucket', 'manual_webhook_secret_gitea', 'redirect', 'github_app_uuid', 'instant_deploy', 'dockerfile', 'docker_compose_location', 'docker_compose_raw', 'docker_compose_custom_start_command', 'docker_compose_custom_build_command', 'docker_compose_domains', 'watch_paths'];
$allowedFields = ['project_uuid', 'environment_name', 'server_uuid', 'destination_uuid', 'type', 'name', 'description', 'is_static', 'domains', 'git_repository', 'git_branch', 'git_commit_sha', 'private_key_uuid', 'docker_registry_image_name', 'docker_registry_image_tag', 'build_pack', 'install_command', 'build_command', 'start_command', 'ports_exposes', 'ports_mappings', 'base_directory', 'publish_directory', 'health_check_enabled', 'health_check_path', 'health_check_port', 'health_check_host', 'health_check_method', 'health_check_return_code', 'health_check_scheme', 'health_check_response_text', 'health_check_interval', 'health_check_timeout', 'health_check_retries', 'health_check_start_period', 'limits_memory', 'limits_memory_swap', 'limits_memory_swappiness', 'limits_memory_reservation', 'limits_cpus', 'limits_cpuset', 'limits_cpu_shares', 'custom_labels', 'custom_docker_run_options', 'post_deployment_command', 'post_deployment_command_container', 'pre_deployment_command', 'pre_deployment_command_container', 'manual_webhook_secret_github', 'manual_webhook_secret_gitlab', 'manual_webhook_secret_bitbucket', 'manual_webhook_secret_gitea', 'redirect', 'github_app_uuid', 'instant_deploy', 'dockerfile', 'docker_compose_location', 'docker_compose_raw', 'docker_compose_custom_start_command', 'docker_compose_custom_build_command', 'docker_compose_domains', 'watch_paths', 'use_build_server'];
$teamId = getTeamIdFromToken();
if (is_null($teamId)) {
return invalidTokenResponse();
@@ -665,6 +671,7 @@ class ApplicationsController extends Controller
$fqdn = $request->domains;
$instantDeploy = $request->instant_deploy;
$githubAppUuid = $request->github_app_uuid;
$useBuildServer = $request->use_build_server;
$project = Project::whereTeamId($teamId)->whereUuid($request->project_uuid)->first();
if (! $project) {
@@ -737,6 +744,10 @@ class ApplicationsController extends Controller
$application->destination_id = $destination->id;
$application->destination_type = $destination->getMorphClass();
$application->environment_id = $environment->id;
if (isset($useBuildServer)) {
$application->settings->is_build_server_enabled = $useBuildServer;
$application->settings->save();
}
$application->save();
$application->refresh();
if (! $application->settings->is_container_label_readonly_enabled) {
@@ -833,6 +844,10 @@ class ApplicationsController extends Controller
$application->environment_id = $environment->id;
$application->source_type = $githubApp->getMorphClass();
$application->source_id = $githubApp->id;
if (isset($useBuildServer)) {
$application->settings->is_build_server_enabled = $useBuildServer;
$application->settings->save();
}
$application->save();
$application->refresh();
if (! $application->settings->is_container_label_readonly_enabled) {
@@ -925,6 +940,10 @@ class ApplicationsController extends Controller
$application->destination_id = $destination->id;
$application->destination_type = $destination->getMorphClass();
$application->environment_id = $environment->id;
if (isset($useBuildServer)) {
$application->settings->is_build_server_enabled = $useBuildServer;
$application->settings->save();
}
$application->save();
$application->refresh();
if (! $application->settings->is_container_label_readonly_enabled) {
@@ -1004,6 +1023,10 @@ class ApplicationsController extends Controller
$application->destination_id = $destination->id;
$application->destination_type = $destination->getMorphClass();
$application->environment_id = $environment->id;
if (isset($useBuildServer)) {
$application->settings->is_build_server_enabled = $useBuildServer;
$application->settings->save();
}
$application->git_repository = 'coollabsio/coolify';
$application->git_branch = 'main';
@@ -1062,6 +1085,10 @@ class ApplicationsController extends Controller
$application->destination_id = $destination->id;
$application->destination_type = $destination->getMorphClass();
$application->environment_id = $environment->id;
if (isset($useBuildServer)) {
$application->settings->is_build_server_enabled = $useBuildServer;
$application->settings->save();
}
$application->git_repository = 'coollabsio/coolify';
$application->git_branch = 'main';
@@ -1259,16 +1286,10 @@ class ApplicationsController extends Controller
format: 'uuid',
)
),
new OA\Parameter(
name: 'cleanup',
in: 'query',
description: 'Delete configurations and volumes.',
required: false,
schema: new OA\Schema(
type: 'boolean',
default: true,
)
),
new OA\Parameter(name: 'delete_configurations', in: 'query', required: false, description: 'Delete configurations.', schema: new OA\Schema(type: 'boolean', default: true)),
new OA\Parameter(name: 'delete_volumes', in: 'query', required: false, description: 'Delete volumes.', schema: new OA\Schema(type: 'boolean', default: true)),
new OA\Parameter(name: 'docker_cleanup', in: 'query', required: false, description: 'Run docker cleanup.', schema: new OA\Schema(type: 'boolean', default: true)),
new OA\Parameter(name: 'delete_connected_networks', in: 'query', required: false, description: 'Delete connected networks.', schema: new OA\Schema(type: 'boolean', default: true)),
],
responses: [
new OA\Response(
@@ -1316,10 +1337,14 @@ class ApplicationsController extends Controller
'message' => 'Application not found',
], 404);
}
DeleteResourceJob::dispatch(
resource: $application,
deleteConfigurations: $cleanup,
deleteVolumes: $cleanup);
deleteConfigurations: $request->query->get('delete_configurations', true),
deleteVolumes: $request->query->get('delete_volumes', true),
dockerCleanup: $request->query->get('docker_cleanup', true),
deleteConnectedNetworks: $request->query->get('delete_connected_networks', true)
);
return response()->json([
'message' => 'Application deletion request queued.',
@@ -1404,6 +1429,7 @@ class ApplicationsController extends Controller
'docker_compose_custom_build_command' => ['type' => 'string', 'description' => 'The Docker Compose custom build command.'],
'docker_compose_domains' => ['type' => 'array', 'description' => 'The Docker Compose domains.'],
'watch_paths' => ['type' => 'string', 'description' => 'The watch paths.'],
'use_build_server' => ['type' => 'boolean', 'nullable' => true, 'description' => 'Use build server.'],
],
)),
]),
@@ -1460,7 +1486,7 @@ class ApplicationsController extends Controller
], 404);
}
$server = $application->destination->server;
$allowedFields = ['name', 'description', 'is_static', 'domains', 'git_repository', 'git_branch', 'git_commit_sha', 'docker_registry_image_name', 'docker_registry_image_tag', 'build_pack', 'static_image', 'install_command', 'build_command', 'start_command', 'ports_exposes', 'ports_mappings', 'base_directory', 'publish_directory', 'health_check_enabled', 'health_check_path', 'health_check_port', 'health_check_host', 'health_check_method', 'health_check_return_code', 'health_check_scheme', 'health_check_response_text', 'health_check_interval', 'health_check_timeout', 'health_check_retries', 'health_check_start_period', 'limits_memory', 'limits_memory_swap', 'limits_memory_swappiness', 'limits_memory_reservation', 'limits_cpus', 'limits_cpuset', 'limits_cpu_shares', 'custom_labels', 'custom_docker_run_options', 'post_deployment_command', 'post_deployment_command_container', 'pre_deployment_command', 'pre_deployment_command_container', 'watch_paths', 'manual_webhook_secret_github', 'manual_webhook_secret_gitlab', 'manual_webhook_secret_bitbucket', 'manual_webhook_secret_gitea', 'docker_compose_location', 'docker_compose_raw', 'docker_compose_custom_start_command', 'docker_compose_custom_build_command', 'docker_compose_domains', 'redirect', 'instant_deploy'];
$allowedFields = ['name', 'description', 'is_static', 'domains', 'git_repository', 'git_branch', 'git_commit_sha', 'docker_registry_image_name', 'docker_registry_image_tag', 'build_pack', 'static_image', 'install_command', 'build_command', 'start_command', 'ports_exposes', 'ports_mappings', 'base_directory', 'publish_directory', 'health_check_enabled', 'health_check_path', 'health_check_port', 'health_check_host', 'health_check_method', 'health_check_return_code', 'health_check_scheme', 'health_check_response_text', 'health_check_interval', 'health_check_timeout', 'health_check_retries', 'health_check_start_period', 'limits_memory', 'limits_memory_swap', 'limits_memory_swappiness', 'limits_memory_reservation', 'limits_cpus', 'limits_cpuset', 'limits_cpu_shares', 'custom_labels', 'custom_docker_run_options', 'post_deployment_command', 'post_deployment_command_container', 'pre_deployment_command', 'pre_deployment_command_container', 'watch_paths', 'manual_webhook_secret_github', 'manual_webhook_secret_gitlab', 'manual_webhook_secret_bitbucket', 'manual_webhook_secret_gitea', 'docker_compose_location', 'docker_compose_raw', 'docker_compose_custom_start_command', 'docker_compose_custom_build_command', 'docker_compose_domains', 'redirect', 'instant_deploy', 'use_build_server'];
$validator = customApiValidator($request->all(), [
sharedDataApplications(),
@@ -1538,6 +1564,13 @@ class ApplicationsController extends Controller
}
$instantDeploy = $request->instant_deploy;
$use_build_server = $request->use_build_server;
if (isset($use_build_server)) {
$application->settings->is_build_server_enabled = $use_build_server;
$application->settings->save();
}
removeUnnecessaryFieldsFromRequest($request);
$data = $request->all();
@@ -2529,6 +2562,131 @@ class ApplicationsController extends Controller
}
#[OA\Post(
summary: 'Execute Command',
description: "Execute a command on the application's current container.",
path: '/applications/{uuid}/execute',
operationId: 'execute-command-application',
security: [
['bearerAuth' => []],
],
tags: ['Applications'],
parameters: [
new OA\Parameter(
name: 'uuid',
in: 'path',
description: 'UUID of the application.',
required: true,
schema: new OA\Schema(
type: 'string',
format: 'uuid',
)
),
],
requestBody: new OA\RequestBody(
required: true,
description: 'Command to execute.',
content: new OA\MediaType(
mediaType: 'application/json',
schema: new OA\Schema(
type: 'object',
properties: [
'command' => ['type' => 'string', 'description' => 'Command to execute.'],
],
),
),
),
responses: [
new OA\Response(
response: 200,
description: "Execute a command on the application's current container.",
content: [
new OA\MediaType(
mediaType: 'application/json',
schema: new OA\Schema(
type: 'object',
properties: [
'message' => ['type' => 'string', 'example' => 'Command executed.'],
'response' => ['type' => 'string'],
]
)
),
]
),
new OA\Response(
response: 401,
ref: '#/components/responses/401',
),
new OA\Response(
response: 400,
ref: '#/components/responses/400',
),
new OA\Response(
response: 404,
ref: '#/components/responses/404',
),
]
)]
public function execute_command_by_uuid(Request $request)
{
// TODO: Need to review this from security perspective, to not allow arbitrary command execution
$allowedFields = ['command'];
$teamId = getTeamIdFromToken();
if (is_null($teamId)) {
return invalidTokenResponse();
}
$uuid = $request->route('uuid');
if (! $uuid) {
return response()->json(['message' => 'UUID is required.'], 400);
}
$application = Application::ownedByCurrentTeamAPI($teamId)->where('uuid', $request->uuid)->first();
if (! $application) {
return response()->json(['message' => 'Application not found.'], 404);
}
$return = validateIncomingRequest($request);
if ($return instanceof \Illuminate\Http\JsonResponse) {
return $return;
}
$validator = customApiValidator($request->all(), [
'command' => 'string|required',
]);
$extraFields = array_diff(array_keys($request->all()), $allowedFields);
if ($validator->fails() || ! empty($extraFields)) {
$errors = $validator->errors();
if (! empty($extraFields)) {
foreach ($extraFields as $field) {
$errors->add($field, 'This field is not allowed.');
}
}
return response()->json([
'message' => 'Validation failed.',
'errors' => $errors,
], 422);
}
$container = getCurrentApplicationContainerStatus($application->destination->server, $application->id)->firstOrFail();
$status = getContainerStatus($application->destination->server, $container['Names']);
if ($status !== 'running') {
return response()->json([
'message' => 'Application is not running.',
], 400);
}
$commands = collect([
executeInDocker($container['Names'], $request->command),
]);
$res = instant_remote_process(command: $commands, server: $application->destination->server);
return response()->json([
'message' => 'Command executed.',
'response' => $res,
]);
}
private function validateDataApplications(Request $request, Server $server)
{
$teamId = getTeamIdFromToken();

View File

@@ -1541,16 +1541,10 @@ class DatabasesController extends Controller
format: 'uuid',
)
),
new OA\Parameter(
name: 'cleanup',
in: 'query',
description: 'Delete configurations and volumes.',
required: false,
schema: new OA\Schema(
type: 'boolean',
default: true,
)
),
new OA\Parameter(name: 'delete_configurations', in: 'query', required: false, description: 'Delete configurations.', schema: new OA\Schema(type: 'boolean', default: true)),
new OA\Parameter(name: 'delete_volumes', in: 'query', required: false, description: 'Delete volumes.', schema: new OA\Schema(type: 'boolean', default: true)),
new OA\Parameter(name: 'docker_cleanup', in: 'query', required: false, description: 'Run docker cleanup.', schema: new OA\Schema(type: 'boolean', default: true)),
new OA\Parameter(name: 'delete_connected_networks', in: 'query', required: false, description: 'Delete connected networks.', schema: new OA\Schema(type: 'boolean', default: true)),
],
responses: [
new OA\Response(
@@ -1595,10 +1589,14 @@ class DatabasesController extends Controller
if (! $database) {
return response()->json(['message' => 'Database not found.'], 404);
}
DeleteResourceJob::dispatch(
resource: $database,
deleteConfigurations: $cleanup,
deleteVolumes: $cleanup);
deleteConfigurations: $request->query->get('delete_configurations', true),
deleteVolumes: $request->query->get('delete_volumes', true),
dockerCleanup: $request->query->get('docker_cleanup', true),
deleteConnectedNetworks: $request->query->get('delete_connected_networks', true)
);
return response()->json([
'message' => 'Database deletion request queued.',

View File

@@ -86,7 +86,7 @@ class DeployController extends Controller
],
tags: ['Deployments'],
parameters: [
new OA\Parameter(name: 'uuid', in: 'path', required: true, description: 'Deployment Uuid', schema: new OA\Schema(type: 'string')),
new OA\Parameter(name: 'uuid', in: 'path', required: true, description: 'Deployment UUID', schema: new OA\Schema(type: 'string')),
],
responses: [
new OA\Response(
@@ -150,7 +150,7 @@ class DeployController extends Controller
responses: [
new OA\Response(
response: 200,
description: 'Get deployment(s) Uuid\'s',
description: 'Get deployment(s) UUID\'s',
content: [
new OA\MediaType(
mediaType: 'application/json',

View File

@@ -86,7 +86,7 @@ class OtherController extends Controller
if ($teamId !== '0') {
return response()->json(['message' => 'You are not allowed to enable the API.'], 403);
}
$settings = \App\Models\InstanceSettings::get();
$settings = instanceSettings();
$settings->update(['is_api_enabled' => true]);
return response()->json(['message' => 'API enabled.'], 200);
@@ -138,7 +138,7 @@ class OtherController extends Controller
if ($teamId !== '0') {
return response()->json(['message' => 'You are not allowed to disable the API.'], 403);
}
$settings = \App\Models\InstanceSettings::get();
$settings = instanceSettings();
$settings->update(['is_api_enabled' => false]);
return response()->json(['message' => 'API disabled.'], 200);

View File

@@ -11,7 +11,7 @@ class ProjectController extends Controller
{
#[OA\Get(
summary: 'List',
description: 'list projects.',
description: 'List projects.',
path: '/projects',
operationId: 'list-projects',
security: [
@@ -47,7 +47,7 @@ class ProjectController extends Controller
if (is_null($teamId)) {
return invalidTokenResponse();
}
$projects = Project::whereTeamId($teamId)->select('id', 'name', 'uuid')->get();
$projects = Project::whereTeamId($teamId)->select('id', 'name', 'description', 'uuid')->get();
return response()->json(serializeApiResponse($projects),
);
@@ -55,7 +55,7 @@ class ProjectController extends Controller
#[OA\Get(
summary: 'Get',
description: 'Get project by Uuid.',
description: 'Get project by UUID.',
path: '/projects/{uuid}',
operationId: 'get-project-by-uuid',
security: [
@@ -139,7 +139,7 @@ class ProjectController extends Controller
return invalidTokenResponse();
}
if (! $request->uuid) {
return response()->json(['message' => 'Uuid is required.'], 422);
return response()->json(['message' => 'UUID is required.'], 422);
}
if (! $request->environment_name) {
return response()->json(['message' => 'Environment name is required.'], 422);
@@ -341,7 +341,7 @@ class ProjectController extends Controller
}
$uuid = $request->uuid;
if (! $uuid) {
return response()->json(['message' => 'Uuid is required.'], 422);
return response()->json(['message' => 'UUID is required.'], 422);
}
$project = Project::whereTeamId($teamId)->whereUuid($uuid)->first();
@@ -417,7 +417,7 @@ class ProjectController extends Controller
}
if (! $request->uuid) {
return response()->json(['message' => 'Uuid is required.'], 422);
return response()->json(['message' => 'UUID is required.'], 422);
}
$project = Project::whereTeamId($teamId)->whereUuid($request->uuid)->first();
if (! $project) {

View File

@@ -75,7 +75,7 @@ class SecurityController extends Controller
],
tags: ['Private Keys'],
parameters: [
new OA\Parameter(name: 'uuid', in: 'path', required: true, description: 'Private Key Uuid', schema: new OA\Schema(type: 'string')),
new OA\Parameter(name: 'uuid', in: 'path', required: true, description: 'Private Key UUID', schema: new OA\Schema(type: 'string')),
],
responses: [
new OA\Response(
@@ -323,7 +323,7 @@ class SecurityController extends Controller
],
tags: ['Private Keys'],
parameters: [
new OA\Parameter(name: 'uuid', in: 'path', required: true, description: 'Private Key Uuid', schema: new OA\Schema(type: 'string')),
new OA\Parameter(name: 'uuid', in: 'path', required: true, description: 'Private Key UUID', schema: new OA\Schema(type: 'string')),
],
responses: [
new OA\Response(

View File

@@ -107,7 +107,7 @@ class ServersController extends Controller
],
tags: ['Servers'],
parameters: [
new OA\Parameter(name: 'uuid', in: 'path', required: true, description: 'Server\'s Uuid', schema: new OA\Schema(type: 'string')),
new OA\Parameter(name: 'uuid', in: 'path', required: true, description: 'Server\'s UUID', schema: new OA\Schema(type: 'string')),
],
responses: [
new OA\Response(
@@ -185,7 +185,7 @@ class ServersController extends Controller
],
tags: ['Servers'],
parameters: [
new OA\Parameter(name: 'uuid', in: 'path', required: true, description: 'Server\'s Uuid', schema: new OA\Schema(type: 'string')),
new OA\Parameter(name: 'uuid', in: 'path', required: true, description: 'Server\'s UUID', schema: new OA\Schema(type: 'string')),
],
responses: [
new OA\Response(
@@ -263,7 +263,7 @@ class ServersController extends Controller
],
tags: ['Servers'],
parameters: [
new OA\Parameter(name: 'uuid', in: 'path', required: true, description: 'Server\'s Uuid', schema: new OA\Schema(type: 'string')),
new OA\Parameter(name: 'uuid', in: 'path', required: true, description: 'Server\'s UUID', schema: new OA\Schema(type: 'string')),
],
responses: [
new OA\Response(
@@ -308,7 +308,7 @@ class ServersController extends Controller
$projects = Project::where('team_id', $teamId)->get();
$domains = collect();
$applications = $projects->pluck('applications')->flatten();
$settings = \App\Models\InstanceSettings::get();
$settings = instanceSettings();
if ($applications->count() > 0) {
foreach ($applications as $application) {
$ip = $application->destination->server->ip;

View File

@@ -378,7 +378,7 @@ class ServicesController extends Controller
responses: [
new OA\Response(
response: 200,
description: 'Get a service by Uuid.',
description: 'Get a service by UUID.',
content: [
new OA\MediaType(
mediaType: 'application/json',
@@ -432,11 +432,15 @@ class ServicesController extends Controller
tags: ['Services'],
parameters: [
new OA\Parameter(name: 'uuid', in: 'path', required: true, description: 'Service UUID', schema: new OA\Schema(type: 'string')),
new OA\Parameter(name: 'delete_configurations', in: 'query', required: false, description: 'Delete configurations.', schema: new OA\Schema(type: 'boolean', default: true)),
new OA\Parameter(name: 'delete_volumes', in: 'query', required: false, description: 'Delete volumes.', schema: new OA\Schema(type: 'boolean', default: true)),
new OA\Parameter(name: 'docker_cleanup', in: 'query', required: false, description: 'Run docker cleanup.', schema: new OA\Schema(type: 'boolean', default: true)),
new OA\Parameter(name: 'delete_connected_networks', in: 'query', required: false, description: 'Delete connected networks.', schema: new OA\Schema(type: 'boolean', default: true)),
],
responses: [
new OA\Response(
response: 200,
description: 'Delete a service by Uuid',
description: 'Delete a service by UUID',
content: [
new OA\MediaType(
mediaType: 'application/json',
@@ -476,7 +480,14 @@ class ServicesController extends Controller
if (! $service) {
return response()->json(['message' => 'Service not found.'], 404);
}
DeleteResourceJob::dispatch($service);
DeleteResourceJob::dispatch(
resource: $service,
deleteConfigurations: $request->query->get('delete_configurations', true),
deleteVolumes: $request->query->get('delete_volumes', true),
dockerCleanup: $request->query->get('docker_cleanup', true),
deleteConnectedNetworks: $request->query->get('delete_connected_networks', true)
);
return response()->json([
'message' => 'Service deletion request queued.',
@@ -516,7 +527,8 @@ class ServicesController extends Controller
items: new OA\Items(ref: '#/components/schemas/EnvironmentVariable')
)
),
]),
]
),
new OA\Response(
response: 401,
ref: '#/components/responses/401',
@@ -619,7 +631,8 @@ class ServicesController extends Controller
]
)
),
]),
]
),
new OA\Response(
response: 401,
ref: '#/components/responses/401',
@@ -738,7 +751,8 @@ class ServicesController extends Controller
]
)
),
]),
]
),
new OA\Response(
response: 401,
ref: '#/components/responses/401',
@@ -853,7 +867,8 @@ class ServicesController extends Controller
]
)
),
]),
]
),
new OA\Response(
response: 401,
ref: '#/components/responses/401',
@@ -953,7 +968,8 @@ class ServicesController extends Controller
]
)
),
]),
]
),
new OA\Response(
response: 401,
ref: '#/components/responses/401',
@@ -1025,9 +1041,11 @@ class ServicesController extends Controller
type: 'object',
properties: [
'message' => ['type' => 'string', 'example' => 'Service starting request queued.'],
])
]
)
),
]),
]
),
new OA\Response(
response: 401,
ref: '#/components/responses/401',
@@ -1101,9 +1119,11 @@ class ServicesController extends Controller
type: 'object',
properties: [
'message' => ['type' => 'string', 'example' => 'Service stopping request queued.'],
])
]
)
),
]),
]
),
new OA\Response(
response: 401,
ref: '#/components/responses/401',
@@ -1177,9 +1197,11 @@ class ServicesController extends Controller
type: 'object',
properties: [
'message' => ['type' => 'string', 'example' => 'Service restaring request queued.'],
])
]
)
),
]),
]
),
new OA\Response(
response: 401,
ref: '#/components/responses/401',

View File

@@ -2,7 +2,6 @@
namespace App\Http\Controllers;
use App\Models\InstanceSettings;
use App\Models\User;
use Illuminate\Support\Facades\Auth;
use Symfony\Component\HttpKernel\Exception\HttpException;
@@ -22,7 +21,7 @@ class OauthController extends Controller
$oauthUser = get_socialite_provider($provider)->user();
$user = User::whereEmail($oauthUser->email)->first();
if (! $user) {
$settings = InstanceSettings::get();
$settings = instanceSettings();
if (! $settings->is_registration_enabled) {
abort(403, 'Registration is disabled');
}

View File

@@ -14,7 +14,7 @@ class ApiAllowed
if (isCloud()) {
return $next($request);
}
$settings = \App\Models\InstanceSettings::get();
$settings = instanceSettings();
if ($settings->is_api_enabled === false) {
return response()->json(['success' => true, 'message' => 'API is disabled.'], 403);
}

View File

@@ -12,7 +12,6 @@ use App\Models\ApplicationPreview;
use App\Models\EnvironmentVariable;
use App\Models\GithubApp;
use App\Models\GitlabApp;
use App\Models\InstanceSettings;
use App\Models\Server;
use App\Models\StandaloneDocker;
use App\Models\SwarmDocker;
@@ -27,6 +26,7 @@ use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Process;
use Illuminate\Support\Sleep;
use Illuminate\Support\Str;
use RuntimeException;
@@ -210,7 +210,6 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
}
ray('New container name: ', $this->container_name)->green();
savePrivateKeyToFs($this->server);
$this->saved_outputs = collect();
// Set preview fqdn
@@ -514,7 +513,7 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
'hidden' => true,
'ignore_errors' => true,
], [
"docker network connect {$networkId} coolify-proxy || true",
"docker network connect {$networkId} coolify-proxy >/dev/null 2>&1 || true",
'hidden' => true,
'ignore_errors' => true,
]);
@@ -919,10 +918,10 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
}
if ($this->application->build_pack !== 'dockercompose' || $this->application->compose_parsing_version === '1' || $this->application->compose_parsing_version === '2') {
if ($this->application->environment_variables_preview->where('key', 'COOLIFY_BRANCH')->isEmpty()) {
$envs->push("COOLIFY_BRANCH={$local_branch}");
$envs->push("COOLIFY_BRANCH=\"{$local_branch}\"");
}
if ($this->application->environment_variables_preview->where('key', 'COOLIFY_CONTAINER_NAME')->isEmpty()) {
$envs->push("COOLIFY_CONTAINER_NAME={$this->container_name}");
$envs->push("COOLIFY_CONTAINER_NAME=\"{$this->container_name}\"");
}
}
@@ -962,7 +961,7 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
}
}
if ($this->application->environment_variables->where('key', 'COOLIFY_FQDN')->isEmpty()) {
if ($this->application->compose_parsing_version === '3') {
if ((int) $this->application->compose_parsing_version >= 3) {
$envs->push("COOLIFY_URL={$this->application->fqdn}");
} else {
$envs->push("COOLIFY_FQDN={$this->application->fqdn}");
@@ -970,7 +969,7 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
}
if ($this->application->environment_variables->where('key', 'COOLIFY_URL')->isEmpty()) {
$url = str($this->application->fqdn)->replace('http://', '')->replace('https://', '');
if ($this->application->compose_parsing_version === '3') {
if ((int) $this->application->compose_parsing_version >= 3) {
$envs->push("COOLIFY_FQDN={$url}");
} else {
$envs->push("COOLIFY_URL={$url}");
@@ -978,10 +977,10 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
}
if ($this->application->build_pack !== 'dockercompose' || $this->application->compose_parsing_version === '1' || $this->application->compose_parsing_version === '2') {
if ($this->application->environment_variables->where('key', 'COOLIFY_BRANCH')->isEmpty()) {
$envs->push("COOLIFY_BRANCH={$local_branch}");
$envs->push("COOLIFY_BRANCH=\"{$local_branch}\"");
}
if ($this->application->environment_variables->where('key', 'COOLIFY_CONTAINER_NAME')->isEmpty()) {
$envs->push("COOLIFY_CONTAINER_NAME={$this->container_name}");
$envs->push("COOLIFY_CONTAINER_NAME=\"{$this->container_name}\"");
}
}
@@ -1066,15 +1065,55 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
$this->environment_variables = $envs;
}
private function elixir_finetunes()
{
if ($this->pull_request_id === 0) {
$envType = 'environment_variables';
} else {
$envType = 'environment_variables_preview';
}
$mix_env = $this->application->{$envType}->where('key', 'MIX_ENV')->first();
if ($mix_env) {
if ($mix_env->is_build_time === false) {
$this->application_deployment_queue->addLogEntry('MIX_ENV environment variable is not set as build time.', type: 'error');
$this->application_deployment_queue->addLogEntry('Please set MIX_ENV environment variable to be build time variable if you facing any issues with the deployment.', type: 'error');
}
} else {
$this->application_deployment_queue->addLogEntry('MIX_ENV environment variable not found.', type: 'error');
$this->application_deployment_queue->addLogEntry('Please add MIX_ENV environment variable and set it to be build time variable if you facing any issues with the deployment.', type: 'error');
}
$secret_key_base = $this->application->{$envType}->where('key', 'SECRET_KEY_BASE')->first();
if ($secret_key_base) {
if ($secret_key_base->is_build_time === false) {
$this->application_deployment_queue->addLogEntry('SECRET_KEY_BASE environment variable is not set as build time.', type: 'error');
$this->application_deployment_queue->addLogEntry('Please set SECRET_KEY_BASE environment variable to be build time variable if you facing any issues with the deployment.', type: 'error');
}
} else {
$this->application_deployment_queue->addLogEntry('SECRET_KEY_BASE environment variable not found.', type: 'error');
$this->application_deployment_queue->addLogEntry('Please add SECRET_KEY_BASE environment variable and set it to be build time variable if you facing any issues with the deployment.', type: 'error');
}
$database_url = $this->application->{$envType}->where('key', 'DATABASE_URL')->first();
if ($database_url) {
if ($database_url->is_build_time === false) {
$this->application_deployment_queue->addLogEntry('DATABASE_URL environment variable is not set as build time.', type: 'error');
$this->application_deployment_queue->addLogEntry('Please set DATABASE_URL environment variable to be build time variable if you facing any issues with the deployment.', type: 'error');
}
} else {
$this->application_deployment_queue->addLogEntry('DATABASE_URL environment variable not found.', type: 'error');
$this->application_deployment_queue->addLogEntry('Please add DATABASE_URL environment variable and set it to be build time variable if you facing any issues with the deployment.', type: 'error');
}
}
private function laravel_finetunes()
{
if ($this->pull_request_id === 0) {
$nixpacks_php_fallback_path = $this->application->environment_variables->where('key', 'NIXPACKS_PHP_FALLBACK_PATH')->first();
$nixpacks_php_root_dir = $this->application->environment_variables->where('key', 'NIXPACKS_PHP_ROOT_DIR')->first();
$envType = 'environment_variables';
} else {
$nixpacks_php_fallback_path = $this->application->environment_variables_preview->where('key', 'NIXPACKS_PHP_FALLBACK_PATH')->first();
$nixpacks_php_root_dir = $this->application->environment_variables_preview->where('key', 'NIXPACKS_PHP_ROOT_DIR')->first();
$envType = 'environment_variables_preview';
}
$nixpacks_php_fallback_path = $this->application->{$envType}->where('key', 'NIXPACKS_PHP_FALLBACK_PATH')->first();
$nixpacks_php_root_dir = $this->application->{$envType}->where('key', 'NIXPACKS_PHP_ROOT_DIR')->first();
if (! $nixpacks_php_fallback_path) {
$nixpacks_php_fallback_path = new EnvironmentVariable;
$nixpacks_php_fallback_path->key = 'NIXPACKS_PHP_FALLBACK_PATH';
@@ -1294,7 +1333,7 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
private function prepare_builder_image()
{
$settings = InstanceSettings::get();
$settings = instanceSettings();
$helperImage = config('coolify.helper_image');
$helperImage = "{$helperImage}:{$settings->helper_version}";
// Get user home directory
@@ -1416,10 +1455,10 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
executeInDocker($this->deployment_uuid, 'chmod 600 /root/.ssh/id_rsa'),
],
[
executeInDocker($this->deployment_uuid, "GIT_SSH_COMMAND=\"ssh -o ConnectTimeout=30 -p {$this->customPort} -o Port={$this->customPort} -o LogLevel=ERROR -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -i /root/.ssh/id_rsa\" git ls-remote {$this->fullRepoUrl} {$local_branch}"),
executeInDocker($this->deployment_uuid, "GIT_SSH_COMMAND=\"ssh -o ConnectTimeout=30 -p {$this->customPort} -o Port={$this->customPort} -o LogLevel=ERROR -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null\" git ls-remote {$this->fullRepoUrl} {$local_branch}"),
'hidden' => true,
'save' => 'git_commit_sha',
],
]
);
} else {
$this->execute_remote_command(
@@ -1533,6 +1572,9 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
data_set($parsed, 'variables.NIXPACKS_PHP_FALLBACK_PATH', $variables[0]->value);
data_set($parsed, 'variables.NIXPACKS_PHP_ROOT_DIR', $variables[1]->value);
}
if ($this->nixpacks_type === 'elixir') {
$this->elixir_finetunes();
}
$this->nixpacks_plan = json_encode($parsed, JSON_PRETTY_PRINT);
$this->application_deployment_queue->addLogEntry("Final Nixpacks plan: {$this->nixpacks_plan}", hidden: true);
if ($this->nixpacks_type === 'rust') {
@@ -2006,6 +2048,10 @@ COPY ./nginx.conf /etc/nginx/conf.d/default.conf");
executeInDocker($this->deployment_uuid, "echo '{$base64_build_command}' | base64 -d | tee /artifacts/build.sh > /dev/null"),
'hidden' => true,
],
[
executeInDocker($this->deployment_uuid, 'cat /artifacts/build.sh'),
'hidden' => true,
],
[
executeInDocker($this->deployment_uuid, 'bash /artifacts/build.sh'),
'hidden' => true,
@@ -2025,6 +2071,10 @@ COPY ./nginx.conf /etc/nginx/conf.d/default.conf");
executeInDocker($this->deployment_uuid, "echo '{$base64_build_command}' | base64 -d | tee /artifacts/build.sh > /dev/null"),
'hidden' => true,
],
[
executeInDocker($this->deployment_uuid, 'cat /artifacts/build.sh'),
'hidden' => true,
],
[
executeInDocker($this->deployment_uuid, 'bash /artifacts/build.sh'),
'hidden' => true,
@@ -2067,6 +2117,10 @@ COPY ./nginx.conf /etc/nginx/conf.d/default.conf");
executeInDocker($this->deployment_uuid, "echo '{$base64_build_command}' | base64 -d | tee /artifacts/build.sh > /dev/null"),
'hidden' => true,
],
[
executeInDocker($this->deployment_uuid, 'cat /artifacts/build.sh'),
'hidden' => true,
],
[
executeInDocker($this->deployment_uuid, 'bash /artifacts/build.sh'),
'hidden' => true,
@@ -2086,6 +2140,10 @@ COPY ./nginx.conf /etc/nginx/conf.d/default.conf");
executeInDocker($this->deployment_uuid, "echo '{$base64_build_command}' | base64 -d | tee /artifacts/build.sh > /dev/null"),
'hidden' => true,
],
[
executeInDocker($this->deployment_uuid, 'cat /artifacts/build.sh'),
'hidden' => true,
],
[
executeInDocker($this->deployment_uuid, 'bash /artifacts/build.sh'),
'hidden' => true,
@@ -2114,6 +2172,10 @@ COPY ./nginx.conf /etc/nginx/conf.d/default.conf");
executeInDocker($this->deployment_uuid, "echo '{$base64_build_command}' | base64 -d | tee /artifacts/build.sh > /dev/null"),
'hidden' => true,
],
[
executeInDocker($this->deployment_uuid, 'cat /artifacts/build.sh'),
'hidden' => true,
],
[
executeInDocker($this->deployment_uuid, 'bash /artifacts/build.sh'),
'hidden' => true,
@@ -2133,6 +2195,10 @@ COPY ./nginx.conf /etc/nginx/conf.d/default.conf");
executeInDocker($this->deployment_uuid, "echo '{$base64_build_command}' | base64 -d | tee /artifacts/build.sh > /dev/null"),
'hidden' => true,
],
[
executeInDocker($this->deployment_uuid, 'cat /artifacts/build.sh'),
'hidden' => true,
],
[
executeInDocker($this->deployment_uuid, 'bash /artifacts/build.sh'),
'hidden' => true,
@@ -2144,20 +2210,40 @@ COPY ./nginx.conf /etc/nginx/conf.d/default.conf");
$this->application_deployment_queue->addLogEntry('Building docker image completed.');
}
/**
* @param int $timeout in seconds
*/
private function graceful_shutdown_container(string $containerName, int $timeout = 30)
private function graceful_shutdown_container(string $containerName, int $timeout = 300)
{
try {
$this->execute_remote_command(
["docker stop --time=$timeout $containerName", 'hidden' => true, 'ignore_errors' => true],
["docker rm $containerName", 'hidden' => true, 'ignore_errors' => true]
);
$process = Process::timeout($timeout)->start("docker stop --time=$timeout $containerName");
$startTime = time();
while ($process->running()) {
if (time() - $startTime >= $timeout) {
$this->execute_remote_command(
["docker kill $containerName", 'hidden' => true, 'ignore_errors' => true]
);
break;
}
usleep(100000);
}
$isRunning = $this->execute_remote_command(
["docker inspect -f '{{.State.Running}}' $containerName", 'hidden' => true, 'ignore_errors' => true]
) === 'true';
if ($isRunning) {
$this->execute_remote_command(
["docker kill $containerName", 'hidden' => true, 'ignore_errors' => true]
);
}
} catch (\Exception $error) {
// report error if needed
$this->application_deployment_queue->addLogEntry("Error stopping container $containerName: ".$error->getMessage(), 'stderr');
}
$this->remove_container($containerName);
}
private function remove_container(string $containerName)
{
$this->execute_remote_command(
["docker rm -f $containerName", 'hidden' => true, 'ignore_errors' => true]
);

View File

@@ -2,15 +2,14 @@
namespace App\Jobs;
use App\Models\InstanceSettings;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldBeEncrypted;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Facades\Http;
class CheckForUpdatesJob implements ShouldBeEncrypted, ShouldQueue
{
@@ -22,7 +21,7 @@ class CheckForUpdatesJob implements ShouldBeEncrypted, ShouldQueue
if (isDev() || isCloud()) {
return;
}
$settings = InstanceSettings::get();
$settings = instanceSettings();
$response = Http::retry(3, 1000)->get('https://cdn.coollabs.io/coolify/versions.json');
if ($response->successful()) {
$versions = $response->json();

View File

@@ -21,11 +21,10 @@ class CleanupHelperContainersJob implements ShouldBeEncrypted, ShouldBeUnique, S
{
try {
ray('Cleaning up helper containers on '.$this->server->name);
$containers = instant_remote_process(['docker container ps --filter "ancestor=ghcr.io/coollabsio/coolify-helper:next" --filter "ancestor=ghcr.io/coollabsio/coolify-helper:latest" --format \'{{json .}}\''], $this->server, false);
$containers = format_docker_command_output_to_json($containers);
if ($containers->count() > 0) {
foreach ($containers as $container) {
$containerId = data_get($container, 'ID');
$containers = instant_remote_process(['docker container ps --format \'{{json .}}\' | jq -s \'map(select(.Image | contains("ghcr.io/coollabsio/coolify-helper")))\''], $this->server, false);
$containerIds = collect(json_decode($containers))->pluck('ID');
if ($containerIds->count() > 0) {
foreach ($containerIds as $containerId) {
ray('Removing container '.$containerId);
instant_remote_process(['docker container rm -f '.$containerId], $this->server, false);
}

View File

@@ -0,0 +1,82 @@
<?php
namespace App\Jobs;
use App\Models\Server;
use Carbon\Carbon;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Process;
use Illuminate\Support\Facades\Storage;
class CleanupStaleMultiplexedConnections implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
public function handle()
{
$this->cleanupStaleConnections();
$this->cleanupNonExistentServerConnections();
}
private function cleanupStaleConnections()
{
$muxFiles = Storage::disk('ssh-mux')->files();
foreach ($muxFiles as $muxFile) {
$serverUuid = $this->extractServerUuidFromMuxFile($muxFile);
$server = Server::where('uuid', $serverUuid)->first();
if (! $server) {
$this->removeMultiplexFile($muxFile);
continue;
}
$muxSocket = "/var/www/html/storage/app/ssh/mux/{$muxFile}";
$checkCommand = "ssh -O check -o ControlPath={$muxSocket} {$server->user}@{$server->ip} 2>/dev/null";
$checkProcess = Process::run($checkCommand);
if ($checkProcess->exitCode() !== 0) {
$this->removeMultiplexFile($muxFile);
} else {
$muxContent = Storage::disk('ssh-mux')->get($muxFile);
$establishedAt = Carbon::parse(substr($muxContent, 37));
$expirationTime = $establishedAt->addSeconds(config('constants.ssh.mux_persist_time'));
if (Carbon::now()->isAfter($expirationTime)) {
$this->removeMultiplexFile($muxFile);
}
}
}
}
private function cleanupNonExistentServerConnections()
{
$muxFiles = Storage::disk('ssh-mux')->files();
$existingServerUuids = Server::pluck('uuid')->toArray();
foreach ($muxFiles as $muxFile) {
$serverUuid = $this->extractServerUuidFromMuxFile($muxFile);
if (! in_array($serverUuid, $existingServerUuids)) {
$this->removeMultiplexFile($muxFile);
}
}
}
private function extractServerUuidFromMuxFile($muxFile)
{
return substr($muxFile, 4);
}
private function removeMultiplexFile($muxFile)
{
$muxSocket = "/var/www/html/storage/app/ssh/mux/{$muxFile}";
$closeCommand = "ssh -O exit -o ControlPath={$muxSocket} localhost 2>/dev/null";
Process::run($closeCommand);
Storage::disk('ssh-mux')->delete($muxFile);
}
}

View File

@@ -9,7 +9,6 @@ use Illuminate\Contracts\Queue\ShouldBeEncrypted;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\Middleware\WithoutOverlapping;
use Illuminate\Queue\SerializesModels;
class ContainerStatusJob implements ShouldBeEncrypted, ShouldQueue
@@ -25,16 +24,6 @@ class ContainerStatusJob implements ShouldBeEncrypted, ShouldQueue
public function __construct(public Server $server) {}
public function middleware(): array
{
return [(new WithoutOverlapping($this->server->uuid))];
}
public function uniqueId(): int
{
return $this->server->uuid;
}
public function handle()
{
GetContainersStatus::run($this->server);

View File

@@ -2,7 +2,6 @@
namespace App\Jobs;
use App\Actions\Database\StopDatabase;
use App\Events\BackupCreated;
use App\Models\S3Storage;
use App\Models\ScheduledDatabaseBackup;
@@ -22,10 +21,8 @@ use Illuminate\Contracts\Queue\ShouldBeEncrypted;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\Middleware\WithoutOverlapping;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Str;
use App\Models\InstanceSettings;
class DatabaseBackupJob implements ShouldBeEncrypted, ShouldQueue
{
@@ -64,42 +61,32 @@ class DatabaseBackupJob implements ShouldBeEncrypted, ShouldQueue
public function __construct($backup)
{
$this->backup = $backup;
$this->team = Team::find($backup->team_id);
if (is_null($this->team)) {
return;
}
if (data_get($this->backup, 'database_type') === 'App\Models\ServiceDatabase') {
$this->database = data_get($this->backup, 'database');
$this->server = $this->database->service->server;
$this->s3 = $this->backup->s3;
} else {
$this->database = data_get($this->backup, 'database');
$this->server = $this->database->destination->server;
$this->s3 = $this->backup->s3;
}
}
public function middleware(): array
{
return [new WithoutOverlapping($this->backup->id)];
}
public function uniqueId(): int
{
return $this->backup->id;
}
public function handle(): void
{
try {
// Check if team is exists
if (is_null($this->team)) {
$this->backup->update(['status' => 'failed']);
StopDatabase::run($this->database);
$this->database->delete();
$this->team = Team::find($this->backup->team_id);
if (! $this->team) {
$this->backup->delete();
return;
}
if (data_get($this->backup, 'database_type') === 'App\Models\ServiceDatabase') {
$this->database = data_get($this->backup, 'database');
$this->server = $this->database->service->server;
$this->s3 = $this->backup->s3;
} else {
$this->database = data_get($this->backup, 'database');
$this->server = $this->database->destination->server;
$this->s3 = $this->backup->s3;
}
if (is_null($this->server)) {
throw new \Exception('Server not found?!');
}
if (is_null($this->database)) {
throw new \Exception('Database not found?!');
}
BackupCreated::dispatch($this->team->id);
@@ -249,7 +236,6 @@ class DatabaseBackupJob implements ShouldBeEncrypted, ShouldQueue
}
}
$this->backup_dir = backup_dir().'/databases/'.str($this->team->name)->slug().'-'.$this->team->id.'/'.$this->directory_name;
if ($this->database->name === 'coolify-db') {
$databasesToBackup = ['coolify'];
$this->directory_name = $this->container_name = 'coolify-db';
@@ -262,6 +248,9 @@ class DatabaseBackupJob implements ShouldBeEncrypted, ShouldQueue
try {
if (str($databaseType)->contains('postgres')) {
$this->backup_file = "/pg-dump-$database-".Carbon::now()->timestamp.'.dmp';
if ($this->backup->dump_all) {
$this->backup_file = '/pg-dump-all-'.Carbon::now()->timestamp.'.gz';
}
$this->backup_location = $this->backup_dir.$this->backup_file;
$this->backup_log = ScheduledDatabaseBackupExecution::create([
'database_name' => $database,
@@ -290,6 +279,9 @@ class DatabaseBackupJob implements ShouldBeEncrypted, ShouldQueue
$this->backup_standalone_mongodb($database);
} elseif (str($databaseType)->contains('mysql')) {
$this->backup_file = "/mysql-dump-$database-".Carbon::now()->timestamp.'.dmp';
if ($this->backup->dump_all) {
$this->backup_file = '/mysql-dump-all-'.Carbon::now()->timestamp.'.gz';
}
$this->backup_location = $this->backup_dir.$this->backup_file;
$this->backup_log = ScheduledDatabaseBackupExecution::create([
'database_name' => $database,
@@ -299,6 +291,9 @@ class DatabaseBackupJob implements ShouldBeEncrypted, ShouldQueue
$this->backup_standalone_mysql($database);
} elseif (str($databaseType)->contains('mariadb')) {
$this->backup_file = "/mariadb-dump-$database-".Carbon::now()->timestamp.'.dmp';
if ($this->backup->dump_all) {
$this->backup_file = '/mariadb-dump-all-'.Carbon::now()->timestamp.'.gz';
}
$this->backup_location = $this->backup_dir.$this->backup_file;
$this->backup_log = ScheduledDatabaseBackupExecution::create([
'database_name' => $database,
@@ -337,7 +332,9 @@ class DatabaseBackupJob implements ShouldBeEncrypted, ShouldQueue
send_internal_notification('DatabaseBackupJob failed with: '.$e->getMessage());
throw $e;
} finally {
BackupCreated::dispatch($this->team->id);
if ($this->team) {
BackupCreated::dispatch($this->team->id);
}
}
}
@@ -396,9 +393,14 @@ class DatabaseBackupJob implements ShouldBeEncrypted, ShouldQueue
if ($this->postgres_password) {
$backupCommand .= " -e PGPASSWORD=$this->postgres_password";
}
$backupCommand .= " $this->container_name pg_dump --format=custom --no-acl --no-owner --username {$this->database->postgres_user} $database > $this->backup_location";
if ($this->backup->dump_all) {
$backupCommand .= " $this->container_name pg_dumpall --username {$this->database->postgres_user} | gzip > $this->backup_location";
} else {
$backupCommand .= " $this->container_name pg_dump --format=custom --no-acl --no-owner --username {$this->database->postgres_user} $database > $this->backup_location";
}
$commands[] = $backupCommand;
ray($commands);
$this->backup_output = instant_remote_process($commands, $this->server);
$this->backup_output = trim($this->backup_output);
if ($this->backup_output === '') {
@@ -416,8 +418,11 @@ class DatabaseBackupJob implements ShouldBeEncrypted, ShouldQueue
{
try {
$commands[] = 'mkdir -p '.$this->backup_dir;
$commands[] = "docker exec $this->container_name mysqldump -u root -p{$this->database->mysql_root_password} $database > $this->backup_location";
ray($commands);
if ($this->backup->dump_all) {
$commands[] = "docker exec $this->container_name mysqldump -u root -p{$this->database->mysql_root_password} --all-databases --single-transaction --quick --lock-tables=false --compress | gzip > $this->backup_location";
} else {
$commands[] = "docker exec $this->container_name mysqldump -u root -p{$this->database->mysql_root_password} $database > $this->backup_location";
}
$this->backup_output = instant_remote_process($commands, $this->server);
$this->backup_output = trim($this->backup_output);
if ($this->backup_output === '') {
@@ -435,7 +440,11 @@ class DatabaseBackupJob implements ShouldBeEncrypted, ShouldQueue
{
try {
$commands[] = 'mkdir -p '.$this->backup_dir;
$commands[] = "docker exec $this->container_name mariadb-dump -u root -p{$this->database->mariadb_root_password} $database > $this->backup_location";
if ($this->backup->dump_all) {
$commands[] = "docker exec $this->container_name mariadb-dump -u root -p{$this->database->mariadb_root_password} --all-databases --single-transaction --quick --lock-tables=false --compress > $this->backup_location";
} else {
$commands[] = "docker exec $this->container_name mariadb-dump -u root -p{$this->database->mariadb_root_password} $database > $this->backup_location";
}
ray($commands);
$this->backup_output = instant_remote_process($commands, $this->server);
$this->backup_output = trim($this->backup_output);
@@ -498,10 +507,27 @@ class DatabaseBackupJob implements ShouldBeEncrypted, ShouldQueue
$this->ensureHelperImageAvailable();
$fullImageName = $this->getFullImageName();
$commands[] = "docker run -d --network {$network} --name backup-of-{$this->backup->uuid} --rm -v $this->backup_location:$this->backup_location:ro {$fullImageName}";
$commands[] = "docker exec backup-of-{$this->backup->uuid} mc config host add temporary {$endpoint} $key $secret";
if (isDev()) {
if ($this->database->name === 'coolify-db') {
$backup_location_from = '/var/lib/docker/volumes/coolify_dev_backups_data/_data/coolify/coolify-db-'.$this->server->ip.$this->backup_file;
$commands[] = "docker run -d --network {$network} --name backup-of-{$this->backup->uuid} --rm -v $backup_location_from:$this->backup_location:ro {$fullImageName}";
} else {
$backup_location_from = '/var/lib/docker/volumes/coolify_dev_backups_data/_data/databases/'.str($this->team->name)->slug().'-'.$this->team->id.'/'.$this->directory_name.$this->backup_file;
$commands[] = "docker run -d --network {$network} --name backup-of-{$this->backup->uuid} --rm -v $backup_location_from:$this->backup_location:ro {$fullImageName}";
}
} else {
$commands[] = "docker run -d --network {$network} --name backup-of-{$this->backup->uuid} --rm -v $this->backup_location:$this->backup_location:ro {$fullImageName}";
}
if ($this->s3->isHetzner()) {
$endpointWithoutBucket = 'https://'.str($endpoint)->after('https://')->after('.')->value();
$commands[] = "docker exec backup-of-{$this->backup->uuid} mc alias set --path=off --api=S3v4 temporary {$endpointWithoutBucket} $key $secret";
} else {
$commands[] = "docker exec backup-of-{$this->backup->uuid} mc config host add temporary {$endpoint} $key $secret";
}
$commands[] = "docker exec backup-of-{$this->backup->uuid} mc cp $this->backup_location temporary/$bucket{$this->backup_dir}/";
instant_remote_process($commands, $this->server);
$this->add_to_backup_output('Uploaded to S3.');
} catch (\Throwable $e) {
$this->add_to_backup_output($e->getMessage());
@@ -518,7 +544,7 @@ class DatabaseBackupJob implements ShouldBeEncrypted, ShouldQueue
$imageExists = $this->checkImageExists($fullImageName);
if (!$imageExists) {
if (! $imageExists) {
$this->pullHelperImage($fullImageName);
}
}
@@ -526,6 +552,7 @@ class DatabaseBackupJob implements ShouldBeEncrypted, ShouldQueue
private function checkImageExists(string $fullImageName): bool
{
$result = instant_remote_process(["docker image inspect {$fullImageName} >/dev/null 2>&1 && echo 'exists' || echo 'not exists'"], $this->server, false);
return trim($result) === 'exists';
}
@@ -534,7 +561,7 @@ class DatabaseBackupJob implements ShouldBeEncrypted, ShouldQueue
try {
instant_remote_process(["docker pull {$fullImageName}"], $this->server);
} catch (\Exception $e) {
$errorMessage = "Failed to pull helper image: " . $e->getMessage();
$errorMessage = 'Failed to pull helper image: '.$e->getMessage();
$this->add_to_backup_output($errorMessage);
throw new \RuntimeException($errorMessage);
}
@@ -542,9 +569,10 @@ class DatabaseBackupJob implements ShouldBeEncrypted, ShouldQueue
private function getFullImageName(): string
{
$settings = InstanceSettings::get();
$settings = instanceSettings();
$helperImage = config('coolify.helper_image');
$latestVersion = $settings->helper_version;
return "{$helperImage}:{$latestVersion}";
}
}

View File

@@ -1,62 +0,0 @@
<?php
namespace App\Jobs;
use App\Models\ScheduledDatabaseBackup;
use App\Models\Team;
use App\Notifications\Database\DailyBackup;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldBeEncrypted;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
class DatabaseBackupStatusJob implements ShouldBeEncrypted, ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
public $tries = 1;
public function __construct() {}
public function handle()
{
// $teams = Team::all();
// foreach ($teams as $team) {
// $scheduled_backups = $team->scheduledDatabaseBackups()->get();
// if ($scheduled_backups->isEmpty()) {
// continue;
// }
// foreach ($scheduled_backups as $scheduled_backup) {
// $last_days_backups = $scheduled_backup->get_last_days_backup_status();
// if ($last_days_backups->isEmpty()) {
// continue;
// }
// $failed = $last_days_backups->where('status', 'failed');
// }
// }
// $scheduled_backups = ScheduledDatabaseBackup::all();
// $databases = collect();
// $teams = collect();
// foreach ($scheduled_backups as $scheduled_backup) {
// $last_days_backups = $scheduled_backup->get_last_days_backup_status();
// if ($last_days_backups->isEmpty()) {
// continue;
// }
// $failed = $last_days_backups->where('status', 'failed');
// $database = $scheduled_backup->database;
// $team = $database->team();
// $teams->put($team->id, $team);
// $databases->put("{$team->id}:{$database->name}", [
// 'failed_count' => $failed->count(),
// ]);
// }
// foreach ($databases as $name => $database) {
// [$team_id, $name] = explode(':', $name);
// $team = $teams->get($team_id);
// $team?->notify(new DailyBackup($databases));
// }
}
}

View File

@@ -4,6 +4,7 @@ namespace App\Jobs;
use App\Actions\Application\StopApplication;
use App\Actions\Database\StopDatabase;
use App\Actions\Server\CleanupDocker;
use App\Actions\Service\DeleteService;
use App\Actions\Service\StopService;
use App\Models\Application;
@@ -30,8 +31,11 @@ class DeleteResourceJob implements ShouldBeEncrypted, ShouldQueue
public function __construct(
public Application|Service|StandalonePostgresql|StandaloneRedis|StandaloneMongodb|StandaloneMysql|StandaloneMariadb|StandaloneKeydb|StandaloneDragonfly|StandaloneClickhouse $resource,
public bool $deleteConfigurations = false,
public bool $deleteVolumes = false) {}
public bool $deleteConfigurations = true,
public bool $deleteVolumes = true,
public bool $dockerCleanup = true,
public bool $deleteConnectedNetworks = true
) {}
public function handle()
{
@@ -51,11 +55,11 @@ class DeleteResourceJob implements ShouldBeEncrypted, ShouldQueue
case 'standalone-dragonfly':
case 'standalone-clickhouse':
$persistentStorages = $this->resource?->persistentStorages()?->get();
StopDatabase::run($this->resource);
StopDatabase::run($this->resource, true);
break;
case 'service':
StopService::run($this->resource);
DeleteService::run($this->resource);
StopService::run($this->resource, true);
DeleteService::run($this->resource, $this->deleteConfigurations, $this->deleteVolumes, $this->dockerCleanup, $this->deleteConnectedNetworks);
break;
}
@@ -65,12 +69,31 @@ class DeleteResourceJob implements ShouldBeEncrypted, ShouldQueue
if ($this->deleteConfigurations) {
$this->resource?->delete_configurations();
}
$isDatabase = $this->resource instanceof StandalonePostgresql
|| $this->resource instanceof StandaloneRedis
|| $this->resource instanceof StandaloneMongodb
|| $this->resource instanceof StandaloneMysql
|| $this->resource instanceof StandaloneMariadb
|| $this->resource instanceof StandaloneKeydb
|| $this->resource instanceof StandaloneDragonfly
|| $this->resource instanceof StandaloneClickhouse;
$server = data_get($this->resource, 'server') ?? data_get($this->resource, 'destination.server');
if (($this->dockerCleanup || $isDatabase) && $server) {
CleanupDocker::dispatch($server, true);
}
if ($this->deleteConnectedNetworks && ! $isDatabase) {
$this->resource?->delete_connected_networks($this->resource->uuid);
}
} catch (\Throwable $e) {
ray($e->getMessage());
send_internal_notification('ContainerStoppingJob failed with: '.$e->getMessage());
throw $e;
} finally {
$this->resource->forceDelete();
if ($this->dockerCleanup) {
CleanupDocker::dispatch($server, true);
}
Artisan::queue('cleanup:stucked-resources');
}
}

View File

@@ -10,7 +10,6 @@ use Illuminate\Contracts\Queue\ShouldBeEncrypted;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\Middleware\WithoutOverlapping;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Log;
@@ -24,17 +23,7 @@ class DockerCleanupJob implements ShouldBeEncrypted, ShouldQueue
public ?string $usageBefore = null;
public function __construct(public Server $server) {}
public function middleware(): array
{
return [new WithoutOverlapping($this->server->id)];
}
public function uniqueId(): int
{
return $this->server->id;
}
public function __construct(public Server $server, public bool $manualCleanup = false) {}
public function handle(): void
{
@@ -42,8 +31,9 @@ class DockerCleanupJob implements ShouldBeEncrypted, ShouldQueue
if (! $this->server->isFunctional()) {
return;
}
if ($this->server->settings->force_docker_cleanup) {
Log::info('DockerCleanupJob force cleanup on '.$this->server->name);
if ($this->manualCleanup || $this->server->settings->force_docker_cleanup) {
Log::info('DockerCleanupJob '.($this->manualCleanup ? 'manual' : 'force').' cleanup on '.$this->server->name);
CleanupDocker::run(server: $this->server);
return;

View File

@@ -8,7 +8,6 @@ use Illuminate\Contracts\Queue\ShouldBeEncrypted;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\Middleware\WithoutOverlapping;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Http;
@@ -25,16 +24,6 @@ class GithubAppPermissionJob implements ShouldBeEncrypted, ShouldQueue
public function __construct(public GithubApp $github_app) {}
public function middleware(): array
{
return [(new WithoutOverlapping($this->github_app->uuid))];
}
public function uniqueId(): int
{
return $this->github_app->uuid;
}
public function handle()
{
try {

View File

@@ -2,14 +2,12 @@
namespace App\Jobs;
use App\Models\InstanceSettings;
use App\Models\Server;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldBeEncrypted;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\Middleware\WithoutOverlapping;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Http;
@@ -19,17 +17,7 @@ class PullHelperImageJob implements ShouldBeEncrypted, ShouldQueue
public $timeout = 1000;
public function middleware(): array
{
return [(new WithoutOverlapping($this->server->uuid))];
}
public function uniqueId(): string
{
return $this->server->uuid;
}
public function __construct(public Server $server) {}
public function __construct() {}
public function handle(): void
{
@@ -37,13 +25,13 @@ class PullHelperImageJob implements ShouldBeEncrypted, ShouldQueue
$response = Http::retry(3, 1000)->get('https://cdn.coollabs.io/coolify/versions.json');
if ($response->successful()) {
$versions = $response->json();
$settings = InstanceSettings::get();
$settings = instanceSettings();
$latest_version = data_get($versions, 'coolify.helper.version');
$current_version = $settings->helper_version;
if (version_compare($latest_version, $current_version, '>')) {
// New version available
$helperImage = config('coolify.helper_image');
instant_remote_process(["docker pull -q {$helperImage}:{$latest_version}"], $this->server);
// $helperImage = config('coolify.helper_image');
// instant_remote_process(["docker pull -q {$helperImage}:{$latest_version}"], $this->server);
$settings->update(['helper_version' => $latest_version]);
}
}

View File

@@ -9,7 +9,6 @@ use Illuminate\Contracts\Queue\ShouldBeEncrypted;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\Middleware\WithoutOverlapping;
use Illuminate\Queue\SerializesModels;
class PullSentinelImageJob implements ShouldBeEncrypted, ShouldQueue
@@ -18,16 +17,6 @@ class PullSentinelImageJob implements ShouldBeEncrypted, ShouldQueue
public $timeout = 1000;
public function middleware(): array
{
return [(new WithoutOverlapping($this->server->uuid))];
}
public function uniqueId(): string
{
return $this->server->uuid;
}
public function __construct(public Server $server) {}
public function handle(): void

View File

@@ -13,7 +13,6 @@ use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\Middleware\WithoutOverlapping;
use Illuminate\Queue\SerializesModels;
class ScheduledTaskJob implements ShouldQueue
@@ -56,24 +55,17 @@ class ScheduledTaskJob implements ShouldQueue
{
if ($this->resource instanceof Application) {
$timezone = $this->resource->destination->server->settings->server_timezone;
return $timezone;
} elseif ($this->resource instanceof Service) {
$timezone = $this->resource->server->settings->server_timezone;
return $timezone;
}
return 'UTC';
}
public function middleware(): array
{
return [new WithoutOverlapping($this->task->id)];
}
public function uniqueId(): int
{
return $this->task->id;
}
public function handle(): void
{
@@ -94,12 +86,12 @@ class ScheduledTaskJob implements ShouldQueue
} elseif ($this->resource->type() == 'service') {
$this->resource->applications()->get()->each(function ($application) {
if (str(data_get($application, 'status'))->contains('running')) {
$this->containers[] = data_get($application, 'name') . '-' . data_get($this->resource, 'uuid');
$this->containers[] = data_get($application, 'name').'-'.data_get($this->resource, 'uuid');
}
});
$this->resource->databases()->get()->each(function ($database) {
if (str(data_get($database, 'status'))->contains('running')) {
$this->containers[] = data_get($database, 'name') . '-' . data_get($this->resource, 'uuid');
$this->containers[] = data_get($database, 'name').'-'.data_get($this->resource, 'uuid');
}
});
}
@@ -112,8 +104,8 @@ class ScheduledTaskJob implements ShouldQueue
}
foreach ($this->containers as $containerName) {
if (count($this->containers) == 1 || str_starts_with($containerName, $this->task->container . '-' . $this->resource->uuid)) {
$cmd = "sh -c '" . str_replace("'", "'\''", $this->task->command) . "'";
if (count($this->containers) == 1 || str_starts_with($containerName, $this->task->container.'-'.$this->resource->uuid)) {
$cmd = "sh -c '".str_replace("'", "'\''", $this->task->command)."'";
$exec = "docker exec {$containerName} {$cmd}";
$this->task_output = instant_remote_process([$exec], $this->server, true);
$this->task_log->update([

View File

@@ -16,7 +16,6 @@ use Illuminate\Contracts\Queue\ShouldBeEncrypted;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\Middleware\WithoutOverlapping;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Arr;
@@ -24,7 +23,9 @@ class ServerCheckJob implements ShouldBeEncrypted, ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
public $tries = 3;
public $tries = 1;
public $timeout = 60;
public $containers;
@@ -43,16 +44,6 @@ class ServerCheckJob implements ShouldBeEncrypted, ShouldQueue
public function __construct(public Server $server) {}
// public function middleware(): array
// {
// return [(new WithoutOverlapping($this->server->uuid))];
// }
// public function uniqueId(): int
// {
// return $this->server->uuid;
// }
public function handle()
{
try {
@@ -78,7 +69,9 @@ class ServerCheckJob implements ShouldBeEncrypted, ShouldQueue
return 'No containers found.';
}
GetContainersStatus::run($this->server, $this->containers, $containerReplicates);
$this->checkLogDrainContainer();
if ($this->server->isLogDrainEnabled()) {
$this->checkLogDrainContainer();
}
}
} catch (\Throwable $e) {
@@ -91,7 +84,7 @@ class ServerCheckJob implements ShouldBeEncrypted, ShouldQueue
private function serverStatus()
{
['uptime' => $uptime] = $this->server->validateConnection();
['uptime' => $uptime] = $this->server->validateConnection(false);
if ($uptime) {
if ($this->server->unreachable_notification_sent === true) {
$this->server->update(['unreachable_notification_sent' => false]);
@@ -124,9 +117,6 @@ class ServerCheckJob implements ShouldBeEncrypted, ShouldQueue
private function checkLogDrainContainer()
{
if(! $this->server->isLogDrainEnabled()) {
return;
}
$foundLogDrainContainer = $this->containers->filter(function ($value, $key) {
return data_get($value, 'Name') === '/coolify-log-drain';
})->first();

View File

@@ -10,7 +10,6 @@ use Illuminate\Contracts\Queue\ShouldBeEncrypted;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\Middleware\WithoutOverlapping;
use Illuminate\Queue\SerializesModels;
class ServerLimitCheckJob implements ShouldBeEncrypted, ShouldQueue
@@ -26,16 +25,6 @@ class ServerLimitCheckJob implements ShouldBeEncrypted, ShouldQueue
public function __construct(public Team $team) {}
public function middleware(): array
{
return [(new WithoutOverlapping($this->team->uuid))];
}
public function uniqueId(): int
{
return $this->team->uuid;
}
public function handle()
{
try {

View File

@@ -8,7 +8,6 @@ use Illuminate\Contracts\Queue\ShouldBeEncrypted;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\Middleware\WithoutOverlapping;
use Illuminate\Queue\SerializesModels;
class ServerStatusJob implements ShouldBeEncrypted, ShouldQueue
@@ -26,16 +25,6 @@ class ServerStatusJob implements ShouldBeEncrypted, ShouldQueue
public function __construct(public Server $server) {}
public function middleware(): array
{
return [(new WithoutOverlapping($this->server->uuid))];
}
public function uniqueId(): int
{
return $this->server->uuid;
}
public function handle()
{
if (! $this->server->isServerReady($this->tries)) {

View File

@@ -0,0 +1,59 @@
<?php
namespace App\Jobs;
use App\Models\Server;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldBeEncrypted;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
class ServerStorageCheckJob implements ShouldBeEncrypted, ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
public $tries = 1;
public $timeout = 60;
public $containers;
public $applications;
public $databases;
public $services;
public $previews;
public function backoff(): int
{
return isDev() ? 1 : 3;
}
public function __construct(public Server $server) {}
public function handle()
{
try {
if (! $this->server->isFunctional()) {
ray('Server is not ready.');
return 'Server is not ready.';
}
$team = $this->server->team;
$percentage = $this->server->storageCheck();
if ($percentage > 1) {
ray('Server storage is at '.$percentage.'%');
}
} catch (\Throwable $e) {
ray($e->getMessage());
return handleError($e);
}
}
}

View File

@@ -3,7 +3,6 @@
namespace App\Jobs;
use App\Actions\Server\UpdateCoolify;
use App\Models\InstanceSettings;
use App\Models\Server;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldBeEncrypted;
@@ -23,7 +22,7 @@ class UpdateCoolifyJob implements ShouldBeEncrypted, ShouldQueue
{
try {
CheckForUpdatesJob::dispatchSync();
$settings = InstanceSettings::get();
$settings = instanceSettings();
if (! $settings->new_version_available) {
Log::info('No new version available. Skipping update.');

View File

@@ -73,6 +73,8 @@ class Index extends Component
}
$this->privateKeyName = generate_random_name();
$this->remoteServerName = generate_random_name();
$this->remoteServerPort = $this->remoteServerPort;
$this->remoteServerUser = $this->remoteServerUser;
if (isDev()) {
$this->privateKey = '-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
@@ -139,7 +141,7 @@ uZx9iFkCELtxrh31QJ68AAAAEXNhaWxANzZmZjY2ZDJlMmRkAQIDBA==
if (! $this->createdServer) {
return $this->dispatch('error', 'Localhost server is not found. Something went wrong during installation. Please try to reinstall or contact support.');
}
$this->serverPublicKey = $this->createdServer->privateKey->publicKey();
$this->serverPublicKey = $this->createdServer->privateKey->getPublicKey();
return $this->validateServer('localhost');
} elseif ($this->selectedServerType === 'remote') {
@@ -154,6 +156,7 @@ uZx9iFkCELtxrh31QJ68AAAAEXNhaWxANzZmZjY2ZDJlMmRkAQIDBA==
$this->servers = Server::ownedByCurrentTeam(['name'])->where('id', '!=', 0)->get();
if ($this->servers->count() > 0) {
$this->selectedExistingServer = $this->servers->first()->id;
$this->updateServerDetails();
$this->currentState = 'select-existing-server';
return;
@@ -172,10 +175,19 @@ uZx9iFkCELtxrh31QJ68AAAAEXNhaWxANzZmZjY2ZDJlMmRkAQIDBA==
return;
}
$this->selectedExistingPrivateKey = $this->createdServer->privateKey->id;
$this->serverPublicKey = $this->createdServer->privateKey->publicKey();
$this->serverPublicKey = $this->createdServer->privateKey->getPublicKey();
$this->updateServerDetails();
$this->currentState = 'validate-server';
}
private function updateServerDetails()
{
if ($this->createdServer) {
$this->remoteServerPort = $this->createdServer->port;
$this->remoteServerUser = $this->createdServer->user;
}
}
public function getProxyType()
{
// Set Default Proxy Type
@@ -219,27 +231,35 @@ uZx9iFkCELtxrh31QJ68AAAAEXNhaWxANzZmZjY2ZDJlMmRkAQIDBA==
public function savePrivateKey()
{
$this->validate([
'privateKeyName' => 'required',
'privateKey' => 'required',
'privateKeyName' => 'required|string|max:255',
'privateKeyDescription' => 'nullable|string|max:255',
'privateKey' => 'required|string',
]);
$this->createdPrivateKey = PrivateKey::create([
'name' => $this->privateKeyName,
'description' => $this->privateKeyDescription,
'private_key' => $this->privateKey,
'team_id' => currentTeam()->id,
]);
$this->createdPrivateKey->save();
$this->currentState = 'create-server';
try {
$privateKey = PrivateKey::createAndStore([
'name' => $this->privateKeyName,
'description' => $this->privateKeyDescription,
'private_key' => $this->privateKey,
'team_id' => currentTeam()->id,
]);
$this->createdPrivateKey = $privateKey;
$this->currentState = 'create-server';
} catch (\Exception $e) {
$this->addError('privateKey', 'Failed to save private key: '.$e->getMessage());
}
}
public function saveServer()
{
$this->validate([
'remoteServerName' => 'required',
'remoteServerHost' => 'required',
'remoteServerName' => 'required|string',
'remoteServerHost' => 'required|string',
'remoteServerPort' => 'required|integer',
'remoteServerUser' => 'required',
'remoteServerUser' => 'required|string',
]);
$this->privateKey = formatPrivateKey($this->privateKey);
$foundServer = Server::whereIp($this->remoteServerHost)->first();
if ($foundServer) {
@@ -269,7 +289,7 @@ uZx9iFkCELtxrh31QJ68AAAAEXNhaWxANzZmZjY2ZDJlMmRkAQIDBA==
public function validateServer()
{
try {
config()->set('coolify.mux_enabled', false);
config()->set('constants.ssh.mux_enabled', false);
// EC2 does not have `uptime` command, lol
instant_remote_process(['ls /'], $this->createdServer, true);
@@ -277,9 +297,12 @@ uZx9iFkCELtxrh31QJ68AAAAEXNhaWxANzZmZjY2ZDJlMmRkAQIDBA==
$this->createdServer->settings()->update([
'is_reachable' => true,
]);
$this->serverReachable = true;
} catch (\Throwable $e) {
$this->serverReachable = false;
$this->createdServer->delete();
$this->createdServer->settings()->update([
'is_reachable' => false,
]);
return handleError(error: $e, livewire: $this);
}
@@ -296,6 +319,10 @@ uZx9iFkCELtxrh31QJ68AAAAEXNhaWxANzZmZjY2ZDJlMmRkAQIDBA==
]);
$this->getProxyType();
} catch (\Throwable $e) {
$this->createdServer->settings()->update([
'is_usable' => false,
]);
return handleError(error: $e, livewire: $this);
}
}
@@ -349,6 +376,21 @@ uZx9iFkCELtxrh31QJ68AAAAEXNhaWxANzZmZjY2ZDJlMmRkAQIDBA==
);
}
public function saveAndValidateServer()
{
$this->validate([
'remoteServerPort' => 'required|integer|min:1|max:65535',
'remoteServerUser' => 'required|string',
]);
$this->createdServer->update([
'port' => $this->remoteServerPort,
'user' => $this->remoteServerUser,
'timezone' => 'UTC',
]);
$this->validateServer();
}
private function createNewPrivateKey()
{
$this->privateKeyName = generate_random_name();

View File

@@ -1,21 +0,0 @@
<?php
namespace App\Livewire\CommandCenter;
use App\Models\Server;
use Livewire\Component;
class Index extends Component
{
public $servers = [];
public function mount()
{
$this->servers = Server::isReachable()->get();
}
public function render()
{
return view('livewire.command-center.index');
}
}

View File

@@ -30,8 +30,7 @@ class Dashboard extends Component
public function cleanup_queue()
{
$this->dispatch('success', 'Cleanup started.');
Artisan::queue('cleanup:application-deployment-queue', [
Artisan::queue('cleanup:deployment-queue', [
'--team-id' => currentTeam()->id,
]);
}

View File

@@ -38,7 +38,7 @@ class Form extends Component
}
$this->destination->delete();
return redirect()->route('dashboard');
return redirect()->route('destination.all');
} catch (\Throwable $e) {
return handleError($e, $this);
}

View File

@@ -47,7 +47,7 @@ class Help extends Component
]
);
$mail->subject("[HELP]: {$this->subject}");
$settings = \App\Models\InstanceSettings::get();
$settings = instanceSettings();
$type = set_transanctional_email_settings($settings);
if (! $type) {
$url = 'https://app.coolify.io/api/feedback';
@@ -61,6 +61,7 @@ class Help extends Component
send_user_an_email($mail, auth()->user()?->email, 'hi@coollabs.io');
}
$this->dispatch('success', 'Feedback sent.', 'We will get in touch with you as soon as possible.');
$this->reset('description', 'subject');
} catch (\Throwable $e) {
return handleError($e, $this);
}

View File

@@ -2,13 +2,28 @@
namespace App\Livewire;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Hash;
use Livewire\Component;
class NavbarDeleteTeam extends Component
{
public function delete()
public $team;
public function mount()
{
$this->team = currentTeam()->name;
}
public function delete($password)
{
if (! Hash::check($password, Auth::user()->password)) {
$this->addError('password', 'The provided password is incorrect.');
return;
}
$currentTeam = currentTeam();
$currentTeam->delete();

View File

@@ -172,7 +172,7 @@ class Email extends Component
public function copyFromInstanceSettings()
{
$settings = \App\Models\InstanceSettings::get();
$settings = instanceSettings();
if ($settings->smtp_enabled) {
$team = currentTeam();
$team->update([

View File

@@ -4,7 +4,6 @@ namespace App\Livewire\Project\Application\Deployment;
use App\Models\Application;
use App\Models\ApplicationDeploymentQueue;
use Illuminate\Support\Collection;
use Livewire\Component;
class Show extends Component

View File

@@ -21,6 +21,8 @@ class Heading extends Component
protected string $deploymentUuid;
public bool $docker_cleanup = true;
public function getListeners()
{
$teamId = auth()->user()->currentTeam()->id;
@@ -102,7 +104,7 @@ class Heading extends Component
public function stop()
{
StopApplication::run($this->application);
StopApplication::run($this->application, false, $this->docker_cleanup);
$this->application->status = 'exited';
$this->application->save();
if ($this->application->additional_servers->count() > 0) {
@@ -135,4 +137,13 @@ class Heading extends Component
'environment_name' => $this->parameters['environment_name'],
]);
}
public function render()
{
return view('livewire.project.application.heading', [
'checkboxes' => [
['id' => 'docker_cleanup', 'label' => __('resource.docker_cleanup')],
],
]);
}
}

View File

@@ -5,7 +5,9 @@ namespace App\Livewire\Project\Application;
use App\Actions\Docker\GetContainersStatus;
use App\Models\Application;
use App\Models\ApplicationPreview;
use Illuminate\Process\InvokedProcess;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Process;
use Livewire\Component;
use Spatie\Url\Url;
use Visus\Cuid2\Cuid2;
@@ -184,17 +186,20 @@ class Previews extends Component
public function stop(int $pull_request_id)
{
try {
$server = $this->application->destination->server;
$timeout = 300;
if ($this->application->destination->server->isSwarm()) {
instant_remote_process(["docker stack rm {$this->application->uuid}-{$pull_request_id}"], $this->application->destination->server);
instant_remote_process(["docker stack rm {$this->application->uuid}-{$pull_request_id}"], $server);
} else {
$containers = getCurrentApplicationContainerStatus($this->application->destination->server, $this->application->id, $pull_request_id);
foreach ($containers as $container) {
$name = str_replace('/', '', $container['Names']);
instant_remote_process(["docker rm -f $name"], $this->application->destination->server, throwError: false);
}
$containers = getCurrentApplicationContainerStatus($server, $this->application->id, $pull_request_id)->toArray();
$this->stopContainers($containers, $server, $timeout);
}
GetContainersStatus::dispatchSync($this->application->destination->server)->onQueue('high');
$this->dispatch('reloadWindow');
GetContainersStatus::run($server);
$this->application->refresh();
$this->dispatch('containerStatusUpdated');
$this->dispatch('success', 'Preview Deployment stopped.');
} catch (\Throwable $e) {
return handleError($e, $this);
}
@@ -203,16 +208,21 @@ class Previews extends Component
public function delete(int $pull_request_id)
{
try {
$server = $this->application->destination->server;
$timeout = 300;
if ($this->application->destination->server->isSwarm()) {
instant_remote_process(["docker stack rm {$this->application->uuid}-{$pull_request_id}"], $this->application->destination->server);
instant_remote_process(["docker stack rm {$this->application->uuid}-{$pull_request_id}"], $server);
} else {
$containers = getCurrentApplicationContainerStatus($this->application->destination->server, $this->application->id, $pull_request_id);
foreach ($containers as $container) {
$name = str_replace('/', '', $container['Names']);
instant_remote_process(["docker rm -f $name"], $this->application->destination->server, throwError: false);
}
$containers = getCurrentApplicationContainerStatus($server, $this->application->id, $pull_request_id)->toArray();
$this->stopContainers($containers, $server, $timeout);
}
ApplicationPreview::where('application_id', $this->application->id)->where('pull_request_id', $pull_request_id)->first()->delete();
ApplicationPreview::where('application_id', $this->application->id)
->where('pull_request_id', $pull_request_id)
->first()
->delete();
$this->application->refresh();
$this->dispatch('update_links');
$this->dispatch('success', 'Preview deleted.');
@@ -220,4 +230,49 @@ class Previews extends Component
return handleError($e, $this);
}
}
private function stopContainers(array $containers, $server, int $timeout)
{
$processes = [];
foreach ($containers as $container) {
$containerName = str_replace('/', '', $container['Names']);
$processes[$containerName] = $this->stopContainer($containerName, $timeout);
}
$startTime = time();
while (count($processes) > 0) {
$finishedProcesses = array_filter($processes, function ($process) {
return ! $process->running();
});
foreach (array_keys($finishedProcesses) as $containerName) {
unset($processes[$containerName]);
$this->removeContainer($containerName, $server);
}
if (time() - $startTime >= $timeout) {
$this->forceStopRemainingContainers(array_keys($processes), $server);
break;
}
usleep(100000);
}
}
private function stopContainer(string $containerName, int $timeout): InvokedProcess
{
return Process::timeout($timeout)->start("docker stop --time=$timeout $containerName");
}
private function removeContainer(string $containerName, $server)
{
instant_remote_process(["docker rm -f $containerName"], $server, throwError: false);
}
private function forceStopRemainingContainers(array $containerNames, $server)
{
foreach ($containerNames as $containerName) {
instant_remote_process(["docker kill $containerName"], $server, throwError: false);
$this->removeContainer($containerName, $server);
}
}
}

View File

@@ -3,6 +3,8 @@
namespace App\Livewire\Project\Database;
use App\Models\ScheduledDatabaseBackup;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Hash;
use Livewire\Component;
use Spatie\Url\Url;
@@ -12,6 +14,12 @@ class BackupEdit extends Component
public $s3s;
public bool $delete_associated_backups_locally = false;
public bool $delete_associated_backups_s3 = false;
public bool $delete_associated_backups_sftp = false;
public ?string $status = null;
public array $parameters;
@@ -23,6 +31,7 @@ class BackupEdit extends Component
'backup.save_s3' => 'required|boolean',
'backup.s3_storage_id' => 'nullable|integer',
'backup.databases_to_backup' => 'nullable',
'backup.dump_all' => 'required|boolean',
];
protected $validationAttributes = [
@@ -32,6 +41,7 @@ class BackupEdit extends Component
'backup.save_s3' => 'Save to S3',
'backup.s3_storage_id' => 'S3 Storage',
'backup.databases_to_backup' => 'Databases to Backup',
'backup.dump_all' => 'Backup All Databases',
];
protected $messages = [
@@ -46,10 +56,24 @@ class BackupEdit extends Component
}
}
public function delete()
public function delete($password)
{
if (! Hash::check($password, Auth::user()->password)) {
$this->addError('password', 'The provided password is incorrect.');
return;
}
try {
if ($this->delete_associated_backups_locally) {
$this->deleteAssociatedBackupsLocally();
}
if ($this->delete_associated_backups_s3) {
$this->deleteAssociatedBackupsS3();
}
$this->backup->delete();
if ($this->backup->database->getMorphClass() === 'App\Models\ServiceDatabase') {
$previousUrl = url()->previous();
$url = Url::fromString($previousUrl);
@@ -104,4 +128,66 @@ class BackupEdit extends Component
$this->dispatch('error', $e->getMessage());
}
}
public function deleteAssociatedBackupsLocally()
{
$executions = $this->backup->executions;
$backupFolder = null;
foreach ($executions as $execution) {
if ($this->backup->database->getMorphClass() === 'App\Models\ServiceDatabase') {
$server = $this->backup->database->service->destination->server;
} else {
$server = $this->backup->database->destination->server;
}
if (! $backupFolder) {
$backupFolder = dirname($execution->filename);
}
delete_backup_locally($execution->filename, $server);
$execution->delete();
}
if ($backupFolder) {
$this->deleteEmptyBackupFolder($backupFolder, $server);
}
}
public function deleteAssociatedBackupsS3()
{
//Add function to delete backups from S3
}
public function deleteAssociatedBackupsSftp()
{
//Add function to delete backups from SFTP
}
private function deleteEmptyBackupFolder($folderPath, $server)
{
$checkEmpty = instant_remote_process(["[ -z \"$(ls -A '$folderPath')\" ] && echo 'empty' || echo 'not empty'"], $server);
if (trim($checkEmpty) === 'empty') {
instant_remote_process(["rmdir '$folderPath'"], $server);
$parentFolder = dirname($folderPath);
$checkParentEmpty = instant_remote_process(["[ -z \"$(ls -A '$parentFolder')\" ] && echo 'empty' || echo 'not empty'"], $server);
if (trim($checkParentEmpty) === 'empty') {
instant_remote_process(["rmdir '$parentFolder'"], $server);
}
}
}
public function render()
{
return view('livewire.project.database.backup-edit', [
'checkboxes' => [
['id' => 'delete_associated_backups_locally', 'label' => __('database.delete_backups_locally')],
// ['id' => 'delete_associated_backups_s3', 'label' => 'All backups associated with this backup job from this database will be permanently deleted from the selected S3 Storage.']
// ['id' => 'delete_associated_backups_sftp', 'label' => 'All backups associated with this backup job from this database will be permanently deleted from the selected SFTP Storage.']
],
]);
}
}

View File

@@ -3,18 +3,28 @@
namespace App\Livewire\Project\Database;
use App\Models\ScheduledDatabaseBackup;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Hash;
use Livewire\Attributes\On;
use Livewire\Component;
class BackupExecutions extends Component
{
public ?ScheduledDatabaseBackup $backup = null;
public $database;
public $executions = [];
public $setDeletableBackup;
public $delete_backup_s3 = true;
public $delete_backup_sftp = true;
public function getListeners()
{
$userId = auth()->user()->id;
$userId = Auth::id();
return [
"echo-private:team.{$userId},BackupCreated" => 'refreshBackupExecutions',
@@ -31,19 +41,36 @@ class BackupExecutions extends Component
}
}
public function deleteBackup($exeuctionId)
#[On('deleteBackup')]
public function deleteBackup($executionId, $password)
{
$execution = $this->backup->executions()->where('id', $exeuctionId)->first();
if (! Hash::check($password, Auth::user()->password)) {
$this->addError('password', 'The provided password is incorrect.');
return;
}
$execution = $this->backup->executions()->where('id', $executionId)->first();
if (is_null($execution)) {
$this->dispatch('error', 'Backup execution not found.');
return;
}
if ($execution->scheduledDatabaseBackup->database->getMorphClass() === 'App\Models\ServiceDatabase') {
delete_backup_locally($execution->filename, $execution->scheduledDatabaseBackup->database->service->destination->server);
} else {
delete_backup_locally($execution->filename, $execution->scheduledDatabaseBackup->database->destination->server);
}
if ($this->delete_backup_s3) {
// Add logic to delete from S3
}
if ($this->delete_backup_sftp) {
// Add logic to delete from SFTP
}
$execution->delete();
$this->dispatch('success', 'Backup deleted.');
$this->refreshBackupExecutions();
@@ -82,16 +109,18 @@ class BackupExecutions extends Component
return $server;
}
}
return null;
}
public function getServerTimezone()
{
$server = $this->server();
if (!$server) {
if (! $server) {
return 'UTC';
}
$serverTimezone = $server->settings->server_timezone;
return $serverTimezone;
}
@@ -104,6 +133,17 @@ class BackupExecutions extends Component
} catch (\Exception $e) {
$dateObj->setTimezone(new \DateTimeZone('UTC'));
}
return $dateObj->format('Y-m-d H:i:s T');
}
public function render()
{
return view('livewire.project.database.backup-executions', [
'checkboxes' => [
['id' => 'delete_backup_s3', 'label' => 'Delete the selected backup permanently form S3 Storage'],
['id' => 'delete_backup_sftp', 'label' => 'Delete the selected backup permanently form SFTP Storage'],
],
]);
}
}

View File

@@ -56,7 +56,7 @@ class General extends Component
public function instantSaveAdvanced()
{
try {
if (!$this->server->isLogDrainEnabled()) {
if (! $this->server->isLogDrainEnabled()) {
$this->database->is_log_drain_enabled = false;
$this->dispatch('error', 'Log drain is not enabled on the server. Please enable it first.');
@@ -73,14 +73,14 @@ class General extends Component
public function instantSave()
{
try {
if ($this->database->is_public && !$this->database->public_port) {
if ($this->database->is_public && ! $this->database->public_port) {
$this->dispatch('error', 'Public port is required.');
$this->database->is_public = false;
return;
}
if ($this->database->is_public) {
if (!str($this->database->status)->startsWith('running')) {
if (! str($this->database->status)->startsWith('running')) {
$this->dispatch('error', 'Database must be started to be publicly accessible.');
$this->database->is_public = false;
@@ -95,7 +95,7 @@ class General extends Component
$this->db_url_public = $this->database->external_db_url;
$this->database->save();
} catch (\Throwable $e) {
$this->database->is_public = !$this->database->is_public;
$this->database->is_public = ! $this->database->is_public;
return handleError($e, $this);
}

View File

@@ -54,7 +54,7 @@ class General extends Component
public function instantSaveAdvanced()
{
try {
if (!$this->server->isLogDrainEnabled()) {
if (! $this->server->isLogDrainEnabled()) {
$this->database->is_log_drain_enabled = false;
$this->dispatch('error', 'Log drain is not enabled on the server. Please enable it first.');
@@ -88,14 +88,14 @@ class General extends Component
public function instantSave()
{
try {
if ($this->database->is_public && !$this->database->public_port) {
if ($this->database->is_public && ! $this->database->public_port) {
$this->dispatch('error', 'Public port is required.');
$this->database->is_public = false;
return;
}
if ($this->database->is_public) {
if (!str($this->database->status)->startsWith('running')) {
if (! str($this->database->status)->startsWith('running')) {
$this->dispatch('error', 'Database must be started to be publicly accessible.');
$this->database->is_public = false;
@@ -110,7 +110,7 @@ class General extends Component
$this->db_url_public = $this->database->external_db_url;
$this->database->save();
} catch (\Throwable $e) {
$this->database->is_public = !$this->database->is_public;
$this->database->is_public = ! $this->database->is_public;
return handleError($e, $this);
}

View File

@@ -14,6 +14,8 @@ class Heading extends Component
public array $parameters;
public $docker_cleanup = true;
public function getListeners()
{
$userId = auth()->user()->id;
@@ -54,7 +56,7 @@ class Heading extends Component
public function stop()
{
StopDatabase::run($this->database);
StopDatabase::run($this->database, false, $this->docker_cleanup);
$this->database->status = 'exited';
$this->database->save();
$this->check_status();
@@ -71,4 +73,13 @@ class Heading extends Component
$activity = StartDatabase::run($this->database);
$this->dispatch('activityMonitor', $activity->id);
}
public function render()
{
return view('livewire.project.database.heading', [
'checkboxes' => [
['id' => 'docker_cleanup', 'label' => __('resource.docker_cleanup')],
],
]);
}
}

View File

@@ -57,7 +57,7 @@ class General extends Component
public function instantSaveAdvanced()
{
try {
if (!$this->server->isLogDrainEnabled()) {
if (! $this->server->isLogDrainEnabled()) {
$this->database->is_log_drain_enabled = false;
$this->dispatch('error', 'Log drain is not enabled on the server. Please enable it first.');
@@ -94,14 +94,14 @@ class General extends Component
public function instantSave()
{
try {
if ($this->database->is_public && !$this->database->public_port) {
if ($this->database->is_public && ! $this->database->public_port) {
$this->dispatch('error', 'Public port is required.');
$this->database->is_public = false;
return;
}
if ($this->database->is_public) {
if (!str($this->database->status)->startsWith('running')) {
if (! str($this->database->status)->startsWith('running')) {
$this->dispatch('error', 'Database must be started to be publicly accessible.');
$this->database->is_public = false;
@@ -116,7 +116,7 @@ class General extends Component
$this->db_url_public = $this->database->external_db_url;
$this->database->save();
} catch (\Throwable $e) {
$this->database->is_public = !$this->database->is_public;
$this->database->is_public = ! $this->database->is_public;
return handleError($e, $this);
}

View File

@@ -63,7 +63,7 @@ class General extends Component
public function instantSaveAdvanced()
{
try {
if (!$this->server->isLogDrainEnabled()) {
if (! $this->server->isLogDrainEnabled()) {
$this->database->is_log_drain_enabled = false;
$this->dispatch('error', 'Log drain is not enabled on the server. Please enable it first.');
@@ -100,14 +100,14 @@ class General extends Component
public function instantSave()
{
try {
if ($this->database->is_public && !$this->database->public_port) {
if ($this->database->is_public && ! $this->database->public_port) {
$this->dispatch('error', 'Public port is required.');
$this->database->is_public = false;
return;
}
if ($this->database->is_public) {
if (!str($this->database->status)->startsWith('running')) {
if (! str($this->database->status)->startsWith('running')) {
$this->dispatch('error', 'Database must be started to be publicly accessible.');
$this->database->is_public = false;
@@ -122,7 +122,7 @@ class General extends Component
$this->db_url_public = $this->database->external_db_url;
$this->database->save();
} catch (\Throwable $e) {
$this->database->is_public = !$this->database->is_public;
$this->database->is_public = ! $this->database->is_public;
return handleError($e, $this);
}

View File

@@ -61,7 +61,7 @@ class General extends Component
public function instantSaveAdvanced()
{
try {
if (!$this->server->isLogDrainEnabled()) {
if (! $this->server->isLogDrainEnabled()) {
$this->database->is_log_drain_enabled = false;
$this->dispatch('error', 'Log drain is not enabled on the server. Please enable it first.');
@@ -101,14 +101,14 @@ class General extends Component
public function instantSave()
{
try {
if ($this->database->is_public && !$this->database->public_port) {
if ($this->database->is_public && ! $this->database->public_port) {
$this->dispatch('error', 'Public port is required.');
$this->database->is_public = false;
return;
}
if ($this->database->is_public) {
if (!str($this->database->status)->startsWith('running')) {
if (! str($this->database->status)->startsWith('running')) {
$this->dispatch('error', 'Database must be started to be publicly accessible.');
$this->database->is_public = false;
@@ -123,7 +123,7 @@ class General extends Component
$this->db_url_public = $this->database->external_db_url;
$this->database->save();
} catch (\Throwable $e) {
$this->database->is_public = !$this->database->is_public;
$this->database->is_public = ! $this->database->is_public;
return handleError($e, $this);
}

Some files were not shown because too many files have changed in this diff Show More