mirror of
https://github.com/ershisan99/coolify.git
synced 2025-12-18 20:59:24 +00:00
Compare commits
31 Commits
v4.0.0-bet
...
v4.0.0-bet
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
53975fcf61 | ||
|
|
76296c1f19 | ||
|
|
c25baf69e1 | ||
|
|
f952512615 | ||
|
|
c6557eada8 | ||
|
|
2c2d74c0d6 | ||
|
|
028a2eb275 | ||
|
|
ce7fad5bef | ||
|
|
cd7852e4f9 | ||
|
|
7b022a2482 | ||
|
|
12d9b6538b | ||
|
|
335788c2d6 | ||
|
|
2352e4a71d | ||
|
|
dc03179bd1 | ||
|
|
cc72f416e8 | ||
|
|
3b67d0a8de | ||
|
|
0135ba7e89 | ||
|
|
a28a28cd23 | ||
|
|
b52680a2d8 | ||
|
|
0670e6c1d6 | ||
|
|
c3882b75c1 | ||
|
|
64b6f86a36 | ||
|
|
b9efc22253 | ||
|
|
e3d9eb0154 | ||
|
|
66f3967479 | ||
|
|
c54439e84c | ||
|
|
db4a4c74fc | ||
|
|
5c7ef80219 | ||
|
|
243d1c06fc | ||
|
|
ef25f7d800 | ||
|
|
45640ffdb1 |
@@ -67,7 +67,7 @@ class InstallDocker
|
|||||||
}
|
}
|
||||||
$command = $command->merge([
|
$command = $command->merge([
|
||||||
"echo 'Installing Docker Engine...'",
|
"echo 'Installing Docker Engine...'",
|
||||||
"curl https://releases.rancher.com/install-docker/{$dockerVersion}.sh | sh",
|
"curl https://releases.rancher.com/install-docker/{$dockerVersion}.sh | sh || curl https://get.docker.com | sh -s -- --version {$dockerVersion}",
|
||||||
"echo 'Configuring Docker Engine (merging existing configuration with the required)...'",
|
"echo 'Configuring Docker Engine (merging existing configuration with the required)...'",
|
||||||
"test -s /etc/docker/daemon.json && cp /etc/docker/daemon.json \"/etc/docker/daemon.json.original-`date +\"%Y%m%d-%H%M%S\"`\" || echo '{$config}' | base64 -d > /etc/docker/daemon.json",
|
"test -s /etc/docker/daemon.json && cp /etc/docker/daemon.json \"/etc/docker/daemon.json.original-`date +\"%Y%m%d-%H%M%S\"`\" || echo '{$config}' | base64 -d > /etc/docker/daemon.json",
|
||||||
"echo '{$config}' | base64 -d > /etc/docker/daemon.json.coolify",
|
"echo '{$config}' | base64 -d > /etc/docker/daemon.json.coolify",
|
||||||
|
|||||||
@@ -16,6 +16,8 @@ class InstallLogDrain
|
|||||||
$type = 'highlight';
|
$type = 'highlight';
|
||||||
} else if ($server->settings->is_logdrain_axiom_enabled) {
|
} else if ($server->settings->is_logdrain_axiom_enabled) {
|
||||||
$type = 'axiom';
|
$type = 'axiom';
|
||||||
|
} else if ($server->settings->is_logdrain_custom_enabled) {
|
||||||
|
$type = 'custom';
|
||||||
} else {
|
} else {
|
||||||
$type = 'none';
|
$type = 'none';
|
||||||
}
|
}
|
||||||
@@ -114,15 +116,23 @@ class InstallLogDrain
|
|||||||
json_date_format iso8601
|
json_date_format iso8601
|
||||||
tls On
|
tls On
|
||||||
");
|
");
|
||||||
|
} else if ($type === 'custom') {
|
||||||
|
if (!$server->settings->is_logdrain_custom_enabled) {
|
||||||
|
throw new \Exception('Custom log drain is not enabled.');
|
||||||
|
}
|
||||||
|
$config = base64_encode($server->settings->logdrain_custom_config);
|
||||||
|
$parsers = base64_encode($server->settings->logdrain_custom_config_parser);
|
||||||
} else {
|
} else {
|
||||||
throw new \Exception('Unknown log drain type.');
|
throw new \Exception('Unknown log drain type.');
|
||||||
}
|
}
|
||||||
$parsers = base64_encode("
|
if ($type !== 'custom') {
|
||||||
|
$parsers = base64_encode("
|
||||||
[PARSER]
|
[PARSER]
|
||||||
Name empty_line_skipper
|
Name empty_line_skipper
|
||||||
Format regex
|
Format regex
|
||||||
Regex /^(?!\s*$).+/
|
Regex /^(?!\s*$).+/
|
||||||
");
|
");
|
||||||
|
}
|
||||||
$compose = base64_encode("
|
$compose = base64_encode("
|
||||||
services:
|
services:
|
||||||
coolify-log-drain:
|
coolify-log-drain:
|
||||||
@@ -179,6 +189,12 @@ Files:
|
|||||||
"echo AXIOM_DATASET_NAME={$server->settings->logdrain_axiom_dataset_name} >> $config_path/.env",
|
"echo AXIOM_DATASET_NAME={$server->settings->logdrain_axiom_dataset_name} >> $config_path/.env",
|
||||||
"echo AXIOM_API_KEY={$server->settings->logdrain_axiom_api_key} >> $config_path/.env",
|
"echo AXIOM_API_KEY={$server->settings->logdrain_axiom_api_key} >> $config_path/.env",
|
||||||
];
|
];
|
||||||
|
} else if ($type === 'custom') {
|
||||||
|
$add_envs_command = [
|
||||||
|
"touch $config_path/.env"
|
||||||
|
];
|
||||||
|
} else {
|
||||||
|
throw new \Exception('Unknown log drain type.');
|
||||||
}
|
}
|
||||||
$restart_command = [
|
$restart_command = [
|
||||||
"echo 'Stopping old Fluent Bit'",
|
"echo 'Stopping old Fluent Bit'",
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ class StartService
|
|||||||
$commands[] = "echo 'Pulling images.'";
|
$commands[] = "echo 'Pulling images.'";
|
||||||
$commands[] = "docker compose pull";
|
$commands[] = "docker compose pull";
|
||||||
$commands[] = "echo 'Starting containers.'";
|
$commands[] = "echo 'Starting containers.'";
|
||||||
$commands[] = "docker compose up -d --remove-orphans --force-recreate";
|
$commands[] = "docker compose up -d --remove-orphans --force-recreate --build";
|
||||||
$commands[] = "docker network connect $service->uuid coolify-proxy >/dev/null 2>&1 || true";
|
$commands[] = "docker network connect $service->uuid coolify-proxy >/dev/null 2>&1 || true";
|
||||||
$compose = data_get($service,'docker_compose',[]);
|
$compose = data_get($service,'docker_compose',[]);
|
||||||
$serviceNames = data_get(Yaml::parse($compose),'services',[]);
|
$serviceNames = data_get(Yaml::parse($compose),'services',[]);
|
||||||
|
|||||||
@@ -37,14 +37,14 @@ class Init extends Command
|
|||||||
$this->cleanup_in_progress_application_deployments();
|
$this->cleanup_in_progress_application_deployments();
|
||||||
$this->cleanup_stucked_helper_containers();
|
$this->cleanup_stucked_helper_containers();
|
||||||
}
|
}
|
||||||
private function cleanup_stucked_helper_containers() {
|
private function cleanup_stucked_helper_containers()
|
||||||
|
{
|
||||||
$servers = Server::all();
|
$servers = Server::all();
|
||||||
foreach ($servers as $server) {
|
foreach ($servers as $server) {
|
||||||
if ($server->isFunctional()) {
|
if ($server->isFunctional()) {
|
||||||
CleanupHelperContainersJob::dispatch($server);
|
CleanupHelperContainersJob::dispatch($server);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
private function alive()
|
private function alive()
|
||||||
{
|
{
|
||||||
@@ -66,7 +66,7 @@ class Init extends Command
|
|||||||
// private function cleanup_ssh()
|
// private function cleanup_ssh()
|
||||||
// {
|
// {
|
||||||
|
|
||||||
// TODO: it will cleanup id.root@host.docker.internal
|
// TODO: it will cleanup id.root@host.docker.internal
|
||||||
// try {
|
// try {
|
||||||
// $files = Storage::allFiles('ssh/keys');
|
// $files = Storage::allFiles('ssh/keys');
|
||||||
// foreach ($files as $file) {
|
// foreach ($files as $file) {
|
||||||
@@ -101,15 +101,15 @@ class Init extends Command
|
|||||||
$applications = Application::all();
|
$applications = Application::all();
|
||||||
foreach ($applications as $application) {
|
foreach ($applications as $application) {
|
||||||
if (!data_get($application, 'environment')) {
|
if (!data_get($application, 'environment')) {
|
||||||
ray('Application without environment', $application->name);
|
echo 'Application without environment' . $application->name . 'deleting\n';
|
||||||
$application->delete();
|
$application->delete();
|
||||||
}
|
}
|
||||||
if (!$application->destination()) {
|
if (!$application->destination()) {
|
||||||
ray('Application without destination', $application->name);
|
echo 'Application without destination' . $application->name . 'deleting\n';
|
||||||
$application->delete();
|
$application->delete();
|
||||||
}
|
}
|
||||||
if (!data_get($application, 'destination.server')) {
|
if (!data_get($application, 'destination.server')) {
|
||||||
ray('Application without server', $application->name);
|
echo 'Application without server' . $application->name . 'deleting\n';
|
||||||
$application->delete();
|
$application->delete();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -120,15 +120,15 @@ class Init extends Command
|
|||||||
$postgresqls = StandalonePostgresql::all();
|
$postgresqls = StandalonePostgresql::all();
|
||||||
foreach ($postgresqls as $postgresql) {
|
foreach ($postgresqls as $postgresql) {
|
||||||
if (!data_get($postgresql, 'environment')) {
|
if (!data_get($postgresql, 'environment')) {
|
||||||
ray('Postgresql without environment', $postgresql->name);
|
echo 'Postgresql without environment' . $postgresql->name . 'deleting\n';
|
||||||
$postgresql->delete();
|
$postgresql->delete();
|
||||||
}
|
}
|
||||||
if (!$postgresql->destination()) {
|
if (!$postgresql->destination()) {
|
||||||
ray('Postgresql without destination', $postgresql->name);
|
echo 'Postgresql without destination' . $postgresql->name . 'deleting\n';
|
||||||
$postgresql->delete();
|
$postgresql->delete();
|
||||||
}
|
}
|
||||||
if (!data_get($postgresql, 'destination.server')) {
|
if (!data_get($postgresql, 'destination.server')) {
|
||||||
ray('Postgresql without server', $postgresql->name);
|
echo 'Postgresql without server' . $postgresql->name . 'deleting\n';
|
||||||
$postgresql->delete();
|
$postgresql->delete();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -139,15 +139,15 @@ class Init extends Command
|
|||||||
$redis = StandaloneRedis::all();
|
$redis = StandaloneRedis::all();
|
||||||
foreach ($redis as $redis) {
|
foreach ($redis as $redis) {
|
||||||
if (!data_get($redis, 'environment')) {
|
if (!data_get($redis, 'environment')) {
|
||||||
ray('Redis without environment', $redis->name);
|
echo 'Redis without environment' . $redis->name . 'deleting\n';
|
||||||
$redis->delete();
|
$redis->delete();
|
||||||
}
|
}
|
||||||
if (!$redis->destination()) {
|
if (!$redis->destination()) {
|
||||||
ray('Redis without destination', $redis->name);
|
echo 'Redis without destination' . $redis->name . 'deleting\n';
|
||||||
$redis->delete();
|
$redis->delete();
|
||||||
}
|
}
|
||||||
if (!data_get($redis, 'destination.server')) {
|
if (!data_get($redis, 'destination.server')) {
|
||||||
ray('Redis without server', $redis->name);
|
echo 'Redis without server' . $redis->name . 'deleting\n';
|
||||||
$redis->delete();
|
$redis->delete();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -159,15 +159,15 @@ class Init extends Command
|
|||||||
$mongodbs = StandaloneMongodb::all();
|
$mongodbs = StandaloneMongodb::all();
|
||||||
foreach ($mongodbs as $mongodb) {
|
foreach ($mongodbs as $mongodb) {
|
||||||
if (!data_get($mongodb, 'environment')) {
|
if (!data_get($mongodb, 'environment')) {
|
||||||
ray('Mongodb without environment', $mongodb->name);
|
echo 'Mongodb without environment' . $mongodb->name . 'deleting\n';
|
||||||
$mongodb->delete();
|
$mongodb->delete();
|
||||||
}
|
}
|
||||||
if (!$mongodb->destination()) {
|
if (!$mongodb->destination()) {
|
||||||
ray('Mongodb without destination', $mongodb->name);
|
echo 'Mongodb without destination' . $mongodb->name . 'deleting\n';
|
||||||
$mongodb->delete();
|
$mongodb->delete();
|
||||||
}
|
}
|
||||||
if (!data_get($mongodb, 'destination.server')) {
|
if (!data_get($mongodb, 'destination.server')) {
|
||||||
ray('Mongodb without server', $mongodb->name);
|
echo 'Mongodb without server' . $mongodb->name . 'deleting\n';
|
||||||
$mongodb->delete();
|
$mongodb->delete();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -179,15 +179,15 @@ class Init extends Command
|
|||||||
$mysqls = StandaloneMysql::all();
|
$mysqls = StandaloneMysql::all();
|
||||||
foreach ($mysqls as $mysql) {
|
foreach ($mysqls as $mysql) {
|
||||||
if (!data_get($mysql, 'environment')) {
|
if (!data_get($mysql, 'environment')) {
|
||||||
ray('Mysql without environment', $mysql->name);
|
echo 'Mysql without environment' . $mysql->name . 'deleting\n';
|
||||||
$mysql->delete();
|
$mysql->delete();
|
||||||
}
|
}
|
||||||
if (!$mysql->destination()) {
|
if (!$mysql->destination()) {
|
||||||
ray('Mysql without destination', $mysql->name);
|
echo 'Mysql without destination' . $mysql->name . 'deleting\n';
|
||||||
$mysql->delete();
|
$mysql->delete();
|
||||||
}
|
}
|
||||||
if (!data_get($mysql, 'destination.server')) {
|
if (!data_get($mysql, 'destination.server')) {
|
||||||
ray('Mysql without server', $mysql->name);
|
echo 'Mysql without server' . $mysql->name . 'deleting\n';
|
||||||
$mysql->delete();
|
$mysql->delete();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -199,15 +199,15 @@ class Init extends Command
|
|||||||
$mariadbs = StandaloneMariadb::all();
|
$mariadbs = StandaloneMariadb::all();
|
||||||
foreach ($mariadbs as $mariadb) {
|
foreach ($mariadbs as $mariadb) {
|
||||||
if (!data_get($mariadb, 'environment')) {
|
if (!data_get($mariadb, 'environment')) {
|
||||||
ray('Mariadb without environment', $mariadb->name);
|
echo 'Mariadb without environment' . $mariadb->name . 'deleting\n';
|
||||||
$mariadb->delete();
|
$mariadb->delete();
|
||||||
}
|
}
|
||||||
if (!$mariadb->destination()) {
|
if (!$mariadb->destination()) {
|
||||||
ray('Mariadb without destination', $mariadb->name);
|
echo 'Mariadb without destination' . $mariadb->name . 'deleting\n';
|
||||||
$mariadb->delete();
|
$mariadb->delete();
|
||||||
}
|
}
|
||||||
if (!data_get($mariadb, 'destination.server')) {
|
if (!data_get($mariadb, 'destination.server')) {
|
||||||
ray('Mariadb without server', $mariadb->name);
|
echo 'Mariadb without server' . $mariadb->name . 'deleting\n';
|
||||||
$mariadb->delete();
|
$mariadb->delete();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -219,15 +219,15 @@ class Init extends Command
|
|||||||
$services = Service::all();
|
$services = Service::all();
|
||||||
foreach ($services as $service) {
|
foreach ($services as $service) {
|
||||||
if (!data_get($service, 'environment')) {
|
if (!data_get($service, 'environment')) {
|
||||||
ray('Service without environment', $service->name);
|
echo 'Service without environment' . $service->name . 'deleting\n';
|
||||||
$service->delete();
|
$service->delete();
|
||||||
}
|
}
|
||||||
if (!$service->destination()) {
|
if (!$service->destination()) {
|
||||||
ray('Service without destination', $service->name);
|
echo 'Service without destination' . $service->name . 'deleting\n';
|
||||||
$service->delete();
|
$service->delete();
|
||||||
}
|
}
|
||||||
if (!data_get($service, 'server')) {
|
if (!data_get($service, 'server')) {
|
||||||
ray('Service without server', $service->name);
|
echo 'Service without server' . $service->name . 'deleting\n';
|
||||||
$service->delete();
|
$service->delete();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -238,7 +238,7 @@ class Init extends Command
|
|||||||
$serviceApplications = ServiceApplication::all();
|
$serviceApplications = ServiceApplication::all();
|
||||||
foreach ($serviceApplications as $service) {
|
foreach ($serviceApplications as $service) {
|
||||||
if (!data_get($service, 'service')) {
|
if (!data_get($service, 'service')) {
|
||||||
ray('ServiceApplication without service', $service->name);
|
echo 'ServiceApplication without service' . $service->name . 'deleting\n';
|
||||||
$service->delete();
|
$service->delete();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -249,7 +249,7 @@ class Init extends Command
|
|||||||
$serviceDatabases = ServiceDatabase::all();
|
$serviceDatabases = ServiceDatabase::all();
|
||||||
foreach ($serviceDatabases as $service) {
|
foreach ($serviceDatabases as $service) {
|
||||||
if (!data_get($service, 'service')) {
|
if (!data_get($service, 'service')) {
|
||||||
ray('ServiceDatabase without service', $service->name);
|
echo 'ServiceDatabase without service' . $service->name . 'deleting\n';
|
||||||
$service->delete();
|
$service->delete();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ class Index extends Component
|
|||||||
public ?int $remoteServerPort = 22;
|
public ?int $remoteServerPort = 22;
|
||||||
public ?string $remoteServerUser = 'root';
|
public ?string $remoteServerUser = 'root';
|
||||||
public bool $isSwarmManager = false;
|
public bool $isSwarmManager = false;
|
||||||
|
public bool $isCloudflareTunnel = false;
|
||||||
public ?Server $createdServer = null;
|
public ?Server $createdServer = null;
|
||||||
|
|
||||||
public Collection $projects;
|
public Collection $projects;
|
||||||
@@ -184,6 +185,7 @@ uZx9iFkCELtxrh31QJ68AAAAEXNhaWxANzZmZjY2ZDJlMmRkAQIDBA==
|
|||||||
'team_id' => currentTeam()->id,
|
'team_id' => currentTeam()->id,
|
||||||
]);
|
]);
|
||||||
$this->createdServer->settings->is_swarm_manager = $this->isSwarmManager;
|
$this->createdServer->settings->is_swarm_manager = $this->isSwarmManager;
|
||||||
|
$this->createdServer->settings->is_cloudflare_tunnel = $this->isCloudflareTunnel;
|
||||||
$this->createdServer->settings->save();
|
$this->createdServer->settings->save();
|
||||||
$this->createdServer->addInitialNetwork();
|
$this->createdServer->addInitialNetwork();
|
||||||
$this->validateServer();
|
$this->validateServer();
|
||||||
@@ -200,6 +202,7 @@ uZx9iFkCELtxrh31QJ68AAAAEXNhaWxANzZmZjY2ZDJlMmRkAQIDBA==
|
|||||||
]);
|
]);
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
$this->serverReachable = false;
|
$this->serverReachable = false;
|
||||||
|
$this->createdServer->delete();
|
||||||
return handleError(error: $e, livewire: $this);
|
return handleError(error: $e, livewire: $this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -22,79 +22,19 @@ class DockerCompose extends Component
|
|||||||
$this->query = request()->query();
|
$this->query = request()->query();
|
||||||
if (isDev()) {
|
if (isDev()) {
|
||||||
$this->dockerComposeRaw = 'services:
|
$this->dockerComposeRaw = 'services:
|
||||||
ghost:
|
appsmith:
|
||||||
image: ghost:5
|
build:
|
||||||
volumes:
|
context: .
|
||||||
- ~/configs:/etc/configs/:ro
|
dockerfile_inline: |
|
||||||
- ./var/lib/ghost/content:/tmp/ghost2/content:ro
|
FROM nginx
|
||||||
- /var/lib/ghost/content:/tmp/ghost/content:rw
|
ARG GIT_COMMIT
|
||||||
- ghost-content-data:/var/lib/ghost/content
|
ARG GIT_BRANCH
|
||||||
- type: volume
|
RUN echo "Hello World ${GIT_COMMIT} ${GIT_BRANCH}"
|
||||||
source: mydata
|
args:
|
||||||
target: /data
|
- GIT_COMMIT=cdc3b19
|
||||||
- type: bind
|
- GIT_BRANCH=${GIT_BRANCH}
|
||||||
source: ./var/lib/ghost/data
|
|
||||||
target: /data
|
|
||||||
- type: bind
|
|
||||||
source: /tmp
|
|
||||||
target: /tmp
|
|
||||||
labels:
|
|
||||||
- "test.label=true"
|
|
||||||
ports:
|
|
||||||
- "3000"
|
|
||||||
- "3000-3005"
|
|
||||||
- "8000:8000"
|
|
||||||
- "9090-9091:8080-8081"
|
|
||||||
- "49100:22"
|
|
||||||
- "127.0.0.1:8001:8001"
|
|
||||||
- "127.0.0.1:5000-5010:5000-5010"
|
|
||||||
- "127.0.0.1::5000"
|
|
||||||
- "6060:6060/udp"
|
|
||||||
- "12400-12500:1240"
|
|
||||||
- target: 80
|
|
||||||
published: 8080
|
|
||||||
protocol: tcp
|
|
||||||
mode: host
|
|
||||||
networks:
|
|
||||||
- some-network
|
|
||||||
- other-network
|
|
||||||
environment:
|
environment:
|
||||||
- database__client=${DATABASE_CLIENT:-mysql}
|
- APPSMITH_MAIL_ENABLED=${APPSMITH_MAIL_ENABLED}
|
||||||
- database__connection__database=${MYSQL_DATABASE:-ghost}
|
|
||||||
- database__connection__host=${DATABASE_CONNECTION_HOST:-mysql}
|
|
||||||
- test=${TEST:?true}
|
|
||||||
- url=$SERVICE_FQDN_GHOST
|
|
||||||
- database__connection__user=$SERVICE_USER_MYSQL
|
|
||||||
- database__connection__password=$SERVICE_PASSWORD_MYSQL
|
|
||||||
depends_on:
|
|
||||||
- mysql
|
|
||||||
mysql:
|
|
||||||
image: mysql:8.0
|
|
||||||
volumes:
|
|
||||||
- ghost-mysql-data:/var/lib/mysql
|
|
||||||
environment:
|
|
||||||
- MYSQL_USER=${SERVICE_USER_MYSQL}
|
|
||||||
- MYSQL_PASSWORD=${SERVICE_PASSWORD_MYSQL}
|
|
||||||
- MYSQL_DATABASE=$MYSQL_DATABASE
|
|
||||||
- MYSQL_ROOT_PASSWORD=${SERVICE_PASSWORD_MYSQLROOT}
|
|
||||||
- SESSION_SECRET
|
|
||||||
minio:
|
|
||||||
image: minio/minio
|
|
||||||
environment:
|
|
||||||
RACK_ENV: development
|
|
||||||
A: $A
|
|
||||||
SHOW: ${SHOW}
|
|
||||||
SHOW1: ${SHOW2-show1}
|
|
||||||
SHOW2: ${SHOW3:-show2}
|
|
||||||
SHOW3: ${SHOW4?show3}
|
|
||||||
SHOW4: ${SHOW5:?show4}
|
|
||||||
SHOW5: ${SERVICE_USER_MINIO}
|
|
||||||
SHOW6: ${SERVICE_PASSWORD_MINIO}
|
|
||||||
SHOW7: ${SERVICE_PASSWORD_64_MINIO}
|
|
||||||
SHOW8: ${SERVICE_BASE64_64_MINIO}
|
|
||||||
SHOW9: ${SERVICE_BASE64_128_MINIO}
|
|
||||||
SHOW10: ${SERVICE_BASE64_MINIO}
|
|
||||||
SHOW11:
|
|
||||||
';
|
';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ class Index extends Component
|
|||||||
}
|
}
|
||||||
public function checkStatus()
|
public function checkStatus()
|
||||||
{
|
{
|
||||||
dispatch_sync(new ContainerStatusJob($this->service->server));
|
dispatch(new ContainerStatusJob($this->service->server));
|
||||||
$this->refreshStacks();
|
$this->refreshStacks();
|
||||||
}
|
}
|
||||||
public function refreshStacks()
|
public function refreshStacks()
|
||||||
|
|||||||
@@ -59,7 +59,6 @@ class Show extends Component
|
|||||||
{
|
{
|
||||||
$this->validate();
|
$this->validate();
|
||||||
$this->env->save();
|
$this->env->save();
|
||||||
ray($this->env);
|
|
||||||
$this->emit('success', 'Environment variable updated successfully.');
|
$this->emit('success', 'Environment variable updated successfully.');
|
||||||
$this->emit('refreshEnvs');
|
$this->emit('refreshEnvs');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,16 @@
|
|||||||
|
|
||||||
namespace App\Http\Livewire\Project\Shared;
|
namespace App\Http\Livewire\Project\Shared;
|
||||||
|
|
||||||
|
use App\Models\Application;
|
||||||
use App\Models\Server;
|
use App\Models\Server;
|
||||||
|
use App\Models\Service;
|
||||||
|
use App\Models\ServiceApplication;
|
||||||
|
use App\Models\ServiceDatabase;
|
||||||
|
use App\Models\StandaloneMariadb;
|
||||||
|
use App\Models\StandaloneMongodb;
|
||||||
|
use App\Models\StandaloneMysql;
|
||||||
|
use App\Models\StandalonePostgresql;
|
||||||
|
use App\Models\StandaloneRedis;
|
||||||
use Illuminate\Support\Facades\Process;
|
use Illuminate\Support\Facades\Process;
|
||||||
use Livewire\Component;
|
use Livewire\Component;
|
||||||
|
|
||||||
@@ -10,17 +19,44 @@ class GetLogs extends Component
|
|||||||
{
|
{
|
||||||
public string $outputs = '';
|
public string $outputs = '';
|
||||||
public string $errors = '';
|
public string $errors = '';
|
||||||
|
public Application|Service|StandalonePostgresql|StandaloneRedis|StandaloneMongodb|StandaloneMysql|StandaloneMariadb $resource;
|
||||||
|
public ServiceApplication|ServiceDatabase|null $servicesubtype = null;
|
||||||
public Server $server;
|
public Server $server;
|
||||||
public ?string $container = null;
|
public ?string $container = null;
|
||||||
public ?bool $streamLogs = false;
|
public ?bool $streamLogs = false;
|
||||||
public ?bool $showTimeStamps = true;
|
public ?bool $showTimeStamps = true;
|
||||||
public int $numberOfLines = 100;
|
public int $numberOfLines = 100;
|
||||||
|
|
||||||
|
public function mount()
|
||||||
|
{
|
||||||
|
if ($this->resource->getMorphClass() === 'App\Models\Application') {
|
||||||
|
$this->showTimeStamps = $this->resource->settings->is_include_timestamps;
|
||||||
|
} else {
|
||||||
|
if ($this->servicesubtype) {
|
||||||
|
$this->showTimeStamps = $this->servicesubtype->is_include_timestamps;
|
||||||
|
} else {
|
||||||
|
$this->showTimeStamps = $this->resource->is_include_timestamps;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
public function doSomethingWithThisChunkOfOutput($output)
|
public function doSomethingWithThisChunkOfOutput($output)
|
||||||
{
|
{
|
||||||
$this->outputs .= removeAnsiColors($output);
|
$this->outputs .= removeAnsiColors($output);
|
||||||
}
|
}
|
||||||
public function instantSave()
|
public function instantSave()
|
||||||
{
|
{
|
||||||
|
if ($this->resource->getMorphClass() === 'App\Models\Application') {
|
||||||
|
$this->resource->settings->is_include_timestamps = $this->showTimeStamps;
|
||||||
|
$this->resource->settings->save();
|
||||||
|
} else {
|
||||||
|
if ($this->servicesubtype) {
|
||||||
|
$this->servicesubtype->is_include_timestamps = $this->showTimeStamps;
|
||||||
|
$this->servicesubtype->save();
|
||||||
|
} else {
|
||||||
|
$this->resource->is_include_timestamps = $this->showTimeStamps;
|
||||||
|
$this->resource->save();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
public function getLogs($refresh = false)
|
public function getLogs($refresh = false)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ class Logs extends Component
|
|||||||
public $parameters;
|
public $parameters;
|
||||||
public $query;
|
public $query;
|
||||||
public $status;
|
public $status;
|
||||||
|
public $serviceSubType;
|
||||||
|
|
||||||
public function mount()
|
public function mount()
|
||||||
{
|
{
|
||||||
@@ -64,6 +65,11 @@ class Logs extends Component
|
|||||||
} else if (data_get($this->parameters, 'service_uuid')) {
|
} else if (data_get($this->parameters, 'service_uuid')) {
|
||||||
$this->type = 'service';
|
$this->type = 'service';
|
||||||
$this->resource = Service::where('uuid', $this->parameters['service_uuid'])->firstOrFail();
|
$this->resource = Service::where('uuid', $this->parameters['service_uuid'])->firstOrFail();
|
||||||
|
$service_name = data_get($this->parameters, 'service_name');
|
||||||
|
$this->serviceSubType = $this->resource->applications()->where('name', $service_name)->first();
|
||||||
|
if (!$this->serviceSubType) {
|
||||||
|
$this->serviceSubType = $this->resource->databases()->where('name', $service_name)->first();
|
||||||
|
}
|
||||||
$this->status = $this->resource->status;
|
$this->status = $this->resource->status;
|
||||||
$this->server = $this->resource->server;
|
$this->server = $this->resource->server;
|
||||||
$this->container = data_get($this->parameters, 'service_name') . '-' . $this->resource->uuid;
|
$this->container = data_get($this->parameters, 'service_name') . '-' . $this->resource->uuid;
|
||||||
|
|||||||
@@ -19,6 +19,9 @@ class LogDrains extends Component
|
|||||||
'server.settings.is_logdrain_axiom_enabled' => 'required|boolean',
|
'server.settings.is_logdrain_axiom_enabled' => 'required|boolean',
|
||||||
'server.settings.logdrain_axiom_dataset_name' => 'required|string',
|
'server.settings.logdrain_axiom_dataset_name' => 'required|string',
|
||||||
'server.settings.logdrain_axiom_api_key' => 'required|string',
|
'server.settings.logdrain_axiom_api_key' => 'required|string',
|
||||||
|
'server.settings.is_logdrain_custom_enabled' => 'required|boolean',
|
||||||
|
'server.settings.logdrain_custom_config' => 'required|string',
|
||||||
|
'server.settings.logdrain_custom_config_parser' => 'nullable',
|
||||||
];
|
];
|
||||||
protected $validationAttributes = [
|
protected $validationAttributes = [
|
||||||
'server.settings.is_logdrain_newrelic_enabled' => 'New Relic log drain',
|
'server.settings.is_logdrain_newrelic_enabled' => 'New Relic log drain',
|
||||||
@@ -29,6 +32,9 @@ class LogDrains extends Component
|
|||||||
'server.settings.is_logdrain_axiom_enabled' => 'Axiom log drain',
|
'server.settings.is_logdrain_axiom_enabled' => 'Axiom log drain',
|
||||||
'server.settings.logdrain_axiom_dataset_name' => 'Axiom dataset name',
|
'server.settings.logdrain_axiom_dataset_name' => 'Axiom dataset name',
|
||||||
'server.settings.logdrain_axiom_api_key' => 'Axiom API key',
|
'server.settings.logdrain_axiom_api_key' => 'Axiom API key',
|
||||||
|
'server.settings.is_logdrain_custom_enabled' => 'Custom log drain',
|
||||||
|
'server.settings.logdrain_custom_config' => 'Custom log drain configuration',
|
||||||
|
'server.settings.logdrain_custom_config_parser' => 'Custom log drain configuration parser',
|
||||||
];
|
];
|
||||||
|
|
||||||
public function mount()
|
public function mount()
|
||||||
@@ -84,6 +90,7 @@ class LogDrains extends Component
|
|||||||
$this->server->settings->update([
|
$this->server->settings->update([
|
||||||
'is_logdrain_highlight_enabled' => false,
|
'is_logdrain_highlight_enabled' => false,
|
||||||
'is_logdrain_axiom_enabled' => false,
|
'is_logdrain_axiom_enabled' => false,
|
||||||
|
'is_logdrain_custom_enabled' => false,
|
||||||
]);
|
]);
|
||||||
} else if ($type === 'highlight') {
|
} else if ($type === 'highlight') {
|
||||||
$this->validate([
|
$this->validate([
|
||||||
@@ -93,6 +100,7 @@ class LogDrains extends Component
|
|||||||
$this->server->settings->update([
|
$this->server->settings->update([
|
||||||
'is_logdrain_newrelic_enabled' => false,
|
'is_logdrain_newrelic_enabled' => false,
|
||||||
'is_logdrain_axiom_enabled' => false,
|
'is_logdrain_axiom_enabled' => false,
|
||||||
|
'is_logdrain_custom_enabled' => false,
|
||||||
]);
|
]);
|
||||||
} else if ($type === 'axiom') {
|
} else if ($type === 'axiom') {
|
||||||
$this->validate([
|
$this->validate([
|
||||||
@@ -103,6 +111,18 @@ class LogDrains extends Component
|
|||||||
$this->server->settings->update([
|
$this->server->settings->update([
|
||||||
'is_logdrain_newrelic_enabled' => false,
|
'is_logdrain_newrelic_enabled' => false,
|
||||||
'is_logdrain_highlight_enabled' => false,
|
'is_logdrain_highlight_enabled' => false,
|
||||||
|
'is_logdrain_custom_enabled' => false,
|
||||||
|
]);
|
||||||
|
} else if ($type === 'custom') {
|
||||||
|
$this->validate([
|
||||||
|
'server.settings.is_logdrain_custom_enabled' => 'required|boolean',
|
||||||
|
'server.settings.logdrain_custom_config' => 'required|string',
|
||||||
|
'server.settings.logdrain_custom_config_parser' => 'nullable',
|
||||||
|
]);
|
||||||
|
$this->server->settings->update([
|
||||||
|
'is_logdrain_newrelic_enabled' => false,
|
||||||
|
'is_logdrain_highlight_enabled' => false,
|
||||||
|
'is_logdrain_axiom_enabled' => false,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
$this->server->settings->save();
|
$this->server->settings->save();
|
||||||
@@ -121,6 +141,10 @@ class LogDrains extends Component
|
|||||||
$this->server->settings->update([
|
$this->server->settings->update([
|
||||||
'is_logdrain_axiom_enabled' => false,
|
'is_logdrain_axiom_enabled' => false,
|
||||||
]);
|
]);
|
||||||
|
} else if ($type === 'custom') {
|
||||||
|
$this->server->settings->update([
|
||||||
|
'is_logdrain_custom_enabled' => false,
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
handleError($e, $this);
|
handleError($e, $this);
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -14,6 +14,9 @@ class Status extends Component
|
|||||||
public int $numberOfPolls = 0;
|
public int $numberOfPolls = 0;
|
||||||
|
|
||||||
protected $listeners = ['proxyStatusUpdated', 'startProxyPolling'];
|
protected $listeners = ['proxyStatusUpdated', 'startProxyPolling'];
|
||||||
|
public function mount() {
|
||||||
|
$this->checkProxy();
|
||||||
|
}
|
||||||
public function startProxyPolling()
|
public function startProxyPolling()
|
||||||
{
|
{
|
||||||
$this->checkProxy();
|
$this->checkProxy();
|
||||||
|
|||||||
@@ -11,6 +11,9 @@ class PricingPlans extends Component
|
|||||||
public bool $isTrial = false;
|
public bool $isTrial = false;
|
||||||
public function mount() {
|
public function mount() {
|
||||||
$this->isTrial = !data_get(currentTeam(),'subscription.stripe_trial_already_ended');
|
$this->isTrial = !data_get(currentTeam(),'subscription.stripe_trial_already_ended');
|
||||||
|
if (config('constants.limits.trial_period') == 0) {
|
||||||
|
$this->isTrial = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
public function subscribeStripe($type)
|
public function subscribeStripe($type)
|
||||||
{
|
{
|
||||||
@@ -63,6 +66,7 @@ class PricingPlans extends Component
|
|||||||
];
|
];
|
||||||
|
|
||||||
if (!data_get($team,'subscription.stripe_trial_already_ended')) {
|
if (!data_get($team,'subscription.stripe_trial_already_ended')) {
|
||||||
|
if (config('constants.limits.trial_period') > 0) {
|
||||||
$payload['subscription_data'] = [
|
$payload['subscription_data'] = [
|
||||||
'trial_period_days' => config('constants.limits.trial_period'),
|
'trial_period_days' => config('constants.limits.trial_period'),
|
||||||
'trial_settings' => [
|
'trial_settings' => [
|
||||||
@@ -71,6 +75,7 @@ class PricingPlans extends Component
|
|||||||
]
|
]
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
|
}
|
||||||
$payload['payment_method_collection'] = 'if_required';
|
$payload['payment_method_collection'] = 'if_required';
|
||||||
}
|
}
|
||||||
$customer = currentTeam()->subscription?->stripe_customer_id ?? null;
|
$customer = currentTeam()->subscription?->stripe_customer_id ?? null;
|
||||||
|
|||||||
@@ -347,6 +347,7 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
|
|||||||
$this->generate_image_names();
|
$this->generate_image_names();
|
||||||
$this->check_image_locally_or_remotely();
|
$this->check_image_locally_or_remotely();
|
||||||
if (str($this->saved_outputs->get('local_image_found'))->isNotEmpty()) {
|
if (str($this->saved_outputs->get('local_image_found'))->isNotEmpty()) {
|
||||||
|
$this->create_workdir();
|
||||||
$this->generate_compose_file();
|
$this->generate_compose_file();
|
||||||
$this->rolling_update();
|
$this->rolling_update();
|
||||||
return;
|
return;
|
||||||
@@ -442,10 +443,9 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
|
|||||||
$this->clone_repository();
|
$this->clone_repository();
|
||||||
$this->generate_image_names();
|
$this->generate_image_names();
|
||||||
$this->cleanup_git();
|
$this->cleanup_git();
|
||||||
|
$this->application->loadComposeFile(isInit: false);
|
||||||
$composeFile = $this->application->parseCompose(pull_request_id: $this->pull_request_id);
|
$composeFile = $this->application->parseCompose(pull_request_id: $this->pull_request_id);
|
||||||
$yaml = Yaml::dump($composeFile->toArray(), 10);
|
$yaml = Yaml::dump($composeFile->toArray(), 10);
|
||||||
ray($composeFile);
|
|
||||||
ray($this->container_name);
|
|
||||||
$this->docker_compose_base64 = base64_encode($yaml);
|
$this->docker_compose_base64 = base64_encode($yaml);
|
||||||
$this->execute_remote_command([
|
$this->execute_remote_command([
|
||||||
executeInDocker($this->deployment_uuid, "echo '{$this->docker_compose_base64}' | base64 -d > {$this->workdir}{$this->docker_compose_location}"), "hidden" => true
|
executeInDocker($this->deployment_uuid, "echo '{$this->docker_compose_base64}' | base64 -d > {$this->workdir}{$this->docker_compose_location}"), "hidden" => true
|
||||||
@@ -453,12 +453,10 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
|
|||||||
$this->save_environment_variables();
|
$this->save_environment_variables();
|
||||||
$this->stop_running_container(force: true);
|
$this->stop_running_container(force: true);
|
||||||
|
|
||||||
ray($this->pull_request_id);
|
|
||||||
$networkId = $this->application->uuid;
|
$networkId = $this->application->uuid;
|
||||||
if ($this->pull_request_id !== 0) {
|
if ($this->pull_request_id !== 0) {
|
||||||
$networkId = "{$this->application->uuid}-{$this->pull_request_id}";
|
$networkId = "{$this->application->uuid}-{$this->pull_request_id}";
|
||||||
}
|
}
|
||||||
ray($networkId);
|
|
||||||
if ($this->server->isSwarm()) {
|
if ($this->server->isSwarm()) {
|
||||||
// TODO
|
// TODO
|
||||||
} else {
|
} else {
|
||||||
@@ -468,9 +466,25 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
|
|||||||
"docker network connect {$networkId} coolify-proxy || true", "hidden" => true, "ignore_errors" => true
|
"docker network connect {$networkId} coolify-proxy || true", "hidden" => true, "ignore_errors" => true
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
if (isset($this->docker_compose_base64)) {
|
||||||
|
$readme = generate_readme_file($this->application->name, $this->application_deployment_queue->updated_at);
|
||||||
|
$composeFileName = "$this->configuration_dir/docker-compose.yml";
|
||||||
|
if ($this->pull_request_id !== 0) {
|
||||||
|
$composeFileName = "$this->configuration_dir/docker-compose-pr-{$this->pull_request_id}.yml";
|
||||||
|
}
|
||||||
|
$this->execute_remote_command(
|
||||||
|
[
|
||||||
|
"mkdir -p $this->configuration_dir"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"echo '{$this->docker_compose_base64}' | base64 -d > $composeFileName",
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"echo '{$readme}' > $this->configuration_dir/README.md",
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
$this->start_by_compose_file();
|
$this->start_by_compose_file();
|
||||||
$this->application->loadComposeFile(isInit: false);
|
|
||||||
}
|
}
|
||||||
private function deploy_dockerfile_buildpack()
|
private function deploy_dockerfile_buildpack()
|
||||||
{
|
{
|
||||||
@@ -513,6 +527,7 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
|
|||||||
if (!$this->force_rebuild) {
|
if (!$this->force_rebuild) {
|
||||||
$this->check_image_locally_or_remotely();
|
$this->check_image_locally_or_remotely();
|
||||||
if (str($this->saved_outputs->get('local_image_found'))->isNotEmpty() && !$this->application->isConfigurationChanged()) {
|
if (str($this->saved_outputs->get('local_image_found'))->isNotEmpty() && !$this->application->isConfigurationChanged()) {
|
||||||
|
$this->create_workdir();
|
||||||
$this->execute_remote_command([
|
$this->execute_remote_command([
|
||||||
"echo 'No configuration changed & image found ({$this->production_image_name}) with the same Git Commit SHA. Build step skipped.'",
|
"echo 'No configuration changed & image found ({$this->production_image_name}) with the same Git Commit SHA. Build step skipped.'",
|
||||||
]);
|
]);
|
||||||
@@ -660,7 +675,14 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
|
|||||||
[executeInDocker($this->deployment_uuid, "docker compose --project-directory {$this->workdir} up -d"), "hidden" => true],
|
[executeInDocker($this->deployment_uuid, "docker compose --project-directory {$this->workdir} up -d"), "hidden" => true],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
private function create_workdir()
|
||||||
|
{
|
||||||
|
$this->execute_remote_command(
|
||||||
|
[
|
||||||
|
"command" => executeInDocker($this->deployment_uuid, "mkdir -p {$this->workdir}")
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
private function prepare_builder_image()
|
private function prepare_builder_image()
|
||||||
{
|
{
|
||||||
$helperImage = config('coolify.helper_image');
|
$helperImage = config('coolify.helper_image');
|
||||||
@@ -669,9 +691,9 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
|
|||||||
$this->dockerConfigFileExists = instant_remote_process(["test -f {$this->serverUserHomeDir}/.docker/config.json && echo 'OK' || echo 'NOK'"], $this->server);
|
$this->dockerConfigFileExists = instant_remote_process(["test -f {$this->serverUserHomeDir}/.docker/config.json && echo 'OK' || echo 'NOK'"], $this->server);
|
||||||
|
|
||||||
if ($this->dockerConfigFileExists === 'OK') {
|
if ($this->dockerConfigFileExists === 'OK') {
|
||||||
$runCommand = "docker run -d --network {$this->destination->network} -v /:/host --name {$this->deployment_uuid} --rm -v {$this->serverUserHomeDir}/.docker/config.json:/root/.docker/config.json:ro -v /var/run/docker.sock:/var/run/docker.sock {$helperImage}";
|
$runCommand = "docker run -d --network {$this->destination->network} --name {$this->deployment_uuid} --rm -v {$this->serverUserHomeDir}/.docker/config.json:/root/.docker/config.json:ro -v /var/run/docker.sock:/var/run/docker.sock {$helperImage}";
|
||||||
} else {
|
} else {
|
||||||
$runCommand = "docker run -d --network {$this->destination->network} -v /:/host --name {$this->deployment_uuid} --rm -v /var/run/docker.sock:/var/run/docker.sock {$helperImage}";
|
$runCommand = "docker run -d --network {$this->destination->network} --name {$this->deployment_uuid} --rm -v /var/run/docker.sock:/var/run/docker.sock {$helperImage}";
|
||||||
}
|
}
|
||||||
$this->execute_remote_command(
|
$this->execute_remote_command(
|
||||||
[
|
[
|
||||||
@@ -684,6 +706,7 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
|
|||||||
[
|
[
|
||||||
"command" => executeInDocker($this->deployment_uuid, "mkdir -p {$this->basedir}")
|
"command" => executeInDocker($this->deployment_uuid, "mkdir -p {$this->basedir}")
|
||||||
],
|
],
|
||||||
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
private function deploy_to_additional_destinations()
|
private function deploy_to_additional_destinations()
|
||||||
@@ -1264,7 +1287,6 @@ COPY ./nginx.conf /etc/nginx/conf.d/default.conf");
|
|||||||
$dockerfile->splice(1, 0, "ARG {$env->key}={$env->value}");
|
$dockerfile->splice(1, 0, "ARG {$env->key}={$env->value}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ray($dockerfile->implode("\n"));
|
|
||||||
$dockerfile_base64 = base64_encode($dockerfile->implode("\n"));
|
$dockerfile_base64 = base64_encode($dockerfile->implode("\n"));
|
||||||
$this->execute_remote_command([
|
$this->execute_remote_command([
|
||||||
executeInDocker($this->deployment_uuid, "echo '{$dockerfile_base64}' | base64 -d > {$this->workdir}{$this->dockerfile_location}"),
|
executeInDocker($this->deployment_uuid, "echo '{$dockerfile_base64}' | base64 -d > {$this->workdir}{$this->dockerfile_location}"),
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ class CheckLogDrainContainerJob implements ShouldQueue, ShouldBeEncrypted
|
|||||||
if (!$this->server->isServerReady()) {
|
if (!$this->server->isServerReady()) {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
$containers = instant_remote_process(["docker container ls -q"], $this->server);
|
$containers = instant_remote_process(["docker container ls -q"], $this->server, false);
|
||||||
if (!$containers) {
|
if (!$containers) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
namespace App\Jobs;
|
namespace App\Jobs;
|
||||||
|
|
||||||
|
use App\Actions\Database\StartDatabaseProxy;
|
||||||
use App\Actions\Proxy\CheckProxy;
|
use App\Actions\Proxy\CheckProxy;
|
||||||
use App\Actions\Proxy\StartProxy;
|
use App\Actions\Proxy\StartProxy;
|
||||||
use App\Models\ApplicationPreview;
|
use App\Models\ApplicationPreview;
|
||||||
@@ -21,10 +22,6 @@ class ContainerStatusJob implements ShouldQueue, ShouldBeEncrypted
|
|||||||
{
|
{
|
||||||
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||||
|
|
||||||
public function __construct(public Server $server)
|
|
||||||
{
|
|
||||||
$this->handle();
|
|
||||||
}
|
|
||||||
public function middleware(): array
|
public function middleware(): array
|
||||||
{
|
{
|
||||||
return [(new WithoutOverlapping($this->server->id))->dontRelease()];
|
return [(new WithoutOverlapping($this->server->id))->dontRelease()];
|
||||||
@@ -35,6 +32,12 @@ class ContainerStatusJob implements ShouldQueue, ShouldBeEncrypted
|
|||||||
return $this->server->id;
|
return $this->server->id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function __construct(public Server $server)
|
||||||
|
{
|
||||||
|
if (isDev()) $this->handle();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public function handle()
|
public function handle()
|
||||||
{
|
{
|
||||||
// ray("checking container statuses for {$this->server->id}");
|
// ray("checking container statuses for {$this->server->id}");
|
||||||
@@ -47,7 +50,7 @@ class ContainerStatusJob implements ShouldQueue, ShouldBeEncrypted
|
|||||||
$containerReplicase = instant_remote_process(["docker service ls --format '{{json .}}'"], $this->server, false);
|
$containerReplicase = instant_remote_process(["docker service ls --format '{{json .}}'"], $this->server, false);
|
||||||
} else {
|
} else {
|
||||||
// Precheck for containers
|
// Precheck for containers
|
||||||
$containers = instant_remote_process(["docker container ls -q"], $this->server);
|
$containers = instant_remote_process(["docker container ls -q"], $this->server, false);
|
||||||
if (!$containers) {
|
if (!$containers) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -83,7 +86,6 @@ class ContainerStatusJob implements ShouldQueue, ShouldBeEncrypted
|
|||||||
$databases = $this->server->databases();
|
$databases = $this->server->databases();
|
||||||
$services = $this->server->services()->get();
|
$services = $this->server->services()->get();
|
||||||
$previews = $this->server->previews();
|
$previews = $this->server->previews();
|
||||||
|
|
||||||
$foundApplications = [];
|
$foundApplications = [];
|
||||||
$foundApplicationPreviews = [];
|
$foundApplicationPreviews = [];
|
||||||
$foundDatabases = [];
|
$foundDatabases = [];
|
||||||
@@ -95,7 +97,6 @@ class ContainerStatusJob implements ShouldQueue, ShouldBeEncrypted
|
|||||||
$uuid = data_get($labels, 'coolify.name');
|
$uuid = data_get($labels, 'coolify.name');
|
||||||
} else {
|
} else {
|
||||||
$labels = data_get($container, 'Config.Labels');
|
$labels = data_get($container, 'Config.Labels');
|
||||||
$uuid = data_get($labels, 'com.docker.compose.service');
|
|
||||||
}
|
}
|
||||||
$containerStatus = data_get($container, 'State.Status');
|
$containerStatus = data_get($container, 'State.Status');
|
||||||
$containerHealth = data_get($container, 'State.Health.Status', 'unhealthy');
|
$containerHealth = data_get($container, 'State.Health.Status', 'unhealthy');
|
||||||
@@ -131,14 +132,29 @@ class ContainerStatusJob implements ShouldQueue, ShouldBeEncrypted
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
$uuid = data_get($labels, 'com.docker.compose.service');
|
||||||
if ($uuid) {
|
if ($uuid) {
|
||||||
$database = $databases->where('uuid', $uuid)->first();
|
$database = $databases->where('uuid', $uuid)->first();
|
||||||
if ($database) {
|
if ($database) {
|
||||||
|
$isPublic = data_get($database, 'is_public');
|
||||||
$foundDatabases[] = $database->id;
|
$foundDatabases[] = $database->id;
|
||||||
$statusFromDb = $database->status;
|
$statusFromDb = $database->status;
|
||||||
if ($statusFromDb !== $containerStatus) {
|
if ($statusFromDb !== $containerStatus) {
|
||||||
$database->update(['status' => $containerStatus]);
|
$database->update(['status' => $containerStatus]);
|
||||||
}
|
}
|
||||||
|
if ($isPublic) {
|
||||||
|
$foundTcpProxy = $containers->filter(function ($value, $key) use ($uuid) {
|
||||||
|
if ($this->server->isSwarm()) {
|
||||||
|
return data_get($value, 'Spec.Name') === "coolify-proxy_$uuid";
|
||||||
|
} else {
|
||||||
|
return data_get($value, 'Name') === "/$uuid-proxy";
|
||||||
|
}
|
||||||
|
})->first();
|
||||||
|
if (!$foundTcpProxy) {
|
||||||
|
StartDatabaseProxy::run($database);
|
||||||
|
$this->server->team?->notify(new ContainerRestarted("TCP Proxy for {$database->name}", $this->server));
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// Notify user that this container should not be there.
|
// Notify user that this container should not be there.
|
||||||
}
|
}
|
||||||
@@ -297,8 +313,6 @@ class ContainerStatusJob implements ShouldQueue, ShouldBeEncrypted
|
|||||||
if ($shouldStart) {
|
if ($shouldStart) {
|
||||||
StartProxy::run($this->server, false);
|
StartProxy::run($this->server, false);
|
||||||
$this->server->team?->notify(new ContainerRestarted('coolify-proxy', $this->server));
|
$this->server->team?->notify(new ContainerRestarted('coolify-proxy', $this->server));
|
||||||
} else {
|
|
||||||
ray('Proxy could not be started.');
|
|
||||||
}
|
}
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
ray($e);
|
ray($e);
|
||||||
|
|||||||
@@ -50,11 +50,14 @@ class Application extends BaseModel
|
|||||||
}
|
}
|
||||||
public function link()
|
public function link()
|
||||||
{
|
{
|
||||||
return route('project.application.configuration', [
|
if (data_get($this, 'environment.project.uuid')) {
|
||||||
'project_uuid' => $this->environment->project->uuid,
|
return route('project.application.configuration', [
|
||||||
'environment_name' => $this->environment->name,
|
'project_uuid' => data_get($this, 'environment.project.uuid'),
|
||||||
'application_uuid' => $this->uuid
|
'environment_name' => data_get($this, 'environment.name'),
|
||||||
]);
|
'application_uuid' => data_get($this, 'uuid')
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
public function settings()
|
public function settings()
|
||||||
{
|
{
|
||||||
@@ -584,12 +587,12 @@ class Application extends BaseModel
|
|||||||
$commands = collect([]);
|
$commands = collect([]);
|
||||||
if ($dockerConfigFileExists === 'OK') {
|
if ($dockerConfigFileExists === 'OK') {
|
||||||
$commands->push([
|
$commands->push([
|
||||||
"command" => "docker run -d --network $network -v /:/host --name $deploymentUuid --rm -v {$serverUserHomeDir}/.docker/config.json:/root/.docker/config.json:ro -v /var/run/docker.sock:/var/run/docker.sock $helperImage",
|
"command" => "docker run -d --network $network --name $deploymentUuid --rm -v {$serverUserHomeDir}/.docker/config.json:/root/.docker/config.json:ro -v /var/run/docker.sock:/var/run/docker.sock $helperImage",
|
||||||
"hidden" => true,
|
"hidden" => true,
|
||||||
]);
|
]);
|
||||||
} else {
|
} else {
|
||||||
$commands->push([
|
$commands->push([
|
||||||
"command" => "docker run -d --network {$network} -v /:/host --name {$deploymentUuid} --rm -v /var/run/docker.sock:/var/run/docker.sock {$helperImage}",
|
"command" => "docker run -d --network {$network} --name {$deploymentUuid} --rm -v /var/run/docker.sock:/var/run/docker.sock {$helperImage}",
|
||||||
"hidden" => true,
|
"hidden" => true,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
@@ -603,7 +606,6 @@ class Application extends BaseModel
|
|||||||
{
|
{
|
||||||
if ($this->docker_compose_raw) {
|
if ($this->docker_compose_raw) {
|
||||||
$mainCompose = parseDockerComposeFile(resource: $this, isNew: false, pull_request_id: $pull_request_id);
|
$mainCompose = parseDockerComposeFile(resource: $this, isNew: false, pull_request_id: $pull_request_id);
|
||||||
ray($this->docker_compose_pr_raw);
|
|
||||||
if ($this->getMorphClass() === 'App\Models\Application' && $this->docker_compose_pr_raw) {
|
if ($this->getMorphClass() === 'App\Models\Application' && $this->docker_compose_pr_raw) {
|
||||||
parseDockerComposeFile(resource: $this, isNew: false, pull_request_id: $pull_request_id, is_pr: true);
|
parseDockerComposeFile(resource: $this, isNew: false, pull_request_id: $pull_request_id, is_pr: true);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -87,8 +87,6 @@ class Server extends BaseModel
|
|||||||
return $this->hasOne(ServerSetting::class);
|
return $this->hasOne(ServerSetting::class);
|
||||||
}
|
}
|
||||||
public function addInitialNetwork() {
|
public function addInitialNetwork() {
|
||||||
ray($this->id);
|
|
||||||
|
|
||||||
if ($this->id === 0) {
|
if ($this->id === 0) {
|
||||||
if ($this->isSwarm()) {
|
if ($this->isSwarm()) {
|
||||||
SwarmDocker::create([
|
SwarmDocker::create([
|
||||||
@@ -349,7 +347,7 @@ class Server extends BaseModel
|
|||||||
}
|
}
|
||||||
public function isLogDrainEnabled()
|
public function isLogDrainEnabled()
|
||||||
{
|
{
|
||||||
return $this->settings->is_logdrain_newrelic_enabled || $this->settings->is_logdrain_highlight_enabled || $this->settings->is_logdrain_axiom_enabled;
|
return $this->settings->is_logdrain_newrelic_enabled || $this->settings->is_logdrain_highlight_enabled || $this->settings->is_logdrain_axiom_enabled || $this->settings->is_logdrain_custom_enabled;
|
||||||
}
|
}
|
||||||
public function validateOS(): bool | Stringable
|
public function validateOS(): bool | Stringable
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -131,6 +131,20 @@ class Service extends BaseModel
|
|||||||
}
|
}
|
||||||
$fields->put('Weblate', $data);
|
$fields->put('Weblate', $data);
|
||||||
break;
|
break;
|
||||||
|
case str($image)?->contains('meilisearch'):
|
||||||
|
$data = collect([]);
|
||||||
|
$SERVICE_PASSWORD_MEILISEARCH = $this->environment_variables()->where('key', 'SERVICE_PASSWORD_MEILISEARCH')->first();
|
||||||
|
if ($SERVICE_PASSWORD_MEILISEARCH) {
|
||||||
|
$data = $data->merge([
|
||||||
|
'API Key' => [
|
||||||
|
'key' => data_get($SERVICE_PASSWORD_MEILISEARCH, 'key'),
|
||||||
|
'value' => data_get($SERVICE_PASSWORD_MEILISEARCH, 'value'),
|
||||||
|
'isPassword' => true,
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
$fields->put('Meilisearch', $data);
|
||||||
|
break;
|
||||||
case str($image)?->contains('ghost'):
|
case str($image)?->contains('ghost'):
|
||||||
$data = collect([]);
|
$data = collect([]);
|
||||||
$MAIL_OPTIONS_AUTH_PASS = $this->environment_variables()->where('key', 'MAIL_OPTIONS_AUTH_PASS')->first();
|
$MAIL_OPTIONS_AUTH_PASS = $this->environment_variables()->where('key', 'MAIL_OPTIONS_AUTH_PASS')->first();
|
||||||
@@ -193,6 +207,7 @@ class Service extends BaseModel
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ray($fields);
|
||||||
$databases = $this->databases()->get();
|
$databases = $this->databases()->get();
|
||||||
|
|
||||||
foreach ($databases as $database) {
|
foreach ($databases as $database) {
|
||||||
@@ -363,11 +378,14 @@ class Service extends BaseModel
|
|||||||
}
|
}
|
||||||
public function link()
|
public function link()
|
||||||
{
|
{
|
||||||
return route('project.service.configuration', [
|
if (data_get($this, 'environment.project.uuid')) {
|
||||||
'project_uuid' => $this->environment->project->uuid,
|
return route('project.service.configuration', [
|
||||||
'environment_name' => $this->environment->name,
|
'project_uuid' => data_get($this, 'environment.project.uuid'),
|
||||||
'service_uuid' => $this->uuid
|
'environment_name' => data_get($this, 'environment.name'),
|
||||||
]);
|
'service_uuid' => data_get($this, 'uuid')
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
public function documentation()
|
public function documentation()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -43,11 +43,14 @@ class StandaloneMariadb extends BaseModel
|
|||||||
}
|
}
|
||||||
public function link()
|
public function link()
|
||||||
{
|
{
|
||||||
return route('project.database.configuration', [
|
if (data_get($this, 'environment.project.uuid')) {
|
||||||
'project_uuid' => $this->environment->project->uuid,
|
return route('project.database.configuration', [
|
||||||
'environment_name' => $this->environment->name,
|
'project_uuid' => data_get($this, 'environment.project.uuid'),
|
||||||
'database_uuid' => $this->uuid
|
'environment_name' => data_get($this, 'environment.name'),
|
||||||
]);
|
'database_uuid' => data_get($this, 'uuid')
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
public function isLogDrainEnabled()
|
public function isLogDrainEnabled()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -50,11 +50,14 @@ class StandaloneMongodb extends BaseModel
|
|||||||
}
|
}
|
||||||
public function link()
|
public function link()
|
||||||
{
|
{
|
||||||
return route('project.database.configuration', [
|
if (data_get($this, 'environment.project.uuid')) {
|
||||||
'project_uuid' => $this->environment->project->uuid,
|
return route('project.database.configuration', [
|
||||||
'environment_name' => $this->environment->name,
|
'project_uuid' => data_get($this, 'environment.project.uuid'),
|
||||||
'database_uuid' => $this->uuid
|
'environment_name' => data_get($this, 'environment.name'),
|
||||||
]);
|
'database_uuid' => data_get($this, 'uuid')
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
public function mongoInitdbRootPassword(): Attribute
|
public function mongoInitdbRootPassword(): Attribute
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -43,11 +43,14 @@ class StandaloneMysql extends BaseModel
|
|||||||
}
|
}
|
||||||
public function link()
|
public function link()
|
||||||
{
|
{
|
||||||
return route('project.database.configuration', [
|
if (data_get($this, 'environment.project.uuid')) {
|
||||||
'project_uuid' => $this->environment->project->uuid,
|
return route('project.database.configuration', [
|
||||||
'environment_name' => $this->environment->name,
|
'project_uuid' => data_get($this, 'environment.project.uuid'),
|
||||||
'database_uuid' => $this->uuid
|
'environment_name' => data_get($this, 'environment.name'),
|
||||||
]);
|
'database_uuid' => data_get($this, 'uuid')
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
public function type(): string
|
public function type(): string
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -43,11 +43,14 @@ class StandalonePostgresql extends BaseModel
|
|||||||
}
|
}
|
||||||
public function link()
|
public function link()
|
||||||
{
|
{
|
||||||
return route('project.database.configuration', [
|
if (data_get($this, 'environment.project.uuid')) {
|
||||||
'project_uuid' => $this->environment->project->uuid,
|
return route('project.database.configuration', [
|
||||||
'environment_name' => $this->environment->name,
|
'project_uuid' => data_get($this, 'environment.project.uuid'),
|
||||||
'database_uuid' => $this->uuid
|
'environment_name' => data_get($this, 'environment.name'),
|
||||||
]);
|
'database_uuid' => data_get($this, 'uuid')
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
public function isLogDrainEnabled()
|
public function isLogDrainEnabled()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -38,11 +38,14 @@ class StandaloneRedis extends BaseModel
|
|||||||
}
|
}
|
||||||
public function link()
|
public function link()
|
||||||
{
|
{
|
||||||
return route('project.database.configuration', [
|
if (data_get($this, 'environment.project.uuid')) {
|
||||||
'project_uuid' => $this->environment->project->uuid,
|
return route('project.database.configuration', [
|
||||||
'environment_name' => $this->environment->name,
|
'project_uuid' => data_get($this, 'environment.project.uuid'),
|
||||||
'database_uuid' => $this->uuid
|
'environment_name' => data_get($this, 'environment.name'),
|
||||||
]);
|
'database_uuid' => data_get($this, 'uuid')
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
public function isLogDrainEnabled()
|
public function isLogDrainEnabled()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -97,12 +97,12 @@ function prepareHelperContainer(Server $server, string $network, string $deploym
|
|||||||
$commands = collect([]);
|
$commands = collect([]);
|
||||||
if ($dockerConfigFileExists === 'OK') {
|
if ($dockerConfigFileExists === 'OK') {
|
||||||
$commands->push([
|
$commands->push([
|
||||||
"command" => "docker run -d --network $network -v /:/host --name $deploymentUuid --rm -v {$serverUserHomeDir}/.docker/config.json:/root/.docker/config.json:ro -v /var/run/docker.sock:/var/run/docker.sock $helperImage",
|
"command" => "docker run -d --network $network --name $deploymentUuid --rm -v {$serverUserHomeDir}/.docker/config.json:/root/.docker/config.json:ro -v /var/run/docker.sock:/var/run/docker.sock $helperImage",
|
||||||
"hidden" => true,
|
"hidden" => true,
|
||||||
]);
|
]);
|
||||||
} else {
|
} else {
|
||||||
$commands->push([
|
$commands->push([
|
||||||
"command" => "docker run -d --network {$network} -v /:/host --name {$deploymentUuid} --rm -v /var/run/docker.sock:/var/run/docker.sock {$helperImage}",
|
"command" => "docker run -d --network {$network} --name {$deploymentUuid} --rm -v /var/run/docker.sock:/var/run/docker.sock {$helperImage}",
|
||||||
"hidden" => true,
|
"hidden" => true,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -913,13 +913,17 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if ($value?->startsWith('$')) {
|
if ($value?->startsWith('$')) {
|
||||||
$value = Str::of(replaceVariables($value));
|
|
||||||
$key = $value;
|
|
||||||
$foundEnv = EnvironmentVariable::where([
|
$foundEnv = EnvironmentVariable::where([
|
||||||
'key' => $key,
|
'key' => $key,
|
||||||
'service_id' => $resource->id,
|
'service_id' => $resource->id,
|
||||||
])->first();
|
])->first();
|
||||||
|
$value = Str::of(replaceVariables($value));
|
||||||
|
$key = $value;
|
||||||
if ($value->startsWith('SERVICE_')) {
|
if ($value->startsWith('SERVICE_')) {
|
||||||
|
$foundEnv = EnvironmentVariable::where([
|
||||||
|
'key' => $key,
|
||||||
|
'service_id' => $resource->id,
|
||||||
|
])->first();
|
||||||
['command' => $command, 'forService' => $forService, 'generatedValue' => $generatedValue, 'port' => $port] = parseEnvVariable($value);
|
['command' => $command, 'forService' => $forService, 'generatedValue' => $generatedValue, 'port' => $port] = parseEnvVariable($value);
|
||||||
if ($command->value() === 'FQDN' || $command->value() === 'URL') {
|
if ($command->value() === 'FQDN' || $command->value() === 'URL') {
|
||||||
if (Str::lower($forService) === $serviceName) {
|
if (Str::lower($forService) === $serviceName) {
|
||||||
@@ -999,7 +1003,7 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal
|
|||||||
if ($savedService->serviceType()) {
|
if ($savedService->serviceType()) {
|
||||||
$fqdns = generateServiceSpecificFqdns($savedService, forTraefik: true);
|
$fqdns = generateServiceSpecificFqdns($savedService, forTraefik: true);
|
||||||
} else {
|
} else {
|
||||||
$fqdns = collect(data_get($savedService, 'fqdns'));
|
$fqdns = collect(data_get($savedService, 'fqdns'))->filter();
|
||||||
}
|
}
|
||||||
$defaultLabels = defaultLabels($resource->id, $containerName, type: 'service', subType: $isDatabase ? 'database' : 'application', subId: $savedService->id);
|
$defaultLabels = defaultLabels($resource->id, $containerName, type: 'service', subType: $isDatabase ? 'database' : 'application', subId: $savedService->id);
|
||||||
$serviceLabels = $serviceLabels->merge($defaultLabels);
|
$serviceLabels = $serviceLabels->merge($defaultLabels);
|
||||||
@@ -1098,6 +1102,8 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal
|
|||||||
$serviceNetworks = collect(data_get($service, 'networks', []));
|
$serviceNetworks = collect(data_get($service, 'networks', []));
|
||||||
$serviceVariables = collect(data_get($service, 'environment', []));
|
$serviceVariables = collect(data_get($service, 'environment', []));
|
||||||
$serviceLabels = collect(data_get($service, 'labels', []));
|
$serviceLabels = collect(data_get($service, 'labels', []));
|
||||||
|
$serviceBuildVariables = collect(data_get($service, 'build.args', []));
|
||||||
|
$serviceVariables = $serviceVariables->merge($serviceBuildVariables);
|
||||||
if ($serviceLabels->count() > 0) {
|
if ($serviceLabels->count() > 0) {
|
||||||
$removedLabels = collect([]);
|
$removedLabels = collect([]);
|
||||||
$serviceLabels = $serviceLabels->filter(function ($serviceLabel, $serviceLabelName) use ($removedLabels) {
|
$serviceLabels = $serviceLabels->filter(function ($serviceLabel, $serviceLabelName) use ($removedLabels) {
|
||||||
@@ -1144,7 +1150,52 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal
|
|||||||
data_set($service, 'volumes', $serviceVolumes->toArray());
|
data_set($service, 'volumes', $serviceVolumes->toArray());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// TODO
|
if (count($serviceVolumes) > 0) {
|
||||||
|
$serviceVolumes = $serviceVolumes->map(function ($volume) use ($resource, $topLevelVolumes) {
|
||||||
|
if (is_string($volume)) {
|
||||||
|
$volume = str($volume);
|
||||||
|
if ($volume->contains(':')) {
|
||||||
|
$name = $volume->before(':');
|
||||||
|
$mount = $volume->after(':');
|
||||||
|
if ($name->startsWith('.') || $name->startsWith('~')) {
|
||||||
|
$dir = base_configuration_dir() . '/applications/' . $resource->uuid;
|
||||||
|
if ($name->startsWith('.')) {
|
||||||
|
$name = $name->replaceFirst('.', $dir);
|
||||||
|
}
|
||||||
|
if ($name->startsWith('~')) {
|
||||||
|
$name = $name->replaceFirst('~', $dir);
|
||||||
|
}
|
||||||
|
$volume = str("$name:$mount");
|
||||||
|
} else {
|
||||||
|
$topLevelVolumes->put($name->value(), [
|
||||||
|
'name' => $name->value(),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (is_array($volume)) {
|
||||||
|
$source = data_get($volume, 'source');
|
||||||
|
if ($source) {
|
||||||
|
if (str($source, '.') || str($source, '~')) {
|
||||||
|
$dir = base_configuration_dir() . '/applications/' . $resource->uuid;
|
||||||
|
if (str($source, '.')) {
|
||||||
|
$source = str('.', $dir, $source);
|
||||||
|
}
|
||||||
|
if (str($source, '~')) {
|
||||||
|
$source = str('~', $dir, $source);
|
||||||
|
}
|
||||||
|
data_set($volume, 'source', $source);
|
||||||
|
} else {
|
||||||
|
data_set($volume, 'source', $source);
|
||||||
|
$topLevelVolumes->put($source, [
|
||||||
|
'name' => $source,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $volume->value();
|
||||||
|
});
|
||||||
|
data_set($service, 'volumes', $serviceVolumes->toArray());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// Decide if the service is a database
|
// Decide if the service is a database
|
||||||
$isDatabase = isDatabaseImage(data_get_str($service, 'image'));
|
$isDatabase = isDatabaseImage(data_get_str($service, 'image'));
|
||||||
@@ -1271,13 +1322,18 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if ($value?->startsWith('$')) {
|
if ($value?->startsWith('$')) {
|
||||||
$value = Str::of(replaceVariables($value));
|
|
||||||
$key = $value;
|
|
||||||
$foundEnv = EnvironmentVariable::where([
|
$foundEnv = EnvironmentVariable::where([
|
||||||
'key' => $key,
|
'key' => $key,
|
||||||
'application_id' => $resource->id,
|
'service_id' => $resource->id,
|
||||||
])->first();
|
])->first();
|
||||||
|
$value = Str::of(replaceVariables($value));
|
||||||
|
$key = $value;
|
||||||
|
|
||||||
if ($value->startsWith('SERVICE_')) {
|
if ($value->startsWith('SERVICE_')) {
|
||||||
|
$foundEnv = EnvironmentVariable::where([
|
||||||
|
'key' => $key,
|
||||||
|
'application_id' => $resource->id,
|
||||||
|
])->first();
|
||||||
['command' => $command, 'forService' => $forService, 'generatedValue' => $generatedValue, 'port' => $port] = parseEnvVariable($value);
|
['command' => $command, 'forService' => $forService, 'generatedValue' => $generatedValue, 'port' => $port] = parseEnvVariable($value);
|
||||||
if ($command->value() === 'FQDN' || $command->value() === 'URL') {
|
if ($command->value() === 'FQDN' || $command->value() === 'URL') {
|
||||||
if (Str::lower($forService) === $serviceName) {
|
if (Str::lower($forService) === $serviceName) {
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ return [
|
|||||||
'official' => 'https://cdn.coollabs.io/coolify/service-templates.json',
|
'official' => 'https://cdn.coollabs.io/coolify/service-templates.json',
|
||||||
],
|
],
|
||||||
'limits' => [
|
'limits' => [
|
||||||
'trial_period' => 7,
|
'trial_period' => 0,
|
||||||
'server' => [
|
'server' => [
|
||||||
'zero' => 0,
|
'zero' => 0,
|
||||||
'self-hosted' => 999999999999,
|
'self-hosted' => 999999999999,
|
||||||
|
|||||||
@@ -3,11 +3,11 @@
|
|||||||
return [
|
return [
|
||||||
|
|
||||||
// @see https://docs.sentry.io/product/sentry-basics/dsn-explainer/
|
// @see https://docs.sentry.io/product/sentry-basics/dsn-explainer/
|
||||||
'dsn' => 'https://396748153b19c469f5ceff50f1664323@o1082494.ingest.sentry.io/4505347448045568',
|
'dsn' => 'https://bea22abf110618b07252032aa2e07859@o1082494.ingest.sentry.io/4505347448045568',
|
||||||
|
|
||||||
// The release version of your application
|
// The release version of your application
|
||||||
// Example with dynamic git hash: trim(exec('git --git-dir ' . base_path('.git') . ' log --pretty="%h" -n1 HEAD'))
|
// Example with dynamic git hash: trim(exec('git --git-dir ' . base_path('.git') . ' log --pretty="%h" -n1 HEAD'))
|
||||||
'release' => '4.0.0-beta.148',
|
'release' => '4.0.0-beta.152',
|
||||||
// When left empty or `null` the Laravel environment will be used
|
// When left empty or `null` the Laravel environment will be used
|
||||||
'environment' => config('app.env'),
|
'environment' => config('app.env'),
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
return '4.0.0-beta.148';
|
return '4.0.0-beta.152';
|
||||||
|
|||||||
@@ -0,0 +1,64 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::table('application_settings', function (Blueprint $table) {
|
||||||
|
$table->boolean('is_include_timestamps')->default(false);
|
||||||
|
});
|
||||||
|
Schema::table('service_applications', function (Blueprint $table) {
|
||||||
|
$table->boolean('is_include_timestamps')->default(false);
|
||||||
|
});
|
||||||
|
Schema::table('service_databases', function (Blueprint $table) {
|
||||||
|
$table->boolean('is_include_timestamps')->default(false);
|
||||||
|
});
|
||||||
|
Schema::table('standalone_mysqls', function (Blueprint $table) {
|
||||||
|
$table->boolean('is_include_timestamps')->default(false);
|
||||||
|
});
|
||||||
|
Schema::table('standalone_postgresqls', function (Blueprint $table) {
|
||||||
|
$table->boolean('is_include_timestamps')->default(false);
|
||||||
|
});
|
||||||
|
Schema::table('standalone_redis', function (Blueprint $table) {
|
||||||
|
$table->boolean('is_include_timestamps')->default(false);
|
||||||
|
});
|
||||||
|
Schema::table('standalone_mongodbs', function (Blueprint $table) {
|
||||||
|
$table->boolean('is_include_timestamps')->default(false);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::table('application_settings', function (Blueprint $table) {
|
||||||
|
$table->dropColumn('is_include_timestamps');
|
||||||
|
});
|
||||||
|
Schema::table('service_applications', function (Blueprint $table) {
|
||||||
|
$table->dropColumn('is_include_timestamps');
|
||||||
|
});
|
||||||
|
Schema::table('service_databases', function (Blueprint $table) {
|
||||||
|
$table->dropColumn('is_include_timestamps');
|
||||||
|
});
|
||||||
|
Schema::table('standalone_mysqls', function (Blueprint $table) {
|
||||||
|
$table->dropColumn('is_include_timestamps');
|
||||||
|
});
|
||||||
|
Schema::table('standalone_postgresqls', function (Blueprint $table) {
|
||||||
|
$table->dropColumn('is_include_timestamps');
|
||||||
|
});
|
||||||
|
Schema::table('standalone_redis', function (Blueprint $table) {
|
||||||
|
$table->dropColumn('is_include_timestamps');
|
||||||
|
});
|
||||||
|
Schema::table('standalone_mongodbs', function (Blueprint $table) {
|
||||||
|
$table->dropColumn('is_include_timestamps');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::table('server_settings', function (Blueprint $table) {
|
||||||
|
$table->boolean('is_logdrain_custom_enabled')->default(false);
|
||||||
|
$table->text('logdrain_custom_config')->nullable();
|
||||||
|
$table->text('logdrain_custom_config_parser')->nullable();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::table('server_settings', function (Blueprint $table) {
|
||||||
|
$table->dropColumn('is_logdrain_custom_enabled');
|
||||||
|
$table->dropColumn('logdrain_custom_config');
|
||||||
|
$table->dropColumn('logdrain_custom_config_parser');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -21,8 +21,11 @@
|
|||||||
</label>
|
</label>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
</div>
|
</div>
|
||||||
<div class="py-2 text-center"><span class="font-bold text-warning">{{ config('constants.limits.trial_period') }}
|
@if (config('constants.limits.trial_period') > 0)
|
||||||
days trial</span> included on all plans, without credit card details.</div>
|
<div class="py-2 text-center"><span
|
||||||
|
class="font-bold text-warning">{{ config('constants.limits.trial_period') }}
|
||||||
|
days trial</span> included on all plans, without credit card details.</div>
|
||||||
|
@endif
|
||||||
<div x-show="selected === 'monthly'" class="flex justify-center h-10 mt-3 text-sm leading-6 ">
|
<div x-show="selected === 'monthly'" class="flex justify-center h-10 mt-3 text-sm leading-6 ">
|
||||||
<div>Save <span class="font-bold text-warning">10%</span> annually with the yearly plans.
|
<div>Save <span class="font-bold text-warning">10%</span> annually with the yearly plans.
|
||||||
</div>
|
</div>
|
||||||
@@ -255,8 +258,8 @@
|
|||||||
<div class="flex items-start gap-4 text-xl tracking-tight">Need official support for
|
<div class="flex items-start gap-4 text-xl tracking-tight">Need official support for
|
||||||
your self-hosted instance?
|
your self-hosted instance?
|
||||||
<x-forms.button>
|
<x-forms.button>
|
||||||
<a class="font-bold text-white hover:no-underline"
|
<a class="font-bold text-white hover:no-underline" href="{{ config('coolify.docs') }}">Contact
|
||||||
href="{{ config('coolify.docs') }}">Contact Us</a>
|
Us</a>
|
||||||
</x-forms.button>
|
</x-forms.button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -207,10 +207,11 @@
|
|||||||
placeholder="Username to connect to your server. Default is root." label="Username"
|
placeholder="Username to connect to your server. Default is root." label="Username"
|
||||||
id="remoteServerUser" />
|
id="remoteServerUser" />
|
||||||
</div>
|
</div>
|
||||||
{{-- <div class="w-64">
|
<div class="w-64">
|
||||||
<x-forms.checkbox type="checkbox" id="isSwarmManager"
|
<x-forms.checkbox
|
||||||
label="Is it a Swarm Manager?" />
|
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'>Coolify does not install/setup Cloudflare (cloudflared) on your server.</span>"
|
||||||
</div> --}}
|
id="isCloudflareTunnel" label="Cloudflare Tunnel" />
|
||||||
|
</div>
|
||||||
<x-forms.button type="submit">Check Connection</x-forms.button>
|
<x-forms.button type="submit">Check Connection</x-forms.button>
|
||||||
</form>
|
</form>
|
||||||
</x-slot:actions>
|
</x-slot:actions>
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
@if ($loop->first)
|
@if ($loop->first)
|
||||||
<h2 class="pb-4">Logs</h2>
|
<h2 class="pb-4">Logs</h2>
|
||||||
@endif
|
@endif
|
||||||
<livewire:project.shared.get-logs :server="$server" :container="$container" />
|
<livewire:project.shared.get-logs :server="$server" :resource="$resource" :container="$container" />
|
||||||
@empty
|
@empty
|
||||||
<div>No containers are not running.</div>
|
<div>No containers are not running.</div>
|
||||||
@endforelse
|
@endforelse
|
||||||
@@ -16,7 +16,7 @@
|
|||||||
<h1>Logs</h1>
|
<h1>Logs</h1>
|
||||||
<livewire:project.database.heading :database="$resource" />
|
<livewire:project.database.heading :database="$resource" />
|
||||||
<div class="pt-4">
|
<div class="pt-4">
|
||||||
<livewire:project.shared.get-logs :server="$server" :container="$container" />
|
<livewire:project.shared.get-logs :resource="$resource" :server="$server" :container="$container" />
|
||||||
</div>
|
</div>
|
||||||
@elseif ($type === 'service')
|
@elseif ($type === 'service')
|
||||||
<livewire:project.service.navbar :service="$resource" :parameters="$parameters" :query="$query" />
|
<livewire:project.service.navbar :service="$resource" :parameters="$parameters" :query="$query" />
|
||||||
@@ -28,7 +28,7 @@
|
|||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex-1 pl-8">
|
<div class="flex-1 pl-8">
|
||||||
<livewire:project.shared.get-logs :server="$server" :container="$container" />
|
<livewire:project.shared.get-logs :server="$server" :resource="$resource" :servicesubtype="$serviceSubType" :container="$container" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@endif
|
@endif
|
||||||
|
|||||||
@@ -9,33 +9,36 @@
|
|||||||
helper="See details in our <a target='_blank' class='text-white underline' href='https://coolify.io/docs/api-authentication'>documentation</a>."
|
helper="See details in our <a target='_blank' class='text-white underline' href='https://coolify.io/docs/api-authentication'>documentation</a>."
|
||||||
label="Deploy Webhook (auth required)" id="deploywebhook"></x-forms.input>
|
label="Deploy Webhook (auth required)" id="deploywebhook"></x-forms.input>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
@if ($resource->type() !== 'service')
|
||||||
<h3>Manual Git Webhooks</h3>
|
<div>
|
||||||
@if ($githubManualWebhook && $gitlabManualWebhook)
|
<h3>Manual Git Webhooks</h3>
|
||||||
<form wire:submit.prevent='saveSecret' class="flex flex-col gap-2">
|
@if ($githubManualWebhook && $gitlabManualWebhook)
|
||||||
<div class="flex items-end gap-2">
|
<form wire:submit.prevent='saveSecret' class="flex flex-col gap-2">
|
||||||
<x-forms.input helper="Content Type in GitHub configuration could be json or form-urlencoded."
|
<div class="flex items-end gap-2">
|
||||||
readonly label="GitHub" id="githubManualWebhook"></x-forms.input>
|
<x-forms.input helper="Content Type in GitHub configuration could be json or form-urlencoded."
|
||||||
<x-forms.input type="password"
|
readonly label="GitHub" id="githubManualWebhook"></x-forms.input>
|
||||||
helper="Need to set a secret to be able to use this webhook. It should match with the secret in GitHub."
|
<x-forms.input type="password"
|
||||||
label="GitHub Webhook Secret" id="resource.manual_webhook_secret_github"></x-forms.input>
|
helper="Need to set a secret to be able to use this webhook. It should match with the secret in GitHub."
|
||||||
|
label="GitHub Webhook Secret" id="resource.manual_webhook_secret_github"></x-forms.input>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<a target="_blank" class="flex hover:no-underline" href="{{ $resource?->gitWebhook }}">
|
||||||
|
<x-forms.button>Webhook Configuration on GitHub
|
||||||
|
<x-external-link />
|
||||||
|
</x-forms.button>
|
||||||
|
</a>
|
||||||
|
<div class="flex gap-2">
|
||||||
|
<x-forms.input readonly label="GitLab" id="gitlabManualWebhook"></x-forms.input>
|
||||||
|
<x-forms.input type="password"
|
||||||
|
helper="Need to set a secret to be able to use this webhook. It should match with the secret in GitLab."
|
||||||
|
label="GitLab Webhook Secret" id="resource.manual_webhook_secret_gitlab"></x-forms.input>
|
||||||
|
</div>
|
||||||
|
<x-forms.button type="submit">Save</x-forms.button>
|
||||||
|
</form>
|
||||||
|
@else
|
||||||
|
You are using an official Git App. You do not need manual webhooks.
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
|
||||||
</div>
|
|
||||||
<a target="_blank" class="flex hover:no-underline" href="{{ $resource?->gitWebhook }}">
|
|
||||||
<x-forms.button>Webhook Configuration on GitHub
|
|
||||||
<x-external-link />
|
|
||||||
</x-forms.button>
|
|
||||||
</a>
|
|
||||||
<div class="flex gap-2">
|
|
||||||
<x-forms.input readonly label="GitLab" id="gitlabManualWebhook"></x-forms.input>
|
|
||||||
<x-forms.input type="password"
|
|
||||||
helper="Need to set a secret to be able to use this webhook. It should match with the secret in GitLab."
|
|
||||||
label="GitLab Webhook Secret" id="resource.manual_webhook_secret_gitlab"></x-forms.input>
|
|
||||||
</div>
|
|
||||||
<x-forms.button type="submit">Save</x-forms.button>
|
|
||||||
</form>
|
|
||||||
@else
|
|
||||||
You are using an official Git App. You do not need manual webhooks.
|
|
||||||
@endif
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -25,10 +25,17 @@
|
|||||||
@if ($loop->first)
|
@if ($loop->first)
|
||||||
<h3 class="pt-4">Defined resources</h3>
|
<h3 class="pt-4">Defined resources</h3>
|
||||||
@endif
|
@endif
|
||||||
<a class="flex gap-2 p-1 hover:bg-coolgray-100 hover:no-underline" href="{{ $resource->link() }}">
|
@if ($resource->link())
|
||||||
<div class="w-64">{{ str($resource->type())->headline() }}</div>
|
<a class="flex gap-2 p-1 hover:bg-coolgray-100 hover:no-underline" href="{{ $resource->link() }}">
|
||||||
<div>{{ $resource->name }}</div>
|
<div class="w-64">{{ str($resource->type())->headline() }}</div>
|
||||||
</a>
|
<div>{{ $resource->name }}</div>
|
||||||
|
</a>
|
||||||
|
@else
|
||||||
|
<div class="flex gap-2 p-1 hover:bg-coolgray-100 hover:no-underline">
|
||||||
|
<div class="w-64">{{ str($resource->type())->headline() }}</div>
|
||||||
|
<div>{{ $resource->name }}</div>
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
@empty
|
@empty
|
||||||
@endforelse
|
@endforelse
|
||||||
</div>
|
</div>
|
||||||
@@ -38,10 +45,17 @@
|
|||||||
@if ($loop->first)
|
@if ($loop->first)
|
||||||
<h3 class="pt-4">Defined resources</h3>
|
<h3 class="pt-4">Defined resources</h3>
|
||||||
@endif
|
@endif
|
||||||
<a class="flex gap-2 p-1 hover:bg-coolgray-100 hover:no-underline" href="{{ $resource->link() }}">
|
@if ($resource->link())
|
||||||
<div class="w-64">{{ str($resource->type())->headline() }}</div>
|
<a class="flex gap-2 p-1 hover:bg-coolgray-100 hover:no-underline" href="{{ $resource->link() }}">
|
||||||
<div>{{ $resource->name }}</div>
|
<div class="w-64">{{ str($resource->type())->headline() }}</div>
|
||||||
</a>
|
<div>{{ $resource->name }}</div>
|
||||||
|
</a>
|
||||||
|
@else
|
||||||
|
<div class="flex gap-2 p-1 hover:bg-coolgray-100 hover:no-underline">
|
||||||
|
<div class="w-64">{{ str($resource->type())->headline() }}</div>
|
||||||
|
<div>{{ $resource->name }}</div>
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
@empty
|
@empty
|
||||||
@endforelse
|
@endforelse
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -62,6 +62,25 @@
|
|||||||
</x-forms.button>
|
</x-forms.button>
|
||||||
</div>
|
</div>
|
||||||
</form> --}}
|
</form> --}}
|
||||||
|
<h3>Custom FluentBit configuration</h3>
|
||||||
|
<div class="w-32">
|
||||||
|
<x-forms.checkbox instantSave='instantSave("custom")' id="server.settings.is_logdrain_custom_enabled"
|
||||||
|
label="Enabled" />
|
||||||
|
</div>
|
||||||
|
<form wire:submit.prevent='submit("custom")' class="flex flex-col">
|
||||||
|
<div class="flex flex-col gap-4">
|
||||||
|
<x-forms.textarea rows="6" required id="server.settings.logdrain_custom_config"
|
||||||
|
label="Custom FluentBit Configuration" />
|
||||||
|
<x-forms.textarea id="server.settings.logdrain_custom_config_parser"
|
||||||
|
label="Custom Parser Configuration" />
|
||||||
|
</div>
|
||||||
|
<div class="flex justify-end gap-4 pt-6">
|
||||||
|
<x-forms.button type="submit">
|
||||||
|
Save
|
||||||
|
</x-forms.button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<div>
|
<div>
|
||||||
@if ($server->isFunctional())
|
@if ($server->isFunctional())
|
||||||
<div class="flex gap-2" wire:poll.5000ms='checkProxy'>
|
<div class="flex gap-2">
|
||||||
@if (data_get($server, 'proxy.status') === 'running')
|
@if (data_get($server, 'proxy.status') === 'running')
|
||||||
<x-status.running status="Proxy Running" />
|
<x-status.running status="Proxy Running" />
|
||||||
@elseif (data_get($server, 'proxy.status') === 'restarting')
|
@elseif (data_get($server, 'proxy.status') === 'restarting')
|
||||||
|
|||||||
@@ -59,15 +59,21 @@ sles | opensuse-leap | opensuse-tumbleweed)
|
|||||||
esac
|
esac
|
||||||
|
|
||||||
if ! [ -x "$(command -v docker)" ]; then
|
if ! [ -x "$(command -v docker)" ]; then
|
||||||
echo "Docker is not installed. Installing Docker..."
|
echo "Docker is not installed. Installing Docker."
|
||||||
curl https://releases.rancher.com/install-docker/${DOCKER_VERSION}.sh | sh
|
curl https://releases.rancher.com/install-docker/${DOCKER_VERSION}.sh | sh
|
||||||
if [ -x "$(command -v docker)" ]; then
|
if [ -x "$(command -v docker)" ]; then
|
||||||
echo "Docker installed successfully."
|
echo "Docker installed successfully."
|
||||||
else
|
else
|
||||||
echo "Docker installation failed."
|
echo "Docker installation failed with Rancher script. Trying with official script."
|
||||||
echo "Maybe your OS is not supported."
|
curl https://get.docker.com | sh -s -- --version ${DOCKER_VERSION}
|
||||||
echo "Please visit https://docs.docker.com/engine/install/ and install Docker manually to continue."
|
if [ -x "$(command -v docker)" ]; then
|
||||||
exit 1
|
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
|
fi
|
||||||
echo -e "-------------"
|
echo -e "-------------"
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ services:
|
|||||||
- REDIS_PORT=6379
|
- REDIS_PORT=6379
|
||||||
- WEBSOCKETS_ENABLED=true
|
- WEBSOCKETS_ENABLED=true
|
||||||
postgresql:
|
postgresql:
|
||||||
image: postgres:15-alpine
|
image: postgres:16-alpine
|
||||||
volumes:
|
volumes:
|
||||||
- directus-postgresql-data:/var/lib/postgresql/data
|
- directus-postgresql-data:/var/lib/postgresql/data
|
||||||
environment:
|
environment:
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ services:
|
|||||||
retries: 15
|
retries: 15
|
||||||
|
|
||||||
postgresql:
|
postgresql:
|
||||||
image: postgres:15-alpine
|
image: postgres:16-alpine
|
||||||
volumes:
|
volumes:
|
||||||
- gitea-postgresql-data:/var/lib/postgresql/data
|
- gitea-postgresql-data:/var/lib/postgresql/data
|
||||||
environment:
|
environment:
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ services:
|
|||||||
depends_on:
|
depends_on:
|
||||||
- postgresql
|
- postgresql
|
||||||
postgresql:
|
postgresql:
|
||||||
image: postgres:15-alpine
|
image: postgres:16-alpine
|
||||||
volumes:
|
volumes:
|
||||||
- postgresql-data:/var/lib/postgresql/data
|
- postgresql-data:/var/lib/postgresql/data
|
||||||
environment:
|
environment:
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ services:
|
|||||||
depends_on:
|
depends_on:
|
||||||
- postgres
|
- postgres
|
||||||
postgres:
|
postgres:
|
||||||
image: postgres:15-alpine
|
image: postgres:16-alpine
|
||||||
volumes:
|
volumes:
|
||||||
- postgresql-data:/var/lib/postgresql/data
|
- postgresql-data:/var/lib/postgresql/data
|
||||||
environment:
|
environment:
|
||||||
|
|||||||
19
templates/compose/meilisearch.yaml
Normal file
19
templates/compose/meilisearch.yaml
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
# documentation: https://www.meilisearch.com/docs/learn/configuration/instance_options
|
||||||
|
# slogan: MeiliSearch is a powerful, fast, open-source, easy to use and deploy search engine.
|
||||||
|
# tags: search,engine,fulltext,full,text,meilisearch
|
||||||
|
|
||||||
|
services:
|
||||||
|
meilisearch:
|
||||||
|
image: getmeili/meilisearch:latest
|
||||||
|
environment:
|
||||||
|
- SERVICE_FQDN_MEILISEARCH
|
||||||
|
- MEILI_NO_ANALYTICS=${MEILI_NO_ANALYTICS:-true}
|
||||||
|
- MEILI_ENV=${MEILI_ENV:-production}
|
||||||
|
- MEILI_MASTER_KEY=${SERVICE_PASSWORD_MEILISEARCH}
|
||||||
|
volumes:
|
||||||
|
- meilisearch-data:/meili_data
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "curl", "-f", "http://localhost:7700/health"]
|
||||||
|
interval: 2s
|
||||||
|
timeout: 10s
|
||||||
|
retries: 15
|
||||||
@@ -24,7 +24,7 @@ services:
|
|||||||
depends_on:
|
depends_on:
|
||||||
- postgresql
|
- postgresql
|
||||||
postgresql:
|
postgresql:
|
||||||
image: postgres:15-alpine
|
image: postgres:16-alpine
|
||||||
volumes:
|
volumes:
|
||||||
- postgresql-data:/var/lib/postgresql/data
|
- postgresql-data:/var/lib/postgresql/data
|
||||||
environment:
|
environment:
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ services:
|
|||||||
postgresql:
|
postgresql:
|
||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
postgresql:
|
postgresql:
|
||||||
image: postgres:15-alpine
|
image: postgres:16-alpine
|
||||||
volumes:
|
volumes:
|
||||||
- postgresql-data:/var/lib/postgresql/data
|
- postgresql-data:/var/lib/postgresql/data
|
||||||
environment:
|
environment:
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ services:
|
|||||||
healthcheck:
|
healthcheck:
|
||||||
test: ["NONE"]
|
test: ["NONE"]
|
||||||
postgresql:
|
postgresql:
|
||||||
image: postgres:15-alpine
|
image: postgres:16-alpine
|
||||||
volumes:
|
volumes:
|
||||||
- postgresql-data:/var/lib/postgresql/data
|
- postgresql-data:/var/lib/postgresql/data
|
||||||
environment:
|
environment:
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ services:
|
|||||||
postgresql:
|
postgresql:
|
||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
postgresql:
|
postgresql:
|
||||||
image: postgres:15-alpine
|
image: postgres:16-alpine
|
||||||
volumes:
|
volumes:
|
||||||
- postgresql-data:/var/lib/postgresql/data
|
- postgresql-data:/var/lib/postgresql/data
|
||||||
environment:
|
environment:
|
||||||
|
|||||||
@@ -68,7 +68,7 @@
|
|||||||
"directus-with-postgresql": {
|
"directus-with-postgresql": {
|
||||||
"documentation": "https:\/\/docs.directus.io\/self-hosted\/quickstart.html",
|
"documentation": "https:\/\/docs.directus.io\/self-hosted\/quickstart.html",
|
||||||
"slogan": "Directus is an open-source tool that wraps custom SQL databases with a dynamic API, and provides an intuitive admin app for managing its content.",
|
"slogan": "Directus is an open-source tool that wraps custom SQL databases with a dynamic API, and provides an intuitive admin app for managing its content.",
|
||||||
"compose": "c2VydmljZXM6CiAgZGlyZWN0dXM6CiAgICBpbWFnZTogJ2RpcmVjdHVzL2RpcmVjdHVzOjEwLjcnCiAgICB2b2x1bWVzOgogICAgICAtICdkaXJlY3R1cy11cGxvYWRzOi9kaXJlY3R1cy91cGxvYWRzJwogICAgICAtICdkaXJlY3R1cy1leHRlbnNpb25zOi9kaXJlY3R1cy9leHRlbnNpb25zJwogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gU0VSVklDRV9GUUROX0RJUkVDVFVTCiAgICAgIC0gS0VZPSRTRVJWSUNFX0JBU0U2NF82NF9LRVkKICAgICAgLSBTRUNSRVQ9JFNFUlZJQ0VfQkFTRTY0XzY0X1NFQ1JFVAogICAgICAtICdBRE1JTl9FTUFJTD0ke0FETUlOX0VNQUlMOi1hZG1pbkBleGFtcGxlLmNvbX0nCiAgICAgIC0gQURNSU5fUEFTU1dPUkQ9JFNFUlZJQ0VfUEFTU1dPUkRfQURNSU4KICAgICAgLSBEQl9DTElFTlQ9cG9zdGdyZXMKICAgICAgLSBEQl9IT1NUPXBvc3RncmVzcWwKICAgICAgLSBEQl9QT1JUPTU0MzIKICAgICAgLSAnREJfREFUQUJBU0U9JHtQT1NUR1JFU1FMX0RBVEFCQVNFOi1kaXJlY3R1c30nCiAgICAgIC0gREJfVVNFUj0kU0VSVklDRV9VU0VSX1BPU1RHUkVTUUwKICAgICAgLSBEQl9QQVNTV09SRD0kU0VSVklDRV9QQVNTV09SRF9QT1NUR1JFU1FMCiAgICAgIC0gUkVESVNfSE9TVD1yZWRpcwogICAgICAtIFJFRElTX1BPUlQ9NjM3OQogICAgICAtIFdFQlNPQ0tFVFNfRU5BQkxFRD10cnVlCiAgcG9zdGdyZXNxbDoKICAgIGltYWdlOiAncG9zdGdyZXM6MTUtYWxwaW5lJwogICAgdm9sdW1lczoKICAgICAgLSAnZGlyZWN0dXMtcG9zdGdyZXNxbC1kYXRhOi92YXIvbGliL3Bvc3RncmVzcWwvZGF0YScKICAgIGVudmlyb25tZW50OgogICAgICAtICdQT1NUR1JFU19VU0VSPSR7U0VSVklDRV9VU0VSX1BPU1RHUkVTUUx9JwogICAgICAtICdQT1NUR1JFU19QQVNTV09SRD0ke1NFUlZJQ0VfUEFTU1dPUkRfUE9TVEdSRVNRTH0nCiAgICAgIC0gJ1BPU1RHUkVTX0RCPSR7UE9TVEdSRVNRTF9EQVRBQkFTRTotZGlyZWN0dXN9JwogICAgaGVhbHRoY2hlY2s6CiAgICAgIHRlc3Q6CiAgICAgICAgLSBDTUQtU0hFTEwKICAgICAgICAtICdwZ19pc3JlYWR5IC1VICQke1BPU1RHUkVTX1VTRVJ9IC1kICQke1BPU1RHUkVTX0RCfScKICAgICAgaW50ZXJ2YWw6IDVzCiAgICAgIHRpbWVvdXQ6IDIwcwogICAgICByZXRyaWVzOiAxMAogIHJlZGlzOgogICAgaW1hZ2U6ICdyZWRpczo3LWFscGluZScKICAgIGNvbW1hbmQ6ICdyZWRpcy1zZXJ2ZXIgLS1hcHBlbmRvbmx5IHllcycKICAgIHZvbHVtZXM6CiAgICAgIC0gJ2RpcmVjdHVzLXJlZGlzLWRhdGE6L2RhdGEnCiAgICBoZWFsdGhjaGVjazoKICAgICAgdGVzdDoKICAgICAgICAtIENNRAogICAgICAgIC0gcmVkaXMtY2xpCiAgICAgICAgLSBwaW5nCiAgICAgIGludGVydmFsOiA1cwogICAgICB0aW1lb3V0OiAyMHMKICAgICAgcmV0cmllczogMTAK",
|
"compose": "c2VydmljZXM6CiAgZGlyZWN0dXM6CiAgICBpbWFnZTogJ2RpcmVjdHVzL2RpcmVjdHVzOjEwLjcnCiAgICB2b2x1bWVzOgogICAgICAtICdkaXJlY3R1cy11cGxvYWRzOi9kaXJlY3R1cy91cGxvYWRzJwogICAgICAtICdkaXJlY3R1cy1leHRlbnNpb25zOi9kaXJlY3R1cy9leHRlbnNpb25zJwogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gU0VSVklDRV9GUUROX0RJUkVDVFVTCiAgICAgIC0gS0VZPSRTRVJWSUNFX0JBU0U2NF82NF9LRVkKICAgICAgLSBTRUNSRVQ9JFNFUlZJQ0VfQkFTRTY0XzY0X1NFQ1JFVAogICAgICAtICdBRE1JTl9FTUFJTD0ke0FETUlOX0VNQUlMOi1hZG1pbkBleGFtcGxlLmNvbX0nCiAgICAgIC0gQURNSU5fUEFTU1dPUkQ9JFNFUlZJQ0VfUEFTU1dPUkRfQURNSU4KICAgICAgLSBEQl9DTElFTlQ9cG9zdGdyZXMKICAgICAgLSBEQl9IT1NUPXBvc3RncmVzcWwKICAgICAgLSBEQl9QT1JUPTU0MzIKICAgICAgLSAnREJfREFUQUJBU0U9JHtQT1NUR1JFU1FMX0RBVEFCQVNFOi1kaXJlY3R1c30nCiAgICAgIC0gREJfVVNFUj0kU0VSVklDRV9VU0VSX1BPU1RHUkVTUUwKICAgICAgLSBEQl9QQVNTV09SRD0kU0VSVklDRV9QQVNTV09SRF9QT1NUR1JFU1FMCiAgICAgIC0gUkVESVNfSE9TVD1yZWRpcwogICAgICAtIFJFRElTX1BPUlQ9NjM3OQogICAgICAtIFdFQlNPQ0tFVFNfRU5BQkxFRD10cnVlCiAgcG9zdGdyZXNxbDoKICAgIGltYWdlOiAncG9zdGdyZXM6MTYtYWxwaW5lJwogICAgdm9sdW1lczoKICAgICAgLSAnZGlyZWN0dXMtcG9zdGdyZXNxbC1kYXRhOi92YXIvbGliL3Bvc3RncmVzcWwvZGF0YScKICAgIGVudmlyb25tZW50OgogICAgICAtICdQT1NUR1JFU19VU0VSPSR7U0VSVklDRV9VU0VSX1BPU1RHUkVTUUx9JwogICAgICAtICdQT1NUR1JFU19QQVNTV09SRD0ke1NFUlZJQ0VfUEFTU1dPUkRfUE9TVEdSRVNRTH0nCiAgICAgIC0gJ1BPU1RHUkVTX0RCPSR7UE9TVEdSRVNRTF9EQVRBQkFTRTotZGlyZWN0dXN9JwogICAgaGVhbHRoY2hlY2s6CiAgICAgIHRlc3Q6CiAgICAgICAgLSBDTUQtU0hFTEwKICAgICAgICAtICdwZ19pc3JlYWR5IC1VICQke1BPU1RHUkVTX1VTRVJ9IC1kICQke1BPU1RHUkVTX0RCfScKICAgICAgaW50ZXJ2YWw6IDVzCiAgICAgIHRpbWVvdXQ6IDIwcwogICAgICByZXRyaWVzOiAxMAogIHJlZGlzOgogICAgaW1hZ2U6ICdyZWRpczo3LWFscGluZScKICAgIGNvbW1hbmQ6ICdyZWRpcy1zZXJ2ZXIgLS1hcHBlbmRvbmx5IHllcycKICAgIHZvbHVtZXM6CiAgICAgIC0gJ2RpcmVjdHVzLXJlZGlzLWRhdGE6L2RhdGEnCiAgICBoZWFsdGhjaGVjazoKICAgICAgdGVzdDoKICAgICAgICAtIENNRAogICAgICAgIC0gcmVkaXMtY2xpCiAgICAgICAgLSBwaW5nCiAgICAgIGludGVydmFsOiA1cwogICAgICB0aW1lb3V0OiAyMHMKICAgICAgcmV0cmllczogMTAK",
|
||||||
"tags": [
|
"tags": [
|
||||||
"directus",
|
"directus",
|
||||||
"cms",
|
"cms",
|
||||||
@@ -208,7 +208,7 @@
|
|||||||
"gitea-with-postgresql": {
|
"gitea-with-postgresql": {
|
||||||
"documentation": "https:\/\/docs.gitea.com",
|
"documentation": "https:\/\/docs.gitea.com",
|
||||||
"slogan": "Gitea (with PostgreSQL)vis a self-hosted, lightweight Git service, offering version control, collaboration, and code hosting.",
|
"slogan": "Gitea (with PostgreSQL)vis a self-hosted, lightweight Git service, offering version control, collaboration, and code hosting.",
|
||||||
"compose": "c2VydmljZXM6CiAgZ2l0ZWE6CiAgICBpbWFnZTogJ2dpdGVhL2dpdGVhOmxhdGVzdCcKICAgIGVudmlyb25tZW50OgogICAgICAtIFNFUlZJQ0VfRlFETl9HSVRFQV8zMDAwCiAgICAgIC0gVVNFUl9VSUQ9MTAwMAogICAgICAtIFVTRVJfR0lEPTEwMDAKICAgICAgLSBHSVRFQV9fZGF0YWJhc2VfX0RCX1RZUEU9cG9zdGdyZXMKICAgICAgLSBHSVRFQV9fZGF0YWJhc2VfX0hPU1Q9cG9zdGdyZXNxbAogICAgICAtICdHSVRFQV9fZGF0YWJhc2VfX05BTUU9JHtQT1NUR1JFU1FMX0RBVEFCQVNFLWdpdGVhfScKICAgICAgLSBHSVRFQV9fZGF0YWJhc2VfX1VTRVI9JFNFUlZJQ0VfVVNFUl9QT1NUR1JFU1FMCiAgICAgIC0gR0lURUFfX2RhdGFiYXNlX19QQVNTV0Q9JFNFUlZJQ0VfUEFTU1dPUkRfUE9TVEdSRVNRTAogICAgdm9sdW1lczoKICAgICAgLSAnZ2l0ZWEtZGF0YTovdmFyL2xpYi9naXRlYScKICAgICAgLSAnZ2l0ZWEtdGltZXpvbmU6L2V0Yy90aW1lem9uZTpybycKICAgICAgLSAnZ2l0ZWEtbG9jYWx0aW1lOi9ldGMvbG9jYWx0aW1lOnJvJwogICAgcG9ydHM6CiAgICAgIC0gJzIyMjIyOjIyJwogICAgZGVwZW5kc19vbjoKICAgICAgcG9zdGdyZXNxbDoKICAgICAgICBjb25kaXRpb246IHNlcnZpY2VfaGVhbHRoeQogICAgaGVhbHRoY2hlY2s6CiAgICAgIHRlc3Q6CiAgICAgICAgLSBDTUQKICAgICAgICAtIGN1cmwKICAgICAgICAtICctZicKICAgICAgICAtICdodHRwOi8vbG9jYWxob3N0OjMwMDAnCiAgICAgIGludGVydmFsOiAycwogICAgICB0aW1lb3V0OiAxMHMKICAgICAgcmV0cmllczogMTUKICBwb3N0Z3Jlc3FsOgogICAgaW1hZ2U6ICdwb3N0Z3JlczoxNS1hbHBpbmUnCiAgICB2b2x1bWVzOgogICAgICAtICdnaXRlYS1wb3N0Z3Jlc3FsLWRhdGE6L3Zhci9saWIvcG9zdGdyZXNxbC9kYXRhJwogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gJ1BPU1RHUkVTX1VTRVI9JHtTRVJWSUNFX1VTRVJfUE9TVEdSRVNRTH0nCiAgICAgIC0gJ1BPU1RHUkVTX1BBU1NXT1JEPSR7U0VSVklDRV9QQVNTV09SRF9QT1NUR1JFU1FMfScKICAgICAgLSAnUE9TVEdSRVNfREI9JHtQT1NUR1JFU1FMX0RBVEFCQVNFfScKICAgIGhlYWx0aGNoZWNrOgogICAgICB0ZXN0OgogICAgICAgIC0gQ01ELVNIRUxMCiAgICAgICAgLSAncGdfaXNyZWFkeSAtVSAkJHtQT1NUR1JFU19VU0VSfSAtZCAkJHtQT1NUR1JFU19EQn0nCiAgICAgIGludGVydmFsOiA1cwogICAgICB0aW1lb3V0OiAyMHMKICAgICAgcmV0cmllczogMTAK",
|
"compose": "c2VydmljZXM6CiAgZ2l0ZWE6CiAgICBpbWFnZTogJ2dpdGVhL2dpdGVhOmxhdGVzdCcKICAgIGVudmlyb25tZW50OgogICAgICAtIFNFUlZJQ0VfRlFETl9HSVRFQV8zMDAwCiAgICAgIC0gVVNFUl9VSUQ9MTAwMAogICAgICAtIFVTRVJfR0lEPTEwMDAKICAgICAgLSBHSVRFQV9fZGF0YWJhc2VfX0RCX1RZUEU9cG9zdGdyZXMKICAgICAgLSBHSVRFQV9fZGF0YWJhc2VfX0hPU1Q9cG9zdGdyZXNxbAogICAgICAtICdHSVRFQV9fZGF0YWJhc2VfX05BTUU9JHtQT1NUR1JFU1FMX0RBVEFCQVNFLWdpdGVhfScKICAgICAgLSBHSVRFQV9fZGF0YWJhc2VfX1VTRVI9JFNFUlZJQ0VfVVNFUl9QT1NUR1JFU1FMCiAgICAgIC0gR0lURUFfX2RhdGFiYXNlX19QQVNTV0Q9JFNFUlZJQ0VfUEFTU1dPUkRfUE9TVEdSRVNRTAogICAgdm9sdW1lczoKICAgICAgLSAnZ2l0ZWEtZGF0YTovdmFyL2xpYi9naXRlYScKICAgICAgLSAnZ2l0ZWEtdGltZXpvbmU6L2V0Yy90aW1lem9uZTpybycKICAgICAgLSAnZ2l0ZWEtbG9jYWx0aW1lOi9ldGMvbG9jYWx0aW1lOnJvJwogICAgcG9ydHM6CiAgICAgIC0gJzIyMjIyOjIyJwogICAgZGVwZW5kc19vbjoKICAgICAgcG9zdGdyZXNxbDoKICAgICAgICBjb25kaXRpb246IHNlcnZpY2VfaGVhbHRoeQogICAgaGVhbHRoY2hlY2s6CiAgICAgIHRlc3Q6CiAgICAgICAgLSBDTUQKICAgICAgICAtIGN1cmwKICAgICAgICAtICctZicKICAgICAgICAtICdodHRwOi8vbG9jYWxob3N0OjMwMDAnCiAgICAgIGludGVydmFsOiAycwogICAgICB0aW1lb3V0OiAxMHMKICAgICAgcmV0cmllczogMTUKICBwb3N0Z3Jlc3FsOgogICAgaW1hZ2U6ICdwb3N0Z3JlczoxNi1hbHBpbmUnCiAgICB2b2x1bWVzOgogICAgICAtICdnaXRlYS1wb3N0Z3Jlc3FsLWRhdGE6L3Zhci9saWIvcG9zdGdyZXNxbC9kYXRhJwogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gJ1BPU1RHUkVTX1VTRVI9JHtTRVJWSUNFX1VTRVJfUE9TVEdSRVNRTH0nCiAgICAgIC0gJ1BPU1RHUkVTX1BBU1NXT1JEPSR7U0VSVklDRV9QQVNTV09SRF9QT1NUR1JFU1FMfScKICAgICAgLSAnUE9TVEdSRVNfREI9JHtQT1NUR1JFU1FMX0RBVEFCQVNFfScKICAgIGhlYWx0aGNoZWNrOgogICAgICB0ZXN0OgogICAgICAgIC0gQ01ELVNIRUxMCiAgICAgICAgLSAncGdfaXNyZWFkeSAtVSAkJHtQT1NUR1JFU19VU0VSfSAtZCAkJHtQT1NUR1JFU19EQn0nCiAgICAgIGludGVydmFsOiA1cwogICAgICB0aW1lb3V0OiAyMHMKICAgICAgcmV0cmllczogMTAK",
|
||||||
"tags": [
|
"tags": [
|
||||||
"version control",
|
"version control",
|
||||||
"collaboration",
|
"collaboration",
|
||||||
@@ -233,7 +233,7 @@
|
|||||||
"grafana-with-postgresql": {
|
"grafana-with-postgresql": {
|
||||||
"documentation": "https:\/\/grafana.com\/docs\/grafana\/latest\/installation\/docker\/",
|
"documentation": "https:\/\/grafana.com\/docs\/grafana\/latest\/installation\/docker\/",
|
||||||
"slogan": "Grafana is the open source analytics & monitoring solution for every database.",
|
"slogan": "Grafana is the open source analytics & monitoring solution for every database.",
|
||||||
"compose": "c2VydmljZXM6CiAgZ3JhZmFuYToKICAgIGltYWdlOiBncmFmYW5hL2dyYWZhbmEtb3NzCiAgICBlbnZpcm9ubWVudDoKICAgICAgLSBTRVJWSUNFX0ZRRE5fR1JBRkFOQQogICAgICAtICdHRl9TRVJWRVJfUk9PVF9VUkw9JHtTRVJWSUNFX0ZRRE5fR1JBRkFOQX0nCiAgICAgIC0gJ0dGX1NFUlZFUl9ET01BSU49JHtTRVJWSUNFX0ZRRE5fR1JBRkFOQX0nCiAgICAgIC0gJ0dGX1NFQ1VSSVRZX0FETUlOX1BBU1NXT1JEPSR7U0VSVklDRV9QQVNTV09SRF9HUkFGQU5BfScKICAgICAgLSBHRl9EQVRBQkFTRV9UWVBFPXBvc3RncmVzCiAgICAgIC0gR0ZfREFUQUJBU0VfSE9TVD1wb3N0Z3Jlc3FsCiAgICAgIC0gR0ZfREFUQUJBU0VfVVNFUj0kU0VSVklDRV9VU0VSX1BPU1RHUkVTCiAgICAgIC0gR0ZfREFUQUJBU0VfUEFTU1dPUkQ9JFNFUlZJQ0VfUEFTU1dPUkRfUE9TVEdSRVMKICAgICAgLSAnR0ZfREFUQUJBU0VfTkFNRT0ke1BPU1RHUkVTX0RCOi1ncmFmYW5hfScKICAgIHZvbHVtZXM6CiAgICAgIC0gJ2dyYWZhbmEtZGF0YTovdmFyL2xpYi9ncmFmYW5hJwogICAgaGVhbHRoY2hlY2s6CiAgICAgIHRlc3Q6CiAgICAgICAgLSBDTUQKICAgICAgICAtIGN1cmwKICAgICAgICAtICctZicKICAgICAgICAtICdodHRwOi8vbG9jYWxob3N0OjMwMDAvYXBpL2hlYWx0aCcKICAgICAgaW50ZXJ2YWw6IDVzCiAgICAgIHRpbWVvdXQ6IDIwcwogICAgICByZXRyaWVzOiAxMAogICAgZGVwZW5kc19vbjoKICAgICAgLSBwb3N0Z3Jlc3FsCiAgcG9zdGdyZXNxbDoKICAgIGltYWdlOiAncG9zdGdyZXM6MTUtYWxwaW5lJwogICAgdm9sdW1lczoKICAgICAgLSAncG9zdGdyZXNxbC1kYXRhOi92YXIvbGliL3Bvc3RncmVzcWwvZGF0YScKICAgIGVudmlyb25tZW50OgogICAgICAtIFBPU1RHUkVTX1VTRVI9JFNFUlZJQ0VfVVNFUl9QT1NUR1JFUwogICAgICAtIFBPU1RHUkVTX1BBU1NXT1JEPSRTRVJWSUNFX1BBU1NXT1JEX1BPU1RHUkVTCiAgICAgIC0gJ1BPU1RHUkVTX0RCPSR7UE9TVEdSRVNfREI6LWdyYWZhbmF9JwogICAgaGVhbHRoY2hlY2s6CiAgICAgIHRlc3Q6CiAgICAgICAgLSBDTUQtU0hFTEwKICAgICAgICAtICdwZ19pc3JlYWR5IC1VICQke1BPU1RHUkVTX1VTRVJ9IC1kICQke1BPU1RHUkVTX0RCfScKICAgICAgaW50ZXJ2YWw6IDVzCiAgICAgIHRpbWVvdXQ6IDIwcwogICAgICByZXRyaWVzOiAxMAo=",
|
"compose": "c2VydmljZXM6CiAgZ3JhZmFuYToKICAgIGltYWdlOiBncmFmYW5hL2dyYWZhbmEtb3NzCiAgICBlbnZpcm9ubWVudDoKICAgICAgLSBTRVJWSUNFX0ZRRE5fR1JBRkFOQQogICAgICAtICdHRl9TRVJWRVJfUk9PVF9VUkw9JHtTRVJWSUNFX0ZRRE5fR1JBRkFOQX0nCiAgICAgIC0gJ0dGX1NFUlZFUl9ET01BSU49JHtTRVJWSUNFX0ZRRE5fR1JBRkFOQX0nCiAgICAgIC0gJ0dGX1NFQ1VSSVRZX0FETUlOX1BBU1NXT1JEPSR7U0VSVklDRV9QQVNTV09SRF9HUkFGQU5BfScKICAgICAgLSBHRl9EQVRBQkFTRV9UWVBFPXBvc3RncmVzCiAgICAgIC0gR0ZfREFUQUJBU0VfSE9TVD1wb3N0Z3Jlc3FsCiAgICAgIC0gR0ZfREFUQUJBU0VfVVNFUj0kU0VSVklDRV9VU0VSX1BPU1RHUkVTCiAgICAgIC0gR0ZfREFUQUJBU0VfUEFTU1dPUkQ9JFNFUlZJQ0VfUEFTU1dPUkRfUE9TVEdSRVMKICAgICAgLSAnR0ZfREFUQUJBU0VfTkFNRT0ke1BPU1RHUkVTX0RCOi1ncmFmYW5hfScKICAgIHZvbHVtZXM6CiAgICAgIC0gJ2dyYWZhbmEtZGF0YTovdmFyL2xpYi9ncmFmYW5hJwogICAgaGVhbHRoY2hlY2s6CiAgICAgIHRlc3Q6CiAgICAgICAgLSBDTUQKICAgICAgICAtIGN1cmwKICAgICAgICAtICctZicKICAgICAgICAtICdodHRwOi8vbG9jYWxob3N0OjMwMDAvYXBpL2hlYWx0aCcKICAgICAgaW50ZXJ2YWw6IDVzCiAgICAgIHRpbWVvdXQ6IDIwcwogICAgICByZXRyaWVzOiAxMAogICAgZGVwZW5kc19vbjoKICAgICAgLSBwb3N0Z3Jlc3FsCiAgcG9zdGdyZXNxbDoKICAgIGltYWdlOiAncG9zdGdyZXM6MTYtYWxwaW5lJwogICAgdm9sdW1lczoKICAgICAgLSAncG9zdGdyZXNxbC1kYXRhOi92YXIvbGliL3Bvc3RncmVzcWwvZGF0YScKICAgIGVudmlyb25tZW50OgogICAgICAtIFBPU1RHUkVTX1VTRVI9JFNFUlZJQ0VfVVNFUl9QT1NUR1JFUwogICAgICAtIFBPU1RHUkVTX1BBU1NXT1JEPSRTRVJWSUNFX1BBU1NXT1JEX1BPU1RHUkVTCiAgICAgIC0gJ1BPU1RHUkVTX0RCPSR7UE9TVEdSRVNfREI6LWdyYWZhbmF9JwogICAgaGVhbHRoY2hlY2s6CiAgICAgIHRlc3Q6CiAgICAgICAgLSBDTUQtU0hFTEwKICAgICAgICAtICdwZ19pc3JlYWR5IC1VICQke1BPU1RHUkVTX1VTRVJ9IC1kICQke1BPU1RHUkVTX0RCfScKICAgICAgaW50ZXJ2YWw6IDVzCiAgICAgIHRpbWVvdXQ6IDIwcwogICAgICByZXRyaWVzOiAxMAo=",
|
||||||
"tags": [
|
"tags": [
|
||||||
"grafana",
|
"grafana",
|
||||||
"analytics",
|
"analytics",
|
||||||
@@ -304,6 +304,19 @@
|
|||||||
"low-code"
|
"low-code"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"meilisearch": {
|
||||||
|
"documentation": "https:\/\/www.meilisearch.com\/docs\/learn\/configuration\/instance_options",
|
||||||
|
"slogan": "MeiliSearch is a powerful, fast, open-source, easy to use and deploy search engine.",
|
||||||
|
"compose": "c2VydmljZXM6CiAgbWVpbGlzZWFyY2g6CiAgICBpbWFnZTogJ2dldG1laWxpL21laWxpc2VhcmNoOmxhdGVzdCcKICAgIGVudmlyb25tZW50OgogICAgICAtIFNFUlZJQ0VfRlFETl9NRUlMSVNFQVJDSAogICAgICAtICdNRUlMSV9OT19BTkFMWVRJQ1M9JHtNRUlMSV9OT19BTkFMWVRJQ1M6LXRydWV9JwogICAgICAtICdNRUlMSV9FTlY9JHtNRUlMSV9FTlY6LXByb2R1Y3Rpb259JwogICAgICAtICdNRUlMSV9NQVNURVJfS0VZPSR7U0VSVklDRV9QQVNTV09SRF9NRUlMSVNFQVJDSH0nCiAgICB2b2x1bWVzOgogICAgICAtICdtZWlsaXNlYXJjaC1kYXRhOi9tZWlsaV9kYXRhJwogICAgaGVhbHRoY2hlY2s6CiAgICAgIHRlc3Q6CiAgICAgICAgLSBDTUQKICAgICAgICAtIGN1cmwKICAgICAgICAtICctZicKICAgICAgICAtICdodHRwOi8vbG9jYWxob3N0Ojc3MDAvaGVhbHRoJwogICAgICBpbnRlcnZhbDogMnMKICAgICAgdGltZW91dDogMTBzCiAgICAgIHJldHJpZXM6IDE1Cg==",
|
||||||
|
"tags": [
|
||||||
|
"search",
|
||||||
|
"engine",
|
||||||
|
"fulltext",
|
||||||
|
"full",
|
||||||
|
"text",
|
||||||
|
"meilisearch"
|
||||||
|
]
|
||||||
|
},
|
||||||
"metube": {
|
"metube": {
|
||||||
"documentation": "https:\/\/github.com\/alexta69\/metube",
|
"documentation": "https:\/\/github.com\/alexta69\/metube",
|
||||||
"slogan": "A web GUI for youtube-dl with playlist support. It enables you to effortlessly download videos from YouTube and dozens of other sites.",
|
"slogan": "A web GUI for youtube-dl with playlist support. It enables you to effortlessly download videos from YouTube and dozens of other sites.",
|
||||||
@@ -346,7 +359,7 @@
|
|||||||
"n8n-with-postgresql": {
|
"n8n-with-postgresql": {
|
||||||
"documentation": "https:\/\/docs.n8n.io\/hosting\/",
|
"documentation": "https:\/\/docs.n8n.io\/hosting\/",
|
||||||
"slogan": "n8n is an extendable workflow automation tool which enables you to connect anything to everything via its open, fair-code model.",
|
"slogan": "n8n is an extendable workflow automation tool which enables you to connect anything to everything via its open, fair-code model.",
|
||||||
"compose": "c2VydmljZXM6CiAgbjhuOgogICAgaW1hZ2U6IGRvY2tlci5uOG4uaW8vbjhuaW8vbjhuCiAgICBlbnZpcm9ubWVudDoKICAgICAgLSBTRVJWSUNFX0ZRRE5fTjhOCiAgICAgIC0gJ044Tl9FRElUT1JfQkFTRV9VUkw9JHtTRVJWSUNFX0ZRRE5fTjhOfScKICAgICAgLSAnV0VCSE9PS19VUkw9JHtTRVJWSUNFX0ZRRE5fTjhOfScKICAgICAgLSAnTjhOX0hPU1Q9JHtTRVJWSUNFX1VSTF9OOE59JwogICAgICAtICdHRU5FUklDX1RJTUVaT05FPSJFdXJvcGUvQmVybGluIicKICAgICAgLSAnVFo9IkV1cm9wZS9CZXJsaW4iJwogICAgICAtIERCX1RZUEU9cG9zdGdyZXNkYgogICAgICAtICdEQl9QT1NUR1JFU0RCX0RBVEFCQVNFPSR7UE9TVEdSRVNfREI6LW44bn0nCiAgICAgIC0gREJfUE9TVEdSRVNEQl9IT1NUPXBvc3RncmVzcWwKICAgICAgLSBEQl9QT1NUR1JFU0RCX1BPUlQ9NTQzMgogICAgICAtIERCX1BPU1RHUkVTREJfVVNFUj0kU0VSVklDRV9VU0VSX1BPU1RHUkVTCiAgICAgIC0gREJfUE9TVEdSRVNEQl9TQ0hFTUE9cHVibGljCiAgICAgIC0gREJfUE9TVEdSRVNEQl9QQVNTV09SRD0kU0VSVklDRV9QQVNTV09SRF9QT1NUR1JFUwogICAgdm9sdW1lczoKICAgICAgLSAnbjhuLWRhdGE6L2hvbWUvbm9kZS8ubjhuJwogICAgZGVwZW5kc19vbjoKICAgICAgLSBwb3N0Z3Jlc3FsCiAgcG9zdGdyZXNxbDoKICAgIGltYWdlOiAncG9zdGdyZXM6MTUtYWxwaW5lJwogICAgdm9sdW1lczoKICAgICAgLSAncG9zdGdyZXNxbC1kYXRhOi92YXIvbGliL3Bvc3RncmVzcWwvZGF0YScKICAgIGVudmlyb25tZW50OgogICAgICAtIFBPU1RHUkVTX1VTRVI9JFNFUlZJQ0VfVVNFUl9QT1NUR1JFUwogICAgICAtIFBPU1RHUkVTX1BBU1NXT1JEPSRTRVJWSUNFX1BBU1NXT1JEX1BPU1RHUkVTCiAgICAgIC0gJ1BPU1RHUkVTX0RCPSR7UE9TVEdSRVNfREI6LW44bn0nCiAgICBoZWFsdGhjaGVjazoKICAgICAgdGVzdDoKICAgICAgICAtIENNRC1TSEVMTAogICAgICAgIC0gJ3BnX2lzcmVhZHkgLVUgJCR7UE9TVEdSRVNfVVNFUn0gLWQgJCR7UE9TVEdSRVNfREJ9JwogICAgICBpbnRlcnZhbDogNXMKICAgICAgdGltZW91dDogMjBzCiAgICAgIHJldHJpZXM6IDEwCg==",
|
"compose": "c2VydmljZXM6CiAgbjhuOgogICAgaW1hZ2U6IGRvY2tlci5uOG4uaW8vbjhuaW8vbjhuCiAgICBlbnZpcm9ubWVudDoKICAgICAgLSBTRVJWSUNFX0ZRRE5fTjhOCiAgICAgIC0gJ044Tl9FRElUT1JfQkFTRV9VUkw9JHtTRVJWSUNFX0ZRRE5fTjhOfScKICAgICAgLSAnV0VCSE9PS19VUkw9JHtTRVJWSUNFX0ZRRE5fTjhOfScKICAgICAgLSAnTjhOX0hPU1Q9JHtTRVJWSUNFX1VSTF9OOE59JwogICAgICAtICdHRU5FUklDX1RJTUVaT05FPSJFdXJvcGUvQmVybGluIicKICAgICAgLSAnVFo9IkV1cm9wZS9CZXJsaW4iJwogICAgICAtIERCX1RZUEU9cG9zdGdyZXNkYgogICAgICAtICdEQl9QT1NUR1JFU0RCX0RBVEFCQVNFPSR7UE9TVEdSRVNfREI6LW44bn0nCiAgICAgIC0gREJfUE9TVEdSRVNEQl9IT1NUPXBvc3RncmVzcWwKICAgICAgLSBEQl9QT1NUR1JFU0RCX1BPUlQ9NTQzMgogICAgICAtIERCX1BPU1RHUkVTREJfVVNFUj0kU0VSVklDRV9VU0VSX1BPU1RHUkVTCiAgICAgIC0gREJfUE9TVEdSRVNEQl9TQ0hFTUE9cHVibGljCiAgICAgIC0gREJfUE9TVEdSRVNEQl9QQVNTV09SRD0kU0VSVklDRV9QQVNTV09SRF9QT1NUR1JFUwogICAgdm9sdW1lczoKICAgICAgLSAnbjhuLWRhdGE6L2hvbWUvbm9kZS8ubjhuJwogICAgZGVwZW5kc19vbjoKICAgICAgLSBwb3N0Z3Jlc3FsCiAgcG9zdGdyZXNxbDoKICAgIGltYWdlOiAncG9zdGdyZXM6MTYtYWxwaW5lJwogICAgdm9sdW1lczoKICAgICAgLSAncG9zdGdyZXNxbC1kYXRhOi92YXIvbGliL3Bvc3RncmVzcWwvZGF0YScKICAgIGVudmlyb25tZW50OgogICAgICAtIFBPU1RHUkVTX1VTRVI9JFNFUlZJQ0VfVVNFUl9QT1NUR1JFUwogICAgICAtIFBPU1RHUkVTX1BBU1NXT1JEPSRTRVJWSUNFX1BBU1NXT1JEX1BPU1RHUkVTCiAgICAgIC0gJ1BPU1RHUkVTX0RCPSR7UE9TVEdSRVNfREI6LW44bn0nCiAgICBoZWFsdGhjaGVjazoKICAgICAgdGVzdDoKICAgICAgICAtIENNRC1TSEVMTAogICAgICAgIC0gJ3BnX2lzcmVhZHkgLVUgJCR7UE9TVEdSRVNfVVNFUn0gLWQgJCR7UE9TVEdSRVNfREJ9JwogICAgICBpbnRlcnZhbDogNXMKICAgICAgdGltZW91dDogMjBzCiAgICAgIHJldHJpZXM6IDEwCg==",
|
||||||
"tags": [
|
"tags": [
|
||||||
"n8n",
|
"n8n",
|
||||||
"workflow",
|
"workflow",
|
||||||
@@ -473,7 +486,7 @@
|
|||||||
"trigger": {
|
"trigger": {
|
||||||
"documentation": "https:\/\/trigger.dev\/docs\/documentation\/guides\/self-hosting",
|
"documentation": "https:\/\/trigger.dev\/docs\/documentation\/guides\/self-hosting",
|
||||||
"slogan": "The open source Background Jobs framework for TypeScript",
|
"slogan": "The open source Background Jobs framework for TypeScript",
|
||||||
"compose": "c2VydmljZXM6CiAgdHJpZ2dlcjoKICAgIGltYWdlOiAnZ2hjci5pby90cmlnZ2VyZG90ZGV2L3RyaWdnZXIuZGV2OmxhdGVzdCcKICAgIGVudmlyb25tZW50OgogICAgICAtIFNFUlZJQ0VfRlFETl9UUklHR0VSCiAgICAgIC0gTE9HSU5fT1JJR0lOPSRTRVJWSUNFX0ZRRE5fVFJJR0dFUgogICAgICAtIEFQUF9PUklHSU49JFNFUlZJQ0VfRlFETl9UUklHR0VSCiAgICAgIC0gTUFHSUNfTElOS19TRUNSRVQ9JFNFUlZJQ0VfUEFTU1dPUkRfNjRfTUFHSUMKICAgICAgLSBFTkNSWVBUSU9OX0tFWT0kU0VSVklDRV9QQVNTV09SRF82NF9FTkNSWVBUSU9OCiAgICAgIC0gU0VTU0lPTl9TRUNSRVQ9JFNFUlZJQ0VfUEFTU1dPUkRfNjRfU0VTU0lPTgogICAgICAtIFBPU1RHUkVTX1VTRVI9JFNFUlZJQ0VfVVNFUl9QT1NUR1JFUwogICAgICAtIFBPU1RHUkVTX1BBU1NXT1JEPSRTRVJWSUNFX1BBU1NXT1JEX1BPU1RHUkVTCiAgICAgIC0gJ1BPU1RHUkVTX0RCPSR7UE9TVEdSRVNfREI6LXRyaWdnZXJ9JwogICAgICAtIFBPU1RHUkVTX0hPU1Q9cG9zdGdyZXMKICAgICAgLSAnREFUQUJBU0VfVVJMPXBvc3RncmVzOi8vJFNFUlZJQ0VfVVNFUl9QT1NUR1JFUzokU0VSVklDRV9QQVNTV09SRF9QT1NUR1JFU0Bwb3N0Z3Jlc3FsOjU0MzIvJFBPU1RHUkVTX0RCJwogICAgICAtICdESVJFQ1RfVVJMPXBvc3RncmVzOi8vJFNFUlZJQ0VfVVNFUl9QT1NUR1JFUzokU0VSVklDRV9QQVNTV09SRF9QT1NUR1JFU0Bwb3N0Z3Jlc3FsOjU0MzIvJFBPU1RHUkVTX0RCJwogICAgICAtIFJVTlRJTUVfUExBVEZPUk09ZG9ja2VyLWNvbXBvc2UKICAgICAgLSBOT0RFX0VOVj1wcm9kdWN0aW9uCiAgICAgIC0gJ0FVVEhfR0lUSFVCX0NMSUVOVF9JRD0ke0FVVEhfR0lUSFVCX0NMSUVOVF9JRH0nCiAgICAgIC0gJ0FVVEhfR0lUSFVCX0NMSUVOVF9TRUNSRVQ9JHtBVVRIX0dJVEhVQl9DTElFTlRfU0VDUkVUfScKICAgICAgLSAnUkVTRU5EX0FQSV9LRVk9JHtSRVNFTkRfQVBJX0tFWX0nCiAgICAgIC0gJ0ZST01fRU1BSUw9JHtGUk9NX0VNQUlMfScKICAgICAgLSAnUkVQTFlfVE9fRU1BSUw9JHtSRVBMWV9UT19FTUFJTH0nCiAgICBkZXBlbmRzX29uOgogICAgICBwb3N0Z3Jlc3FsOgogICAgICAgIGNvbmRpdGlvbjogc2VydmljZV9oZWFsdGh5CiAgICBoZWFsdGhjaGVjazoKICAgICAgdGVzdDoKICAgICAgICAtIE5PTkUKICBwb3N0Z3Jlc3FsOgogICAgaW1hZ2U6ICdwb3N0Z3JlczoxNS1hbHBpbmUnCiAgICB2b2x1bWVzOgogICAgICAtICdwb3N0Z3Jlc3FsLWRhdGE6L3Zhci9saWIvcG9zdGdyZXNxbC9kYXRhJwogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gUE9TVEdSRVNfVVNFUj0kU0VSVklDRV9VU0VSX1BPU1RHUkVTCiAgICAgIC0gUE9TVEdSRVNfUEFTU1dPUkQ9JFNFUlZJQ0VfUEFTU1dPUkRfUE9TVEdSRVMKICAgICAgLSAnUE9TVEdSRVNfREI9JHtQT1NUR1JFU19EQjotdHJpZ2dlcn0nCiAgICBoZWFsdGhjaGVjazoKICAgICAgdGVzdDoKICAgICAgICAtIENNRC1TSEVMTAogICAgICAgIC0gJ3BnX2lzcmVhZHkgLVUgJCR7UE9TVEdSRVNfVVNFUn0gLWQgJCR7UE9TVEdSRVNfREJ9JwogICAgICBpbnRlcnZhbDogNXMKICAgICAgdGltZW91dDogMjBzCiAgICAgIHJldHJpZXM6IDEwCg==",
|
"compose": "c2VydmljZXM6CiAgdHJpZ2dlcjoKICAgIGltYWdlOiAnZ2hjci5pby90cmlnZ2VyZG90ZGV2L3RyaWdnZXIuZGV2OmxhdGVzdCcKICAgIGVudmlyb25tZW50OgogICAgICAtIFNFUlZJQ0VfRlFETl9UUklHR0VSCiAgICAgIC0gTE9HSU5fT1JJR0lOPSRTRVJWSUNFX0ZRRE5fVFJJR0dFUgogICAgICAtIEFQUF9PUklHSU49JFNFUlZJQ0VfRlFETl9UUklHR0VSCiAgICAgIC0gTUFHSUNfTElOS19TRUNSRVQ9JFNFUlZJQ0VfUEFTU1dPUkRfNjRfTUFHSUMKICAgICAgLSBFTkNSWVBUSU9OX0tFWT0kU0VSVklDRV9QQVNTV09SRF82NF9FTkNSWVBUSU9OCiAgICAgIC0gU0VTU0lPTl9TRUNSRVQ9JFNFUlZJQ0VfUEFTU1dPUkRfNjRfU0VTU0lPTgogICAgICAtIFBPU1RHUkVTX1VTRVI9JFNFUlZJQ0VfVVNFUl9QT1NUR1JFUwogICAgICAtIFBPU1RHUkVTX1BBU1NXT1JEPSRTRVJWSUNFX1BBU1NXT1JEX1BPU1RHUkVTCiAgICAgIC0gJ1BPU1RHUkVTX0RCPSR7UE9TVEdSRVNfREI6LXRyaWdnZXJ9JwogICAgICAtIFBPU1RHUkVTX0hPU1Q9cG9zdGdyZXMKICAgICAgLSAnREFUQUJBU0VfVVJMPXBvc3RncmVzOi8vJFNFUlZJQ0VfVVNFUl9QT1NUR1JFUzokU0VSVklDRV9QQVNTV09SRF9QT1NUR1JFU0Bwb3N0Z3Jlc3FsOjU0MzIvJFBPU1RHUkVTX0RCJwogICAgICAtICdESVJFQ1RfVVJMPXBvc3RncmVzOi8vJFNFUlZJQ0VfVVNFUl9QT1NUR1JFUzokU0VSVklDRV9QQVNTV09SRF9QT1NUR1JFU0Bwb3N0Z3Jlc3FsOjU0MzIvJFBPU1RHUkVTX0RCJwogICAgICAtIFJVTlRJTUVfUExBVEZPUk09ZG9ja2VyLWNvbXBvc2UKICAgICAgLSBOT0RFX0VOVj1wcm9kdWN0aW9uCiAgICAgIC0gJ0FVVEhfR0lUSFVCX0NMSUVOVF9JRD0ke0FVVEhfR0lUSFVCX0NMSUVOVF9JRH0nCiAgICAgIC0gJ0FVVEhfR0lUSFVCX0NMSUVOVF9TRUNSRVQ9JHtBVVRIX0dJVEhVQl9DTElFTlRfU0VDUkVUfScKICAgICAgLSAnUkVTRU5EX0FQSV9LRVk9JHtSRVNFTkRfQVBJX0tFWX0nCiAgICAgIC0gJ0ZST01fRU1BSUw9JHtGUk9NX0VNQUlMfScKICAgICAgLSAnUkVQTFlfVE9fRU1BSUw9JHtSRVBMWV9UT19FTUFJTH0nCiAgICBkZXBlbmRzX29uOgogICAgICBwb3N0Z3Jlc3FsOgogICAgICAgIGNvbmRpdGlvbjogc2VydmljZV9oZWFsdGh5CiAgICBoZWFsdGhjaGVjazoKICAgICAgdGVzdDoKICAgICAgICAtIE5PTkUKICBwb3N0Z3Jlc3FsOgogICAgaW1hZ2U6ICdwb3N0Z3JlczoxNi1hbHBpbmUnCiAgICB2b2x1bWVzOgogICAgICAtICdwb3N0Z3Jlc3FsLWRhdGE6L3Zhci9saWIvcG9zdGdyZXNxbC9kYXRhJwogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gUE9TVEdSRVNfVVNFUj0kU0VSVklDRV9VU0VSX1BPU1RHUkVTCiAgICAgIC0gUE9TVEdSRVNfUEFTU1dPUkQ9JFNFUlZJQ0VfUEFTU1dPUkRfUE9TVEdSRVMKICAgICAgLSAnUE9TVEdSRVNfREI9JHtQT1NUR1JFU19EQjotdHJpZ2dlcn0nCiAgICBoZWFsdGhjaGVjazoKICAgICAgdGVzdDoKICAgICAgICAtIENNRC1TSEVMTAogICAgICAgIC0gJ3BnX2lzcmVhZHkgLVUgJCR7UE9TVEdSRVNfVVNFUn0gLWQgJCR7UE9TVEdSRVNfREJ9JwogICAgICBpbnRlcnZhbDogNXMKICAgICAgdGltZW91dDogMjBzCiAgICAgIHJldHJpZXM6IDEwCg==",
|
||||||
"tags": [
|
"tags": [
|
||||||
"trigger.dev",
|
"trigger.dev",
|
||||||
"background jobs",
|
"background jobs",
|
||||||
@@ -487,7 +500,7 @@
|
|||||||
"umami": {
|
"umami": {
|
||||||
"documentation": "https:\/\/umami.is\/docs\/getting-started",
|
"documentation": "https:\/\/umami.is\/docs\/getting-started",
|
||||||
"slogan": "Umami is a lightweight, self-hosted web analytics platform designed to provide website owners with insights into visitor behavior without compromising user privacy.",
|
"slogan": "Umami is a lightweight, self-hosted web analytics platform designed to provide website owners with insights into visitor behavior without compromising user privacy.",
|
||||||
"compose": "c2VydmljZXM6CiAgdW1hbWk6CiAgICBpbWFnZTogJ2doY3IuaW8vdW1hbWktc29mdHdhcmUvdW1hbWk6cG9zdGdyZXNxbC1sYXRlc3QnCiAgICBlbnZpcm9ubWVudDoKICAgICAgLSBTRVJWSUNFX0ZRRE5fVU1BTUkKICAgICAgLSAnREFUQUJBU0VfVVJMPXBvc3RncmVzOi8vJFNFUlZJQ0VfVVNFUl9QT1NUR1JFUzokU0VSVklDRV9QQVNTV09SRF9QT1NUR1JFU0Bwb3N0Z3Jlc3FsOjU0MzIvJFBPU1RHUkVTX0RCJwogICAgICAtIERBVEFCQVNFX1RZUEU9cG9zdGdyZXMKICAgICAgLSBBUFBfU0VDUkVUPSRTRVJWSUNFX1BBU1NXT1JEXzY0X1VNQU1JCiAgICBkZXBlbmRzX29uOgogICAgICBwb3N0Z3Jlc3FsOgogICAgICAgIGNvbmRpdGlvbjogc2VydmljZV9oZWFsdGh5CiAgcG9zdGdyZXNxbDoKICAgIGltYWdlOiAncG9zdGdyZXM6MTUtYWxwaW5lJwogICAgdm9sdW1lczoKICAgICAgLSAncG9zdGdyZXNxbC1kYXRhOi92YXIvbGliL3Bvc3RncmVzcWwvZGF0YScKICAgIGVudmlyb25tZW50OgogICAgICAtIFBPU1RHUkVTX1VTRVI9JFNFUlZJQ0VfVVNFUl9QT1NUR1JFUwogICAgICAtIFBPU1RHUkVTX1BBU1NXT1JEPSRTRVJWSUNFX1BBU1NXT1JEX1BPU1RHUkVTCiAgICAgIC0gJ1BPU1RHUkVTX0RCPSR7UE9TVEdSRVNfREI6LXVtYW1pfScKICAgIGhlYWx0aGNoZWNrOgogICAgICB0ZXN0OgogICAgICAgIC0gQ01ELVNIRUxMCiAgICAgICAgLSAncGdfaXNyZWFkeSAtVSAkJHtQT1NUR1JFU19VU0VSfSAtZCAkJHtQT1NUR1JFU19EQn0nCiAgICAgIGludGVydmFsOiA1cwogICAgICB0aW1lb3V0OiAyMHMKICAgICAgcmV0cmllczogMTAK",
|
"compose": "c2VydmljZXM6CiAgdW1hbWk6CiAgICBpbWFnZTogJ2doY3IuaW8vdW1hbWktc29mdHdhcmUvdW1hbWk6cG9zdGdyZXNxbC1sYXRlc3QnCiAgICBlbnZpcm9ubWVudDoKICAgICAgLSBTRVJWSUNFX0ZRRE5fVU1BTUkKICAgICAgLSAnREFUQUJBU0VfVVJMPXBvc3RncmVzOi8vJFNFUlZJQ0VfVVNFUl9QT1NUR1JFUzokU0VSVklDRV9QQVNTV09SRF9QT1NUR1JFU0Bwb3N0Z3Jlc3FsOjU0MzIvJFBPU1RHUkVTX0RCJwogICAgICAtIERBVEFCQVNFX1RZUEU9cG9zdGdyZXMKICAgICAgLSBBUFBfU0VDUkVUPSRTRVJWSUNFX1BBU1NXT1JEXzY0X1VNQU1JCiAgICBkZXBlbmRzX29uOgogICAgICBwb3N0Z3Jlc3FsOgogICAgICAgIGNvbmRpdGlvbjogc2VydmljZV9oZWFsdGh5CiAgcG9zdGdyZXNxbDoKICAgIGltYWdlOiAncG9zdGdyZXM6MTYtYWxwaW5lJwogICAgdm9sdW1lczoKICAgICAgLSAncG9zdGdyZXNxbC1kYXRhOi92YXIvbGliL3Bvc3RncmVzcWwvZGF0YScKICAgIGVudmlyb25tZW50OgogICAgICAtIFBPU1RHUkVTX1VTRVI9JFNFUlZJQ0VfVVNFUl9QT1NUR1JFUwogICAgICAtIFBPU1RHUkVTX1BBU1NXT1JEPSRTRVJWSUNFX1BBU1NXT1JEX1BPU1RHUkVTCiAgICAgIC0gJ1BPU1RHUkVTX0RCPSR7UE9TVEdSRVNfREI6LXVtYW1pfScKICAgIGhlYWx0aGNoZWNrOgogICAgICB0ZXN0OgogICAgICAgIC0gQ01ELVNIRUxMCiAgICAgICAgLSAncGdfaXNyZWFkeSAtVSAkJHtQT1NUR1JFU19VU0VSfSAtZCAkJHtQT1NUR1JFU19EQn0nCiAgICAgIGludGVydmFsOiA1cwogICAgICB0aW1lb3V0OiAyMHMKICAgICAgcmV0cmllczogMTAK",
|
||||||
"tags": [
|
"tags": [
|
||||||
"analytics",
|
"analytics",
|
||||||
"insights",
|
"insights",
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
"version": "3.12.36"
|
"version": "3.12.36"
|
||||||
},
|
},
|
||||||
"v4": {
|
"v4": {
|
||||||
"version": "4.0.0-beta.148"
|
"version": "4.0.0-beta.152"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user