Compare commits
5 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
fe0f5321be | ||
|
172589a805 | ||
|
8e9b3efeb9 | ||
|
0ab9001dbf | ||
|
f28e52e7b2 |
132
README.md
Normal file
132
README.md
Normal file
@ -0,0 +1,132 @@
|
||||
![Latest Release Version](https://img.shields.io/badge/dynamic/json?labelColor=grey&color=6366f1&label=Latest_released_version&url=https%3A%2F%2Fcdn.coollabs.io%2Fcoolify%2Fversions.json&query=coolify.v4.version&style=for-the-badge
|
||||
)
|
||||
|
||||
[![Bounty Issues](https://img.shields.io/static/v1?labelColor=grey&color=6366f1&label=Algora&message=%F0%9F%92%8E+Bounty+issues&style=for-the-badge)](https://console.algora.io/org/coollabsio/bounties/new)
|
||||
|
||||
# About the Project
|
||||
|
||||
Coolify is an open-source & self-hostable alternative to Heroku / Netlify / Vercel / etc.
|
||||
|
||||
It helps you manage your servers, applications, and databases on your own hardware; you only need an SSH connection. You can manage VPS, Bare Metal, Raspberry PIs, and anything else.
|
||||
|
||||
Imagine having the ease of a cloud but with your own servers. That is **Coolify**.
|
||||
|
||||
No vendor lock-in, which means that all the configurations for your applications/databases/etc are saved to your server. So, if you decide to stop using Coolify (oh nooo), you could still manage your running resources. You lose the automations and all the magic. 🪄️
|
||||
|
||||
For more information, take a look at our landing page at [coolify.io](https://coolify.io).
|
||||
|
||||
# Installation
|
||||
|
||||
```bash
|
||||
curl -fsSL https://cdn.coollabs.io/coolify/install.sh | bash
|
||||
```
|
||||
You can find the installation script source [here](./scripts/install.sh).
|
||||
|
||||
# Support
|
||||
|
||||
Contact us at [coolify.io/docs/contact](https://coolify.io/docs/contact).
|
||||
|
||||
# Donations
|
||||
To stay completely free and open-source, with no feature behind the paywall and evolve the project, we need your help. If you like Coolify, please consider donating to help us fund the project's future development.
|
||||
|
||||
[coolify.io/sponsorships](https://coolify.io/sponsorships)
|
||||
|
||||
Thank you so much!
|
||||
|
||||
Special thanks to our biggest sponsors!
|
||||
|
||||
<a href="https://cccareers.org/" target="_blank"><img src="./other/logos/ccc-logo.webp" alt="cccareers logo" width="200"/></a>
|
||||
<a href="http://htznr.li/CoolifyXHetzner" target="_blank"><img src="./other/logos/hetzner.jpg" alt="hetzner logo" width="150"/></a>
|
||||
<a href="https://logto.io/?ref=coolify" target="_blank"><img src="./other/logos/logto.webp" alt="logto logo" width="150"/></a>
|
||||
<a href="https://bc.direct/?ref=coolify.io" target="_blank"><img src="./other/logos/bc.png" alt="bc direct logo" width="200"/></a>
|
||||
<a href="https://www.quantcdn.io/?ref=coolify.io" target="_blank"><img src="./other/logos/quant.svg" alt="quantcdn logo" width="150"/></a>
|
||||
<a href="https://arcjet.com/?ref=coolify.io" target="_blank"><img src="./other/logos/arcjet.svg" alt="arcjet logo" width="200"/></a>
|
||||
<a href="https://supa.guide/?ref=coolify.io" target="_blank"><img src="./other/logos/supaguide.png" alt="supaguide logo" width="200"/></a>
|
||||
<a href="https://tigrisdata.com/?ref=coolify.io" target="_blank"><img src="./other/logos/tigris.svg" alt="tigris logo" width="140"/></a>
|
||||
<a href="https://fractalnetworks.co/?ref=coolify.io" target="_blank"><img src="./other/logos/fractal.svg" alt="fractal logo" width="180"/></a>
|
||||
<a href="https://coolify.ad.vin/?ref=coolify.io" target="_blank"><img src="./other/logos/advin.png" alt="advin logo" width="250"/></a>
|
||||
<a href="https://trieve.ai/?ref=coolify.io" target="_blank"><img src="./other/logos/trieve_bg.png" alt="trieve logo" width="180"/></a>
|
||||
<a href="https://blacksmith.sh/?ref=coolify.io" target="_blank"><img src="./other/logos/blacksmith.svg" alt="blacksmith logo" width="200"/></a>
|
||||
<a href="https://latitude.sh/?ref=coolify.io" target="_blank"><img src="./other/logos/latitude.svg" alt="latitude logo" width="200"/></a>
|
||||
<a href="https://brand.dev/?ref=coolify.io" target="_blank"><img src="./other/logos/branddev.png" alt="branddev logo" width="200"/></a>
|
||||
|
||||
## Github Sponsors ($40+)
|
||||
<a href="https://serpapi.com/?ref=coolify.io"><img width="60px" alt="SerpAPI" src="https://github.com/serpapi.png"/></a>
|
||||
<a href="https://typebot.io/?ref=coolify.io"><img src="https://pbs.twimg.com/profile_images/1509194008366657543/9I-C7uWT_400x400.jpg" width="60px" alt="typebot"/></a>
|
||||
<a href="https://www.runpod.io/?ref=coolify.io">
|
||||
<svg style="width:60px;height:60px;background:#fff;" xmlns="http://www.w3.org/2000/svg" version="1.0" viewBox="0 0 200 200"><g><path d="M74.5 51.1c-25.4 14.9-27 16-29.6 20.2-1.8 3-1.9 5.3-1.9 32.3 0 21.7.3 29.4 1.3 30.6 1.9 2.5 46.7 27.9 48.5 27.6 1.5-.3 1.7-3.1 2-27.7.2-21.9 0-27.8-1.1-29.5-.8-1.2-9.9-6.8-20.2-12.6-10.3-5.8-19.4-11.5-20.2-12.7-1.8-2.6-.9-5.9 1.8-7.4 1.6-.8 6.3 0 21.8 4C87.8 78.7 98 81 99.6 81c4.4 0 49.9-25.9 49.9-28.4 0-1.6-3.4-2.8-24-8.2-13.2-3.5-25.1-6.3-26.5-6.3-1.4.1-12.4 5.9-24.5 13z"></path><path d="m137.2 68.1-3.3 2.1 6.3 3.7c3.5 2 6.3 4.3 6.3 5.1 0 .9-8 6.1-19.4 12.6-10.6 6-20 11.9-20.7 12.9-1.2 1.6-1.4 7.2-1.2 29.4.3 24.8.5 27.6 2 27.9 1.8.3 46.6-25.1 48.6-27.6.9-1.2 1.2-8.8 1.2-30.2s-.3-29-1.2-30.2c-1.6-1.9-12.1-7.8-13.9-7.8-.8 0-2.9 1-4.7 2.1z"></path></g></svg></a>
|
||||
<a href="https://lightspeed.run/?ref=coolify.io"><img src="https://github.com/lightspeedrun.png" width="60px" alt="Lightspeed.run"/></a>
|
||||
<a href="https://www.flint.sh/en/home?ref=coolify.io"> <img src="https://github.com/Flint-company.png" width="60px" alt="FlintCompany"/></a>
|
||||
<a href="https://americancloud.com/?ref=coolify.io"><img src="https://github.com/American-Cloud.png" width="60px" alt="American Cloud"/></a>
|
||||
<a href="https://cryptojobslist.com/?ref=coolify.io"><img src="https://github.com/cryptojobslist.png" width="60px" alt="CryptoJobsList" /></a>
|
||||
<a href="https://codext.link/coolify-io?ref=coolify.io"><img src="./other/logos/codext.jpg" width="60px" alt="Codext" /></a>
|
||||
<a href="https://x.com/mrsmith9ja?ref=coolify.io"><img width="60px" alt="Thompson Edolo" src="https://github.com/verygreenboi.png"/></a>
|
||||
<a href="https://www.uxwizz.com/?ref=coolify.io"><img width="60px" alt="UXWizz" src="https://github.com/UXWizz.png"/></a>
|
||||
<a href="https://github.com/Flowko"><img src="https://barrad.me/_ipx/f_webp&s_300x300/younes.jpg" width="60px" alt="Younes Barrad" /></a>
|
||||
<a href="https://github.com/automazeio"><img src="https://github.com/automazeio.png" width="60px" alt="Automaze" /></a>
|
||||
<a href="https://github.com/corentinclichy"><img src="https://github.com/corentinclichy.png" width="60px" alt="Corentin Clichy" /></a>
|
||||
<a href="https://github.com/Niki2k1"><img src="https://github.com/Niki2k1.png" width="60px" alt="Niklas Lausch" /></a>
|
||||
<a href="https://github.com/pixelinfinito"><img src="https://github.com/pixelinfinito.png" width="60px" alt="Pixel Infinito" /></a>
|
||||
<a href="https://github.com/whitesidest"><img src="https://avatars.githubusercontent.com/u/12365916?s=52&v=4" width="60px" alt="Tyler Whitesides" /></a>
|
||||
<a href="https://github.com/aniftyco"><img src="https://github.com/aniftyco.png" width="60px" alt="NiftyCo" /></a>
|
||||
<a href="https://github.com/iujlaki"><img src="https://github.com/iujlaki.png" width="60px" alt="Imre Ujlaki" /></a>
|
||||
<a href="https://il.ly"><img src="https://github.com/Illyism.png" width="60px" alt="Ilias Ism" /></a>
|
||||
<a href="https://github.com/urtho"><img src="https://github.com/urtho.png" width="60px" alt="Paweł Pierścionek" /></a>
|
||||
<a href="https://github.com/monocursive"><img src="https://github.com/monocursive.png" width="60px" alt="Michael Mazurczak" /></a>
|
||||
|
||||
## Organizations
|
||||
<a href="https://opencollective.com/coollabsio/organization/0/website"><img src="https://opencollective.com/coollabsio/organization/0/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/coollabsio/organization/1/website"><img src="https://opencollective.com/coollabsio/organization/1/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/coollabsio/organization/2/website"><img src="https://opencollective.com/coollabsio/organization/2/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/coollabsio/organization/3/website"><img src="https://opencollective.com/coollabsio/organization/3/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/coollabsio/organization/4/website"><img src="https://opencollective.com/coollabsio/organization/4/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/coollabsio/organization/5/website"><img src="https://opencollective.com/coollabsio/organization/5/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/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>
|
||||
|
||||
|
||||
## Individuals
|
||||
|
||||
<a href="https://opencollective.com/coollabsio"><img src="https://opencollective.com/coollabsio/individuals.svg?width=890"></a>
|
||||
|
||||
# Cloud
|
||||
|
||||
If you do not want to self-host Coolify, there is a paid cloud version available: [app.coolify.io](https://app.coolify.io)
|
||||
|
||||
For more information & pricing, take a look at our landing page [coolify.io](https://coolify.io).
|
||||
|
||||
## Why should I use the Cloud version?
|
||||
The recommended way to use Coolify is to have one server for Coolify and one (or more) for the resources you are deploying. A server is around 4-5$/month.
|
||||
|
||||
By subscribing to the cloud version, you get the Coolify server for the same price, but with:
|
||||
- High-availability
|
||||
- Free email notifications
|
||||
- Better support
|
||||
- Less maintenance for you
|
||||
|
||||
|
||||
# Recognitions
|
||||
|
||||
<p>
|
||||
<a href="https://news.ycombinator.com/item?id=26624341">
|
||||
<img
|
||||
style="width: 250px; height: 54px;" width="250" height="54"
|
||||
alt="Featured on Hacker News"
|
||||
src="https://hackernews-badge.vercel.app/api?id=26624341"
|
||||
/>
|
||||
</a>
|
||||
</p>
|
||||
|
||||
<a href="https://www.producthunt.com/posts/coolify?ref=badge-featured&utm_medium=badge&utm_souce=badge-coolify" target="_blank"><img src="https://api.producthunt.com/widgets/embed-image/v1/featured.svg?post_id=338273&theme=light" alt="Coolify - An open-source & self-hostable Heroku, Netlify alternative | Product Hunt" style="width: 250px; height: 54px;" width="250" height="54" /></a>
|
||||
|
||||
<a href="https://trendshift.io/repositories/634" target="_blank"><img src="https://trendshift.io/api/badge/repositories/634" alt="coollabsio%2Fcoolify | Trendshift" style="width: 250px; height: 55px;" width="250" height="55"/></a>
|
||||
|
||||
# Repo Activity
|
||||
|
||||
![Alt](https://repobeats.axiom.co/api/embed/eab1c8066f9c59d0ad37b76c23ebb5ccac4278ae.svg "Repobeats analytics image")
|
||||
|
||||
# Star History
|
||||
|
||||
[![Star History Chart](https://api.star-history.com/svg?repos=coollabsio/coolify&type=Date)](https://star-history.com/#coollabsio/coolify&Date)
|
@ -57,14 +57,14 @@ private function update()
|
||||
} else {
|
||||
ray('Running update on production server');
|
||||
remote_process([
|
||||
"curl -fsSL https://cdn.lasthourhosting.org/lasthourcloud/scripts/upgrade.sh -o /data/coolify/source/upgrade.sh",
|
||||
"curl -fsSL https://cdn.lasthourhosting.org/lasthourcloudprod/scripts/upgrade.sh -o /data/coolify/source/upgrade.sh",
|
||||
"bash /data/coolify/source/upgrade.sh $this->latestVersion"
|
||||
], $this->server);
|
||||
|
||||
return;
|
||||
}
|
||||
remote_process([
|
||||
'curl -fsSL https://cdn.coollabs.io/coolify/upgrade.sh -o /data/coolify/source/upgrade.sh',
|
||||
"curl -fsSL https://cdn.lasthourhosting.org/lasthourcloudprod/scripts/upgrade.sh -o /data/coolify/source/upgrade.sh",
|
||||
"bash /data/coolify/source/upgrade.sh $this->latestVersion",
|
||||
], $this->server);
|
||||
}
|
||||
|
@ -163,7 +163,7 @@ function get_route_parameters(): array
|
||||
function get_latest_sentinel_version(): string
|
||||
{
|
||||
try {
|
||||
$response = Http::get('https://cdn.lasthourhosting.org/lasthourcloud/versions.json');
|
||||
$response = Http::get('https://cdn.lasthourhosting.org/lasthourcloudprod/versions.json');
|
||||
$versions = $response->json();
|
||||
|
||||
return data_get($versions, 'sentinel.version');
|
||||
|
@ -1,6 +1,6 @@
|
||||
services:
|
||||
coolify:
|
||||
image: "githaven.org/shiloh/lasthourcloud:latest"
|
||||
image: "githaven.org/shiloh/lasthourcloud:prod"
|
||||
volumes:
|
||||
- type: bind
|
||||
source: /data/coolify/source/.env
|
||||
|
@ -336,7 +336,7 @@ class="flex h-6 w-6 shrink-0 items-center justify-center rounded-lg border text-
|
||||
@endpersist
|
||||
@endif
|
||||
<li title="Get Involved">
|
||||
<a class="hover:bg-transparent" href="https://shilohcode.com/get-involved" target="_blank">
|
||||
<a class="hover:bg-transparent" href="https://githaven.org/Shiloh/lasthourcloud" target="_blank">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon hover:text-blue-500" viewBox="0 0 16 16">
|
||||
<path d="M13.5 1a1.5 1.5 0 1 0 0 3 1.5 1.5 0 0 0 0-3M11 2.5a2.5 2.5 0 1 1 .603 1.628l-6.718 3.12a2.5 2.5 0 0 1 0 1.504l6.718 3.12a2.5 2.5 0 1 1-.488.876l-6.718-3.12a2.5 2.5 0 1 1 0-3.256l6.718-3.12A2.5 2.5 0 0 1 11 2.5m-8.5 4a1.5 1.5 0 1 0 0 3 1.5 1.5 0 0 0 0-3m11 5.5a1.5 1.5 0 1 0 0 3 1.5 1.5 0 0 0 0-3"/>
|
||||
=======
|
||||
@ -494,7 +494,7 @@ class="flex h-6 w-6 shrink-0 items-center justify-center rounded-lg border text-
|
||||
@endpersist
|
||||
@endif
|
||||
<li title="Get Involved">
|
||||
<a class="justify-center hover:text-white hover:bg-transparent" href="https://shilohcode.com/get-involved" target="_blank">
|
||||
<a class="justify-center hover:text-white hover:bg-transparent" href="https://githaven.org/Shiloh/lasthourcloud" target="_blank">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon" viewBox="0 0 16 16">
|
||||
<path fill="currentColor" d="M13.5 1a1.5 1.5 0 1 0 0 3 1.5 1.5 0 0 0 0-3M11 2.5a2.5 2.5 0 1 1 .603 1.628l-6.718 3.12a2.5 2.5 0 0 1 0 1.504l6.718 3.12a2.5 2.5 0 1 1-.488.876l-6.718-3.12a2.5 2.5 0 1 1 0-3.256l6.718-3.12A2.5 2.5 0 0 1 11 2.5m-8.5 4a1.5 1.5 0 1 0 0 3 1.5 1.5 0 0 0 0-3m11 5.5a1.5 1.5 0 1 0 0 3 1.5 1.5 0 0 0 0-3" />
|
||||
</svg>
|
||||
|
@ -3,100 +3,143 @@
|
||||
Onboarding | Last Hour Cloud
|
||||
</x-slot>
|
||||
<section class="flex flex-col h-full lg:items-center lg:justify-center">
|
||||
<div class="flex flex-col items-center justify-center p-10 mx-2 mt-10 bg-white border rounded-lg shadow lg:p-20 dark:bg-transparent dark:border-none max-w-7xl ">
|
||||
<div
|
||||
class="flex flex-col items-center justify-center p-10 mx-2 mt-10 bg-white border rounded-lg shadow lg:p-20 dark:bg-transparent dark:border-none max-w-7xl ">
|
||||
@if ($currentState === 'welcome')
|
||||
<h1 class="text-5xl font-bold">Welcome to your Last Hour Cloud</h1>
|
||||
<p class="py-6 text-xl text-center">Let's help you to set up the basics and show you around.</p>
|
||||
<h1 class="text-3xl font-bold lg:text-5xl">Welcome to Last Hour Cloud</h1>
|
||||
<div class="py-6 text-center lg:text-xl">Let's help you get set up.</div>
|
||||
<div class="flex justify-center ">
|
||||
<x-forms.button class="justify-center w-64 box" wire:click="$set('currentState','explanation')">Let's Start
|
||||
<x-forms.button class="justify-center w-64 box-boarding"
|
||||
wire:click="$set('currentState','explanation')">Get
|
||||
Started
|
||||
</x-forms.button>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
<h1 class="text-5xl font-bold">Welcome to your Last Hour Cloud</h1>
|
||||
<p class="py-6 text-xl text-center">Let's help you to set up the basics and show you around.</p>
|
||||
<div class="flex justify-center ">
|
||||
<x-forms.button class="justify-center w-64 box" wire:click="$set('currentState','explanation')">Let's Start
|
||||
</x-forms.button>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
<div>
|
||||
@if ($currentState === 'explanation')
|
||||
<x-boarding-step title="What is this?">
|
||||
@elseif ($currentState === 'explanation')
|
||||
<x-boarding-step title="What is Last Hour Cloud?">
|
||||
<x-slot:question>
|
||||
Last Hour Cloud is an all-in-one application to automate tasks on your servers, deploy applications with Git
|
||||
integrations, deploy databases and services, monitor these resources with notifications and alerts
|
||||
Last Hour Cloud is an all-in-one application to automate tasks on your servers, deploy application with
|
||||
Git
|
||||
integrations, deploy databases and services, monitor these resources with notifications and
|
||||
alerts
|
||||
without vendor lock-in
|
||||
and <a href="https://lasthourhosting.org/cloud.html" class="text-white hover:underline">much much more</a>.
|
||||
and <a href="https://lasthourhosting.org/cloud-apps.html" class="dark:text-white hover:underline">more</a>.
|
||||
<br><br>
|
||||
<span class="text-xl">
|
||||
<x-highlighted text="Self-hosting for the Last Hour Cloud." /></span>
|
||||
<x-highlighted text="Cloud apps for the last hour" /></span>
|
||||
</x-slot:question>
|
||||
<x-slot:explanation>
|
||||
<p><x-highlighted text="Task automation:" /> You do not to manage your servers too much. This does
|
||||
it for you.</p>
|
||||
<p><x-highlighted text="No vendor lock-in:" /> All configurations are stored on your server, so
|
||||
everything works without this (except integrations and automations).</p>
|
||||
<p><x-highlighted text="Monitoring:" />You will get notified on your favourite platform (Discord,
|
||||
Telegram, Email, etc.) when something goes wrong, or if an action is needed from your side.</p>
|
||||
<p>
|
||||
<x-highlighted text="Task automation:" /> You don't need to manage your servers anymore.
|
||||
Last Hour Cloud does
|
||||
it for you.
|
||||
</p>
|
||||
<p>
|
||||
<x-highlighted text="No vendor lock-in:" /> All configurations are stored on your servers, so
|
||||
everything works without a connection to Last Hour Cloud (except integrations and automations).
|
||||
</p>
|
||||
<p>
|
||||
<x-highlighted text="Monitoring:" />You can get notified on your favourite platforms
|
||||
(Discord,
|
||||
Telegram, Email, etc.) when something goes wrong, or an action is needed from your side.
|
||||
</p>
|
||||
</x-slot:explanation>
|
||||
<x-slot:actions>
|
||||
<x-forms.button class="justify-center w-64 box" wire:click="explanation">Next
|
||||
<x-forms.button class="justify-center w-64 box-boarding" wire:click="explanation">Next
|
||||
</x-forms.button>
|
||||
</x-slot:actions>
|
||||
</x-boarding-step>
|
||||
@endif
|
||||
@if ($currentState === 'select-server-type')
|
||||
@elseif ($currentState === 'select-server-type')
|
||||
<x-boarding-step title="Server">
|
||||
<x-slot:question>
|
||||
Do you want to deploy your resources on your <x-highlighted text="Localhost" />
|
||||
or on a <x-highlighted text="Remote Server" />?
|
||||
Do you want to deploy your resources to your
|
||||
<x-highlighted text="Localhost" />
|
||||
or to a
|
||||
<x-highlighted text="Remote Server" />?
|
||||
</x-slot:question>
|
||||
<x-slot:actions>
|
||||
<x-forms.button class="justify-center w-64 box" wire:target="setServerType('localhost')" wire:click="setServerType('localhost')">Localhost
|
||||
<x-forms.button class="justify-center w-64 box-boarding" wire:target="setServerType('localhost')"
|
||||
wire:click="setServerType('localhost')">Localhost
|
||||
</x-forms.button>
|
||||
|
||||
<x-forms.button class="justify-center w-64 box " wire:target="setServerType('remote')" wire:click="setServerType('remote')">Remote Server
|
||||
<x-forms.button class="justify-center w-64 box-boarding " wire:target="setServerType('remote')"
|
||||
wire:click="setServerType('remote')">Remote Server
|
||||
</x-forms.button>
|
||||
|
||||
@if (!$serverReachable)
|
||||
Localhost is not reachable with the following public key.
|
||||
<br /> <br />
|
||||
Please make sure you have the correct public key in your ~/.ssh/authorized_keys file for user
|
||||
'root' or skip the guided tour and add a new private key manually to Last Hour Cloud and to the
|
||||
server.
|
||||
<br />
|
||||
Check the upstream <a target="_blank" class="underline" href="https://coolify.io/docs/server/openssh">documentation</a> for further help.
|
||||
<x-forms.input readonly id="serverPublicKey"></x-forms.input>
|
||||
<x-forms.button class="w-64 box" wire:target="setServerType('localhost')" wire:click="setServerType('localhost')">Check again
|
||||
<div class="mt-6 p-4 border border-error rounded-lg text-gray-800 dark:text-gray-200">
|
||||
<h2 class="text-lg font-bold mb-2">Server is not reachable</h2>
|
||||
<p class="mb-4">Please check the connection details below and correct them if they are
|
||||
incorrect.</p>
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-4">
|
||||
<x-forms.input placeholder="Default is 22" label="Port" id="remoteServerPort"
|
||||
wire:model="remoteServerPort" :value="$remoteServerPort" />
|
||||
<div>
|
||||
<x-forms.input placeholder="Default is root" label="User" id="remoteServerUser"
|
||||
wire:model="remoteServerUser" :value="$remoteServerUser" />
|
||||
<p class="text-xs mt-1">
|
||||
Non-root user is experimental:
|
||||
<a class="font-bold underline" target="_blank"
|
||||
href="https://coolify.io/docs/knowledge-base/server/non-root-user">See upstream docs</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-4">
|
||||
<p class="mb-2">If the connection details are correct, please ensure:</p>
|
||||
<ul class="list-disc list-inside">
|
||||
<li>The correct public key is in your <code
|
||||
class="bg-red-200 dark:bg-red-900 px-1 rounded">~/.ssh/authorized_keys</code>
|
||||
file for the specified user</li>
|
||||
<li>Or skip the boarding process and manually add a new private key to Last Hour Cloud and
|
||||
the server</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<p class="mb-4">
|
||||
For more help, check this <a target="_blank" class="underline font-semibold"
|
||||
href="https://coolify.io/docs/knowledge-base/server/openssh">upstream documentation</a>.
|
||||
</p>
|
||||
|
||||
<x-forms.input readonly id="serverPublicKey" class="mb-4"
|
||||
label="Current Public Key"></x-forms.input>
|
||||
|
||||
<x-forms.button class="w-full box-boarding" wire:click="saveAndValidateServer">
|
||||
Check Again
|
||||
</x-forms.button>
|
||||
</div>
|
||||
@endif
|
||||
</x-slot:actions>
|
||||
<x-slot:explanation>
|
||||
<p>Servers are the main building blocks, as they will host your applications, databases,
|
||||
services, called resources. Any CPU intensive process will use the server's CPU where you
|
||||
are deploying your resources.</p>
|
||||
<p>Localhost is the server where Last Hour Cloud is running on. It is not recommended to use one server
|
||||
for everything.</p>
|
||||
<p>Remote Server is a server reachable through SSH. It can be hosted at home, or from any cloud
|
||||
provider.</p>
|
||||
<p>
|
||||
<x-highlighted text="Localhost" /> is the server where Last Hour Cloud is running on. It is not
|
||||
recommended to use one server
|
||||
for everything.
|
||||
</p>
|
||||
<p>
|
||||
<x-highlighted text="A remote server" /> is a server reachable through SSH. It can be hosted
|
||||
at home, or from any cloud
|
||||
provider.
|
||||
</p>
|
||||
</x-slot:explanation>
|
||||
</x-boarding-step>
|
||||
@endif
|
||||
</div>
|
||||
<div>
|
||||
@if ($currentState === 'private-key')
|
||||
@elseif ($currentState === 'private-key')
|
||||
<x-boarding-step title="SSH Key">
|
||||
<x-slot:question>
|
||||
Do you have your own SSH Private Key?
|
||||
</x-slot:question>
|
||||
<x-slot:actions>
|
||||
<x-forms.button class="justify-center w-64 box" wire:target="setPrivateKey('own')" wire:click="setPrivateKey('own')">Yes
|
||||
<x-forms.button class="justify-center lg:w-64 box-boarding" wire:target="setPrivateKey('own')"
|
||||
wire:click="setPrivateKey('own')">Yes
|
||||
</x-forms.button>
|
||||
<x-forms.button class="justify-center w-64 box" wire:target="setPrivateKey('create')" wire:click="setPrivateKey('create')">No (create one for me)
|
||||
<x-forms.button class="justify-center lg:w-64 box-boarding" wire:target="setPrivateKey('create')"
|
||||
wire:click="setPrivateKey('create')">No (create one for me)
|
||||
</x-forms.button>
|
||||
@if (count($privateKeys) > 0)
|
||||
<form wire:submit='selectExistingPrivateKey' class="flex flex-col w-full gap-4 pr-10">
|
||||
<form wire:submit='selectExistingPrivateKey' class="flex flex-col w-full gap-4 lg:pr-10">
|
||||
<x-forms.select label="Existing SSH Keys" id='selectedExistingPrivateKey'>
|
||||
@foreach ($privateKeys as $privateKey)
|
||||
<option wire:key="{{ $loop->index }}" value="{{ $privateKey->id }}">
|
||||
@ -110,17 +153,14 @@
|
||||
</x-slot:actions>
|
||||
<x-slot:explanation>
|
||||
<p>SSH Keys are used to connect to a remote server through a secure shell, called SSH.</p>
|
||||
<p>You can use your own ssh private key, or you can allow Last Hour Cloud to create one for you.</p>
|
||||
<p>You can use your own ssh private key, or you can let Last Hour Cloud to create one for you.</p>
|
||||
<p>In both ways, you need to add the public version of your ssh private key to the remote
|
||||
server's
|
||||
<code class="text-warning">~/.ssh/authorized_keys</code> file.
|
||||
<code class="dark:text-warning">~/.ssh/authorized_keys</code> file.
|
||||
</p>
|
||||
</x-slot:explanation>
|
||||
</x-boarding-step>
|
||||
@endif
|
||||
</div>
|
||||
<div>
|
||||
@if ($currentState === 'select-existing-server')
|
||||
@elseif ($currentState === 'select-existing-server')
|
||||
<x-boarding-step title="Select a server">
|
||||
<x-slot:question>
|
||||
There are already servers available for your Team. Do you want to use one of them?
|
||||
@ -128,9 +168,8 @@
|
||||
<x-slot:actions>
|
||||
<div class="flex flex-col gap-4">
|
||||
<div>
|
||||
<x-forms.button class="justify-center w-64 box" wire:click="createNewServer">No (create one
|
||||
for
|
||||
me)
|
||||
<x-forms.button class="justify-center w-64 box-boarding" wire:click="createNewServer">No
|
||||
(create one for me)
|
||||
</x-forms.button>
|
||||
</div>
|
||||
<div>
|
||||
@ -147,241 +186,75 @@
|
||||
</div>
|
||||
</div>
|
||||
@if (!$serverReachable)
|
||||
This server is not reachable with the following public key.
|
||||
<br /> <br />
|
||||
Please make sure you have the correct public key in your ~/.ssh/authorized_keys file for user
|
||||
'root' or skip the boarding process and add a new private key manually to Last Hour Cloud and to the
|
||||
server.
|
||||
<x-forms.input readonly id="serverPublicKey"></x-forms.input>
|
||||
<x-forms.button class="w-64 box" wire:target="validateServer" wire:click="validateServer">Check
|
||||
again
|
||||
</x-forms.button>
|
||||
@endif
|
||||
</x-slot:actions>
|
||||
<x-slot:explanation>
|
||||
<p>Private Keys are used to connect to a remote server through a secure shell, called SSH.</p>
|
||||
<p>You can use your own private key, or you can let Last Hour Cloud create one for you.</p>
|
||||
<p>In both ways, you need to add the public version of your private key to the remote server's
|
||||
<code>~/.ssh/authorized_keys</code> file.
|
||||
</p>
|
||||
</x-slot:explanation>
|
||||
</x-boarding-step>
|
||||
@endif
|
||||
</div>
|
||||
<div>
|
||||
@if ($currentState === 'create-private-key')
|
||||
<x-boarding-step title="Create Private Key">
|
||||
<x-slot:question>
|
||||
Please let me know your key details.
|
||||
</x-slot:question>
|
||||
<x-slot:actions>
|
||||
<form wire:submit='savePrivateKey' class="flex flex-col w-full gap-4 pr-10">
|
||||
<x-forms.input required placeholder="Choose a name for your Private Key. Could be anything." label="Name" id="privateKeyName" />
|
||||
<x-forms.input placeholder="Description, so others will know more about this." label="Description" id="privateKeyDescription" />
|
||||
<x-forms.textarea required placeholder="-----BEGIN OPENSSH PRIVATE KEY-----" label="Private Key" id="privateKey" />
|
||||
@if ($privateKeyType === 'create')
|
||||
<x-forms.textarea rows="7" readonly label="Public Key" id="publicKey" />
|
||||
<span class="font-bold text-warning">ACTION REQUIRED: Copy the 'Public Key' to your server's
|
||||
~/.ssh/authorized_keys
|
||||
file.</span>
|
||||
@endif
|
||||
<x-forms.button type="submit">Save</x-forms.button>
|
||||
</form>
|
||||
</x-slot:actions>
|
||||
<x-slot:explanation>
|
||||
<p>Private Keys are used to connect to a remote server through a secure shell, called SSH.</p>
|
||||
<p>You can use your own private key, or you can let Last Hour Cloud create one for you.</p>
|
||||
<p>In both ways, you need to add the public version of your private key to the remote server's
|
||||
<code>~/.ssh/authorized_keys</code> file.
|
||||
</p>
|
||||
</x-slot:explanation>
|
||||
</x-boarding-step>
|
||||
@endif
|
||||
</div>
|
||||
<div>
|
||||
@if ($currentState === 'create-server')
|
||||
<x-boarding-step title="Create a Server">
|
||||
<x-slot:question>
|
||||
Please let us know your server details.
|
||||
</x-slot:question>
|
||||
<x-slot:actions>
|
||||
<form wire:submit='saveServer' class="flex flex-col w-full gap-4 pr-10">
|
||||
<div class="flex gap-2">
|
||||
<x-forms.input required placeholder="Choose a name for your Server. It could be anything." label="Name" id="remoteServerName" />
|
||||
<x-forms.input placeholder="Description, so others will know more about it." label="Description" id="remoteServerDescription" />
|
||||
</div>
|
||||
<div class="flex gap-2">
|
||||
<x-forms.input required placeholder="127.0.0.1" label="IP Address" id="remoteServerHost" />
|
||||
<x-forms.input required placeholder="Port number of your server. Default is 22." label="Port" id="remoteServerPort" />
|
||||
<x-forms.input required readonly placeholder="Username to connect to your server. Default is root." label="Username" id="remoteServerUser" />
|
||||
</div>
|
||||
<div class="w-64">
|
||||
<x-forms.checkbox helper="If you are using Cloudflare Tunnels, enable this. It will proxy all ssh requests to your server through Cloudflare.<br><span class='text-warning'>Last Hour Cloud does not install/setup Cloudflare (cloudflared) on your server.</span>" id="isCloudflareTunnel" label="Cloudflare Tunnel" />
|
||||
</div>
|
||||
<x-forms.button type="submit">Continue</x-forms.button>
|
||||
</form>
|
||||
</x-slot:actions>
|
||||
<x-slot:explanation>
|
||||
<p>Username should be <x-highlighted text="root" /> for now. We are working on using
|
||||
non-root users.</p>
|
||||
</x-slot:explanation>
|
||||
</x-boarding-step>
|
||||
@endif
|
||||
</div>
|
||||
<div>
|
||||
@if ($currentState === 'validate-server')
|
||||
<x-boarding-step title="Validate & Configure Server">
|
||||
<x-slot:question>
|
||||
we need to validate your server (connection, Docker Engine, etc) and configure to see if something is
|
||||
missing. Are you okay with this?
|
||||
</x-slot:question>
|
||||
<x-slot:actions>
|
||||
<x-slide-over closeWithX fullScreen>
|
||||
<x-slot:title>Validate & configure</x-slot:title>
|
||||
<x-slot:content>
|
||||
<livewire:server.validate-and-install :server="$this->createdServer" />
|
||||
</x-slot:content>
|
||||
<x-forms.button @click="slideOverOpen=true" class="font-bold box w-96" wire:click.prevent='installServer' isHighlighted>
|
||||
Send it!
|
||||
</x-forms.button>
|
||||
</x-slot:actions>
|
||||
</x-boarding-step>
|
||||
@endif
|
||||
@if ($currentState === 'select-server-type')
|
||||
<x-boarding-step title="Server">
|
||||
<x-slot:question>
|
||||
Do you want to deploy your resources on your <x-highlighted text="Localhost" />
|
||||
or on a <x-highlighted text="Remote Server" />?
|
||||
</x-slot:question>
|
||||
<x-slot:actions>
|
||||
<x-forms.button class="justify-center w-64 box" wire:target="setServerType('localhost')" wire:click="setServerType('localhost')">Localhost
|
||||
</x-forms.button>
|
||||
<div class="mt-6 p-4 bg-red-100 dark:bg-red-950 rounded-lg text-gray-800 dark:text-gray-200">
|
||||
<h2 class="text-lg font-bold mb-2">Server is not reachable</h2>
|
||||
<p class="mb-4">Please check the connection details below and correct them if they are
|
||||
incorrect.</p>
|
||||
|
||||
<x-forms.button class="justify-center w-64 box " wire:target="setServerType('remote')" wire:click="setServerType('remote')">Remote Server
|
||||
</x-forms.button>
|
||||
@if (!$serverReachable)
|
||||
Localhost is not reachable with the following public key.
|
||||
<br /> <br />
|
||||
Please make sure you have the correct public key in your ~/.ssh/authorized_keys file for user
|
||||
'root' or skip the guided tour and add a new private key manually to Last Hour Cloud and to the
|
||||
server.
|
||||
<br />
|
||||
Check the upstream <a target="_blank" class="underline" href="https://coolify.io/docs/server/openssh">documentation</a> for further help.
|
||||
<x-forms.input readonly id="serverPublicKey"></x-forms.input>
|
||||
<x-forms.button class="w-64 box" wire:target="setServerType('localhost')" wire:click="setServerType('localhost')">Check again
|
||||
</x-forms.button>
|
||||
@endif
|
||||
</x-slot:actions>
|
||||
<x-slot:explanation>
|
||||
<p>Servers are the main building blocks, as they will host your applications, databases,
|
||||
services, called resources. Any CPU intensive process will use the server's CPU where you
|
||||
are deploying your resources.</p>
|
||||
<p>Localhost is the server where Last Hour Cloud is running on. It is not recommended to use one server
|
||||
for everything.</p>
|
||||
<p>Remote Server is a server reachable through SSH. It can be hosted at home, or from any cloud
|
||||
provider.</p>
|
||||
</x-slot:explanation>
|
||||
</x-boarding-step>
|
||||
@endif
|
||||
</div>
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-4">
|
||||
<x-forms.input placeholder="Default is 22" label="Port" id="remoteServerPort"
|
||||
wire:model="remoteServerPort" :value="$remoteServerPort" />
|
||||
<div>
|
||||
@if ($currentState === 'private-key')
|
||||
<x-boarding-step title="SSH Key">
|
||||
<x-slot:question>
|
||||
Do you have your own SSH Private Key?
|
||||
</x-slot:question>
|
||||
<x-slot:actions>
|
||||
<x-forms.button class="justify-center w-64 box" wire:target="setPrivateKey('own')" wire:click="setPrivateKey('own')">Yes
|
||||
</x-forms.button>
|
||||
<x-forms.button class="justify-center w-64 box" wire:target="setPrivateKey('create')" wire:click="setPrivateKey('create')">No (create one for me)
|
||||
</x-forms.button>
|
||||
@if (count($privateKeys) > 0)
|
||||
<form wire:submit='selectExistingPrivateKey' class="flex flex-col w-full gap-4 pr-10">
|
||||
<x-forms.select label="Existing SSH Keys" id='selectedExistingPrivateKey'>
|
||||
@foreach ($privateKeys as $privateKey)
|
||||
<option wire:key="{{ $loop->index }}" value="{{ $privateKey->id }}">
|
||||
{{ $privateKey->name }}
|
||||
</option>
|
||||
@endforeach
|
||||
</x-forms.select>
|
||||
<x-forms.button type="submit">Use this SSH Key</x-forms.button>
|
||||
</form>
|
||||
@endif
|
||||
</x-slot:actions>
|
||||
<x-slot:explanation>
|
||||
<p>SSH Keys are used to connect to a remote server through a secure shell, called SSH.</p>
|
||||
<p>You can use your own ssh private key, or you can allow Last Hour Cloud to create one for you.</p>
|
||||
<p>In both ways, you need to add the public version of your ssh private key to the remote
|
||||
server's
|
||||
<code class="text-warning">~/.ssh/authorized_keys</code> file.
|
||||
<x-forms.input placeholder="Default is root" label="User" id="remoteServerUser"
|
||||
wire:model="remoteServerUser" :value="$remoteServerUser" />
|
||||
<p class="text-xs mt-1">
|
||||
Non-root user is experimental:
|
||||
<a class="font-bold underline" target="_blank"
|
||||
href="https://coolify.io/docs/knowledge-base/server/non-root-user">upstream docs</a>
|
||||
</p>
|
||||
</x-slot:explanation>
|
||||
</x-boarding-step>
|
||||
@endif
|
||||
</div>
|
||||
<div>
|
||||
@if ($currentState === 'select-existing-server')
|
||||
<x-boarding-step title="Select a server">
|
||||
<x-slot:question>
|
||||
There are already servers available for your Team. Do you want to use one of them?
|
||||
</x-slot:question>
|
||||
<x-slot:actions>
|
||||
<div class="flex flex-col gap-4">
|
||||
<div>
|
||||
<x-forms.button class="justify-center w-64 box" wire:click="createNewServer">No (create one
|
||||
for
|
||||
me)
|
||||
</div>
|
||||
|
||||
<div class="mb-4">
|
||||
<p class="mb-2">If the connection details are correct, please ensure:</p>
|
||||
<ul class="list-disc list-inside">
|
||||
<li>The correct public key is in your <code
|
||||
class="bg-red-200 dark:bg-red-900 px-1 rounded">~/.ssh/authorized_keys</code>
|
||||
file for the specified user</li>
|
||||
<li>Or skip the boarding process and manually add a new private key to Last Hour Cloud and
|
||||
the server</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<p class="mb-4">
|
||||
For more help, check this <a target="_blank" class="underline font-semibold"
|
||||
href="https://coolify.io/docs/knowledge-base/server/openssh">upstream documentation</a>.
|
||||
</p>
|
||||
|
||||
<x-forms.input readonly id="serverPublicKey" class="mb-4"
|
||||
label="Current Public Key"></x-forms.input>
|
||||
|
||||
<x-forms.button class="w-full md:w-auto box-boarding" wire:click="saveAndValidateServer">
|
||||
Check again
|
||||
</x-forms.button>
|
||||
</div>
|
||||
<div>
|
||||
<form wire:submit='selectExistingServer' class="flex flex-col w-full gap-4 lg:w-96">
|
||||
<x-forms.select label="Existing servers" class="w-96" id='selectedExistingServer'>
|
||||
@foreach ($servers as $server)
|
||||
<option wire:key="{{ $loop->index }}" value="{{ $server->id }}">
|
||||
{{ $server->name }}
|
||||
</option>
|
||||
@endforeach
|
||||
</x-forms.select>
|
||||
<x-forms.button type="submit">Use this Server</x-forms.button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
@if (!$serverReachable)
|
||||
This server is not reachable with the following public key.
|
||||
<br /> <br />
|
||||
Please make sure you have the correct public key in your ~/.ssh/authorized_keys file for user
|
||||
'root' or skip the boarding process and add a new private key manually to Last Hour Cloud and to the
|
||||
server.
|
||||
<x-forms.input readonly id="serverPublicKey"></x-forms.input>
|
||||
<x-forms.button class="w-64 box" wire:target="validateServer" wire:click="validateServer">Check
|
||||
again
|
||||
</x-forms.button>
|
||||
@endif
|
||||
</x-slot:actions>
|
||||
<x-slot:explanation>
|
||||
<p>Private Keys are used to connect to a remote server through a secure shell, called SSH.</p>
|
||||
<p>You can use your own private key, or you can let Last Hour Cloud create one for you.</p>
|
||||
<p>You can use your own private key, or you can let Last Hour Cloud to create one for you.</p>
|
||||
<p>In both ways, you need to add the public version of your private key to the remote server's
|
||||
<code>~/.ssh/authorized_keys</code> file.
|
||||
</p>
|
||||
</x-slot:explanation>
|
||||
</x-boarding-step>
|
||||
@endif
|
||||
</div>
|
||||
<div>
|
||||
@if ($currentState === 'create-private-key')
|
||||
@elseif ($currentState === 'create-private-key')
|
||||
<x-boarding-step title="Create Private Key">
|
||||
<x-slot:question>
|
||||
Please let me know your key details.
|
||||
</x-slot:question>
|
||||
<x-slot:actions>
|
||||
<form wire:submit='savePrivateKey' class="flex flex-col w-full gap-4 pr-10">
|
||||
<x-forms.input required placeholder="Choose a name for your Private Key. Could be anything." label="Name" id="privateKeyName" />
|
||||
<x-forms.input placeholder="Description, so others will know more about this." label="Description" id="privateKeyDescription" />
|
||||
<x-forms.textarea required placeholder="-----BEGIN OPENSSH PRIVATE KEY-----" label="Private Key" id="privateKey" />
|
||||
<form wire:submit='savePrivateKey' class="flex flex-col w-full gap-4 lg:pr-10">
|
||||
<x-forms.input required placeholder="Choose a name for your Private Key. Could be anything."
|
||||
label="Name" id="privateKeyName" />
|
||||
<x-forms.input placeholder="Description, so others will know more about this."
|
||||
label="Description" id="privateKeyDescription" />
|
||||
<x-forms.textarea required placeholder="-----BEGIN OPENSSH PRIVATE KEY-----"
|
||||
label="Private Key" id="privateKey" />
|
||||
@if ($privateKeyType === 'create')
|
||||
<x-forms.textarea rows="7" readonly label="Public Key" id="publicKey" />
|
||||
<span class="font-bold text-warning">ACTION REQUIRED: Copy the 'Public Key' to your server's
|
||||
<span class="font-bold dark:text-warning">ACTION REQUIRED: Copy the 'Public Key' to your
|
||||
server's
|
||||
~/.ssh/authorized_keys
|
||||
file.</span>
|
||||
@endif
|
||||
@ -390,50 +263,62 @@
|
||||
</x-slot:actions>
|
||||
<x-slot:explanation>
|
||||
<p>Private Keys are used to connect to a remote server through a secure shell, called SSH.</p>
|
||||
<p>You can use your own private key, or you can let Last Hour Cloud create one for you.</p>
|
||||
<p>You can use your own private key, or you can let Last Hour Cloud to create one for you.</p>
|
||||
<p>In both ways, you need to add the public version of your private key to the remote server's
|
||||
<code>~/.ssh/authorized_keys</code> file.
|
||||
</p>
|
||||
</x-slot:explanation>
|
||||
</x-boarding-step>
|
||||
@endif
|
||||
</div>
|
||||
<div>
|
||||
@if ($currentState === 'create-server')
|
||||
<x-boarding-step title="Create a Server">
|
||||
@elseif ($currentState === 'create-server')
|
||||
<x-boarding-step title="Create Server">
|
||||
<x-slot:question>
|
||||
Please let us know your server details.
|
||||
Please let me know your server details.
|
||||
</x-slot:question>
|
||||
<x-slot:actions>
|
||||
<form wire:submit='saveServer' class="flex flex-col w-full gap-4 pr-10">
|
||||
<div class="flex gap-2">
|
||||
<x-forms.input required placeholder="Choose a name for your Server. It could be anything." label="Name" id="remoteServerName" />
|
||||
<x-forms.input placeholder="Description, so others will know more about it." label="Description" id="remoteServerDescription" />
|
||||
<form wire:submit='saveServer' class="flex flex-col w-full gap-4 lg:pr-10">
|
||||
<div class="flex flex-col gap-2 lg:flex-row">
|
||||
<x-forms.input required placeholder="Choose a name for your Server. Could be anything."
|
||||
label="Name" id="remoteServerName" wire:model="remoteServerName" />
|
||||
<x-forms.input placeholder="Description, so others will know more about this."
|
||||
label="Description" id="remoteServerDescription"
|
||||
wire:model="remoteServerDescription" />
|
||||
</div>
|
||||
<div class="flex gap-2">
|
||||
<x-forms.input required placeholder="127.0.0.1" label="IP Address" id="remoteServerHost" />
|
||||
<x-forms.input required placeholder="Port number of your server. Default is 22." label="Port" id="remoteServerPort" />
|
||||
<x-forms.input required readonly placeholder="Username to connect to your server. Default is root." label="Username" id="remoteServerUser" />
|
||||
<div class="flex flex-col gap-2 lg:flex-row ">
|
||||
<x-forms.input required placeholder="127.0.0.1" label="IP Address" id="remoteServerHost"
|
||||
wire:model="remoteServerHost" />
|
||||
</div>
|
||||
<div class="w-64">
|
||||
<x-forms.checkbox helper="If you are using Cloudflare Tunnels, enable this. It will proxy all ssh requests to your server through Cloudflare.<br><span class='text-warning'>Last Hour Cloud does not install/setup Cloudflare (cloudflared) on your server.</span>" id="isCloudflareTunnel" label="Cloudflare Tunnel" />
|
||||
<div x-data="{ showAdvanced: false }" class="flex flex-col gap-2">
|
||||
<button @click="showAdvanced = !showAdvanced" type="button"
|
||||
class="text-left text-sm text-gray-600 dark:text-gray-300 hover:underline">
|
||||
Advanced Settings
|
||||
</button>
|
||||
<div x-show="showAdvanced" class="flex flex-col gap-2 lg:flex-row">
|
||||
<x-forms.input placeholder="Port number of your server. Default is 22." label="Port"
|
||||
id="remoteServerPort" wire:model="remoteServerPort" />
|
||||
<div class="w-full">
|
||||
<x-forms.input placeholder="Default is root." label="User"
|
||||
id="remoteServerUser" wire:model="remoteServerUser" />
|
||||
<div class="text-xs text-gray-600 dark:text-gray-300">Non-root user is
|
||||
experimental: <a class="font-bold underline" target="_blank"
|
||||
href="https://coolify.io/docs/knowledge-base/server/non-root-user">upstream docs</a>.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="lg:w-64">
|
||||
<x-forms.checkbox
|
||||
helper="If you are using Cloudflare Tunnels, enable this. It will proxy all ssh requests to your server through Cloudflare.<br><span class='dark:text-warning'>Coolify does not install/setup Cloudflare (cloudflared) on your server.</span>"
|
||||
id="isCloudflareTunnel" label="Cloudflare Tunnel" wire:model="isCloudflareTunnel" />
|
||||
</div>
|
||||
<x-forms.button type="submit">Continue</x-forms.button>
|
||||
</form>
|
||||
</x-slot:actions>
|
||||
<x-slot:explanation>
|
||||
<p>Username should be <x-highlighted text="root" /> for now. We are working on using
|
||||
non-root users.</p>
|
||||
</x-slot:explanation>
|
||||
</x-boarding-step>
|
||||
@endif
|
||||
</div>
|
||||
<div>
|
||||
@if ($currentState === 'validate-server')
|
||||
@elseif ($currentState === 'validate-server')
|
||||
<x-boarding-step title="Validate & Configure Server">
|
||||
<x-slot:question>
|
||||
we need to validate your server (connection, Docker Engine, etc) and configure to see if something is
|
||||
missing. Are you okay with this?
|
||||
I need to validate your server (connection, Docker Engine, etc) and configure if something is
|
||||
missing for me. Are you okay with this?
|
||||
</x-slot:question>
|
||||
<x-slot:actions>
|
||||
<x-slide-over closeWithX fullScreen>
|
||||
@ -441,65 +326,39 @@
|
||||
<x-slot:content>
|
||||
<livewire:server.validate-and-install :server="$this->createdServer" />
|
||||
</x-slot:content>
|
||||
<x-forms.button @click="slideOverOpen=true" class="font-bold box w-96" wire:click.prevent='installServer' isHighlighted>
|
||||
Send it!
|
||||
<x-forms.button @click="slideOverOpen=true" class="w-full font-bold box-boarding lg:w-96"
|
||||
wire:click.prevent='installServer' isHighlighted>
|
||||
Let's do it!
|
||||
</x-forms.button>
|
||||
</x-slide-over>
|
||||
</x-slot:actions>
|
||||
<x-slot:explanation>
|
||||
<p>This will install the latest Docker Engine on your server, configure a few things to be able
|
||||
to run optimal.<br><br>Minimum Docker Engine version is: 22<br><br>To manually install Docker
|
||||
Engine, check <a target="_blank" class="underline text-warning" href="https://docs.docker.com/engine/install/#server">this
|
||||
to run optimal.<br><br>Minimum Docker Engine version is: 22<br><br>To manually install
|
||||
Docker
|
||||
Engine, check <a target="_blank" class="underline dark:text-warning"
|
||||
href="https://docs.docker.com/engine/install/#server">this
|
||||
documentation</a>.</p>
|
||||
</x-slot:explanation>
|
||||
</x-boarding-step>
|
||||
@endif
|
||||
</div>
|
||||
{{-- <div>
|
||||
@if ($currentState === 'select-proxy')
|
||||
<x-boarding-step title="Select a Proxy">
|
||||
<x-slot:question>
|
||||
If you would like to attach any kind of domain to your resources, you need a proxy.
|
||||
</x-slot:question>
|
||||
<x-slot:actions>
|
||||
<x-forms.button wire:click="selectProxy" class="w-64 box">
|
||||
Decide later
|
||||
</x-forms.button>
|
||||
<x-forms.button class="w-32 box" wire:click="selectProxy('{{ ProxyTypes::TRAEFIK_V2 }}')">
|
||||
Traefik
|
||||
v2
|
||||
</x-forms.button>
|
||||
<x-forms.button disabled class="w-32 box">
|
||||
Nginx
|
||||
</x-forms.button>
|
||||
<x-forms.button disabled class="w-32 box">
|
||||
Caddy
|
||||
</x-forms.button>
|
||||
</x-slot:actions>
|
||||
<x-slot:explanation>
|
||||
<p>This will install the latest Docker Engine on your server and configure a few items to be able
|
||||
to run optimally.</p>
|
||||
</x-slot:explanation>
|
||||
</x-boarding-step>
|
||||
@endif
|
||||
</div> --}}
|
||||
<div>
|
||||
@if ($currentState === 'create-project')
|
||||
@elseif ($currentState === 'create-project')
|
||||
<x-boarding-step title="Project">
|
||||
<x-slot:question>
|
||||
@if (count($projects) > 0)
|
||||
You already have some projects. Do you want to use one of them or should we create a new one for
|
||||
You already have some projects. Do you want to use one of them or should I create a new one
|
||||
for
|
||||
you?
|
||||
@else
|
||||
We will create an initial project for you. You can change it later on.
|
||||
Let's create an initial project for you. You can change all the details later on.
|
||||
@endif
|
||||
</x-slot:question>
|
||||
<x-slot:actions>
|
||||
<x-forms.button class="justify-center w-64 box" wire:click="createNewProject">Create New Project</x-forms.button>
|
||||
<x-forms.button class="justify-center w-64 box-boarding" wire:click="createNewProject">Create new
|
||||
project!</x-forms.button>
|
||||
<div>
|
||||
@if (count($projects) > 0)
|
||||
<form wire:submit='selectExistingProject' class="flex flex-col w-full gap-4 lg:w-96">
|
||||
<x-forms.select label="Existing projects" class="w-96" id='selectedExistingProject'>
|
||||
<x-forms.select label="Existing projects" class="w-96" id='selectedProject'>
|
||||
@foreach ($projects as $project)
|
||||
<option wire:key="{{ $loop->index }}" value="{{ $project->id }}">
|
||||
{{ $project->name }}
|
||||
@ -512,32 +371,42 @@
|
||||
</div>
|
||||
</x-slot:actions>
|
||||
<x-slot:explanation>
|
||||
<p>Projects put together several resources into one virtual group. There are no
|
||||
limitations on the number of projects you can have here.</p>
|
||||
<p>Each project should have at least one environment. This helps you to create a production &
|
||||
<p>Projects contain several resources combined into one virtual group. There are no
|
||||
limitations on the number of projects you can add.</p>
|
||||
<p>Each project should have at least one environment, this allows you to create a production &
|
||||
staging version of the same application, but grouped separately.</p>
|
||||
</x-slot:explanation>
|
||||
</x-boarding-step>
|
||||
@endif
|
||||
</div>
|
||||
<div>
|
||||
@if ($currentState === 'create-resource')
|
||||
@elseif ($currentState === 'create-resource')
|
||||
<x-boarding-step title="Resources">
|
||||
<x-slot:question>
|
||||
Next we will redirect you to the resource page, where you can create your first resource.
|
||||
Let's go to the new resource page, where you can create your first resource.
|
||||
</x-slot:question>
|
||||
<x-slot:actions>
|
||||
<div class="items-center justify-center w-64 box" wire:click="showNewResource">Let's do
|
||||
<div class="items-center justify-center w-64 box-boarding" wire:click="showNewResource">Let's do
|
||||
it!</div>
|
||||
</x-slot:actions>
|
||||
<x-slot:explanation>
|
||||
<p>A resource is an application, a database or a service (like WordPress).</p>
|
||||
<p>A resource could be an application, a database or a service (like WordPress).</p>
|
||||
</x-slot:explanation>
|
||||
</x-boarding-step>
|
||||
@endif
|
||||
</div>
|
||||
<div class="flex justify-center gap-2 pt-4">
|
||||
<a wire:click='skipBoarding'>Skip Guided Tour</a>
|
||||
<a wire:click='restartBoarding'>Restart Guided Tour</a>
|
||||
<div class="flex flex-col justify-center gap-4 pt-4 lg:gap-2 lg:flex">
|
||||
<div class="flex justify-center w-full gap-2">
|
||||
<div class="cursor-pointer hover:underline dark:hover:text-white" wire:click='skipBoarding'>Skip
|
||||
onboarding</div>
|
||||
<div class="cursor-pointer hover:underline dark:hover:text-white" wire:click='restartBoarding'>Restart
|
||||
onboarding</div>
|
||||
</div>
|
||||
<x-modal-input title="How can we help?">
|
||||
<x-slot:content>
|
||||
<div class="w-full text-center cursor-pointer hover:underline dark:hover:text-white"
|
||||
title="Send us feedback or get help!">
|
||||
Feedback
|
||||
</div>
|
||||
</x-slot:content>
|
||||
<livewire:help />
|
||||
</x-modal-input>
|
||||
</div>
|
||||
</section>
|
@ -2,7 +2,7 @@ set -e
|
||||
export IMAGE=$1
|
||||
docker system prune -af
|
||||
docker compose pull
|
||||
read -p "Press Enter to update Coolify to $IMAGE..." </dev/tty
|
||||
read -p "Press Enter to update Last Hour Cloud to $IMAGE..." </dev/tty
|
||||
docker exec coolify sh -c "php artisan tinker --execute='isAnyDeploymentInprogress()'"
|
||||
docker compose up --remove-orphans --force-recreate -d --wait
|
||||
echo $IMAGE > last_version
|
||||
|
@ -1,283 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e # Exit immediately if a command exits with a non-zero status
|
||||
## $1 could be empty, so we need to disable this check
|
||||
#set -u # Treat unset variables as an error and exit
|
||||
set -o pipefail # Cause a pipeline to return the status of the last command that exited with a non-zero status
|
||||
|
||||
VERSION="1.2.2"
|
||||
DOCKER_VERSION="24.0"
|
||||
|
||||
CDN="https://cdn.lasthourhosting.org/lasthourcloud"
|
||||
OS_TYPE=$(grep -w "ID" /etc/os-release | cut -d "=" -f 2 | tr -d '"')
|
||||
|
||||
if [ "$OS_TYPE" = "arch" ]; then
|
||||
OS_VERSION="rolling"
|
||||
else
|
||||
OS_VERSION=$(grep -w "VERSION_ID" /etc/os-release | cut -d "=" -f 2 | tr -d '"')
|
||||
fi
|
||||
|
||||
LATEST_VERSION=$(wget -q -O - $CDN/versions.json | grep -i version | sed -n '2p' | xargs | awk '{print $2}' | tr -d ',')
|
||||
DATE=$(date +"%Y%m%d-%H%M%S")
|
||||
|
||||
if [ $EUID != 0 ]; then
|
||||
echo "Please run as root"
|
||||
exit
|
||||
fi
|
||||
|
||||
case "$OS_TYPE" in
|
||||
arch | ubuntu | debian | raspbian | centos | fedora | rhel | ol | rocky | sles | opensuse-leap | opensuse-tumbleweed | almalinux) ;;
|
||||
*)
|
||||
echo "This script only supports Debian, Redhat, Arch Linux, or SLES based operating systems for now."
|
||||
exit
|
||||
;;
|
||||
esac
|
||||
|
||||
# Overwrite LATEST_VERSION if user pass a version number
|
||||
if [ "$1" != "" ]; then
|
||||
LATEST_VERSION=$1
|
||||
LATEST_VERSION="${LATEST_VERSION,,}"
|
||||
LATEST_VERSION="${LATEST_VERSION#v}"
|
||||
fi
|
||||
|
||||
echo -e "-------------"
|
||||
echo -e "Welcome to Last Hour Cloud v4 development installer!"
|
||||
echo -e "This script will install everything for you."
|
||||
echo -e "(Source code: https://githaven.org/Shiloh/lasthourcloud/src/branch/main/scripts/dev_install.sh)\n"
|
||||
echo -e "-------------"
|
||||
|
||||
echo "OS: $OS_TYPE $OS_VERSION"
|
||||
echo "Last Hour Cloud version: $LATEST_VERSION"
|
||||
|
||||
echo -e "-------------"
|
||||
echo "Installing required packages..."
|
||||
|
||||
case "$OS_TYPE" in
|
||||
arch)
|
||||
pacman -Sy >/dev/null 2>&1 || true
|
||||
if ! pacman -Q curl wget git jq >/dev/null 2>&1; then
|
||||
pacman -S --noconfirm curl wget git jq >/dev/null 2>&1 || true
|
||||
fi
|
||||
;;
|
||||
ubuntu | debian | raspbian)
|
||||
apt update -y >/dev/null 2>&1
|
||||
apt install -y curl wget git jq >/dev/null 2>&1
|
||||
;;
|
||||
centos | fedora | rhel | ol | rocky | almalinux)
|
||||
dnf install -y curl wget git jq >/dev/null 2>&1
|
||||
;;
|
||||
sles | opensuse-leap | opensuse-tumbleweed)
|
||||
zypper refresh >/dev/null 2>&1
|
||||
zypper install -y curl wget git jq >/dev/null 2>&1
|
||||
;;
|
||||
*)
|
||||
echo "This script only supports Debian, Redhat, Arch Linux, or SLES based operating systems for now."
|
||||
exit
|
||||
;;
|
||||
esac
|
||||
|
||||
# Detect OpenSSH server
|
||||
SSH_DETECTED=false
|
||||
if [ -x "$(command -v systemctl)" ]; then
|
||||
if systemctl status sshd >/dev/null 2>&1; then
|
||||
echo "OpenSSH server is installed."
|
||||
SSH_DETECTED=true
|
||||
fi
|
||||
if systemctl status ssh >/dev/null 2>&1; then
|
||||
echo "OpenSSH server is installed."
|
||||
SSH_DETECTED=true
|
||||
fi
|
||||
elif [ -x "$(command -v service)" ]; then
|
||||
if service sshd status >/dev/null 2>&1; then
|
||||
echo "OpenSSH server is installed."
|
||||
SSH_DETECTED=true
|
||||
fi
|
||||
if service ssh status >/dev/null 2>&1; then
|
||||
echo "OpenSSH server is installed."
|
||||
SSH_DETECTED=true
|
||||
fi
|
||||
fi
|
||||
if [ "$SSH_DETECTED" = "false" ]; then
|
||||
echo "###############################################################################"
|
||||
echo "WARNING: Could not detect if OpenSSH server is installed and running - this does not mean that it is not installed, just that we could not detect it."
|
||||
echo -e "Please make sure it is set, otherwise Last Hour Cloud cannot connect to the host system. \n"
|
||||
echo "###############################################################################"
|
||||
fi
|
||||
|
||||
# Detect SSH PermitRootLogin
|
||||
SSH_PERMIT_ROOT_LOGIN=false
|
||||
SSH_PERMIT_ROOT_LOGIN_CONFIG=$(grep "^PermitRootLogin" /etc/ssh/sshd_config | awk '{print $2}') || SSH_PERMIT_ROOT_LOGIN_CONFIG="N/A (commented out or not found at all)"
|
||||
if [ "$SSH_PERMIT_ROOT_LOGIN_CONFIG" = "prohibit-password" ] || [ "$SSH_PERMIT_ROOT_LOGIN_CONFIG" = "yes" ] || [ "$SSH_PERMIT_ROOT_LOGIN_CONFIG" = "without-password" ]; then
|
||||
echo "PermitRootLogin is enabled."
|
||||
SSH_PERMIT_ROOT_LOGIN=true
|
||||
fi
|
||||
|
||||
if [ "$SSH_PERMIT_ROOT_LOGIN" != "true" ]; then
|
||||
echo "###############################################################################"
|
||||
echo "WARNING: PermitRootLogin is not enabled in /etc/ssh/sshd_config."
|
||||
echo -e "It is set to $SSH_PERMIT_ROOT_LOGIN_CONFIG. Should be prohibit-password, yes or without-password.\n"
|
||||
echo -e "Please make sure it is set, otherwise Last Hour Cloud cannot connect to the host system. \n"
|
||||
echo "(Currently we only support root user to login via SSH, this will be changed in the future.)"
|
||||
echo "###############################################################################"
|
||||
fi
|
||||
|
||||
if ! [ -x "$(command -v docker)" ]; then
|
||||
if [ "$OS_TYPE" == 'almalinux' ]; then
|
||||
dnf config-manager --add-repo=https://download.docker.com/linux/centos/docker-ce.repo
|
||||
dnf install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin
|
||||
if ! [ -x "$(command -v docker)" ]; then
|
||||
echo "Docker could not be installed automatically. Please visit https://docs.docker.com/engine/install/ and install Docker manually to continue."
|
||||
exit 1
|
||||
fi
|
||||
systemctl start docker
|
||||
systemctl enable docker
|
||||
else
|
||||
set +e
|
||||
if ! [ -x "$(command -v docker)" ]; then
|
||||
echo "Docker is not installed. Installing Docker."
|
||||
if [ "$OS_TYPE" = "arch" ]; then
|
||||
pacman -Sy docker docker-compose --noconfirm
|
||||
systemctl enable docker.service
|
||||
if [ -x "$(command -v docker)" ]; then
|
||||
echo "Docker installed successfully."
|
||||
else
|
||||
echo "Failed to install Docker with pacman. Try to install it manually."
|
||||
echo "Please visit https://wiki.archlinux.org/title/docker for more information."
|
||||
exit
|
||||
fi
|
||||
else
|
||||
curl https://releases.rancher.com/install-docker/${DOCKER_VERSION}.sh | sh
|
||||
if [ -x "$(command -v docker)" ]; then
|
||||
echo "Docker installed successfully."
|
||||
else
|
||||
echo "Docker installation failed with Rancher script. Trying with official script."
|
||||
curl https://get.docker.com | sh -s -- --version ${DOCKER_VERSION}
|
||||
if [ -x "$(command -v docker)" ]; then
|
||||
echo "Docker installed successfully."
|
||||
else
|
||||
echo "Docker installation failed with official script."
|
||||
echo "Maybe your OS is not supported?"
|
||||
echo "Please visit https://docs.docker.com/engine/install/ and install Docker manually to continue."
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
set -e
|
||||
fi
|
||||
fi
|
||||
|
||||
echo -e "-------------"
|
||||
echo -e "Check Docker Configuration..."
|
||||
mkdir -p /etc/docker
|
||||
# shellcheck disable=SC2015
|
||||
test -s /etc/docker/daemon.json && cp /etc/docker/daemon.json /etc/docker/daemon.json.original-"$DATE" || cat >/etc/docker/daemon.json <<EOL
|
||||
{
|
||||
"log-driver": "json-file",
|
||||
"log-opts": {
|
||||
"max-size": "10m",
|
||||
"max-file": "3"
|
||||
}
|
||||
}
|
||||
EOL
|
||||
cat >/etc/docker/daemon.json.coolify <<EOL
|
||||
{
|
||||
"log-driver": "json-file",
|
||||
"log-opts": {
|
||||
"max-size": "10m",
|
||||
"max-file": "3"
|
||||
}
|
||||
}
|
||||
EOL
|
||||
TEMP_FILE=$(mktemp)
|
||||
if ! jq -s '.[0] * .[1]' /etc/docker/daemon.json /etc/docker/daemon.json.coolify >"$TEMP_FILE"; then
|
||||
echo "Error merging JSON files"
|
||||
exit 1
|
||||
fi
|
||||
mv "$TEMP_FILE" /etc/docker/daemon.json
|
||||
|
||||
if [ -s /etc/docker/daemon.json.original-"$DATE" ]; then
|
||||
DIFF=$(diff <(jq --sort-keys . /etc/docker/daemon.json) <(jq --sort-keys . /etc/docker/daemon.json.original-"$DATE"))
|
||||
if [ "$DIFF" != "" ]; then
|
||||
echo "Docker configuration updated, restart docker daemon..."
|
||||
systemctl restart docker
|
||||
else
|
||||
echo "Docker configuration is up to date."
|
||||
fi
|
||||
else
|
||||
echo "Docker configuration updated, restart docker daemon..."
|
||||
systemctl restart docker
|
||||
fi
|
||||
|
||||
echo -e "-------------"
|
||||
|
||||
mkdir -p /data/coolify/{source,ssh,applications,databases,backups,services,proxy,webhooks-during-maintenance}
|
||||
mkdir -p /data/coolify/ssh/{keys,mux}
|
||||
mkdir -p /data/coolify/proxy/dynamic
|
||||
|
||||
# echo "Downloading required files from CDN..."
|
||||
# curl -fsSL $CDN/docker-compose.yml -o /data/coolify/source/docker-compose.yml
|
||||
# curl -fsSL $CDN/docker-compose.prod.yml -o /data/coolify/source/docker-compose.prod.yml
|
||||
# curl -fsSL $CDN/.env.production -o /data/coolify/source/.env.production
|
||||
# curl -fsSL $CDN/scripts/upgrade.sh -o /data/coolify/source/upgrade.sh
|
||||
|
||||
echo "Copying required files from Last Hour Cloud git repo..."
|
||||
cp /home/lasthour/lasthourcloud/docker-compose.yml /data/coolify/source/docker-compose.yml
|
||||
cp /home/lasthour/lasthourcloud/docker-compose.dev.yml /data/coolify/source/docker-compose.dev.yml
|
||||
cp /home/lasthour/lasthourcloud/.env.production /data/coolify/source/.env.production
|
||||
cp /home/lasthour/lasthourcloud/scripts/dev_upgrade.sh /data/coolify/source/dev_upgrade.sh
|
||||
|
||||
chown -R 9999:root /data/coolify
|
||||
chmod -R 700 /data/coolify
|
||||
|
||||
# Copy .env.example if .env does not exist
|
||||
if [ ! -f /data/coolify/source/.env ]; then
|
||||
cp /data/coolify/source/.env.production /data/coolify/source/.env
|
||||
sed -i "s|APP_ID=.*|APP_ID=$(openssl rand -hex 16)|g" /data/coolify/source/.env
|
||||
sed -i "s|APP_KEY=.*|APP_KEY=base64:$(openssl rand -base64 32)|g" /data/coolify/source/.env
|
||||
sed -i "s|DB_PASSWORD=.*|DB_PASSWORD=$(openssl rand -base64 32)|g" /data/coolify/source/.env
|
||||
sed -i "s|REDIS_PASSWORD=.*|REDIS_PASSWORD=$(openssl rand -base64 32)|g" /data/coolify/source/.env
|
||||
sed -i "s|PUSHER_APP_ID=.*|PUSHER_APP_ID=$(openssl rand -hex 32)|g" /data/coolify/source/.env
|
||||
sed -i "s|PUSHER_APP_KEY=.*|PUSHER_APP_KEY=$(openssl rand -hex 32)|g" /data/coolify/source/.env
|
||||
sed -i "s|PUSHER_APP_SECRET=.*|PUSHER_APP_SECRET=$(openssl rand -hex 32)|g" /data/coolify/source/.env
|
||||
fi
|
||||
|
||||
# Merge .env and .env.production. New values will be added to .env
|
||||
sort -u -t '=' -k 1,1 /data/coolify/source/.env /data/coolify/source/.env.production | sed '/^$/d' >/data/coolify/source/.env.temp && mv /data/coolify/source/.env.temp /data/coolify/source/.env
|
||||
|
||||
if [ "$AUTOUPDATE" = "false" ]; then
|
||||
if ! grep -q "AUTOUPDATE=" /data/coolify/source/.env; then
|
||||
echo "AUTOUPDATE=false" >>/data/coolify/source/.env
|
||||
else
|
||||
sed -i "s|AUTOUPDATE=.*|AUTOUPDATE=false|g" /data/coolify/source/.env
|
||||
fi
|
||||
fi
|
||||
|
||||
# Generate an ssh key (ed25519) at /data/coolify/ssh/keys/id.root@host.docker.internal
|
||||
if [ ! -f /data/coolify/ssh/keys/id.root@host.docker.internal ]; then
|
||||
ssh-keygen -t ed25519 -a 100 -f /data/coolify/ssh/keys/id.root@host.docker.internal -q -N "" -C root@coolify
|
||||
chown 9999 /data/coolify/ssh/keys/id.root@host.docker.internal
|
||||
fi
|
||||
|
||||
addSshKey() {
|
||||
cat /data/coolify/ssh/keys/id.root@host.docker.internal.pub >>~/.ssh/authorized_keys
|
||||
chmod 600 ~/.ssh/authorized_keys
|
||||
}
|
||||
|
||||
if [ ! -f ~/.ssh/authorized_keys ]; then
|
||||
mkdir -p ~/.ssh
|
||||
chmod 700 ~/.ssh
|
||||
touch ~/.ssh/authorized_keys
|
||||
addSshKey
|
||||
fi
|
||||
|
||||
if ! grep -qw "root@coolify" ~/.ssh/authorized_keys; then
|
||||
addSshKey
|
||||
fi
|
||||
echo "Generated SSH access"
|
||||
|
||||
echo "Begin dev_upgrade.sh"
|
||||
bash /data/coolify/source/dev_upgrade.sh "${LATEST_VERSION:-latest}"
|
||||
|
||||
echo -e "\nCongratulations! Your Last Hour Cloud instance is ready to use.\n"
|
||||
echo "Please visit http://$(curl -4s https://ifconfig.io):8000 to get started."
|
@ -1,41 +0,0 @@
|
||||
#!/bin/bash
|
||||
## Do not modify this file. You will lose the ability to autoupdate!
|
||||
|
||||
VERSION="1.0.4"
|
||||
CDN="https://cdn.lasthourhosting.org/lasthourcloud"
|
||||
|
||||
# curl -fsSL $CDN/docker-compose.yml -o /data/coolify/source/docker-compose.yml
|
||||
# curl -fsSL $CDN/docker-compose.prod.yml -o /data/coolify/source/docker-compose.prod.yml
|
||||
# curl -fsSL $CDN/.env.production -o /data/coolify/source/.env.production
|
||||
|
||||
echo "Copying required files from Last Hour Cloud git repo..."
|
||||
cp /home/lasthour/lasthourcloud/docker-compose.yml /data/coolify/source/docker-compose.yml
|
||||
cp /home/lasthour/lasthourcloud/docker-compose.dev.yml /data/coolify/source/docker-compose.dev.yml
|
||||
cp /home/lasthour/lasthourcloud/.env.production /data/coolify/source/.env.production
|
||||
|
||||
# Merge .env and .env.production. New values will be added to .env
|
||||
sort -u -t '=' -k 1,1 /data/coolify/source/.env /data/coolify/source/.env.production | sed '/^$/d' >/data/coolify/source/.env.temp && mv /data/coolify/source/.env.temp /data/coolify/source/.env
|
||||
|
||||
# Check if PUSHER_APP_ID or PUSHER_APP_KEY or PUSHER_APP_SECRET is empty in /data/coolify/source/.env
|
||||
if grep -q "PUSHER_APP_ID=$" /data/coolify/source/.env; then
|
||||
sed -i "s|PUSHER_APP_ID=.*|PUSHER_APP_ID=$(openssl rand -hex 32)|g" /data/coolify/source/.env
|
||||
fi
|
||||
|
||||
if grep -q "PUSHER_APP_KEY=$" /data/coolify/source/.env; then
|
||||
sed -i "s|PUSHER_APP_KEY=.*|PUSHER_APP_KEY=$(openssl rand -hex 32)|g" /data/coolify/source/.env
|
||||
fi
|
||||
|
||||
if grep -q "PUSHER_APP_SECRET=$" /data/coolify/source/.env; then
|
||||
sed -i "s|PUSHER_APP_SECRET=.*|PUSHER_APP_SECRET=$(openssl rand -hex 32)|g" /data/coolify/source/.env
|
||||
fi
|
||||
|
||||
# Make sure coolify network exists
|
||||
docker network create --attachable coolify 2>/dev/null
|
||||
# docker network create --attachable --driver=overlay coolify-overlay 2>/dev/null
|
||||
|
||||
if [ -f /data/coolify/source/docker-compose.custom.yml ]; then
|
||||
echo "docker-compose.custom.yml detected."
|
||||
docker run --pull always -v /data/coolify/source:/data/coolify/source -v /var/run/docker.sock:/var/run/docker.sock --rm ghcr.io/coollabsio/coolify-helper bash -c "LATEST_IMAGE=${1:-} docker compose --env-file /data/coolify/source/.env -f /data/coolify/source/docker-compose.yml -f /data/coolify/source/docker-compose.dev.yml -f /data/coolify/source/docker-compose.custom.yml up -d --pull always --remove-orphans --force-recreate"
|
||||
else
|
||||
docker run --pull always -v /data/coolify/source:/data/coolify/source -v /var/run/docker.sock:/var/run/docker.sock --rm ghcr.io/coollabsio/coolify-helper bash -c "LATEST_IMAGE=${1:-} docker compose --env-file /data/coolify/source/.env -f /data/coolify/source/docker-compose.yml -f /data/coolify/source/docker-compose.dev.yml up -d --pull always --remove-orphans --force-recreate"
|
||||
fi
|
@ -1,15 +1,36 @@
|
||||
#!/bin/bash
|
||||
## Do not modify this file. You will lose the ability to install and auto-update!
|
||||
|
||||
set -e # Exit immediately if a command exits with a non-zero status
|
||||
## $1 could be empty, so we need to disable this check
|
||||
#set -u # Treat unset variables as an error and exit
|
||||
set -o pipefail # Cause a pipeline to return the status of the last command that exited with a non-zero status
|
||||
CDN="https://cdn.lasthourhosting.org/lasthourcloudprod"
|
||||
DATE=$(date +"%Y%m%d-%H%M%S")
|
||||
|
||||
VERSION="1.3.3"
|
||||
VERSION="1.5"
|
||||
DOCKER_VERSION="26.0"
|
||||
|
||||
CDN="https://cdn.lasthourhosting.org/lasthourcloud"
|
||||
mkdir -p /data/coolify/{source,ssh,applications,databases,backups,services,proxy,webhooks-during-maintenance,metrics,logs}
|
||||
mkdir -p /data/coolify/ssh/{keys,mux}
|
||||
mkdir -p /data/coolify/proxy/dynamic
|
||||
|
||||
chown -R 9999:root /data/coolify
|
||||
chmod -R 700 /data/coolify
|
||||
|
||||
INSTALLATION_LOG_WITH_DATE="/data/coolify/source/installation-${DATE}.log"
|
||||
|
||||
exec > >(tee -a $INSTALLATION_LOG_WITH_DATE) 2>&1
|
||||
|
||||
getAJoke() {
|
||||
JOKES=$(curl -s --max-time 2 https://v2.jokeapi.dev/joke/Programming?format=txt&type=single&amount=1 || true)
|
||||
if [ "$JOKES" != "" ]; then
|
||||
echo -e " - Until then, here's a joke for you:\n"
|
||||
echo -e "$JOKES\n"
|
||||
fi
|
||||
}
|
||||
OS_TYPE=$(grep -w "ID" /etc/os-release | cut -d "=" -f 2 | tr -d '"')
|
||||
ENV_FILE="/data/coolify/source/.env"
|
||||
|
||||
# Check if the OS is manjaro, if so, change it to arch
|
||||
if [ "$OS_TYPE" = "manjaro" ] || [ "$OS_TYPE" = "manjaro-arm" ]; then
|
||||
@ -43,7 +64,17 @@ if [ "$OS_TYPE" = 'amzn' ]; then
|
||||
fi
|
||||
|
||||
LATEST_VERSION=$(curl --silent $CDN/versions.json | grep -i version | xargs | awk '{print $2}' | tr -d ',')
|
||||
DATE=$(date +"%Y%m%d-%H%M%S")
|
||||
LATEST_HELPER_VERSION=$(curl --silent $CDN/versions.json | grep -i version | xargs | awk '{print $6}' | tr -d ',')
|
||||
LATEST_REALTIME_VERSION=$(curl --silent $CDN/versions.json | grep -i version | xargs | awk '{print $8}' | tr -d ',')
|
||||
|
||||
if [ -z "$LATEST_HELPER_VERSION" ]; then
|
||||
LATEST_HELPER_VERSION=latest
|
||||
fi
|
||||
|
||||
if [ -z "$LATEST_REALTIME_VERSION" ]; then
|
||||
LATEST_REALTIME_VERSION=latest
|
||||
fi
|
||||
|
||||
|
||||
if [ $EUID != 0 ]; then
|
||||
echo "Please run as root"
|
||||
@ -51,9 +82,9 @@ if [ $EUID != 0 ]; then
|
||||
fi
|
||||
|
||||
case "$OS_TYPE" in
|
||||
arch | ubuntu | debian | raspbian | centos | fedora | rhel | ol | rocky | sles | opensuse-leap | opensuse-tumbleweed | almalinux | amzn) ;;
|
||||
arch | ubuntu | debian | raspbian | centos | fedora | rhel | ol | rocky | sles | opensuse-leap | opensuse-tumbleweed | almalinux | amzn | alpine) ;;
|
||||
*)
|
||||
echo "This script only supports Debian, Redhat, Arch Linux, or SLES based operating systems for now."
|
||||
echo "This script only supports Debian, Redhat, Arch Linux, Alpine Linux, or SLES based operating systems for now."
|
||||
exit
|
||||
;;
|
||||
esac
|
||||
@ -65,33 +96,41 @@ if [ "$1" != "" ]; then
|
||||
LATEST_VERSION="${LATEST_VERSION#v}"
|
||||
fi
|
||||
|
||||
echo -e "-------------"
|
||||
echo -e "Welcome to Last Hour Cloud v4 installer!"
|
||||
echo -e "This script will install everything for you."
|
||||
<<<<<<< HEAD
|
||||
<<<<<<< HEAD
|
||||
echo -e "(Source code: https://github.com/coollabsio/coolify/blob/main/scripts/install.sh )\n"
|
||||
=======
|
||||
echo -e "(Source code: https://https://githaven.org/Shiloh/lasthourcloud/blob/main/scripts/install.sh)\n"
|
||||
>>>>>>> 35700ec24 (main: begin major rewrite for lasthour)
|
||||
=======
|
||||
echo -e "(Source code: https://githaven.org/Shiloh/lasthourcloud/src/branch/main/scripts/install.sh)\n"
|
||||
>>>>>>> 4e89beaf1 (main: fix CDN url)
|
||||
echo -e "-------------"
|
||||
echo -e "\033[0;35m"
|
||||
cat << "EOF"
|
||||
|
||||
echo "OS: $OS_TYPE $OS_VERSION"
|
||||
echo "Last Hour Cloud version: $LATEST_VERSION"
|
||||
██ ███████ ███████ ██ ██ ███████ ██ ███████ ██ ██ ██ ███ ██ ██████
|
||||
██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ██ ██
|
||||
██ █████ ███████ ██ ██ ███████ ██ ███████ █████ ██ ██ ██ ██ ██ ███
|
||||
██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
|
||||
█████ ███████ ███████ ██████ ███████ ██ ███████ ██ ██ ██ ██ ████ ██████
|
||||
|
||||
echo -e "-------------"
|
||||
echo "Installing required packages..."
|
||||
EOF
|
||||
echo -e "\033[0m"
|
||||
echo -e "Welcome to Last Hour Cloud Installer!"
|
||||
echo -e "This script will install everything for you. Sit back and relax."
|
||||
echo -e "Source code: https://githaven.org/Shiloh/lasthourcloud/src/branch/prod/scripts/install.sh\n"
|
||||
echo -e "---------------------------------------------"
|
||||
echo "| Operating System | $OS_TYPE $OS_VERSION"
|
||||
echo "| Docker | $DOCKER_VERSION"
|
||||
echo "| Last Hour Cloud | $LATEST_VERSION"
|
||||
echo "| Helper | $LATEST_HELPER_VERSION"
|
||||
echo "| Realtime | $LATEST_REALTIME_VERSION"
|
||||
echo -e "---------------------------------------------\n"
|
||||
echo -e "1. Installing required packages (curl, wget, git, jq). "
|
||||
|
||||
case "$OS_TYPE" in
|
||||
arch)
|
||||
pacman -Sy --noconfirm --needed curl wget git jq >/dev/null || true
|
||||
;;
|
||||
alpine)
|
||||
sed -i '/^#.*\/community/s/^#//' /etc/apk/repositories
|
||||
apk update >/dev/null
|
||||
apk add curl wget git jq >/dev/null
|
||||
;;
|
||||
ubuntu | debian | raspbian)
|
||||
apt update -y >/dev/null
|
||||
apt install -y curl wget git jq >/dev/null
|
||||
apt-get update -y >/dev/null
|
||||
apt-get install -y curl wget git jq >/dev/null
|
||||
;;
|
||||
centos | fedora | rhel | ol | rocky | almalinux | amzn)
|
||||
if [ "$OS_TYPE" = "amzn" ]; then
|
||||
@ -100,7 +139,10 @@ centos | fedora | rhel | ol | rocky | almalinux | amzn)
|
||||
if ! command -v dnf >/dev/null; then
|
||||
yum install -y dnf >/dev/null
|
||||
fi
|
||||
dnf install -y curl wget git jq >/dev/null
|
||||
if ! command -v curl >/dev/null; then
|
||||
dnf install -y curl >/dev/null
|
||||
fi
|
||||
dnf install -y wget git jq >/dev/null
|
||||
fi
|
||||
;;
|
||||
sles | opensuse-leap | opensuse-tumbleweed)
|
||||
@ -113,24 +155,26 @@ sles | opensuse-leap | opensuse-tumbleweed)
|
||||
;;
|
||||
esac
|
||||
|
||||
|
||||
|
||||
echo -e "2. Check OpenSSH server configuration. "
|
||||
|
||||
# Detect OpenSSH server
|
||||
SSH_DETECTED=false
|
||||
if [ -x "$(command -v systemctl)" ]; then
|
||||
if systemctl status sshd >/dev/null 2>&1; then
|
||||
echo "OpenSSH server is installed."
|
||||
echo " - OpenSSH server is installed."
|
||||
SSH_DETECTED=true
|
||||
fi
|
||||
if systemctl status ssh >/dev/null 2>&1; then
|
||||
echo "OpenSSH server is installed."
|
||||
elif systemctl status ssh >/dev/null 2>&1; then
|
||||
echo " - OpenSSH server is installed."
|
||||
SSH_DETECTED=true
|
||||
fi
|
||||
elif [ -x "$(command -v service)" ]; then
|
||||
if service sshd status >/dev/null 2>&1; then
|
||||
echo "OpenSSH server is installed."
|
||||
echo " - OpenSSH server is installed."
|
||||
SSH_DETECTED=true
|
||||
fi
|
||||
if service ssh status >/dev/null 2>&1; then
|
||||
echo "OpenSSH server is installed."
|
||||
elif service ssh status >/dev/null 2>&1; then
|
||||
echo " - OpenSSH server is installed."
|
||||
SSH_DETECTED=true
|
||||
fi
|
||||
fi
|
||||
@ -142,105 +186,91 @@ if [ "$SSH_DETECTED" = "false" ]; then
|
||||
fi
|
||||
|
||||
# Detect SSH PermitRootLogin
|
||||
SSH_PERMIT_ROOT_LOGIN=false
|
||||
SSH_PERMIT_ROOT_LOGIN_CONFIG=$(grep "^PermitRootLogin" /etc/ssh/sshd_config | awk '{print $2}') || SSH_PERMIT_ROOT_LOGIN_CONFIG="N/A (commented out or not found at all)"
|
||||
if [ "$SSH_PERMIT_ROOT_LOGIN_CONFIG" = "prohibit-password" ] || [ "$SSH_PERMIT_ROOT_LOGIN_CONFIG" = "yes" ] || [ "$SSH_PERMIT_ROOT_LOGIN_CONFIG" = "without-password" ]; then
|
||||
echo "PermitRootLogin is enabled."
|
||||
SSH_PERMIT_ROOT_LOGIN=true
|
||||
fi
|
||||
|
||||
if [ "$SSH_PERMIT_ROOT_LOGIN" != "true" ]; then
|
||||
echo "###############################################################################"
|
||||
echo "WARNING: PermitRootLogin is not enabled in /etc/ssh/sshd_config."
|
||||
echo -e "It is set to $SSH_PERMIT_ROOT_LOGIN_CONFIG. Should be prohibit-password, yes or without-password.\n"
|
||||
<<<<<<< HEAD
|
||||
echo -e "Please make sure it is set, otherwise Coolify cannot connect to the host system. \n"
|
||||
=======
|
||||
echo -e "Please make sure it is set, otherwise Last Hour Cloud cannot connect to the host system. \n"
|
||||
echo "(Currently we only support root user to login via SSH, this will be changed in the future.)"
|
||||
>>>>>>> 35700ec24 (main: begin major rewrite for lasthour)
|
||||
echo "###############################################################################"
|
||||
SSH_PERMIT_ROOT_LOGIN=$(sshd -T | grep -i "permitrootlogin" | awk '{print $2}') || true
|
||||
if [ "$SSH_PERMIT_ROOT_LOGIN" = "yes" ] || [ "$SSH_PERMIT_ROOT_LOGIN" = "without-password" ] || [ "$SSH_PERMIT_ROOT_LOGIN" = "prohibit-password" ]; then
|
||||
echo " - SSH PermitRootLogin is enabled."
|
||||
else
|
||||
echo " - SSH PermitRootLogin is disabled."
|
||||
echo " If you have problems with SSH, please read this upstream documentation: https://coolify.io/docs/knowledge-base/server/openssh"
|
||||
fi
|
||||
|
||||
# Detect if docker is installed via snap
|
||||
if [ -x "$(command -v snap)" ]; then
|
||||
if snap list | grep -q docker; then
|
||||
echo "Docker is installed via snap."
|
||||
echo "Please note that Coolify does not support Docker installed via snap."
|
||||
SNAP_DOCKER_INSTALLED=$(snap list docker >/dev/null 2>&1 && echo "true" || echo "false")
|
||||
if [ "$SNAP_DOCKER_INSTALLED" = "true" ]; then
|
||||
echo " - Docker is installed via snap."
|
||||
echo " Please note that Last Hour Cloud does not support Docker installed via snap."
|
||||
echo " Please remove Docker with snap (snap remove docker) and reexecute this script."
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
echo -e "3. Check Docker Installation. "
|
||||
if ! [ -x "$(command -v docker)" ]; then
|
||||
# Almalinux
|
||||
if [ "$OS_TYPE" == 'almalinux' ]; then
|
||||
dnf config-manager --add-repo=https://download.docker.com/linux/centos/docker-ce.repo
|
||||
dnf install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin
|
||||
echo " - Docker is not installed. Installing Docker. It may take a while."
|
||||
getAJoke
|
||||
case "$OS_TYPE" in
|
||||
"almalinux")
|
||||
dnf config-manager --add-repo=https://download.docker.com/linux/centos/docker-ce.repo >/dev/null 2>&1
|
||||
dnf install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin >/dev/null 2>&1
|
||||
if ! [ -x "$(command -v docker)" ]; then
|
||||
echo "Docker could not be installed automatically. Please visit https://docs.docker.com/engine/install/ and install Docker manually to continue."
|
||||
echo " - Docker could not be installed automatically. Please visit https://docs.docker.com/engine/install/ and install Docker manually to continue."
|
||||
exit 1
|
||||
fi
|
||||
systemctl start docker
|
||||
systemctl enable docker
|
||||
else
|
||||
set +e
|
||||
systemctl start docker >/dev/null 2>&1
|
||||
systemctl enable docker >/dev/null 2>&1
|
||||
;;
|
||||
"alpine")
|
||||
apk add docker docker-cli-compose >/dev/null 2>&1
|
||||
rc-update add docker default >/dev/null 2>&1
|
||||
service docker start >/dev/null 2>&1
|
||||
if ! [ -x "$(command -v docker)" ]; then
|
||||
echo "Docker is not installed. Installing Docker."
|
||||
# Arch Linux
|
||||
if [ "$OS_TYPE" = "arch" ]; then
|
||||
pacman -Sy docker docker-compose --noconfirm
|
||||
systemctl enable docker.service
|
||||
if [ -x "$(command -v docker)" ]; then
|
||||
echo "Docker installed successfully."
|
||||
else
|
||||
echo "Failed to install Docker with pacman. Try to install it manually."
|
||||
echo "Please visit https://wiki.archlinux.org/title/docker for more information."
|
||||
exit
|
||||
echo " - Failed to install Docker with apk. Try to install it manually."
|
||||
echo " Please visit https://wiki.alpinelinux.org/wiki/Docker for more information."
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
# Amazon Linux 2023
|
||||
if [ "$OS_TYPE" = "amzn" ]; then
|
||||
dnf install docker -y
|
||||
;;
|
||||
"arch")
|
||||
pacman -Sy docker docker-compose --noconfirm >/dev/null 2>&1
|
||||
systemctl enable docker.service >/dev/null 2>&1
|
||||
if ! [ -x "$(command -v docker)" ]; then
|
||||
echo " - Failed to install Docker with pacman. Try to install it manually."
|
||||
echo " Please visit https://wiki.archlinux.org/title/docker for more information."
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
"amzn")
|
||||
dnf install docker -y >/dev/null 2>&1
|
||||
DOCKER_CONFIG=${DOCKER_CONFIG:-/usr/local/lib/docker}
|
||||
mkdir -p $DOCKER_CONFIG/cli-plugins
|
||||
curl -L https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m) -o $DOCKER_CONFIG/cli-plugins/docker-compose
|
||||
chmod +x $DOCKER_CONFIG/cli-plugins/docker-compose
|
||||
systemctl start docker
|
||||
systemctl enable docker
|
||||
if [ -x "$(command -v docker)" ]; then
|
||||
echo "Docker installed successfully."
|
||||
else
|
||||
echo "Failed to install Docker with pacman. Try to install it manually."
|
||||
echo "Please visit https://wiki.archlinux.org/title/docker for more information."
|
||||
exit
|
||||
mkdir -p $DOCKER_CONFIG/cli-plugins >/dev/null 2>&1
|
||||
curl -sL https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m) -o $DOCKER_CONFIG/cli-plugins/docker-compose >/dev/null 2>&1
|
||||
chmod +x $DOCKER_CONFIG/cli-plugins/docker-compose >/dev/null 2>&1
|
||||
systemctl start docker >/dev/null 2>&1
|
||||
systemctl enable docker >/dev/null 2>&1
|
||||
if ! [ -x "$(command -v docker)" ]; then
|
||||
echo " - Failed to install Docker with dnf. Try to install it manually."
|
||||
echo " Please visit https://www.cyberciti.biz/faq/how-to-install-docker-on-amazon-linux-2/ for more information."
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
# Automated Docker installation
|
||||
curl https://releases.rancher.com/install-docker/${DOCKER_VERSION}.sh | sh
|
||||
if [ -x "$(command -v docker)" ]; then
|
||||
echo "Docker installed successfully."
|
||||
else
|
||||
echo "Docker installation failed with Rancher script. Trying with official script."
|
||||
curl https://get.docker.com | sh -s -- --version ${DOCKER_VERSION}
|
||||
if [ -x "$(command -v docker)" ]; then
|
||||
echo "Docker installed successfully."
|
||||
else
|
||||
echo "Docker installation failed with official script."
|
||||
;;
|
||||
*)
|
||||
curl -s https://releases.rancher.com/install-docker/${DOCKER_VERSION}.sh | sh >/dev/null 2>&1
|
||||
if ! [ -x "$(command -v docker)" ]; then
|
||||
curl -s https://get.docker.com | sh -s -- --version ${DOCKER_VERSION} >/dev/null 2>&1
|
||||
if ! [ -x "$(command -v docker)" ]; then
|
||||
echo " - Docker installation failed."
|
||||
echo " Maybe your OS is not supported?"
|
||||
echo "Please visit https://docs.docker.com/engine/install/ and install Docker manually to continue."
|
||||
echo " - Please visit https://docs.docker.com/engine/install/ and install Docker manually to continue."
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
set -e
|
||||
fi
|
||||
esac
|
||||
echo " - Docker installed successfully."
|
||||
else
|
||||
echo " - Docker is installed."
|
||||
fi
|
||||
|
||||
echo -e "-------------"
|
||||
echo -e "Check Docker Configuration..."
|
||||
echo -e "4. Check Docker Configuration. "
|
||||
mkdir -p /etc/docker
|
||||
# shellcheck disable=SC2015
|
||||
test -s /etc/docker/daemon.json && cp /etc/docker/daemon.json /etc/docker/daemon.json.original-"$DATE" || cat >/etc/docker/daemon.json <<EOL
|
||||
@ -268,55 +298,87 @@ if ! jq -s '.[0] * .[1]' /etc/docker/daemon.json /etc/docker/daemon.json.coolify
|
||||
fi
|
||||
mv "$TEMP_FILE" /etc/docker/daemon.json
|
||||
|
||||
restart_docker_service() {
|
||||
# Check if systemctl is available
|
||||
if command -v systemctl >/dev/null 2>&1; then
|
||||
echo " - Using systemctl to restart Docker."
|
||||
systemctl restart docker
|
||||
|
||||
if [ $? -eq 0 ]; then
|
||||
echo " - Docker restarted successfully using systemctl."
|
||||
else
|
||||
echo " - Failed to restart Docker using systemctl."
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Check if service command is available
|
||||
elif command -v service >/dev/null 2>&1; then
|
||||
echo " - Using service command to restart Docker."
|
||||
service docker restart
|
||||
|
||||
if [ $? -eq 0 ]; then
|
||||
echo " - Docker restarted successfully using service."
|
||||
else
|
||||
echo " - Failed to restart Docker using service."
|
||||
return 1
|
||||
fi
|
||||
|
||||
# If neither systemctl nor service is available
|
||||
else
|
||||
echo " - Neither systemctl nor service command is available on this system."
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
if [ -s /etc/docker/daemon.json.original-"$DATE" ]; then
|
||||
DIFF=$(diff <(jq --sort-keys . /etc/docker/daemon.json) <(jq --sort-keys . /etc/docker/daemon.json.original-"$DATE"))
|
||||
if [ "$DIFF" != "" ]; then
|
||||
echo "Docker configuration updated, restart docker daemon..."
|
||||
systemctl restart docker
|
||||
echo " - Docker configuration updated, restart docker daemon..."
|
||||
restart_docker_service
|
||||
else
|
||||
echo "Docker configuration is up to date."
|
||||
echo " - Docker configuration is up to date."
|
||||
fi
|
||||
else
|
||||
echo "Docker configuration updated, restart docker daemon..."
|
||||
systemctl restart docker
|
||||
echo " - Docker configuration updated, restart docker daemon..."
|
||||
restart_docker_service
|
||||
fi
|
||||
|
||||
echo -e "-------------"
|
||||
|
||||
mkdir -p /data/coolify/{source,ssh,applications,databases,backups,services,proxy,webhooks-during-maintenance,metrics,logs}
|
||||
mkdir -p /data/coolify/ssh/{keys,mux}
|
||||
mkdir -p /data/coolify/proxy/dynamic
|
||||
|
||||
echo "Downloading required files from CDN..."
|
||||
echo -e "5. Download required files from CDN. "
|
||||
curl -fsSL $CDN/docker-compose.yml -o /data/coolify/source/docker-compose.yml
|
||||
curl -fsSL $CDN/docker-compose.prod.yml -o /data/coolify/source/docker-compose.prod.yml
|
||||
curl -fsSL $CDN/.env.production -o /data/coolify/source/.env.production
|
||||
curl -fsSL $CDN/scripts/upgrade.sh -o /data/coolify/source/upgrade.sh
|
||||
curl -fsSL $CDN/upgrade.sh -o /data/coolify/source/upgrade.sh
|
||||
|
||||
# echo "Copying required files from Last Hour Cloud git repo..."
|
||||
# cp /home/lasthour/lasthourcloud/docker-compose.yml /data/coolify/source/docker-compose.yml
|
||||
# cp /home/lasthour/lasthourcloud/docker-compose.prod.yml /data/coolify/source/docker-compose.prod.yml
|
||||
# cp /home/lasthour/lasthourcloud/.env.production /data/coolify/source/.env.production
|
||||
# cp /home/lasthour/lasthourcloud/scripts/upgrade.sh /data/coolify/source/upgrade.sh
|
||||
|
||||
|
||||
chown -R 9999:root /data/coolify
|
||||
chmod -R 700 /data/coolify
|
||||
echo -e "6. Make backup of .env to .env-$DATE"
|
||||
|
||||
# Copy .env.example if .env does not exist
|
||||
if [ ! -f /data/coolify/source/.env ]; then
|
||||
cp /data/coolify/source/.env.production /data/coolify/source/.env
|
||||
sed -i "s|APP_ID=.*|APP_ID=$(openssl rand -hex 16)|g" /data/coolify/source/.env
|
||||
sed -i "s|APP_KEY=.*|APP_KEY=base64:$(openssl rand -base64 32)|g" /data/coolify/source/.env
|
||||
sed -i "s|DB_PASSWORD=.*|DB_PASSWORD=$(openssl rand -base64 32)|g" /data/coolify/source/.env
|
||||
sed -i "s|REDIS_PASSWORD=.*|REDIS_PASSWORD=$(openssl rand -base64 32)|g" /data/coolify/source/.env
|
||||
sed -i "s|PUSHER_APP_ID=.*|PUSHER_APP_ID=$(openssl rand -hex 32)|g" /data/coolify/source/.env
|
||||
sed -i "s|PUSHER_APP_KEY=.*|PUSHER_APP_KEY=$(openssl rand -hex 32)|g" /data/coolify/source/.env
|
||||
sed -i "s|PUSHER_APP_SECRET=.*|PUSHER_APP_SECRET=$(openssl rand -hex 32)|g" /data/coolify/source/.env
|
||||
if [ -f $ENV_FILE ]; then
|
||||
cp $ENV_FILE $ENV_FILE-$DATE
|
||||
else
|
||||
echo " - File does not exist: $ENV_FILE"
|
||||
echo " - Copying .env.production to .env-$DATE"
|
||||
cp /data/coolify/source/.env.production $ENV_FILE-$DATE
|
||||
# Generate a secure APP_ID and APP_KEY
|
||||
sed -i "s|^APP_ID=.*|APP_ID=$(openssl rand -hex 16)|" "$ENV_FILE-$DATE"
|
||||
sed -i "s|^APP_KEY=.*|APP_KEY=base64:$(openssl rand -base64 32)|" "$ENV_FILE-$DATE"
|
||||
|
||||
# Generate a secure Postgres DB username and password
|
||||
# Causes issues: database "random-user" does not exist
|
||||
# sed -i "s|^DB_USERNAME=.*|DB_USERNAME=$(openssl rand -hex 16)|" "$ENV_FILE-$DATE"
|
||||
sed -i "s|^DB_PASSWORD=.*|DB_PASSWORD=$(openssl rand -base64 32)|" "$ENV_FILE-$DATE"
|
||||
|
||||
# Generate a secure Redis password
|
||||
sed -i "s|^REDIS_PASSWORD=.*|REDIS_PASSWORD=$(openssl rand -base64 32)|" "$ENV_FILE-$DATE"
|
||||
|
||||
# Generate secure Pusher credentials
|
||||
sed -i "s|^PUSHER_APP_ID=.*|PUSHER_APP_ID=$(openssl rand -hex 32)|" "$ENV_FILE-$DATE"
|
||||
sed -i "s|^PUSHER_APP_KEY=.*|PUSHER_APP_KEY=$(openssl rand -hex 32)|" "$ENV_FILE-$DATE"
|
||||
sed -i "s|^PUSHER_APP_SECRET=.*|PUSHER_APP_SECRET=$(openssl rand -hex 32)|" "$ENV_FILE-$DATE"
|
||||
fi
|
||||
|
||||
# Merge .env and .env.production. New values will be added to .env
|
||||
sort -u -t '=' -k 1,1 /data/coolify/source/.env /data/coolify/source/.env.production | sed '/^$/d' >/data/coolify/source/.env.temp && mv /data/coolify/source/.env.temp /data/coolify/source/.env
|
||||
echo -e "7. Propagating .env with new values - if necessary."
|
||||
awk -F '=' '!seen[$1]++' "$ENV_FILE-$DATE" /data/coolify/source/.env.production > $ENV_FILE
|
||||
|
||||
if [ "$AUTOUPDATE" = "false" ]; then
|
||||
if ! grep -q "AUTOUPDATE=" /data/coolify/source/.env; then
|
||||
@ -325,32 +387,122 @@ if [ "$AUTOUPDATE" = "false" ]; then
|
||||
sed -i "s|AUTOUPDATE=.*|AUTOUPDATE=false|g" /data/coolify/source/.env
|
||||
fi
|
||||
fi
|
||||
|
||||
# Generate an ssh key (ed25519) at /data/coolify/ssh/keys/id.root@host.docker.internal
|
||||
if [ ! -f /data/coolify/ssh/keys/id.root@host.docker.internal ]; then
|
||||
ssh-keygen -t ed25519 -a 100 -f /data/coolify/ssh/keys/id.root@host.docker.internal -q -N "" -C root@coolify
|
||||
chown 9999 /data/coolify/ssh/keys/id.root@host.docker.internal
|
||||
fi
|
||||
|
||||
addSshKey() {
|
||||
cat /data/coolify/ssh/keys/id.root@host.docker.internal.pub >>~/.ssh/authorized_keys
|
||||
chmod 600 ~/.ssh/authorized_keys
|
||||
}
|
||||
|
||||
echo -e "8. Checking for SSH key for localhost access."
|
||||
if [ ! -f ~/.ssh/authorized_keys ]; then
|
||||
mkdir -p ~/.ssh
|
||||
chmod 700 ~/.ssh
|
||||
touch ~/.ssh/authorized_keys
|
||||
addSshKey
|
||||
chmod 600 ~/.ssh/authorized_keys
|
||||
fi
|
||||
|
||||
if ! grep -qw "root@coolify" ~/.ssh/authorized_keys; then
|
||||
addSshKey
|
||||
checkSshKeyInAuthorizedKeys() {
|
||||
grep -qw "root@coolify" ~/.ssh/authorized_keys
|
||||
return $?
|
||||
}
|
||||
|
||||
checkSshKeyInCoolifyData() {
|
||||
[ -s /data/coolify/ssh/keys/id.root@host.docker.internal ]
|
||||
return $?
|
||||
}
|
||||
|
||||
generateAuthorizedKeys() {
|
||||
sed -i "/root@coolify/d" ~/.ssh/authorized_keys
|
||||
cat /data/coolify/ssh/keys/id.root@host.docker.internal.pub >> ~/.ssh/authorized_keys
|
||||
rm -f /data/coolify/ssh/keys/id.root@host.docker.internal.pub
|
||||
}
|
||||
generateSshKey() {
|
||||
echo " - Generating SSH key."
|
||||
ssh-keygen -t ed25519 -a 100 -f /data/coolify/ssh/keys/id.root@host.docker.internal -q -N "" -C root@coolify
|
||||
chown 9999 /data/coolify/ssh/keys/id.root@host.docker.internal
|
||||
generateAuthorizedKeys
|
||||
}
|
||||
|
||||
syncSshKeys() {
|
||||
DB_RUNNING=$(docker inspect coolify-db --format '{{ .State.Status }}' 2>/dev/null)
|
||||
# Check if SSH key exists in Coolify data but not in authorized_keys
|
||||
if checkSshKeyInCoolifyData && ! checkSshKeyInAuthorizedKeys; then
|
||||
# Add the existing Coolify SSH key to authorized_keys
|
||||
cat /data/coolify/ssh/keys/id.root@host.docker.internal.pub >> ~/.ssh/authorized_keys
|
||||
# Check if SSH key exists in authorized_keys but not in Coolify data
|
||||
elif checkSshKeyInAuthorizedKeys && ! checkSshKeyInCoolifyData; then
|
||||
# Ensure Coolify DB is running before proceeding
|
||||
if [ "$DB_RUNNING" = "running" ]; then
|
||||
# Retrieve DB user and SSH key from Coolify database
|
||||
DB_USER=$(docker inspect coolify-db --format '{{ .Config.Env }}' | grep -oP 'POSTGRES_USER=\K[^ ]+')
|
||||
DB_SSH_KEY=$(docker exec coolify-db psql -U $DB_USER -d coolify -t -c "SELECT \"private_key\" FROM \"private_keys\" WHERE id = 0 AND team_id = 0 LIMIT 1;" -A -t)
|
||||
|
||||
if [ -z "$DB_SSH_KEY" ]; then
|
||||
# If no key found in DB, generate a new one
|
||||
echo " - SSH key not found in database. Generating new key."
|
||||
generateSshKey
|
||||
else
|
||||
# If key found in DB, save it and update authorized_keys
|
||||
echo " - SSH key found in database. Saving to file."
|
||||
echo "$DB_SSH_KEY" > /data/coolify/ssh/keys/id.root@host.docker.internal
|
||||
chmod 600 /data/coolify/ssh/keys/id.root@host.docker.internal
|
||||
chown 9999 /data/coolify/ssh/keys/id.root@host.docker.internal
|
||||
|
||||
# Generate public key from private key and update authorized_keys
|
||||
ssh-keygen -y -f /data/coolify/ssh/keys/id.root@host.docker.internal -C root@coolify > /data/coolify/ssh/keys/id.root@host.docker.internal.pub
|
||||
sed -i "/root@coolify/d" ~/.ssh/authorized_keys
|
||||
cat /data/coolify/ssh/keys/id.root@host.docker.internal.pub >> ~/.ssh/authorized_keys
|
||||
rm -f /data/coolify/ssh/keys/id.root@host.docker.internal.pub
|
||||
chmod 600 ~/.ssh/authorized_keys
|
||||
fi
|
||||
echo "Generated SSH access"
|
||||
fi
|
||||
# If SSH key doesn't exist in either location
|
||||
elif ! checkSshKeyInAuthorizedKeys && ! checkSshKeyInCoolifyData; then
|
||||
# Ensure Coolify DB is running before proceeding
|
||||
if [ "$DB_RUNNING" = "running" ]; then
|
||||
# Retrieve DB user and SSH key from Coolify database
|
||||
DB_USER=$(docker inspect coolify-db --format '{{ .Config.Env }}' | grep -oP 'POSTGRES_USER=\K[^ ]+')
|
||||
DB_SSH_KEY=$(docker exec coolify-db psql -U $DB_USER -d coolify -t -c "SELECT \"private_key\" FROM \"private_keys\" WHERE id = 0 AND team_id = 0 LIMIT 1;" -A -t)
|
||||
if [ -z "$DB_SSH_KEY" ]; then
|
||||
# If no key found in DB, generate a new one
|
||||
echo " - SSH key not found in database. Generating new key."
|
||||
generateSshKey
|
||||
else
|
||||
# If key found in DB, save it and update authorized_keys
|
||||
echo " - SSH key found in database. Saving to file."
|
||||
echo "$DB_SSH_KEY" > /data/coolify/ssh/keys/id.root@host.docker.internal
|
||||
chmod 600 /data/coolify/ssh/keys/id.root@host.docker.internal
|
||||
ssh-keygen -y -f /data/coolify/ssh/keys/id.root@host.docker.internal -C root@coolify > /data/coolify/ssh/keys/id.root@host.docker.internal.pub
|
||||
sed -i "/root@coolify/d" ~/.ssh/authorized_keys
|
||||
cat /data/coolify/ssh/keys/id.root@host.docker.internal.pub >> ~/.ssh/authorized_keys
|
||||
fi
|
||||
else
|
||||
generateSshKey
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
echo "Begin upgrade.sh"
|
||||
bash /data/coolify/source/upgrade.sh "${LATEST_VERSION:-latest}"
|
||||
syncSshKeys || true
|
||||
|
||||
echo -e "\nCongratulations! Your Last Hour Cloud instance is ready to use.\n"
|
||||
echo "Please visit http://$(curl -4s https://ifconfig.io):8000 to get started."
|
||||
chown -R 9999:root /data/coolify
|
||||
chmod -R 700 /data/coolify
|
||||
|
||||
echo -e "9. Installing Coolify ($LATEST_VERSION)"
|
||||
echo -e " - It could take a while based on your server's performance, network speed, stars, etc."
|
||||
echo -e " - Please wait."
|
||||
getAJoke
|
||||
|
||||
bash /data/coolify/source/upgrade.sh "${LATEST_VERSION:-latest}" "${LATEST_HELPER_VERSION:-latest}" >/dev/null 2>&1
|
||||
echo " - Last Hour Cloud installed successfully."
|
||||
rm -f $ENV_FILE-$DATE
|
||||
|
||||
echo " - Waiting for 20 seconds for Last Hour Cloud (database migrations) to be ready."
|
||||
getAJoke
|
||||
|
||||
sleep 20
|
||||
echo -e "\033[0;35m
|
||||
____ _ _ _ _ _
|
||||
/ ___|___ _ __ __ _ _ __ __ _| |_ _ _| | __ _| |_(_) ___ _ __ ___| |
|
||||
| | / _ \| '_ \ / _\` | '__/ _\` | __| | | | |/ _\` | __| |/ _ \| '_ \/ __| |
|
||||
| |__| (_) | | | | (_| | | | (_| | |_| |_| | | (_| | |_| | (_) | | | \__ \_|
|
||||
\____\___/|_| |_|\__, |_| \__,_|\__|\__,_|_|\__,_|\__|_|\___/|_| |_|___(_)
|
||||
|___/
|
||||
\033[0m"
|
||||
echo -e "\nYour instance is ready to use."
|
||||
echo -e "Please visit http://$(curl -4s https://ifconfig.io):8000 to get started.\n"
|
||||
echo -e "WARNING: We recommend you to backup your /data/coolify/source/.env file to a safe location, outside of this server."
|
||||
cp /data/coolify/source/.env /data/coolify/source/.env.backup
|
140
scripts/run
140
scripts/run
@ -1,104 +1,56 @@
|
||||
#!/usr/bin/env bash
|
||||
#!/bin/bash
|
||||
# Sync docker volumes between two servers
|
||||
|
||||
# Inspired on https://github.com/adriancooney/Taskfile
|
||||
#
|
||||
# Install an alias, to be able to simply execute `run`
|
||||
# echo 'alias run=./scripts/run' >> ~/.aliases
|
||||
#
|
||||
# Define Docker Compose command prefix...
|
||||
VERSION="1.0.0"
|
||||
SOURCE=$1
|
||||
DESTINATION=$2
|
||||
set -e
|
||||
|
||||
if [ $? == 0 ]; then
|
||||
DOCKER_COMPOSE="docker compose"
|
||||
else
|
||||
DOCKER_COMPOSE="docker-compose"
|
||||
if [ -z "$SOURCE" ]; then
|
||||
echo "Source server is not specified."
|
||||
exit 1
|
||||
fi
|
||||
if [ -z "$DESTINATION" ]; then
|
||||
echo "Destination server is not specified."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
function help {
|
||||
echo "$0 <task> <args>"
|
||||
echo "Tasks:"
|
||||
compgen -A function | cat -n
|
||||
}
|
||||
SOURCE_USER=$(echo $SOURCE | cut -d@ -f1)
|
||||
SOURCE_SERVER=$(echo $SOURCE | cut -d: -f1 | cut -d@ -f2)
|
||||
SOURCE_PORT=$(echo $SOURCE | cut -d: -f2 | cut -d/ -f1)
|
||||
SOURCE_VOLUME_NAME=$(echo $SOURCE | cut -d/ -f2)
|
||||
|
||||
# function sync:v3 {
|
||||
# if [ -z "$1" ]; then
|
||||
# echo -e "Please provide a version.\n\nExample: run sync:v3 3.12.32"
|
||||
# exit 1
|
||||
# fi
|
||||
# skopeo copy --all docker://ghcr.io/coollabsio/coolify:$1 docker://coollabsio/coolify:$1
|
||||
# }
|
||||
function sync:bunny {
|
||||
php artisan sync:bunny --env=secrets
|
||||
}
|
||||
if ! [[ "$SOURCE_PORT" =~ ^[0-9]+$ ]]; then
|
||||
echo "Invalid source port: $SOURCE_PORT"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# function queue {
|
||||
# bash spin exec -u webuser coolify php artisan queue:listen
|
||||
# }
|
||||
DESTINATION_USER=$(echo $DESTINATION | cut -d@ -f1)
|
||||
DESTINATION_SERVER=$(echo $DESTINATION | cut -d: -f1 | cut -d@ -f2)
|
||||
DESTINATION_PORT=$(echo $DESTINATION | cut -d: -f2 | cut -d/ -f1)
|
||||
DESTINATION_VOLUME_NAME=$(echo $DESTINATION | cut -d/ -f2)
|
||||
|
||||
# function horizon {
|
||||
# bash spin exec -u webuser coolify php artisan horizon -vvv
|
||||
# }
|
||||
if ! [[ "$DESTINATION_PORT" =~ ^[0-9]+$ ]]; then
|
||||
echo "Invalid destination port: $DESTINATION_PORT"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# function schedule {
|
||||
# bash spin exec -u webuser coolify php artisan schedule:work
|
||||
# }
|
||||
echo "Generating backup file to ./$SOURCE_VOLUME_NAME.tgz"
|
||||
ssh -p $SOURCE_PORT $SOURCE_USER@$SOURCE_SERVER "docker run -v $SOURCE_VOLUME_NAME:/volume --rm --log-driver none loomchild/volume-backup backup -c pigz -v" >./$SOURCE_VOLUME_NAME.tgz
|
||||
echo ""
|
||||
if [ -f "./$SOURCE_VOLUME_NAME.tgz" ]; then
|
||||
echo "Uploading backup file to $DESTINATION_SERVER:~/$DESTINATION_VOLUME_NAME.tgz"
|
||||
scp -P $DESTINATION_PORT ./$SOURCE_VOLUME_NAME.tgz $DESTINATION_USER@$DESTINATION_SERVER:~/$DESTINATION_VOLUME_NAME.tgz
|
||||
echo ""
|
||||
echo "Restoring backup file on remote ($DESTINATION_SERVER:/~/$DESTINATION_VOLUME_NAME.tgz)"
|
||||
ssh -p $DESTINATION_PORT $DESTINATION_USER@$DESTINATION_SERVER "docker run -i -v $DESTINATION_VOLUME_NAME:/volume --log-driver none --rm loomchild/volume-backup restore -c pigz -vf < ~/$DESTINATION_VOLUME_NAME.tgz"
|
||||
echo ""
|
||||
echo "Deleting backup file on remote ($DESTINATION_SERVER:/~/$DESTINATION_VOLUME_NAME.tgz)"
|
||||
ssh -p $DESTINATION_PORT $DESTINATION_USER@$DESTINATION_SERVER "rm ~/$DESTINATION_VOLUME_NAME.tgz"
|
||||
|
||||
# function schedule:run {
|
||||
# bash spin exec -u webuser coolify php artisan schedule:run
|
||||
# }
|
||||
echo ""
|
||||
echo "Local file ./$SOURCE_VOLUME_NAME.tgz is not deleted."
|
||||
|
||||
# function db {
|
||||
# bash spin exec -u webuser coolify php artisan db
|
||||
# }
|
||||
# function db:seed {
|
||||
# bash spin exec -u webuser coolify php artisan migrate --seed
|
||||
# }
|
||||
|
||||
# function db:migrate {
|
||||
# bash spin exec -u webuser coolify php artisan migrate --step
|
||||
# }
|
||||
|
||||
function db:reset {
|
||||
bash spin exec -u webuser coolify php artisan migrate:fresh --seed
|
||||
}
|
||||
function db:reset-prod {
|
||||
bash spin exec -u webuser coolify php artisan migrate:fresh --force --seed --seeder=ProductionSeeder ||
|
||||
php artisan migrate:fresh --force --seed --seeder=ProductionSeeder
|
||||
}
|
||||
|
||||
function mfs {
|
||||
db:reset
|
||||
}
|
||||
|
||||
function coolify {
|
||||
bash spin exec -u webuser coolify bash
|
||||
}
|
||||
|
||||
function coolify:root {
|
||||
bash spin exec coolify bash
|
||||
}
|
||||
function coolify:proxy {
|
||||
docker exec -ti coolify-proxy sh
|
||||
}
|
||||
|
||||
function redis {
|
||||
docker exec -ti coolify-redis redis-cli
|
||||
}
|
||||
|
||||
function vite {
|
||||
bash spin exec vite bash
|
||||
}
|
||||
|
||||
function tinker {
|
||||
bash spin exec -u webuser coolify php artisan tinker
|
||||
}
|
||||
|
||||
# function build:helper {
|
||||
# act -W .github/workflows/coolify-helper.yml --secret-file .env.secrets
|
||||
# }
|
||||
function default {
|
||||
help
|
||||
}
|
||||
|
||||
TIMEFORMAT="Task completed in %3lR"
|
||||
time "${@:-default}"
|
||||
echo ""
|
||||
echo "WARNING: If you are copying a database volume, you need to set the right users/passwords on the destination service's environment variables."
|
||||
echo "Why? Because we are copying the volume as-is, so the database credentials will bethe same as on the source volume."
|
||||
fi
|
||||
|
@ -1,23 +1,17 @@
|
||||
#!/bin/bash
|
||||
## Do not modify this file. You will lose the ability to autoupdate!
|
||||
|
||||
VERSION="1.0.5"
|
||||
CDN="https://cdn.lasthourhosting.org/lasthourcloud"
|
||||
VERSION="1.1"
|
||||
CDN="https://cdn.lasthourhosting.org/lasthourcloudprod"
|
||||
LATEST_IMAGE=${1:-latest}
|
||||
LATEST_HELPER_VERSION=${2:-latest}
|
||||
|
||||
curl -fsSL $CDN/docker-compose.yml -o /data/coolify/source/docker-compose.yml
|
||||
curl -fsSL $CDN/docker-compose.prod.yml -o /data/coolify/source/docker-compose.prod.yml
|
||||
curl -fsSL $CDN/.env.production -o /data/coolify/source/.env.production
|
||||
|
||||
# echo "Copying required files from Last Hour Cloud git repo..."
|
||||
# cp /home/lasthour/lasthourcloud/docker-compose.yml /data/coolify/source/docker-compose.yml
|
||||
# cp /home/lasthour/lasthourcloud/docker-compose.prod.yml /data/coolify/source/docker-compose.prod.yml
|
||||
# cp /home/lasthour/lasthourcloud/.env.production /data/coolify/source/.env.production
|
||||
# cp /home/lasthour/lasthourcloud/scripts/upgrade.sh /data/coolify/source/upgrade.sh
|
||||
|
||||
|
||||
# Merge .env and .env.production. New values will be added to .env
|
||||
sort -u -t '=' -k 1,1 /data/coolify/source/.env /data/coolify/source/.env.production | sed '/^$/d' >/data/coolify/source/.env.temp && mv /data/coolify/source/.env.temp /data/coolify/source/.env
|
||||
|
||||
awk -F '=' '!seen[$1]++' /data/coolify/source/.env /data/coolify/source/.env.production > /data/coolify/source/.env.tmp && mv /data/coolify/source/.env.tmp /data/coolify/source/.env
|
||||
# Check if PUSHER_APP_ID or PUSHER_APP_KEY or PUSHER_APP_SECRET is empty in /data/coolify/source/.env
|
||||
if grep -q "PUSHER_APP_ID=$" /data/coolify/source/.env; then
|
||||
sed -i "s|PUSHER_APP_ID=.*|PUSHER_APP_ID=$(openssl rand -hex 32)|g" /data/coolify/source/.env
|
||||
@ -31,13 +25,14 @@ if grep -q "PUSHER_APP_SECRET=$" /data/coolify/source/.env; then
|
||||
sed -i "s|PUSHER_APP_SECRET=.*|PUSHER_APP_SECRET=$(openssl rand -hex 32)|g" /data/coolify/source/.env
|
||||
fi
|
||||
|
||||
# Make sure coolify network exists
|
||||
# Make sure Last Hour Cloud network exists
|
||||
# It is created when starting Last Hour Cloud with docker compose
|
||||
docker network create --attachable coolify 2>/dev/null
|
||||
# docker network create --attachable --driver=overlay coolify-overlay 2>/dev/null
|
||||
|
||||
if [ -f /data/coolify/source/docker-compose.custom.yml ]; then
|
||||
echo "docker-compose.custom.yml detected."
|
||||
docker run -v /data/coolify/source:/data/coolify/source -v /var/run/docker.sock:/var/run/docker.sock --rm ghcr.io/coollabsio/coolify-helper bash -c "LATEST_IMAGE=${1:-} docker compose --env-file /data/coolify/source/.env -f /data/coolify/source/docker-compose.yml -f /data/coolify/source/docker-compose.prod.yml -f /data/coolify/source/docker-compose.custom.yml up -d --remove-orphans --force-recreate"
|
||||
docker run -v /data/coolify/source:/data/coolify/source -v /var/run/docker.sock:/var/run/docker.sock --rm ghcr.io/coollabsio/coolify-helper:${LATEST_HELPER_VERSION:-latest} bash -c "LATEST_IMAGE=${1:-} docker compose --env-file /data/coolify/source/.env -f /data/coolify/source/docker-compose.yml -f /data/coolify/source/docker-compose.prod.yml -f /data/coolify/source/docker-compose.custom.yml up -d --remove-orphans --force-recreate --wait --wait-timeout 60"
|
||||
else
|
||||
docker run -v /data/coolify/source:/data/coolify/source -v /var/run/docker.sock:/var/run/docker.sock --rm ghcr.io/coollabsio/coolify-helper bash -c "LATEST_IMAGE=${1:-} docker compose --env-file /data/coolify/source/.env -f /data/coolify/source/docker-compose.yml -f /data/coolify/source/docker-compose.prod.yml up -d --remove-orphans --force-recreate"
|
||||
docker run -v /data/coolify/source:/data/coolify/source -v /var/run/docker.sock:/var/run/docker.sock --rm ghcr.io/coollabsio/coolify-helper:${LATEST_HELPER_VERSION:-latest} bash -c "LATEST_IMAGE=${1:-} docker compose --env-file /data/coolify/source/.env -f /data/coolify/source/docker-compose.yml -f /data/coolify/source/docker-compose.prod.yml up -d --remove-orphans --force-recreate --wait --wait-timeout 60"
|
||||
fi
|
Loading…
Reference in New Issue
Block a user