Merge pull request #540 from coollabsio/next

v3.4.0
This commit is contained in:
Andras Bacsai 2022-08-16 14:42:12 +02:00 committed by GitHub
commit 14cdf33473
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
39 changed files with 1349 additions and 913 deletions

2
.gitpod.Dockerfile vendored Normal file
View File

@ -0,0 +1,2 @@
FROM gitpod/workspace-node:2022-06-20-19-54-55
RUN (curl -sSL "https://github.com/buildpacks/pack/releases/download/v0.27.0/pack-v0.27.0-linux.tgz" | tar -C /usr/local/bin/ --no-same-owner -xzv pack)

View File

@ -1,7 +1,8 @@
# This configuration file was automatically generated by Gitpod. # This configuration file was automatically generated by Gitpod.
# Please adjust to your needs (see https://www.gitpod.io/docs/config-gitpod-file) # Please adjust to your needs (see https://www.gitpod.io/docs/config-gitpod-file)
# and commit this file to your remote git repository to share the goodness with others. # and commit this file to your remote git repository to share the goodness with others.
image: gitpod/workspace-node:2022-06-20-19-54-55 image:
file: .gitpod.Dockerfile
tasks: tasks:
- init: pnpm install && pnpm db:push && pnpm db:seed - init: pnpm install && pnpm db:push && pnpm db:seed
command: pnpm dev command: pnpm dev

230
README.md
View File

@ -1,7 +1,108 @@
# Coolify # Coolify
An open-source & self-hostable Heroku / Netlify alternative An open-source & self-hostable Heroku / Netlify alternative.
(ARM support is in beta).
## Live Demo
https://demo.coolify.io/
(If it is unresponsive, that means someone overloaded the server. 😄)
## Feedback
If you have a new service / build pack you would like to add, raise an idea [here](https://feedback.coolify.io/) to get feedback from the community!
---
## How to install
For more details goto the [docs](https://docs.coollabs.io/coolify/installation.html).
Installation is automated with the following command:
```bash
wget -q https://get.coollabs.io/coolify/install.sh -O install.sh; sudo bash ./install.sh
```
If you would like no questions during installation:
```bash
wget -q https://get.coollabs.io/coolify/install.sh -O install.sh; sudo bash ./install.sh -f
```
---
## Features
### Git Sources
Self-hosted versions also!
<a href="https://github.com"><img style="width:40px;height:40px" src="https://icon.horse/icon/github.com"></a>
<a href="https://gitlab.com"><img style="width:40px;height:40px" src="https://icon.horse/icon/gitlab.com"></a>
### Destinations
Deploy your resource to:
- Local Docker Engine
- Remote Docker Engine
### Applications
<a href="https://heroku.com"><img style="width:40px;height:40px" src="https://icon.horse/icon/heroku.com"></a>
<a href="https://html5.org/">
<svg style="width:40px;height:40px" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg" ><g clip-path="url(#HTML5_Clip0_4)" ><path d="M30.216 0L27.6454 28.7967L16.0907 32L4.56783 28.8012L2 0H30.216Z" fill="#E44D26" /><path d="M16.108 29.5515L25.4447 26.963L27.6415 2.35497H16.108V29.5515Z" fill="#F16529" /><path d="M11.1109 9.4197H16.108V5.88731H7.25053L7.33509 6.83499L8.20327 16.5692H16.108V13.0369H11.4338L11.1109 9.4197Z" fill="#EBEBEB" /><path d="M11.907 18.3354H8.36111L8.856 23.8818L16.0917 25.8904L16.108 25.8859V22.2108L16.0925 22.2149L12.1585 21.1527L11.907 18.3354Z" fill="#EBEBEB" /><path d="M16.0958 16.5692H20.4455L20.0354 21.1504L16.0958 22.2138V25.8887L23.3373 23.8817L23.3904 23.285L24.2205 13.9855L24.3067 13.0369H16.0958V16.5692Z" fill="white" /><path d="M16.0958 9.41105V9.41969H24.6281L24.6989 8.62572L24.8599 6.83499L24.9444 5.88731H16.0958V9.41105Z" fill="white" /></g><defs><clipPath id="HTML5_Clip0_4"><rect width="32" height="32" fill="white" /></clipPath></defs></svg></a>
<a href="https://nodejs.org"><img style="width:40px;height:40px" src="https://icon.horse/icon/nodejs.org"></a>
<a href="https://vuejs.org"><img style="width:40px;height:40px" src="https://icon.horse/icon/vuejs.org"></a>
<a href="https://nuxtjs.org"><img style="width:40px;height:40px" src="https://icon.horse/icon/nuxtjs.org"></a>
<a href="https://nextjs.org"><img style="width:40px;height:40px" src="https://icon.horse/icon/nextjs.org"></a>
<a href="https://reactjs.org"><img style="width:40px;height:40px" src="https://icon.horse/icon/reactjs.org"></a>
<a href="https://preactjs.org"><img style="width:40px;height:40px" src="https://icon.horse/icon/preactjs.org"></a>
<a href="https://gatsbyjs.org"><img style="width:40px;height:40px" src="https://icon.horse/icon/gatsbyjs.org"></a>
<a href="https://svelte.dev"><img style="width:40px;height:40px" src="https://icon.horse/icon/svelte.dev"></a>
<a href="https://php.net"><img style="width:40px;height:40px" src="https://icon.horse/icon/php.net"></a>
<a href="https://laravel.com"><img style="width:40px;height:40px" src="https://icon.horse/icon/laravel.com"></a>
<a href="https://python.org"><img style="width:40px;height:40px" src="https://icon.horse/icon/python.org"></a>
<a href="https://deno.com"><img style="width:40px;height:40px" src="https://icon.horse/icon/deno.com"></a>
<a href="https://docker.com"><img style="width:40px;height:40px" src="https://icon.horse/icon/docker.com"></a>
### Databases
<a href="https://mongodb.org"><img style="width:40px;height:40px" src="https://icon.horse/icon/mongodb.org"></a>
<a href="https://mariadb.org"><img style="width:40px;height:40px" src="https://icon.horse/icon/mariadb.org"></a>
<a href="https://mysql.com"><svg style="width:40px;height:40px" xmlns="http://www.w3.org/2000/svg" width="64" height="64" viewBox="0 0 25.6 25.6" ><path d="M179.076 94.886c-3.568-.1-6.336.268-8.656 1.25-.668.27-1.74.27-1.828 1.116.357.355.4.936.713 1.428.535.893 1.473 2.096 2.32 2.72l2.855 2.053c1.74 1.07 3.703 1.695 5.398 2.766.982.625 1.963 1.428 2.945 2.098.5.357.803.938 1.428 1.16v-.135c-.312-.4-.402-.98-.713-1.428l-1.34-1.293c-1.293-1.74-2.9-3.258-4.64-4.506-1.428-.982-4.55-2.32-5.13-3.97l-.088-.1c.98-.1 2.14-.447 3.078-.715 1.518-.4 2.9-.312 4.46-.713l2.143-.625v-.4c-.803-.803-1.383-1.874-2.23-2.632-2.275-1.963-4.775-3.882-7.363-5.488-1.383-.892-3.168-1.473-4.64-2.23-.537-.268-1.428-.402-1.74-.848-.805-.98-1.25-2.275-1.83-3.436l-3.658-7.763c-.803-1.74-1.295-3.48-2.275-5.086-4.596-7.585-9.594-12.18-17.268-16.687-1.65-.937-3.613-1.34-5.7-1.83l-3.346-.18c-.715-.312-1.428-1.16-2.053-1.562-2.543-1.606-9.102-5.086-10.977-.5-1.205 2.9 1.785 5.755 2.8 7.228.76 1.026 1.74 2.186 2.277 3.346.3.758.4 1.562.713 2.365.713 1.963 1.383 4.15 2.32 5.98.5.937 1.025 1.92 1.65 2.767.357.5.982.714 1.115 1.517-.625.893-.668 2.23-1.025 3.347-1.607 5.042-.982 11.288 1.293 15 .715 1.115 2.4 3.57 4.686 2.632 2.008-.803 1.56-3.346 2.14-5.577.135-.535.045-.892.312-1.25v.1l1.83 3.703c1.383 2.186 3.793 4.462 5.8 5.98 1.07.803 1.918 2.187 3.256 2.677v-.135h-.088c-.268-.4-.67-.58-1.027-.892-.803-.803-1.695-1.785-2.32-2.677-1.873-2.498-3.523-5.265-4.996-8.12-.715-1.383-1.34-2.9-1.918-4.283-.27-.536-.27-1.34-.715-1.606-.67.98-1.65 1.83-2.143 3.034-.848 1.918-.936 4.283-1.248 6.737-.18.045-.1 0-.18.1-1.426-.356-1.918-1.83-2.453-3.078-1.338-3.168-1.562-8.254-.402-11.913.312-.937 1.652-3.882 1.117-4.774-.27-.848-1.16-1.338-1.652-2.008-.58-.848-1.203-1.918-1.605-2.855-1.07-2.5-1.605-5.265-2.766-7.764-.537-1.16-1.473-2.365-2.232-3.435-.848-1.205-1.783-2.053-2.453-3.48-.223-.5-.535-1.294-.178-1.83.088-.357.268-.5.623-.58.58-.5 2.232.134 2.812.4 1.65.67 3.033 1.294 4.416 2.23.625.446 1.295 1.294 2.098 1.518h.938c1.428.312 3.033.1 4.37.5 2.365.76 4.506 1.874 6.426 3.08 5.844 3.703 10.664 8.968 13.92 15.26.535 1.026.758 1.963 1.25 3.034.938 2.187 2.098 4.417 3.033 6.56.938 2.097 1.83 4.24 3.168 5.98.67.937 3.346 1.427 4.55 1.918.893.4 2.275.76 3.08 1.25 1.516.937 3.033 2.008 4.46 3.034.713.534 2.945 1.65 3.078 2.54zm-45.5-38.772a7.09 7.09 0 0 0-1.828.223v.1h.088c.357.714.982 1.205 1.428 1.83l1.027 2.142.088-.1c.625-.446.938-1.16.938-2.23-.268-.312-.312-.625-.535-.937-.268-.446-.848-.67-1.206-1.026z" transform="matrix(.390229 0 0 .38781 -46.300037 -16.856717)" fill-rule="evenodd" fill="#00678c" /></svg></a>
<a href="https://postgresql.org"><img style="width:40px;height:40px" src="https://icon.horse/icon/postgresql.org"></a>
<a href="https://couchdb.apache.org"><img style="width:40px;height:40px" src="https://icon.horse/icon/couchdb.apache.org"></a>
<a href="https://redis.io"><svg style="width:40px;height:40px" viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" ><defs ><path id="a" d="m45.536 38.764c-2.013 1.05-12.44 5.337-14.66 6.494s-3.453 1.146-5.207.308-12.85-5.32-14.85-6.276c-1-.478-1.524-.88-1.524-1.26v-3.813s14.447-3.145 16.78-3.982 3.14-.867 5.126-.14 13.853 2.868 15.814 3.587v3.76c0 .377-.452.8-1.477 1.324z" /><path id="b" d="m45.536 28.733c-2.013 1.05-12.44 5.337-14.66 6.494s-3.453 1.146-5.207.308-12.85-5.32-14.85-6.276-2.04-1.613-.077-2.382l15.332-5.935c2.332-.837 3.14-.867 5.126-.14s12.35 4.853 14.312 5.57 2.037 1.31.024 2.36z" /></defs ><g transform="matrix(.848327 0 0 .848327 -7.883573 -9.449691)" ><use fill="#a41e11" xlink:href="#a" /><path d="m45.536 34.95c-2.013 1.05-12.44 5.337-14.66 6.494s-3.453 1.146-5.207.308-12.85-5.32-14.85-6.276-2.04-1.613-.077-2.382l15.332-5.936c2.332-.836 3.14-.867 5.126-.14s12.35 4.852 14.31 5.582 2.037 1.31.024 2.36z" fill="#d82c20" /><use fill="#a41e11" xlink:href="#a" y="-6.218" /><use fill="#d82c20" xlink:href="#b" /><path d="m45.536 26.098c-2.013 1.05-12.44 5.337-14.66 6.495s-3.453 1.146-5.207.308-12.85-5.32-14.85-6.276c-1-.478-1.524-.88-1.524-1.26v-3.815s14.447-3.145 16.78-3.982 3.14-.867 5.126-.14 13.853 2.868 15.814 3.587v3.76c0 .377-.452.8-1.477 1.324z" fill="#a41e11" /><use fill="#d82c20" xlink:href="#b" y="-6.449" /><g fill="#fff" ><path d="m29.096 20.712-1.182-1.965-3.774-.34 2.816-1.016-.845-1.56 2.636 1.03 2.486-.814-.672 1.612 2.534.95-3.268.34zm-6.296 3.912 8.74-1.342-2.64 3.872z" /><ellipse cx="20.444" cy="21.402" rx="4.672" ry="1.811" /></g ><path d="m42.132 21.138-5.17 2.042-.004-4.087z" fill="#7a0c00" /><path d="m36.963 23.18-.56.22-5.166-2.042 5.723-2.264z" fill="#ad2115" /></g ></svg ></a>
### Services
- [Appwrite](https://appwrite.io)
- [WordPress](https://docs.coollabs.io/coolify/services/wordpress)
- [Ghost](https://ghost.org)
- [Plausible Analytics](https://docs.coollabs.io/coolify/services/plausible-analytics)
- [NocoDB](https://nocodb.com)
- [VSCode Server](https://github.com/cdr/code-server)
- [MinIO](https://min.io)
- [VaultWarden](https://github.com/dani-garcia/vaultwarden)
- [LanguageTool](https://languagetool.org)
- [n8n](https://n8n.io)
- [Uptime Kuma](https://github.com/louislam/uptime-kuma)
- [MeiliSearch](https://github.com/meilisearch/meilisearch)
- [Umami](https://github.com/mikecao/umami)
- [Fider](https://fider.io)
- [Hasura](https://hasura.io)
## Migration from v1
A fresh installation is necessary. v2 and v3 are not compatible with v1.
## Support
- Twitter: [@andrasbacsai](https://twitter.com/andrasbacsai)
- Telegram: [@andrasbacsai](https://t.me/andrasbacsai)
- Email: [andras@coollabs.io](mailto:andras@coollabs.io)
- Discord: [Invitation](https://discord.gg/6rDM4fkymF)
## Financial Contributors ## Financial Contributors
@ -24,127 +125,4 @@ ### Organizations
<a href="https://opencollective.com/coollabsio/organization/6/website"><img src="https://opencollective.com/coollabsio/organization/6/avatar.svg"></a> <a href="https://opencollective.com/coollabsio/organization/6/website"><img src="https://opencollective.com/coollabsio/organization/6/avatar.svg"></a>
<a href="https://opencollective.com/coollabsio/organization/7/website"><img src="https://opencollective.com/coollabsio/organization/7/avatar.svg"></a> <a href="https://opencollective.com/coollabsio/organization/7/website"><img src="https://opencollective.com/coollabsio/organization/7/avatar.svg"></a>
<a href="https://opencollective.com/coollabsio/organization/8/website"><img src="https://opencollective.com/coollabsio/organization/8/avatar.svg"></a> <a href="https://opencollective.com/coollabsio/organization/8/website"><img src="https://opencollective.com/coollabsio/organization/8/avatar.svg"></a>
<a href="https://opencollective.com/coollabsio/organization/9/website"><img src="https://opencollective.com/coollabsio/organization/9/avatar.svg"></a> <a href="https://opencollective.com/coollabsio/organization/9/website"><img src="https://opencollective.com/coollabsio/organization/9/avatar.svg"></a>
---
## Live Demo
https://demo.coolify.io/
(If it is unresponsive, that means someone overloaded the server. 😄)
## Feedback
If you have a new service / build pack you would like to add, raise an idea [here](https://feedback.coolify.io/) to get feedback from the community!
---
## How to install
Installation is automated with the following command:
```bash
wget -q https://get.coollabs.io/coolify/install.sh -O install.sh; sudo bash ./install.sh
```
If you would like no questions during installation:
```bash
wget -q https://get.coollabs.io/coolify/install.sh -O install.sh; sudo bash ./install.sh -f
```
For more details goto the [docs](https://docs.coollabs.io/coolify/installation).
---
## Features
### Git Sources
You can use the following Git Sources to be auto-deployed to your Coolify instance! (Self-hosted versions are also supported.)
<a href="https://github.com"><img style="width:40px;height:40px" src="https://icon.horse/icon/github.com"></a>
<a href="https://gitlab.com"><img style="width:40px;height:40px" src="https://icon.horse/icon/gitlab.com"></a>
### Destinations
You can deploy your applications to the following destinations:
- Local Docker Engine
- Remote Docker Engine
### Applications
Predefined build packs to cover the basic needs to deploy applications.
If you have an advanced use case, you can use the Docker build pack that allows you to deploy your application based on your custom Dockerfile.
<a href="https://html5.org/">
<svg style="width:40px;height:40px" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg" ><g clip-path="url(#HTML5_Clip0_4)" ><path d="M30.216 0L27.6454 28.7967L16.0907 32L4.56783 28.8012L2 0H30.216Z" fill="#E44D26" /><path d="M16.108 29.5515L25.4447 26.963L27.6415 2.35497H16.108V29.5515Z" fill="#F16529" /><path d="M11.1109 9.4197H16.108V5.88731H7.25053L7.33509 6.83499L8.20327 16.5692H16.108V13.0369H11.4338L11.1109 9.4197Z" fill="#EBEBEB" /><path d="M11.907 18.3354H8.36111L8.856 23.8818L16.0917 25.8904L16.108 25.8859V22.2108L16.0925 22.2149L12.1585 21.1527L11.907 18.3354Z" fill="#EBEBEB" /><path d="M16.0958 16.5692H20.4455L20.0354 21.1504L16.0958 22.2138V25.8887L23.3373 23.8817L23.3904 23.285L24.2205 13.9855L24.3067 13.0369H16.0958V16.5692Z" fill="white" /><path d="M16.0958 9.41105V9.41969H24.6281L24.6989 8.62572L24.8599 6.83499L24.9444 5.88731H16.0958V9.41105Z" fill="white" /></g><defs><clipPath id="HTML5_Clip0_4"><rect width="32" height="32" fill="white" /></clipPath></defs></svg></a>
<a href="https://nodejs.org"><img style="width:40px;height:40px" src="https://icon.horse/icon/nodejs.org"></a>
<a href="https://vuejs.org"><img style="width:40px;height:40px" src="https://icon.horse/icon/vuejs.org"></a>
<a href="https://nuxtjs.org"><img style="width:40px;height:40px" src="https://icon.horse/icon/nuxtjs.org"></a>
<a href="https://nextjs.org"><img style="width:40px;height:40px" src="https://icon.horse/icon/nextjs.org"></a>
<a href="https://reactjs.org"><img style="width:40px;height:40px" src="https://icon.horse/icon/reactjs.org"></a>
<a href="https://preactjs.org"><img style="width:40px;height:40px" src="https://icon.horse/icon/preactjs.org"></a>
<a href="https://gatsbyjs.org"><img style="width:40px;height:40px" src="https://icon.horse/icon/gatsbyjs.org"></a>
<a href="https://svelte.dev"><img style="width:40px;height:40px" src="https://icon.horse/icon/svelte.dev"></a>
<a href="https://php.net"><img style="width:40px;height:40px" src="https://icon.horse/icon/php.net"></a>
<a href="https://laravel.com"><img style="width:40px;height:40px" src="https://icon.horse/icon/laravel.com"></a>
<a href="https://python.org"><img style="width:40px;height:40px" src="https://icon.horse/icon/python.org"></a>
<a href="https://deno.com"><img style="width:40px;height:40px" src="https://icon.horse/icon/deno.com"></a>
<a href="https://docker.com"><img style="width:40px;height:40px" src="https://icon.horse/icon/docker.com"></a>
If you have a new build pack you would like to add, raise an idea [here](https://feedback.coolify.io/) to get feedback from the community!
### Databases
One-click database is ready to be used internally or shared over the internet:
<a href="https://mongodb.org"><img style="width:40px;height:40px" src="https://icon.horse/icon/mongodb.org"></a>
<a href="https://mariadb.org"><img style="width:40px;height:40px" src="https://icon.horse/icon/mariadb.org"></a>
<a href="https://mysql.com"><svg style="width:40px;height:40px" xmlns="http://www.w3.org/2000/svg" width="64" height="64" viewBox="0 0 25.6 25.6" ><path d="M179.076 94.886c-3.568-.1-6.336.268-8.656 1.25-.668.27-1.74.27-1.828 1.116.357.355.4.936.713 1.428.535.893 1.473 2.096 2.32 2.72l2.855 2.053c1.74 1.07 3.703 1.695 5.398 2.766.982.625 1.963 1.428 2.945 2.098.5.357.803.938 1.428 1.16v-.135c-.312-.4-.402-.98-.713-1.428l-1.34-1.293c-1.293-1.74-2.9-3.258-4.64-4.506-1.428-.982-4.55-2.32-5.13-3.97l-.088-.1c.98-.1 2.14-.447 3.078-.715 1.518-.4 2.9-.312 4.46-.713l2.143-.625v-.4c-.803-.803-1.383-1.874-2.23-2.632-2.275-1.963-4.775-3.882-7.363-5.488-1.383-.892-3.168-1.473-4.64-2.23-.537-.268-1.428-.402-1.74-.848-.805-.98-1.25-2.275-1.83-3.436l-3.658-7.763c-.803-1.74-1.295-3.48-2.275-5.086-4.596-7.585-9.594-12.18-17.268-16.687-1.65-.937-3.613-1.34-5.7-1.83l-3.346-.18c-.715-.312-1.428-1.16-2.053-1.562-2.543-1.606-9.102-5.086-10.977-.5-1.205 2.9 1.785 5.755 2.8 7.228.76 1.026 1.74 2.186 2.277 3.346.3.758.4 1.562.713 2.365.713 1.963 1.383 4.15 2.32 5.98.5.937 1.025 1.92 1.65 2.767.357.5.982.714 1.115 1.517-.625.893-.668 2.23-1.025 3.347-1.607 5.042-.982 11.288 1.293 15 .715 1.115 2.4 3.57 4.686 2.632 2.008-.803 1.56-3.346 2.14-5.577.135-.535.045-.892.312-1.25v.1l1.83 3.703c1.383 2.186 3.793 4.462 5.8 5.98 1.07.803 1.918 2.187 3.256 2.677v-.135h-.088c-.268-.4-.67-.58-1.027-.892-.803-.803-1.695-1.785-2.32-2.677-1.873-2.498-3.523-5.265-4.996-8.12-.715-1.383-1.34-2.9-1.918-4.283-.27-.536-.27-1.34-.715-1.606-.67.98-1.65 1.83-2.143 3.034-.848 1.918-.936 4.283-1.248 6.737-.18.045-.1 0-.18.1-1.426-.356-1.918-1.83-2.453-3.078-1.338-3.168-1.562-8.254-.402-11.913.312-.937 1.652-3.882 1.117-4.774-.27-.848-1.16-1.338-1.652-2.008-.58-.848-1.203-1.918-1.605-2.855-1.07-2.5-1.605-5.265-2.766-7.764-.537-1.16-1.473-2.365-2.232-3.435-.848-1.205-1.783-2.053-2.453-3.48-.223-.5-.535-1.294-.178-1.83.088-.357.268-.5.623-.58.58-.5 2.232.134 2.812.4 1.65.67 3.033 1.294 4.416 2.23.625.446 1.295 1.294 2.098 1.518h.938c1.428.312 3.033.1 4.37.5 2.365.76 4.506 1.874 6.426 3.08 5.844 3.703 10.664 8.968 13.92 15.26.535 1.026.758 1.963 1.25 3.034.938 2.187 2.098 4.417 3.033 6.56.938 2.097 1.83 4.24 3.168 5.98.67.937 3.346 1.427 4.55 1.918.893.4 2.275.76 3.08 1.25 1.516.937 3.033 2.008 4.46 3.034.713.534 2.945 1.65 3.078 2.54zm-45.5-38.772a7.09 7.09 0 0 0-1.828.223v.1h.088c.357.714.982 1.205 1.428 1.83l1.027 2.142.088-.1c.625-.446.938-1.16.938-2.23-.268-.312-.312-.625-.535-.937-.268-.446-.848-.67-1.206-1.026z" transform="matrix(.390229 0 0 .38781 -46.300037 -16.856717)" fill-rule="evenodd" fill="#00678c" /></svg></a>
<a href="https://postgresql.org"><img style="width:40px;height:40px" src="https://icon.horse/icon/postgresql.org"></a>
<a href="https://couchdb.apache.org"><img style="width:40px;height:40px" src="https://icon.horse/icon/couchdb.apache.org"></a>
<a href="https://redis.io"><svg style="width:40px;height:40px" viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" ><defs ><path id="a" d="m45.536 38.764c-2.013 1.05-12.44 5.337-14.66 6.494s-3.453 1.146-5.207.308-12.85-5.32-14.85-6.276c-1-.478-1.524-.88-1.524-1.26v-3.813s14.447-3.145 16.78-3.982 3.14-.867 5.126-.14 13.853 2.868 15.814 3.587v3.76c0 .377-.452.8-1.477 1.324z" /><path id="b" d="m45.536 28.733c-2.013 1.05-12.44 5.337-14.66 6.494s-3.453 1.146-5.207.308-12.85-5.32-14.85-6.276-2.04-1.613-.077-2.382l15.332-5.935c2.332-.837 3.14-.867 5.126-.14s12.35 4.853 14.312 5.57 2.037 1.31.024 2.36z" /></defs ><g transform="matrix(.848327 0 0 .848327 -7.883573 -9.449691)" ><use fill="#a41e11" xlink:href="#a" /><path d="m45.536 34.95c-2.013 1.05-12.44 5.337-14.66 6.494s-3.453 1.146-5.207.308-12.85-5.32-14.85-6.276-2.04-1.613-.077-2.382l15.332-5.936c2.332-.836 3.14-.867 5.126-.14s12.35 4.852 14.31 5.582 2.037 1.31.024 2.36z" fill="#d82c20" /><use fill="#a41e11" xlink:href="#a" y="-6.218" /><use fill="#d82c20" xlink:href="#b" /><path d="m45.536 26.098c-2.013 1.05-12.44 5.337-14.66 6.495s-3.453 1.146-5.207.308-12.85-5.32-14.85-6.276c-1-.478-1.524-.88-1.524-1.26v-3.815s14.447-3.145 16.78-3.982 3.14-.867 5.126-.14 13.853 2.868 15.814 3.587v3.76c0 .377-.452.8-1.477 1.324z" fill="#a41e11" /><use fill="#d82c20" xlink:href="#b" y="-6.449" /><g fill="#fff" ><path d="m29.096 20.712-1.182-1.965-3.774-.34 2.816-1.016-.845-1.56 2.636 1.03 2.486-.814-.672 1.612 2.534.95-3.268.34zm-6.296 3.912 8.74-1.342-2.64 3.872z" /><ellipse cx="20.444" cy="21.402" rx="4.672" ry="1.811" /></g ><path d="m42.132 21.138-5.17 2.042-.004-4.087z" fill="#7a0c00" /><path d="m36.963 23.18-.56.22-5.166-2.042 5.723-2.264z" fill="#ad2115" /></g ></svg ></a>
If you have a new database you would like to add, raise an idea [here](https://feedback.coolify.io/) to get feedback from the community!
### Services
You quickly need to host a self-hostable, open-source service? You can do it with a few clicks!
- [WordPress](https://docs.coollabs.io/coolify/services/wordpress)
- [Ghost](https://ghost.org)
- [Plausible Analytics](https://docs.coollabs.io/coolify/services/plausible-analytics)
- [NocoDB](https://nocodb.com)
- [VSCode Server](https://github.com/cdr/code-server)
- [MinIO](https://min.io)
- [VaultWarden](https://github.com/dani-garcia/vaultwarden)
- [LanguageTool](https://languagetool.org)
- [n8n](https://n8n.io)
- [Uptime Kuma](https://github.com/louislam/uptime-kuma)
- [MeiliSearch](https://github.com/meilisearch/meilisearch)
- [Umami](https://github.com/mikecao/umami)
- [Fider](https://fider.io)
- [Hasura](https://hasura.io)
If you have a new service you would like to add, raise an idea [here](https://feedback.coolify.io/) to get feedback from the community!
## Migration from v1
A fresh installation is necessary. v2 and v3 are not compatible with v1.
## Support
- Twitter: [@andrasbacsai](https://twitter.com/andrasbacsai)
- Telegram: [@andrasbacsai](https://t.me/andrasbacsai)
- Email: [andras@coollabs.io](mailto:andras@coollabs.io)
- Discord: [Invitation](https://discord.gg/xhBCC7eGKw)
## License
This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Please see the [LICENSE](/LICENSE) file in our repository for the full text.

View File

@ -0,0 +1,22 @@
-- CreateTable
CREATE TABLE "Appwrite" (
"id" TEXT NOT NULL PRIMARY KEY,
"serviceId" TEXT NOT NULL,
"opensslKeyV1" TEXT NOT NULL,
"executorSecret" TEXT NOT NULL,
"redisPassword" TEXT NOT NULL,
"mariadbHost" TEXT,
"mariadbPort" INTEGER NOT NULL DEFAULT 3306,
"mariadbUser" TEXT NOT NULL,
"mariadbPassword" TEXT NOT NULL,
"mariadbRootUser" TEXT NOT NULL,
"mariadbRootUserPassword" TEXT NOT NULL,
"mariadbDatabase" TEXT NOT NULL,
"mariadbPublicPort" INTEGER,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" DATETIME NOT NULL,
CONSTRAINT "Appwrite_serviceId_fkey" FOREIGN KEY ("serviceId") REFERENCES "Service" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
);
-- CreateIndex
CREATE UNIQUE INDEX "Appwrite_serviceId_key" ON "Appwrite"("serviceId");

View File

@ -312,30 +312,33 @@ model DatabaseSettings {
} }
model Service { model Service {
id String @id @default(cuid()) id String @id @default(cuid())
name String name String
fqdn String? fqdn String?
exposePort Int? exposePort Int?
dualCerts Boolean @default(false) dualCerts Boolean @default(false)
type String? type String?
version String? version String?
destinationDockerId String? destinationDockerId String?
createdAt DateTime @default(now()) createdAt DateTime @default(now())
updatedAt DateTime @updatedAt updatedAt DateTime @updatedAt
destinationDocker DestinationDocker? @relation(fields: [destinationDockerId], references: [id]) destinationDocker DestinationDocker? @relation(fields: [destinationDockerId], references: [id])
fider Fider?
ghost Ghost? fider Fider?
hasura Hasura? ghost Ghost?
meiliSearch MeiliSearch? hasura Hasura?
minio Minio? meiliSearch MeiliSearch?
moodle Moodle? minio Minio?
plausibleAnalytics PlausibleAnalytics? moodle Moodle?
persistentStorage ServicePersistentStorage[] plausibleAnalytics PlausibleAnalytics?
serviceSecret ServiceSecret[] persistentStorage ServicePersistentStorage[]
umami Umami? serviceSecret ServiceSecret[]
vscodeserver Vscodeserver? umami Umami?
wordpress Wordpress? vscodeserver Vscodeserver?
teams Team[] wordpress Wordpress?
appwrite Appwrite?
teams Team[]
} }
model PlausibleAnalytics { model PlausibleAnalytics {
@ -491,3 +494,22 @@ model Moodle {
updatedAt DateTime @updatedAt updatedAt DateTime @updatedAt
service Service @relation(fields: [serviceId], references: [id]) service Service @relation(fields: [serviceId], references: [id])
} }
model Appwrite {
id String @id @default(cuid())
serviceId String @unique
opensslKeyV1 String
executorSecret String
redisPassword String
mariadbHost String?
mariadbPort Int @default(3306)
mariadbUser String
mariadbPassword String
mariadbRootUser String
mariadbRootUserPassword String
mariadbDatabase String
mariadbPublicPort Int?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
service Service @relation(fields: [serviceId], references: [id])
}

View File

@ -152,6 +152,13 @@ import * as buildpacks from '../lib/buildPacks';
.createHash('sha256') .createHash('sha256')
.update( .update(
JSON.stringify({ JSON.stringify({
pythonWSGI,
pythonModule,
pythonVariable,
deploymentType,
denoOptions,
baseImage,
baseBuildImage,
buildPack, buildPack,
port, port,
exposePort, exposePort,
@ -291,6 +298,7 @@ import * as buildpacks from '../lib/buildPacks';
} }
}; };
}); });
console.log({port})
const composeFile = { const composeFile = {
version: '3.8', version: '3.8',
services: { services: {

View File

@ -252,6 +252,20 @@ export function setDefaultBaseImage(buildPack: string | null, deploymentType: st
label: 'python:3.7-slim-bullseye' label: 'python:3.7-slim-bullseye'
} }
]; ];
const herokuVersions = [
{
value: 'heroku/builder:22',
label: 'heroku/builder:22'
},
{
value: 'heroku/buildpacks:20',
label: 'heroku/buildpacks:20'
},
{
value: 'heroku/builder-classic:22',
label: 'heroku/builder-classic:22'
},
]
let payload: any = { let payload: any = {
baseImage: null, baseImage: null,
baseBuildImage: null, baseBuildImage: null,
@ -299,6 +313,11 @@ export function setDefaultBaseImage(buildPack: string | null, deploymentType: st
payload.baseBuildImage = 'node:18'; payload.baseBuildImage = 'node:18';
payload.baseBuildImages = nodeVersions; payload.baseBuildImages = nodeVersions;
} }
if (buildPack === 'heroku') {
payload.baseImage = 'heroku/buildpacks:20';
payload.baseImages = herokuVersions;
}
return payload; return payload;
} }

View File

@ -2,14 +2,14 @@ import { executeDockerCmd, prisma } from "../common"
import { saveBuildLog } from "./common"; import { saveBuildLog } from "./common";
export default async function (data: any): Promise<void> { export default async function (data: any): Promise<void> {
const { buildId, applicationId, tag, dockerId, debug, workdir } = data
try { try {
const { buildId, applicationId, tag, dockerId, debug, workdir } = data
await saveBuildLog({ line: `Building image started.`, buildId, applicationId }); await saveBuildLog({ line: `Building image started.`, buildId, applicationId });
const { stdout } = await executeDockerCmd({ const { stdout } = await executeDockerCmd({
dockerId, dockerId,
command: `pack build -p ${workdir} ${applicationId}:${tag} --builder heroku/buildpacks:20` command: `pack build -p ${workdir} ${applicationId}:${tag} --builder heroku/buildpacks:20`
}) })
if (debug) { if (debug) {
const array = stdout.split('\n') const array = stdout.split('\n')
for (const line of array) { for (const line of array) {
@ -24,6 +24,16 @@ export default async function (data: any): Promise<void> {
} }
await saveBuildLog({ line: `Building image successful.`, buildId, applicationId }); await saveBuildLog({ line: `Building image successful.`, buildId, applicationId });
} catch (error) { } catch (error) {
const array = error.stdout.split('\n')
for (const line of array) {
if (line !== '\n') {
await saveBuildLog({
line: `${line.replace('\n', '')}`,
buildId,
applicationId
});
}
}
throw error; throw error;
} }
} }

View File

@ -17,7 +17,7 @@ import { checkContainer, removeContainer } from './docker';
import { day } from './dayjs'; import { day } from './dayjs';
import * as serviceFields from './serviceFields' import * as serviceFields from './serviceFields'
export const version = '3.3.4'; export const version = '3.4.0';
export const isDev = process.env.NODE_ENV === 'development'; export const isDev = process.env.NODE_ENV === 'development';
const algorithm = 'aes-256-ctr'; const algorithm = 'aes-256-ctr';
@ -78,6 +78,8 @@ export const include: any = {
umami: true, umami: true,
hasura: true, hasura: true,
fider: true, fider: true,
moodle: true,
appwrite: true
}; };
export const uniqueName = (): string => uniqueNamesGenerator(customConfig); export const uniqueName = (): string => uniqueNamesGenerator(customConfig);
@ -258,8 +260,8 @@ export const supportedServiceTypesAndVersions = [
fancyName: 'Hasura', fancyName: 'Hasura',
baseImage: 'hasura/graphql-engine', baseImage: 'hasura/graphql-engine',
images: ['postgres:12-alpine'], images: ['postgres:12-alpine'],
versions: ['latest', 'v2.8.4', 'v2.5.1'], versions: ['latest', 'v2.10.0', 'v2.5.1'],
recommendedVersion: 'v2.8.4', recommendedVersion: 'v2.10.0',
ports: { ports: {
main: 8080 main: 8080
} }
@ -275,6 +277,17 @@ export const supportedServiceTypesAndVersions = [
main: 3000 main: 3000
} }
}, },
{
name: 'appwrite',
fancyName: 'Appwrite',
baseImage: 'appwrite/appwrite',
images: ['mariadb:10.7', 'redis:6.2-alpine', 'appwrite/telegraf:1.4.0'],
versions: ['latest', '0.15.3'],
recommendedVersion: '0.15.3',
ports: {
main: 80
}
}
// { // {
// name: 'moodle', // name: 'moodle',
// fancyName: 'Moodle', // fancyName: 'Moodle',
@ -579,6 +592,11 @@ export async function executeDockerCmd({ dockerId, command }: { dockerId: string
} else { } else {
engine = 'unix:///var/run/docker.sock' engine = 'unix:///var/run/docker.sock'
} }
if (process.env.CODESANDBOX_HOST) {
if (command.startsWith('docker compose')) {
command = command.replace(/docker compose/gi, 'docker-compose')
}
}
return await asyncExecShell( return await asyncExecShell(
`DOCKER_BUILDKIT=1 DOCKER_HOST="${engine}" ${command}` `DOCKER_BUILDKIT=1 DOCKER_HOST="${engine}" ${command}`
); );
@ -590,6 +608,11 @@ export async function startTraefikProxy(id: string): Promise<void> {
const { id: settingsId, ipv4, ipv6 } = await listSettings(); const { id: settingsId, ipv4, ipv6 } = await listSettings();
if (!found) { if (!found) {
const { stdout: coolifyNetwork } = await executeDockerCmd({ dockerId: id, command: `docker network ls --filter 'name=coolify-infra' --no-trunc --format "{{json .}}"` })
if (!coolifyNetwork) {
await executeDockerCmd({ dockerId: id, command: `docker network create --attachable coolify-infra` })
}
const { stdout: Config } = await executeDockerCmd({ dockerId: id, command: `docker network inspect ${network} --format '{{json .IPAM.Config }}'` }) const { stdout: Config } = await executeDockerCmd({ dockerId: id, command: `docker network inspect ${network} --format '{{json .IPAM.Config }}'` })
const ip = JSON.parse(Config)[0].Gateway; const ip = JSON.parse(Config)[0].Gateway;
let traefikUrl = mainTraefikEndpoint let traefikUrl = mainTraefikEndpoint
@ -873,11 +896,11 @@ export function generateDatabaseConfiguration(database: any, arch: string):
} }
if (isARM(arch)) { if (isARM(arch)) {
configuration.volume = `${id}-${type}-data:/var/lib/postgresql`; configuration.volume = `${id}-${type}-data:/var/lib/postgresql`;
configuration.environmentVariables = { configuration.environmentVariables = {
POSTGRES_PASSWORD: dbUserPassword, POSTGRES_PASSWORD: dbUserPassword,
POSTGRES_USER: dbUser, POSTGRES_USER: dbUser,
POSTGRES_DB: defaultDatabase POSTGRES_DB: defaultDatabase
} }
} }
return configuration return configuration
} else if (type === 'redis') { } else if (type === 'redis') {
@ -1528,6 +1551,35 @@ export async function configureServiceType({
} }
} }
}); });
} else if (type === 'appwrite') {
const opensslKeyV1 = encrypt(generatePassword());
const executorSecret = encrypt(generatePassword());
const redisPassword = encrypt(generatePassword());
const mariadbHost = `${id}-mariadb`
const mariadbUser = cuid();
const mariadbPassword = encrypt(generatePassword());
const mariadbDatabase = 'appwrite';
const mariadbRootUser = cuid();
const mariadbRootUserPassword = encrypt(generatePassword());
await prisma.service.update({
where: { id },
data: {
type,
appwrite: {
create: {
opensslKeyV1,
executorSecret,
redisPassword,
mariadbHost,
mariadbUser,
mariadbPassword,
mariadbDatabase,
mariadbRootUser,
mariadbRootUserPassword
}
}
}
});
} else { } else {
await prisma.service.update({ await prisma.service.update({
where: { id }, where: { id },
@ -1539,6 +1591,7 @@ export async function configureServiceType({
} }
export async function removeService({ id }: { id: string }): Promise<void> { export async function removeService({ id }: { id: string }): Promise<void> {
await prisma.serviceSecret.deleteMany({ where: { serviceId: id } });
await prisma.servicePersistentStorage.deleteMany({ where: { serviceId: id } }); await prisma.servicePersistentStorage.deleteMany({ where: { serviceId: id } });
await prisma.meiliSearch.deleteMany({ where: { serviceId: id } }); await prisma.meiliSearch.deleteMany({ where: { serviceId: id } });
await prisma.fider.deleteMany({ where: { serviceId: id } }); await prisma.fider.deleteMany({ where: { serviceId: id } });
@ -1549,8 +1602,8 @@ export async function removeService({ id }: { id: string }): Promise<void> {
await prisma.minio.deleteMany({ where: { serviceId: id } }); await prisma.minio.deleteMany({ where: { serviceId: id } });
await prisma.vscodeserver.deleteMany({ where: { serviceId: id } }); await prisma.vscodeserver.deleteMany({ where: { serviceId: id } });
await prisma.wordpress.deleteMany({ where: { serviceId: id } }); await prisma.wordpress.deleteMany({ where: { serviceId: id } });
await prisma.serviceSecret.deleteMany({ where: { serviceId: id } }); await prisma.moodle.deleteMany({ where: { serviceId: id } });
await prisma.appwrite.deleteMany({ where: { serviceId: id } });
await prisma.service.delete({ where: { id } }); await prisma.service.delete({ where: { id } });
} }
@ -1615,9 +1668,9 @@ export const getServiceMainPort = (service: string) => {
export function makeLabelForServices(type) { export function makeLabelForServices(type) {
return [ return [
'coolify.managed=true', 'coolify.managed=true',
`coolify.version = ${version} `, `coolify.version = ${version}`,
`coolify.type = service`, `coolify.type = service`,
`coolify.service.type = ${type} ` `coolify.service.type = ${type}`
]; ];
} }
export function errorHandler({ status = 500, message = 'Unknown error.' }: { status: number, message: string | any }) { export function errorHandler({ status = 500, message = 'Unknown error.' }: { status: number, message: string | any }) {

View File

@ -71,7 +71,7 @@ export async function removeContainer({
}): Promise<void> { }): Promise<void> {
try { try {
const { stdout } = await executeDockerCmd({ dockerId, command: `docker inspect --format '{{json .State}}' ${id}` }) const { stdout } = await executeDockerCmd({ dockerId, command: `docker inspect --format '{{json .State}}' ${id}` })
console.log(id)
if (JSON.parse(stdout).Running) { if (JSON.parse(stdout).Running) {
await executeDockerCmd({ dockerId, command: `docker stop -t 0 ${id}` }) await executeDockerCmd({ dockerId, command: `docker stop -t 0 ${id}` })
await executeDockerCmd({ dockerId, command: `docker rm ${id}` }) await executeDockerCmd({ dockerId, command: `docker rm ${id}` })

View File

@ -469,6 +469,87 @@ export const moodle = [{
isBoolean: false, isBoolean: false,
isEncrypted: true isEncrypted: true
}, },
{
name: 'mariadbDatabase',
isEditable: true,
isLowerCase: false,
isNumber: false,
isBoolean: false,
isEncrypted: false
}]
export const appwrite = [{
name: 'opensslKeyV1',
isEditable: false,
isLowerCase: false,
isNumber: false,
isBoolean: false,
isEncrypted: true
},
{
name: 'executorSecret',
isEditable: false,
isLowerCase: false,
isNumber: false,
isBoolean: false,
isEncrypted: true
},
{
name: 'redisPassword',
isEditable: false,
isLowerCase: false,
isNumber: false,
isBoolean: false,
isEncrypted: true
},
{
name: 'mariadbHost',
isEditable: false,
isLowerCase: false,
isNumber: false,
isBoolean: false,
isEncrypted: false
},
{
name: 'mariadbPort',
isEditable: false,
isLowerCase: false,
isNumber: false,
isBoolean: false,
isEncrypted: false
},
{
name: 'mariadbUser',
isEditable: false,
isLowerCase: false,
isNumber: false,
isBoolean: false,
isEncrypted: false
},
{
name: 'mariadbPassword',
isEditable: false,
isLowerCase: false,
isNumber: false,
isBoolean: false,
isEncrypted: true
},
{
name: 'mariadbRootUser',
isEditable: false,
isLowerCase: false,
isNumber: false,
isBoolean: false,
isEncrypted: false
},
{
name: 'mariadbRootUserPassword',
isEditable: false,
isLowerCase: false,
isNumber: false,
isBoolean: false,
isEncrypted: true
},
{ {
name: 'mariadbDatabase', name: 'mariadbDatabase',
isEditable: true, isEditable: true,

View File

@ -0,0 +1,35 @@
import { createDirectories, getServiceFromDB, getServiceImage, getServiceMainPort, makeLabelForServices } from "./common";
export async function defaultServiceConfigurations({ id, teamId }) {
const service = await getServiceFromDB({ id, teamId });
const { destinationDockerId, destinationDocker, type, serviceSecret } = service;
const network = destinationDockerId && destinationDocker.network;
const port = getServiceMainPort(type);
const { workdir } = await createDirectories({ repository: type, buildId: id });
const image = getServiceImage(type);
let secrets = [];
if (serviceSecret.length > 0) {
serviceSecret.forEach((secret) => {
secrets.push(`${secret.name}=${secret.value}`);
});
}
return { ...service, network, port, workdir, image, secrets }
}
export function defaultServiceComposeConfiguration(network: string): any {
return {
networks: [network],
restart: 'always',
deploy: {
restart_policy: {
condition: 'on-failure',
delay: '10s',
max_attempts: 10,
window: '120s'
}
}
}
}

View File

@ -3,8 +3,7 @@ import type { FastifyRequest } from 'fastify';
import { FastifyReply } from 'fastify'; import { FastifyReply } from 'fastify';
import yaml from 'js-yaml'; import yaml from 'js-yaml';
import fs from 'fs/promises'; import fs from 'fs/promises';
import { ComposeFile, createDirectories, decrypt, encrypt, errorHandler, executeDockerCmd, generateDatabaseConfiguration, generatePassword, getContainerUsage, getDatabaseImage, getDatabaseVersions, getFreePublicPort, isARM, listSettings, makeLabelForStandaloneDatabase, prisma, startTraefikTCPProxy, stopDatabaseContainer, stopTcpHttpProxy, supportedDatabaseTypesAndVersions, uniqueName, updatePasswordInDb } from '../../../../lib/common'; import { ComposeFile, createDirectories, decrypt, encrypt, errorHandler, executeDockerCmd, generateDatabaseConfiguration, generatePassword, getContainerUsage, getDatabaseImage, getDatabaseVersions, getFreePublicPort, listSettings, makeLabelForStandaloneDatabase, prisma, startTraefikTCPProxy, stopDatabaseContainer, stopTcpHttpProxy, supportedDatabaseTypesAndVersions, uniqueName, updatePasswordInDb } from '../../../../lib/common';
import { checkContainer } from '../../../../lib/docker';
import { day } from '../../../../lib/dayjs'; import { day } from '../../../../lib/dayjs';
import { GetDatabaseLogs, OnlyId, SaveDatabase, SaveDatabaseDestination, SaveDatabaseSettings, SaveVersion } from '../../../../types'; import { GetDatabaseLogs, OnlyId, SaveDatabase, SaveDatabaseDestination, SaveDatabaseSettings, SaveVersion } from '../../../../types';

File diff suppressed because it is too large Load Diff

View File

@ -131,8 +131,8 @@ export const supportedServiceTypesAndVersions = [
fancyName: 'Hasura', fancyName: 'Hasura',
baseImage: 'hasura/graphql-engine', baseImage: 'hasura/graphql-engine',
images: ['postgres:12-alpine'], images: ['postgres:12-alpine'],
versions: ['latest', 'v2.5.1'], versions: ['latest', 'v2.10.0', 'v2.5.1'],
recommendedVersion: 'v2.5.1', recommendedVersion: 'v2.10.0',
ports: { ports: {
main: 8080 main: 8080
} }
@ -148,6 +148,17 @@ export const supportedServiceTypesAndVersions = [
main: 3000 main: 3000
} }
}, },
{
name: 'appwrite',
fancyName: 'Appwrite',
baseImage: 'appwrite/appwrite',
images: ['mariadb:10.7', 'redis:6.2-alpine', 'appwrite/telegraf:1.4.0'],
versions: ['latest', '0.15.3'],
recommendedVersion: '0.15.3',
ports: {
main: 80
}
}
// { // {
// name: 'moodle', // name: 'moodle',
// fancyName: 'Moodle', // fancyName: 'Moodle',
@ -218,7 +229,7 @@ export const staticDeployments = [
'astro', 'astro',
'eleventy' 'eleventy'
]; ];
export const notNodeDeployments = ['php', 'docker', 'rust', 'python', 'deno', 'laravel']; export const notNodeDeployments = ['php', 'docker', 'rust', 'python', 'deno', 'laravel', 'heroku'];
export function generateRemoteEngine(destination: any) { export function generateRemoteEngine(destination: any) {

View File

@ -5,16 +5,17 @@
</script> </script>
<div <div
on:click={() => dispatch('click')}
on:mouseover={() => dispatch('pause')} on:mouseover={() => dispatch('pause')}
on:focus={() => dispatch('pause')} on:focus={() => dispatch('pause')}
on:mouseout={() => dispatch('resume')} on:mouseout={() => dispatch('resume')}
on:blur={() => dispatch('resume')} on:blur={() => dispatch('resume')}
class="alert shadow-lg text-white rounded" class="alert shadow-lg text-white rounded hover:scale-105 transition-all duration-100 cursor-pointer"
class:bg-coollabs={type === 'success'} class:bg-coollabs={type === 'success'}
class:alert-error={type === 'error'} class:alert-error={type === 'error'}
class:alert-info={type === 'info'} class:alert-info={type === 'info'}
> >
<!-- {#if type === 'success'} {#if type === 'success'}
<svg <svg
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
class="stroke-current flex-shrink-0 h-6 w-6" class="stroke-current flex-shrink-0 h-6 w-6"
@ -53,6 +54,6 @@
d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"
/></svg /></svg
> >
{/if} --> {/if}
<slot /> <slot />
</div> </div>

View File

@ -2,7 +2,7 @@
import { fade } from 'svelte/transition'; import { fade } from 'svelte/transition';
import Toast from './Toast.svelte'; import Toast from './Toast.svelte';
import { pauseToast, resumeToast, toasts } from '$lib/store'; import { dismissToast, pauseToast, resumeToast, toasts } from '$lib/store';
</script> </script>
{#if $toasts} {#if $toasts}
@ -12,7 +12,8 @@
<Toast <Toast
type={toast.type} type={toast.type}
on:resume={() => resumeToast(toast.id)} on:resume={() => resumeToast(toast.id)}
on:pause={() => pauseToast(toast.id)}>{@html toast.message}</Toast on:pause={() => pauseToast(toast.id)}
on:click={() => dismissToast(toast.id)}>{@html toast.message}</Toast
> >
{/each} {/each}
</article> </article>

View File

@ -38,4 +38,6 @@
<Icons.Deno {isAbsolute} /> <Icons.Deno {isAbsolute} />
{:else if application.buildPack?.toLowerCase() === 'laravel'} {:else if application.buildPack?.toLowerCase() === 'laravel'}
<Icons.Laravel {isAbsolute} /> <Icons.Laravel {isAbsolute} />
{:else if application.buildPack?.toLowerCase() === 'heroku'}
<Icons.Heroku {isAbsolute} />
{/if} {/if}

View File

@ -0,0 +1,15 @@
<script lang="ts">
export let isAbsolute = true;
</script>
<svg
xmlns="http://www.w3.org/2000/svg"
class={isAbsolute ? 'absolute top-0 left-0 -m-4 h-10 w-10' : 'mx-auto w-8 h-8 '}
viewBox="0 0 72 80"
>
<path
xmlns="http://www.w3.org/2000/svg"
fill="#430098"
d="M64.8,0 L7.2,0 C3.224,0 0,3.224 0,7.2 L0,72.8 C0,76.776 3.224,80 7.2,80 L64.8,80 C68.776,80 72,76.776 72,72.8 L72,7.2 C72,3.224 68.776,0 64.8,0 Z M18,68 L18,52 L27,60 L18,68 Z M46,68 L46,44.11 C45.961,42.243 45.062,40 41,40 C32.866,40 23.742,44.091 23.651,44.132 L18,46.692 L18,12 L26,12 L26,34.711 C29.994,33.411 35.577,32 41,32 C45.945,32 48.905,33.944 50.517,35.575 C53.958,39.055 54.005,43.488 54.0002258,44 L54.0002258,68 L46,68 Z M48,25 L40,25 C43.144,20.875 45.118,16.534 46,12 L54,12 C53.46,16.544 51.618,20.9 48,25 Z"
/>
</svg>

View File

@ -16,4 +16,4 @@ export { default as Astro } from './Astro.svelte';
export { default as Eleventy } from './Eleventy.svelte'; export { default as Eleventy } from './Eleventy.svelte';
export { default as Deno } from './Deno.svelte'; export { default as Deno } from './Deno.svelte';
export { default as Laravel } from './Laravel.svelte'; export { default as Laravel } from './Laravel.svelte';
export { default as Heroku } from './Heroku.svelte';

File diff suppressed because one or more lines are too long

View File

@ -32,6 +32,8 @@
<Icons.Hasura {isAbsolute} /> <Icons.Hasura {isAbsolute} />
{:else if type === 'fider'} {:else if type === 'fider'}
<Icons.Fider {isAbsolute} /> <Icons.Fider {isAbsolute} />
{:else if type === 'appwrite'}
<Icons.Appwrite {isAbsolute} />
{:else if type === 'moodle'} {:else if type === 'moodle'}
<Icons.Moodle {isAbsolute} /> <Icons.Moodle {isAbsolute} />
{/if} {/if}

View File

@ -1,17 +1,18 @@
//@ts-nocheck //@ts-nocheck
export { default as PlausibleAnalytics } from './PlausibleAnalytics.svelte'; export { default as PlausibleAnalytics } from './PlausibleAnalytics.svelte';
export { default as NocoDb } from './NocoDB.svelte'; export { default as NocoDb } from './NocoDB.svelte';
export { default as MinIo } from './MinIO.svelte'; export { default as MinIo } from './MinIO.svelte';
export { default as VsCodeServer } from './VSCodeServer.svelte'; export { default as VsCodeServer } from './VSCodeServer.svelte';
export { default as Wordpress } from './Wordpress.svelte'; export { default as Wordpress } from './Wordpress.svelte';
export { default as VaultWarden } from './VaultWarden.svelte'; export { default as VaultWarden } from './VaultWarden.svelte';
export { default as LanguageTool } from './LanguageTool.svelte'; export { default as LanguageTool } from './LanguageTool.svelte';
export { default as N8n } from './N8n.svelte'; export { default as N8n } from './N8n.svelte';
export { default as UptimeKuma } from './UptimeKuma.svelte'; export { default as UptimeKuma } from './UptimeKuma.svelte';
export { default as Ghost } from './Ghost.svelte'; export { default as Ghost } from './Ghost.svelte';
export { default as MeiliSearch } from './MeiliSearch.svelte'; export { default as MeiliSearch } from './MeiliSearch.svelte';
export { default as Umami } from './Umami.svelte'; export { default as Umami } from './Umami.svelte';
export { default as Hasura } from './Hasura.svelte'; export { default as Hasura } from './Hasura.svelte';
export { default as Fider } from './Fider.svelte'; export { default as Fider } from './Fider.svelte';
export { default as Moodle } from './Moodle.svelte'; export { default as Appwrite } from './Appwrite.svelte';
export { default as Moodle } from './Moodle.svelte';

View File

@ -170,6 +170,16 @@ export function findBuildPack(pack: string, packageManager = 'npm') {
port: 80 port: 80
}; };
} }
if (pack === 'heroku') {
return {
...metaData,
installCommand: null,
buildCommand: null,
startCommand: null,
publishDirectory: null,
port: 5000
};
}
return { return {
name: 'node', name: 'node',
fancyName: 'Node.js', fancyName: 'Node.js',
@ -187,119 +197,137 @@ export const buildPacks = [
name: 'node', name: 'node',
fancyName: 'Node.js', fancyName: 'Node.js',
hoverColor: 'hover:bg-green-700', hoverColor: 'hover:bg-green-700',
color: 'bg-green-700' color: 'bg-green-700',
isCoolifyBuildPack: true,
}, },
{ {
name: 'static', name: 'static',
fancyName: 'Static', fancyName: 'Static',
hoverColor: 'hover:bg-orange-700', hoverColor: 'hover:bg-orange-700',
color: 'bg-orange-700' color: 'bg-orange-700',
isCoolifyBuildPack: true,
}, },
{ {
name: 'php', name: 'php',
fancyName: 'PHP', fancyName: 'PHP',
hoverColor: 'hover:bg-indigo-700', hoverColor: 'hover:bg-indigo-700',
color: 'bg-indigo-700' color: 'bg-indigo-700',
isCoolifyBuildPack: true,
}, },
{ {
name: 'laravel', name: 'laravel',
fancyName: 'Laravel', fancyName: 'Laravel',
hoverColor: 'hover:bg-indigo-700', hoverColor: 'hover:bg-indigo-700',
color: 'bg-indigo-700' color: 'bg-indigo-700',
isCoolifyBuildPack: true,
}, },
{ {
name: 'docker', name: 'docker',
fancyName: 'Docker', fancyName: 'Docker',
hoverColor: 'hover:bg-sky-700', hoverColor: 'hover:bg-sky-700',
color: 'bg-sky-700' color: 'bg-sky-700',
isCoolifyBuildPack: true,
}, },
{ {
name: 'svelte', name: 'svelte',
fancyName: 'Svelte', fancyName: 'Svelte',
hoverColor: 'hover:bg-orange-700', hoverColor: 'hover:bg-orange-700',
color: 'bg-orange-700' color: 'bg-orange-700',
isCoolifyBuildPack: true,
}, },
{ {
name: 'vuejs', name: 'vuejs',
fancyName: 'VueJS', fancyName: 'VueJS',
hoverColor: 'hover:bg-green-700', hoverColor: 'hover:bg-green-700',
color: 'bg-green-700' color: 'bg-green-700',
isCoolifyBuildPack: true,
}, },
{ {
name: 'nuxtjs', name: 'nuxtjs',
fancyName: 'NuxtJS', fancyName: 'NuxtJS',
hoverColor: 'hover:bg-green-700', hoverColor: 'hover:bg-green-700',
color: 'bg-green-700' color: 'bg-green-700',
isCoolifyBuildPack: true,
}, },
{ {
name: 'gatsby', name: 'gatsby',
fancyName: 'Gatsby', fancyName: 'Gatsby',
hoverColor: 'hover:bg-blue-700', hoverColor: 'hover:bg-blue-700',
color: 'bg-blue-700' color: 'bg-blue-700',
isCoolifyBuildPack: true,
}, },
{ {
name: 'astro', name: 'astro',
fancyName: 'Astro', fancyName: 'Astro',
hoverColor: 'hover:bg-pink-700', hoverColor: 'hover:bg-pink-700',
color: 'bg-pink-700' color: 'bg-pink-700',
isCoolifyBuildPack: true,
}, },
{ {
name: 'eleventy', name: 'eleventy',
fancyName: 'Eleventy', fancyName: 'Eleventy',
hoverColor: 'hover:bg-red-700', hoverColor: 'hover:bg-red-700',
color: 'bg-red-700' color: 'bg-red-700',
isCoolifyBuildPack: true,
}, },
{ {
name: 'react', name: 'react',
fancyName: 'React', fancyName: 'React',
hoverColor: 'hover:bg-blue-700', hoverColor: 'hover:bg-blue-700',
color: 'bg-blue-700' color: 'bg-blue-700',
isCoolifyBuildPack: true,
}, },
{ {
name: 'preact', name: 'preact',
fancyName: 'Preact', fancyName: 'Preact',
hoverColor: 'hover:bg-blue-700', hoverColor: 'hover:bg-blue-700',
color: 'bg-blue-700' color: 'bg-blue-700',
isCoolifyBuildPack: true,
}, },
{ {
name: 'nextjs', name: 'nextjs',
fancyName: 'NextJS', fancyName: 'NextJS',
hoverColor: 'hover:bg-blue-700', hoverColor: 'hover:bg-blue-700',
color: 'bg-blue-700' color: 'bg-blue-700',
isCoolifyBuildPack: true,
}, },
{ {
name: 'nestjs', name: 'nestjs',
fancyName: 'NestJS', fancyName: 'NestJS',
hoverColor: 'hover:bg-red-700', hoverColor: 'hover:bg-red-700',
color: 'bg-red-700' color: 'bg-red-700',
isCoolifyBuildPack: true,
}, },
{ {
name: 'rust', name: 'rust',
fancyName: 'Rust', fancyName: 'Rust',
hoverColor: 'hover:bg-pink-700', hoverColor: 'hover:bg-pink-700',
color: 'bg-pink-700' color: 'bg-pink-700',
isCoolifyBuildPack: true,
}, },
{ {
name: 'python', name: 'python',
fancyName: 'Python', fancyName: 'Python',
hoverColor: 'hover:bg-green-700', hoverColor: 'hover:bg-green-700',
color: 'bg-green-700' color: 'bg-green-700',
isCoolifyBuildPack: true,
}, },
{ {
name: 'deno', name: 'deno',
fancyName: 'Deno', fancyName: 'Deno',
hoverColor: 'hover:bg-green-700', hoverColor: 'hover:bg-green-700',
color: 'bg-green-700' color: 'bg-green-700',
} isCoolifyBuildPack: true,
// }, },
// { {
// name: 'heroku', name: 'heroku',
// fancyName: 'Heroku Buildpack', fancyName: 'Heroku',
// hoverColor: 'hover:bg-indigo-700', hoverColor: 'hover:bg-purple-700',
// color: 'bg-indigo-700' color: 'bg-purple-700',
// } isHerokuBuildPack: true,
}
]; ];
export const scanningTemplates = { export const scanningTemplates = {
'@sveltejs/kit': { '@sveltejs/kit': {

View File

@ -30,7 +30,6 @@
import { page } from '$app/stores'; import { page } from '$app/stores';
import { get } from '$lib/api'; import { get } from '$lib/api';
import { appSession } from '$lib/store'; import { appSession } from '$lib/store';
import { browser } from '$app/env';
import { t } from '$lib/translations'; import { t } from '$lib/translations';
import { buildPacks, findBuildPack, scanningTemplates } from '$lib/templates'; import { buildPacks, findBuildPack, scanningTemplates } from '$lib/templates';
import { errorNotification } from '$lib/common'; import { errorNotification } from '$lib/common';
@ -263,11 +262,27 @@
</div> </div>
</div> </div>
{:else} {:else}
<div class="max-w-7xl mx-auto flex flex-wrap justify-center">
{#each buildPacks as buildPack}
<div class="max-w-7xl mx-auto ">
<div class="title pb-2">Coolify Buildpacks</div>
<div class="flex flex-wrap justify-center">
{#each buildPacks.filter(bp => bp.isCoolifyBuildPack === true) as buildPack}
<div class="p-2">
<BuildPack {packageManager} {buildPack} {scanning} bind:foundConfig />
</div>
{/each}
</div>
</div>
<div class="max-w-7xl mx-auto ">
<div class="title pb-2">Heroku</div>
<div class="flex flex-wrap justify-center">
{#each buildPacks.filter(bp => bp.isHerokuBuildPack === true) as buildPack}
<div class="p-2"> <div class="p-2">
<BuildPack {packageManager} {buildPack} {scanning} bind:foundConfig /> <BuildPack {packageManager} {buildPack} {scanning} bind:foundConfig />
</div> </div>
{/each} {/each}
</div> </div>
</div>
{/if} {/if}

View File

@ -31,6 +31,7 @@
import { t } from '$lib/translations'; import { t } from '$lib/translations';
import { appSession } from '$lib/store'; import { appSession } from '$lib/store';
import { errorNotification } from '$lib/common'; import { errorNotification } from '$lib/common';
import { onMount } from 'svelte';
const { id } = $page.params; const { id } = $page.params;
const from = $page.url.searchParams.get('from'); const from = $page.url.searchParams.get('from');
@ -55,6 +56,11 @@
return errorNotification(error); return errorNotification(error);
} }
} }
onMount(async () => {
if (destinations.length === 1) {
await handleSubmit(destinations[0].id);
}
});
</script> </script>
<div class="flex space-x-1 p-6 font-bold"> <div class="flex space-x-1 p-6 font-bold">
@ -65,7 +71,9 @@
<div class="flex flex-col justify-center"> <div class="flex flex-col justify-center">
{#if !destinations || ownDestinations.length === 0} {#if !destinations || ownDestinations.length === 0}
<div class="flex-col"> <div class="flex-col">
<div class="pb-2 text-center font-bold">{$t('application.configuration.no_configurable_destination')}</div> <div class="pb-2 text-center font-bold">
{$t('application.configuration.no_configurable_destination')}
</div>
<div class="flex justify-center"> <div class="flex justify-center">
<a href="/new/destination" sveltekit:prefetch class="add-icon bg-sky-600 hover:bg-sky-500"> <a href="/new/destination" sveltekit:prefetch class="add-icon bg-sky-600 hover:bg-sky-500">
<svg <svg

View File

@ -332,53 +332,56 @@
<label for="gitSource" class="text-base font-bold text-stone-100" <label for="gitSource" class="text-base font-bold text-stone-100"
>{$t('application.git_source')}</label >{$t('application.git_source')}</label
> >
<a {#if isDisabled}
href={!isDisabled <input disabled={isDisabled} value={application.gitSource.name} />
? `/applications/${id}/configuration/source?from=/applications/${id}` {:else}
: ''} <a
class="no-underline" href={`/applications/${id}/configuration/source?from=/applications/${id}`}
><input class="no-underline"
value={application.gitSource.name} ><input
id="gitSource" value={application.gitSource.name}
disabled id="gitSource"
class="cursor-pointer hover:bg-coolgray-500" class="cursor-pointer hover:bg-coolgray-500"
/></a /></a
> >
{/if}
</div> </div>
<div class="grid grid-cols-2 items-center"> <div class="grid grid-cols-2 items-center">
<label for="repository" class="text-base font-bold text-stone-100" <label for="repository" class="text-base font-bold text-stone-100"
>{$t('application.git_repository')}</label >{$t('application.git_repository')}</label
> >
<a {#if isDisabled}
href={!isDisabled <input disabled={isDisabled} value="{application.repository}/{application.branch}" />
? `/applications/${id}/configuration/repository?from=/applications/${id}&to=/applications/${id}/configuration/buildpack` {:else}
: ''} <a
class="no-underline" href={`/applications/${id}/configuration/repository?from=/applications/${id}&to=/applications/${id}/configuration/buildpack`}
><input class="no-underline"
value="{application.repository}/{application.branch}" ><input
id="repository" value="{application.repository}/{application.branch}"
disabled id="repository"
class="cursor-pointer hover:bg-coolgray-500" class="cursor-pointer hover:bg-coolgray-500"
/></a /></a
> >
{/if}
</div> </div>
<div class="grid grid-cols-2 items-center"> <div class="grid grid-cols-2 items-center">
<label for="buildPack" class="text-base font-bold text-stone-100" <label for="buildPack" class="text-base font-bold text-stone-100"
>{$t('application.build_pack')}</label >{$t('application.build_pack')}</label
> >
{#if isDisabled}
<input class="capitalize" disabled={isDisabled} value={application.buildPack} />
{:else}
<a <a
href={!isDisabled href={`/applications/${id}/configuration/buildpack?from=/applications/${id}`}
? `/applications/${id}/configuration/buildpack?from=/applications/${id}`
: ''}
class="no-underline " class="no-underline "
> >
<input <input
value={application.buildPack} value={application.buildPack}
id="buildPack" id="buildPack"
disabled class="cursor-pointer hover:bg-coolgray-500 capitalize"
class="cursor-pointer hover:bg-coolgray-500"
/></a /></a
> >
{/if}
</div> </div>
<div class="grid grid-cols-2 items-center pb-8"> <div class="grid grid-cols-2 items-center pb-8">
<label for="destination" class="text-base font-bold text-stone-100" <label for="destination" class="text-base font-bold text-stone-100"
@ -698,7 +701,7 @@
/> />
</div> </div>
{/if} {/if}
{#if application.buildPack !== 'laravel'} {#if application.buildPack !== 'laravel' && application.buildPack !== 'heroku'}
<div class="grid grid-cols-2 items-center"> <div class="grid grid-cols-2 items-center">
<div class="flex-col"> <div class="flex-col">
<label for="baseDirectory" class="pt-2 text-base font-bold text-stone-100" <label for="baseDirectory" class="pt-2 text-base font-bold text-stone-100"

View File

@ -30,6 +30,7 @@
import { get, post } from '$lib/api'; import { get, post } from '$lib/api';
import { t } from '$lib/translations'; import { t } from '$lib/translations';
import { errorNotification } from '$lib/common'; import { errorNotification } from '$lib/common';
import { onMount } from 'svelte';
const { id } = $page.params; const { id } = $page.params;
const from = $page.url.searchParams.get('from'); const from = $page.url.searchParams.get('from');
@ -45,6 +46,11 @@
return errorNotification(error); return errorNotification(error);
} }
} }
onMount(async () => {
if (destinations.length === 1) {
await handleSubmit(destinations[0].id);
}
});
</script> </script>
<div class="flex space-x-1 p-6 font-bold"> <div class="flex space-x-1 p-6 font-bold">
@ -55,7 +61,9 @@
<div class="flex justify-center"> <div class="flex justify-center">
{#if !destinations || destinations.length === 0} {#if !destinations || destinations.length === 0}
<div class="flex-col"> <div class="flex-col">
<div class="pb-2 text-center font-bold">{$t('application.configuration.no_configurable_destination')}</div> <div class="pb-2 text-center font-bold">
{$t('application.configuration.no_configurable_destination')}
</div>
<div class="flex justify-center"> <div class="flex justify-center">
<a href="/new/destination" sveltekit:prefetch class="add-icon bg-sky-600 hover:bg-sky-500"> <a href="/new/destination" sveltekit:prefetch class="add-icon bg-sky-600 hover:bg-sky-500">
<svg <svg

View File

@ -39,7 +39,7 @@
export let services: any; export let services: any;
let numberOfGetStatus = 0; let numberOfGetStatus = 0;
function getRndInteger(min, max) { function getRndInteger(min: number, max: number) {
return Math.floor(Math.random() * (max - min + 1) ) + min; return Math.floor(Math.random() * (max - min + 1) ) + min;
} }
@ -97,6 +97,7 @@
<div class="mt-10 pb-12 tracking-tight sm:pb-16"> <div class="mt-10 pb-12 tracking-tight sm:pb-16">
<div class="mx-auto px-10"> <div class="mx-auto px-10">
<div class="flex flex-col justify-center xl:flex-row"> <div class="flex flex-col justify-center xl:flex-row">
{#if applications.length > 0}
<div> <div>
<div class="title">Resources</div> <div class="title">Resources</div>
<div class="flex items-start justify-center p-8"> <div class="flex items-start justify-center p-8">
@ -308,6 +309,7 @@
</table> </table>
</div> </div>
</div> </div>
{/if}
{#if $appSession.teamId === '0'} {#if $appSession.teamId === '0'}
<Usage /> <Usage />
{/if} {/if}

View File

@ -55,9 +55,12 @@
<a href="https://fider.io" target="_blank"> <a href="https://fider.io" target="_blank">
<Icons.Fider /> <Icons.Fider />
</a> </a>
{:else if service.type === 'appwrite'}
<a href="https://appwrite.io" target="_blank">
<Icons.Appwrite/>
</a>
{:else if service.type === 'moodle'} {:else if service.type === 'moodle'}
<a href="https://moodle.org" target="_blank"> <a href="https://moodle.org" target="_blank">
<Icons.Moodle /> <Icons.Moodle />
</a> </a>
{/if} {/if}

View File

@ -0,0 +1,126 @@
<script lang="ts">
import CopyPasswordField from '$lib/components/CopyPasswordField.svelte';
import { t } from '$lib/translations';
import Select from 'svelte-select';
export let service: any;
export let readOnly: any;
</script>
<div class="flex space-x-1 py-5 font-bold">
<div class="title">Appwrite</div>
</div>
<div class="grid grid-cols-2 items-center px-10">
<label for="opensslKeyV1">Encryption Key</label>
<CopyPasswordField
name="opensslKeyV1"
id="opensslKeyV1"
isPasswordField
value={service.appwrite.opensslKeyV1}
readonly
disabled
/>
</div>
<div class="grid grid-cols-2 items-center px-10">
<label for="executorSecret">Executor Secret</label>
<CopyPasswordField
name="executorSecret"
id="executorSecret"
isPasswordField
value={service.appwrite.executorSecret}
readonly
disabled
/>
</div>
<!-- <div class="flex space-x-1 py-5 font-bold">
<div class="title">Redis</div>
</div>
<div class="grid grid-cols-2 items-center px-10">
<label for="redisPassword">Password</label>
<CopyPasswordField
name="redisPassword"
id="redisPassword"
isPasswordField
value={service.appwrite.redisPassword}
readonly
disabled
/>
</div> -->
<div class="flex space-x-1 py-5 font-bold">
<div class="title">MariaDB</div>
</div>
<!-- <div class="grid grid-cols-2 items-center px-10">
<label for="mariadbHost">MariaDB Host</label>
<CopyPasswordField
name="mariadbHost"
id="mariadbHost"
value={service.appwrite.mariadbHost}
readonly
disabled
/>
</div>
<div class="grid grid-cols-2 items-center px-10">
<label for="mariadbPort">MariaDB Port</label>
<CopyPasswordField
name="mariadbPort"
id="mariadbPort"
value={service.appwrite.mariadbPort}
readonly
disabled
/>
</div> -->
<div class="grid grid-cols-2 items-center px-10">
<label for="mariadbUser">{$t('forms.username')}</label>
<CopyPasswordField
name="mariadbUser"
id="mariadbUser"
value={service.appwrite.mariadbUser}
readonly
disabled
/>
</div>
<div class="grid grid-cols-2 items-center px-10">
<label for="mariadbPassword">{$t('forms.password')}</label>
<CopyPasswordField
id="mariadbPassword"
isPasswordField
readonly
disabled
name="mariadbPassword"
value={service.appwrite.mariadbPassword}
/>
</div>
<div class="grid grid-cols-2 items-center px-10">
<label for="mariadbRootUser">Root User</label>
<CopyPasswordField
name="mariadbRootUser"
id="mariadbRootUser"
value={service.appwrite.mariadbRootUser}
readonly
disabled
/>
</div>
<div class="grid grid-cols-2 items-center px-10">
<label for="mariadbRootUserPassword">Root Password</label>
<CopyPasswordField
id="mariadbRootUserPassword"
isPasswordField
readonly
disabled
name="mariadbRootUserPassword"
value={service.appwrite.mariadbRootUserPassword}
/>
</div>
<div class="grid grid-cols-2 items-center px-10">
<label for="mariadbDatabase">{$t('index.database')}</label>
<CopyPasswordField
name="mariadbDatabase"
id="mariadbDatabase"
value={service.appwrite.mariadbDatabase}
readonly
disabled
/>
</div>

View File

@ -26,6 +26,7 @@
import Umami from './_Umami.svelte'; import Umami from './_Umami.svelte';
import VsCodeServer from './_VSCodeServer.svelte'; import VsCodeServer from './_VSCodeServer.svelte';
import Wordpress from './_Wordpress.svelte'; import Wordpress from './_Wordpress.svelte';
import Appwrite from './_Appwrite.svelte';
import Moodle from './_Moodle.svelte'; import Moodle from './_Moodle.svelte';
const { id } = $page.params; const { id } = $page.params;
@ -37,7 +38,7 @@
save: false, save: false,
verification: false, verification: false,
cleanup: false cleanup: false
} };
let dualCerts = service.dualCerts; let dualCerts = service.dualCerts;
let nonWWWDomain = service.fqdn && getDomain(service.fqdn).replace(/^www\./, ''); let nonWWWDomain = service.fqdn && getDomain(service.fqdn).replace(/^www\./, '');
@ -394,6 +395,8 @@
<Hasura bind:service /> <Hasura bind:service />
{:else if service.type === 'fider'} {:else if service.type === 'fider'}
<Fider bind:service {readOnly} /> <Fider bind:service {readOnly} />
{:else if service.type === 'appwrite'}
<Appwrite bind:service {readOnly} />
{:else if service.type === 'moodle'} {:else if service.type === 'moodle'}
<Moodle bind:service {readOnly} /> <Moodle bind:service {readOnly} />
{/if} {/if}

View File

@ -22,7 +22,7 @@
function generateUrl(publicPort: any) { function generateUrl(publicPort: any) {
return browser return browser
? `sftp://${ ? `sftp://${
settings.fqdn ? getDomain(settings.fqdn) : window.location.hostname settings?.fqdn ? getDomain(settings.fqdn) : window.location.hostname
}:${publicPort}` }:${publicPort}`
: 'Loading...'; : 'Loading...';
} }

View File

@ -110,7 +110,6 @@
loading = true; loading = true;
try { try {
await post(`/services/${service.id}/${service.type}/start`, {}); await post(`/services/${service.id}/${service.type}/start`, {});
return window.location.reload();
} catch (error) { } catch (error) {
return errorNotification(error); return errorNotification(error);
} finally { } finally {

View File

@ -32,10 +32,16 @@
import { get, post } from '$lib/api'; import { get, post } from '$lib/api';
import { t } from '$lib/translations'; import { t } from '$lib/translations';
import { errorNotification } from '$lib/common'; import { errorNotification } from '$lib/common';
import { onMount } from 'svelte';
const { id } = $page.params; const { id } = $page.params;
const from = $page.url.searchParams.get('from'); const from = $page.url.searchParams.get('from');
onMount(async () => {
if (destinations.length === 1) {
await handleSubmit(destinations[0].id);
}
});
async function handleSubmit(destinationId: any) { async function handleSubmit(destinationId: any) {
try { try {
await post(`/services/${id}/configuration/destination`, { destinationId }); await post(`/services/${id}/configuration/destination`, { destinationId });
@ -54,7 +60,9 @@
<div class="flex justify-center"> <div class="flex justify-center">
{#if !destinations || destinations.length === 0} {#if !destinations || destinations.length === 0}
<div class="flex-col"> <div class="flex-col">
<div class="pb-2 text-center font-bold">{$t('application.configuration.no_configurable_destination')}</div> <div class="pb-2 text-center font-bold">
{$t('application.configuration.no_configurable_destination')}
</div>
<div class="flex justify-center"> <div class="flex justify-center">
<a href="/new/destination" sveltekit:prefetch class="add-icon bg-sky-600 hover:bg-sky-500"> <a href="/new/destination" sveltekit:prefetch class="add-icon bg-sky-600 hover:bg-sky-500">
<svg <svg

View File

@ -32,13 +32,20 @@
import { get, post } from '$lib/api'; import { get, post } from '$lib/api';
import { t } from '$lib/translations'; import { t } from '$lib/translations';
import { errorNotification, supportedServiceTypesAndVersions } from '$lib/common'; import { errorNotification, supportedServiceTypesAndVersions } from '$lib/common';
import { onMount } from 'svelte';
const { id } = $page.params; const { id } = $page.params;
const from = $page.url.searchParams.get('from'); const from = $page.url.searchParams.get('from');
let recommendedVersion = supportedServiceTypesAndVersions.find( let recommendedVersion = supportedServiceTypesAndVersions.find(
({ name }) => name === type ({ name }) => name === type
)?.recommendedVersion; )?.recommendedVersion;
onMount(async () => {
if (versions.length === 1) {
await handleSubmit(versions[0]);
}
});
async function handleSubmit(version: any) { async function handleSubmit(version: any) {
try { try {
await post(`/services/${id}/configuration/version`, { version }); await post(`/services/${id}/configuration/version`, { version });

View File

@ -102,7 +102,7 @@
{#each otherServices as service} {#each otherServices as service}
<a href="/services/{service.id}" class="p-2 no-underline"> <a href="/services/{service.id}" class="p-2 no-underline">
<div class="box-selection group relative hover:bg-pink-600"> <div class="box-selection group relative hover:bg-pink-600">
<Services type={service.type} /> <ServiceIcons type={service.type} />
<div class="truncate text-center text-xl font-bold"> <div class="truncate text-center text-xl font-bold">
{service.name} {service.name}
</div> </div>

View File

@ -46,7 +46,7 @@ #svelte .custom-select-wrapper .selectContainer input {
} }
#svelte .custom-select-wrapper .selectContainer { #svelte .custom-select-wrapper .selectContainer {
@apply h-12 w-96 rounded border-none bg-coolgray-200 p-2 px-0 text-xs tracking-tight outline-none transition duration-150 hover:bg-coolgray-500 focus:bg-coolgray-500 md:text-sm; @apply h-12 w-96 rounded border border-coolgray-300 border-dashed bg-coolgray-200 p-2 px-0 text-xs tracking-tight outline-none transition duration-150 hover:bg-coolgray-500 focus:bg-coolgray-500 md:text-sm;
} }
#svelte .listContainer { #svelte .listContainer {

View File

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