Merge pull request #3783 from coollabsio/next

v4.0.0-beta.357
This commit is contained in:
Andras Bacsai
2024-10-10 15:26:05 +02:00
committed by GitHub
82 changed files with 4346 additions and 150 deletions

View File

@@ -22,3 +22,4 @@ yarn-error.log
/_data
.rnd
/.ssh
.ignition.json

1
.gitignore vendored
View File

@@ -32,3 +32,4 @@ _ide_helper_models.php
.rnd
/.ssh
scripts/load-test/*
.ignition.json

View File

@@ -0,0 +1,17 @@
<?php
namespace App\Actions\Application;
use App\Models\Application;
use Lorisleiva\Actions\Concerns\AsAction;
class GenerateConfig
{
use AsAction;
public function handle(Application $application, bool $is_json = false)
{
ray()->clearAll();
return $application->generateConfig(is_json: $is_json);
}
}

View File

@@ -39,8 +39,8 @@ class ServicesGenerate extends Command
$serviceTemplatesJson[$name] = $parsed;
}
}
$serviceTemplatesJson = json_encode($serviceTemplatesJson);
file_put_contents(base_path('templates/service-templates.json'), $serviceTemplatesJson);
$serviceTemplatesJson = json_encode($serviceTemplatesJson, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
file_put_contents(base_path('templates/service-templates.json'), $serviceTemplatesJson.PHP_EOL);
}
private function process_file($file)

View File

@@ -0,0 +1,8 @@
<?php
namespace App\Enums;
enum StaticImageTypes: string
{
case NGINX_ALPINE = 'nginx:alpine';
}

View File

@@ -132,6 +132,7 @@ class ApplicationsController extends Controller
'docker_registry_image_name' => ['type' => 'string', 'description' => 'The docker registry image name.'],
'docker_registry_image_tag' => ['type' => 'string', 'description' => 'The docker registry image tag.'],
'is_static' => ['type' => 'boolean', 'description' => 'The flag to indicate if the application is static.'],
'static_image' => ['type' => 'string', 'enum' => ['nginx:alpine'], 'description' => 'The static image.'],
'install_command' => ['type' => 'string', 'description' => 'The install command.'],
'build_command' => ['type' => 'string', 'description' => 'The build command.'],
'start_command' => ['type' => 'string', 'description' => 'The start command.'],
@@ -236,6 +237,7 @@ class ApplicationsController extends Controller
'docker_registry_image_name' => ['type' => 'string', 'description' => 'The docker registry image name.'],
'docker_registry_image_tag' => ['type' => 'string', 'description' => 'The docker registry image tag.'],
'is_static' => ['type' => 'boolean', 'description' => 'The flag to indicate if the application is static.'],
'static_image' => ['type' => 'string', 'enum' => ['nginx:alpine'], 'description' => 'The static image.'],
'install_command' => ['type' => 'string', 'description' => 'The install command.'],
'build_command' => ['type' => 'string', 'description' => 'The build command.'],
'start_command' => ['type' => 'string', 'description' => 'The start command.'],
@@ -339,6 +341,7 @@ class ApplicationsController extends Controller
'docker_registry_image_name' => ['type' => 'string', 'description' => 'The docker registry image name.'],
'docker_registry_image_tag' => ['type' => 'string', 'description' => 'The docker registry image tag.'],
'is_static' => ['type' => 'boolean', 'description' => 'The flag to indicate if the application is static.'],
'static_image' => ['type' => 'string', 'enum' => ['nginx:alpine'], 'description' => 'The static image.'],
'install_command' => ['type' => 'string', 'description' => 'The install command.'],
'build_command' => ['type' => 'string', 'description' => 'The build command.'],
'start_command' => ['type' => 'string', 'description' => 'The start command.'],
@@ -633,7 +636,7 @@ class ApplicationsController extends Controller
private function create_application(Request $request, $type)
{
$allowedFields = ['project_uuid', 'environment_name', 'server_uuid', 'destination_uuid', 'type', 'name', 'description', 'is_static', 'domains', 'git_repository', 'git_branch', 'git_commit_sha', 'private_key_uuid', 'docker_registry_image_name', 'docker_registry_image_tag', 'build_pack', 'install_command', 'build_command', 'start_command', 'ports_exposes', 'ports_mappings', 'base_directory', 'publish_directory', 'health_check_enabled', 'health_check_path', 'health_check_port', 'health_check_host', 'health_check_method', 'health_check_return_code', 'health_check_scheme', 'health_check_response_text', 'health_check_interval', 'health_check_timeout', 'health_check_retries', 'health_check_start_period', 'limits_memory', 'limits_memory_swap', 'limits_memory_swappiness', 'limits_memory_reservation', 'limits_cpus', 'limits_cpuset', 'limits_cpu_shares', 'custom_labels', 'custom_docker_run_options', 'post_deployment_command', 'post_deployment_command_container', 'pre_deployment_command', 'pre_deployment_command_container', 'manual_webhook_secret_github', 'manual_webhook_secret_gitlab', 'manual_webhook_secret_bitbucket', 'manual_webhook_secret_gitea', 'redirect', 'github_app_uuid', 'instant_deploy', 'dockerfile', 'docker_compose_location', 'docker_compose_raw', 'docker_compose_custom_start_command', 'docker_compose_custom_build_command', 'docker_compose_domains', 'watch_paths', 'use_build_server'];
$allowedFields = ['project_uuid', 'environment_name', 'server_uuid', 'destination_uuid', 'type', 'name', 'description', 'is_static', 'domains', 'git_repository', 'git_branch', 'git_commit_sha', 'private_key_uuid', 'docker_registry_image_name', 'docker_registry_image_tag', 'build_pack', 'install_command', 'build_command', 'start_command', 'ports_exposes', 'ports_mappings', 'base_directory', 'publish_directory', 'health_check_enabled', 'health_check_path', 'health_check_port', 'health_check_host', 'health_check_method', 'health_check_return_code', 'health_check_scheme', 'health_check_response_text', 'health_check_interval', 'health_check_timeout', 'health_check_retries', 'health_check_start_period', 'limits_memory', 'limits_memory_swap', 'limits_memory_swappiness', 'limits_memory_reservation', 'limits_cpus', 'limits_cpuset', 'limits_cpu_shares', 'custom_labels', 'custom_docker_run_options', 'post_deployment_command', 'post_deployment_command_container', 'pre_deployment_command', 'pre_deployment_command_container', 'manual_webhook_secret_github', 'manual_webhook_secret_gitlab', 'manual_webhook_secret_bitbucket', 'manual_webhook_secret_gitea', 'redirect', 'github_app_uuid', 'instant_deploy', 'dockerfile', 'docker_compose_location', 'docker_compose_raw', 'docker_compose_custom_start_command', 'docker_compose_custom_build_command', 'docker_compose_domains', 'watch_paths', 'use_build_server', 'static_image'];
$teamId = getTeamIdFromToken();
if (is_null($teamId)) {
return invalidTokenResponse();
@@ -672,6 +675,7 @@ class ApplicationsController extends Controller
$instantDeploy = $request->instant_deploy;
$githubAppUuid = $request->github_app_uuid;
$useBuildServer = $request->use_build_server;
$isStatic = $request->is_static;
$project = Project::whereTeamId($teamId)->whereUuid($request->project_uuid)->first();
if (! $project) {
@@ -700,8 +704,7 @@ class ApplicationsController extends Controller
if ($request->build_pack === 'dockercompose') {
$request->offsetSet('ports_exposes', '80');
}
$validator = customApiValidator($request->all(), [
sharedDataApplications(),
$validationRules = [
'git_repository' => 'string|required',
'git_branch' => 'string|required',
'build_pack' => ['required', Rule::enum(BuildPackTypes::class)],
@@ -709,19 +712,21 @@ class ApplicationsController extends Controller
'docker_compose_location' => 'string',
'docker_compose_raw' => 'string|nullable',
'docker_compose_domains' => 'array|nullable',
'docker_compose_custom_start_command' => 'string|nullable',
'docker_compose_custom_build_command' => 'string|nullable',
]);
];
$validationRules = array_merge($validationRules, sharedDataApplications());
$validator = customApiValidator($request->all(), $validationRules);
if ($validator->fails()) {
return response()->json([
'message' => 'Validation failed.',
'errors' => $validator->errors(),
], 422);
}
$return = $this->validateDataApplications($request, $server);
if ($return instanceof \Illuminate\Http\JsonResponse) {
return $return;
}
$application = new Application;
removeUnnecessaryFieldsFromRequest($request);
@@ -744,11 +749,15 @@ class ApplicationsController extends Controller
$application->destination_id = $destination->id;
$application->destination_type = $destination->getMorphClass();
$application->environment_id = $environment->id;
$application->save();
if (isset($isStatic)) {
$application->settings->is_static = $isStatic;
$application->settings->save();
}
if (isset($useBuildServer)) {
$application->settings->is_build_server_enabled = $useBuildServer;
$application->settings->save();
}
$application->save();
$application->refresh();
if (! $application->settings->is_container_label_readonly_enabled) {
$application->custom_labels = str(implode('|coolify|', generateLabelsApplication($application)))->replace('|coolify|', "\n");
@@ -782,8 +791,7 @@ class ApplicationsController extends Controller
if ($request->build_pack === 'dockercompose') {
$request->offsetSet('ports_exposes', '80');
}
$validator = customApiValidator($request->all(), [
sharedDataApplications(),
$validationRules = [
'git_repository' => 'string|required',
'git_branch' => 'string|required',
'build_pack' => ['required', Rule::enum(BuildPackTypes::class)],
@@ -792,10 +800,10 @@ class ApplicationsController extends Controller
'watch_paths' => 'string|nullable',
'docker_compose_location' => 'string',
'docker_compose_raw' => 'string|nullable',
'docker_compose_domains' => 'array|nullable',
'docker_compose_custom_start_command' => 'string|nullable',
'docker_compose_custom_build_command' => 'string|nullable',
]);
];
$validationRules = array_merge($validationRules, sharedDataApplications());
$validator = customApiValidator($request->all(), $validationRules);
if ($validator->fails()) {
return response()->json([
'message' => 'Validation failed.',
@@ -882,8 +890,8 @@ class ApplicationsController extends Controller
if ($request->build_pack === 'dockercompose') {
$request->offsetSet('ports_exposes', '80');
}
$validator = customApiValidator($request->all(), [
sharedDataApplications(),
$validationRules = [
'git_repository' => 'string|required',
'git_branch' => 'string|required',
'build_pack' => ['required', Rule::enum(BuildPackTypes::class)],
@@ -892,10 +900,10 @@ class ApplicationsController extends Controller
'watch_paths' => 'string|nullable',
'docker_compose_location' => 'string',
'docker_compose_raw' => 'string|nullable',
'docker_compose_domains' => 'array|nullable',
'docker_compose_custom_start_command' => 'string|nullable',
'docker_compose_custom_build_command' => 'string|nullable',
]);
];
$validationRules = array_merge($validationRules, sharedDataApplications());
$validator = customApiValidator($request->all(), $validationRules);
if ($validator->fails()) {
return response()->json([
@@ -975,10 +983,13 @@ class ApplicationsController extends Controller
if (! $request->has('name')) {
$request->offsetSet('name', 'dockerfile-'.new Cuid2);
}
$validator = customApiValidator($request->all(), [
sharedDataApplications(),
$validationRules = [
'dockerfile' => 'string|required',
]);
];
$validationRules = array_merge($validationRules, sharedDataApplications());
$validator = customApiValidator($request->all(), $validationRules);
if ($validator->fails()) {
return response()->json([
'message' => 'Validation failed.',
@@ -1057,12 +1068,14 @@ class ApplicationsController extends Controller
if (! $request->has('name')) {
$request->offsetSet('name', 'docker-image-'.new Cuid2);
}
$validator = customApiValidator($request->all(), [
sharedDataApplications(),
$validationRules = [
'docker_registry_image_name' => 'string|required',
'docker_registry_image_tag' => 'string',
'ports_exposes' => 'string|regex:/^(\d+)(,\d+)*$/|required',
]);
];
$validationRules = array_merge($validationRules, sharedDataApplications());
$validator = customApiValidator($request->all(), $validationRules);
if ($validator->fails()) {
return response()->json([
'message' => 'Validation failed.',
@@ -1135,10 +1148,12 @@ class ApplicationsController extends Controller
if (! $request->has('name')) {
$request->offsetSet('name', 'service'.new Cuid2);
}
$validator = customApiValidator($request->all(), [
sharedDataApplications(),
$validationRules = [
'docker_compose_raw' => 'string|required',
]);
];
$validationRules = array_merge($validationRules, sharedDataApplications());
$validator = customApiValidator($request->all(), $validationRules);
if ($validator->fails()) {
return response()->json([
'message' => 'Validation failed.',
@@ -1488,8 +1503,7 @@ class ApplicationsController extends Controller
$server = $application->destination->server;
$allowedFields = ['name', 'description', 'is_static', 'domains', 'git_repository', 'git_branch', 'git_commit_sha', 'docker_registry_image_name', 'docker_registry_image_tag', 'build_pack', 'static_image', 'install_command', 'build_command', 'start_command', 'ports_exposes', 'ports_mappings', 'base_directory', 'publish_directory', 'health_check_enabled', 'health_check_path', 'health_check_port', 'health_check_host', 'health_check_method', 'health_check_return_code', 'health_check_scheme', 'health_check_response_text', 'health_check_interval', 'health_check_timeout', 'health_check_retries', 'health_check_start_period', 'limits_memory', 'limits_memory_swap', 'limits_memory_swappiness', 'limits_memory_reservation', 'limits_cpus', 'limits_cpuset', 'limits_cpu_shares', 'custom_labels', 'custom_docker_run_options', 'post_deployment_command', 'post_deployment_command_container', 'pre_deployment_command', 'pre_deployment_command_container', 'watch_paths', 'manual_webhook_secret_github', 'manual_webhook_secret_gitlab', 'manual_webhook_secret_bitbucket', 'manual_webhook_secret_gitea', 'docker_compose_location', 'docker_compose_raw', 'docker_compose_custom_start_command', 'docker_compose_custom_build_command', 'docker_compose_domains', 'redirect', 'instant_deploy', 'use_build_server'];
$validator = customApiValidator($request->all(), [
sharedDataApplications(),
$validationRules = [
'name' => 'string|max:255',
'description' => 'string|nullable',
'static_image' => 'string',
@@ -1499,7 +1513,9 @@ class ApplicationsController extends Controller
'docker_compose_domains' => 'array|nullable',
'docker_compose_custom_start_command' => 'string|nullable',
'docker_compose_custom_build_command' => 'string|nullable',
]);
];
$validationRules = array_merge($validationRules, sharedDataApplications());
$validator = customApiValidator($request->all(), $validationRules);
// Validate ports_exposes
if ($request->has('ports_exposes')) {

View File

@@ -2,6 +2,7 @@
namespace App\Livewire\Project\Application;
use App\Actions\Application\GenerateConfig;
use App\Models\Application;
use Illuminate\Support\Collection;
use Livewire\Component;
@@ -243,12 +244,19 @@ class General extends Component
public function updatedApplicationFqdn()
{
$this->application->fqdn = str($this->application->fqdn)->replaceEnd(',', '')->trim();
$this->application->fqdn = str($this->application->fqdn)->replaceStart(',', '')->trim();
$this->application->fqdn = str($this->application->fqdn)->trim()->explode(',')->map(function ($domain) {
return str($domain)->trim()->lower();
});
$this->application->fqdn = $this->application->fqdn->unique()->implode(',');
try {
$this->application->fqdn = str($this->application->fqdn)->replaceEnd(',', '')->trim();
$this->application->fqdn = str($this->application->fqdn)->replaceStart(',', '')->trim();
$this->application->fqdn = str($this->application->fqdn)->trim()->explode(',')->map(function ($domain) {
return str($domain)->trim()->lower();
});
$this->application->fqdn = $this->application->fqdn->unique()->implode(',');
$this->application->save();
} catch (\Throwable $e) {
$originalFqdn = $this->application->getOriginal('fqdn');
$this->application->fqdn = $originalFqdn;
return handleError($e, $this);
}
$this->resetDefaultLabels();
}
@@ -287,18 +295,22 @@ class General extends Component
public function resetDefaultLabels()
{
if ($this->application->settings->is_container_label_readonly_enabled) {
return;
try {
if ($this->application->settings->is_container_label_readonly_enabled) {
return;
}
$this->customLabels = str(implode('|coolify|', generateLabelsApplication($this->application)))->replace('|coolify|', "\n");
$this->ports_exposes = $this->application->ports_exposes;
$this->is_container_label_escape_enabled = $this->application->settings->is_container_label_escape_enabled;
$this->application->custom_labels = base64_encode($this->customLabels);
$this->application->save();
if ($this->application->build_pack === 'dockercompose') {
$this->loadComposeFile();
}
$this->dispatch('configurationChanged');
} catch (\Throwable $e) {
return handleError($e, $this);
}
$this->customLabels = str(implode('|coolify|', generateLabelsApplication($this->application)))->replace('|coolify|', "\n");
$this->ports_exposes = $this->application->ports_exposes;
$this->is_container_label_escape_enabled = $this->application->settings->is_container_label_escape_enabled;
$this->application->custom_labels = base64_encode($this->customLabels);
$this->application->save();
if ($this->application->build_pack === 'dockercompose') {
$this->loadComposeFile();
}
$this->dispatch('configurationChanged');
}
public function checkFqdns($showToaster = true)
@@ -413,4 +425,16 @@ class General extends Component
$this->dispatch('configurationChanged');
}
}
public function downloadConfig()
{
$config = GenerateConfig::run($this->application, true);
$fileName = str($this->application->name)->slug()->append('_config.json');
return response()->streamDownload(function () use ($config) {
echo $config;
}, $fileName, [
'Content-Type' => 'application/json',
'Content-Disposition' => 'attachment; filename=' . $fileName,
]);
}
}

View File

@@ -31,10 +31,12 @@ class PublicGitRepository extends Component
public bool $isStatic = false;
public bool $checkCoolifyConfig = true;
public ?string $publish_directory = null;
// In case of docker compose
public ?string $base_directory = null;
public string $base_directory = '/';
public ?string $docker_compose_location = '/docker-compose.yaml';
// End of docker compose
@@ -97,6 +99,7 @@ class PublicGitRepository extends Component
$this->base_directory = '/'.$this->base_directory;
}
}
}
public function updatedDockerComposeLocation()
@@ -275,6 +278,7 @@ class PublicGitRepository extends Component
'destination_id' => $destination->id,
'destination_type' => $destination_class,
'build_pack' => $this->build_pack,
'base_directory' => $this->base_directory,
];
} else {
$application_init = [
@@ -289,6 +293,7 @@ class PublicGitRepository extends Component
'source_id' => $this->git_source->id,
'source_type' => $this->git_source->getMorphClass(),
'build_pack' => $this->build_pack,
'base_directory' => $this->base_directory,
];
}
@@ -303,11 +308,15 @@ class PublicGitRepository extends Component
$application->settings->is_static = $this->isStatic;
$application->settings->save();
$fqdn = generateFqdn($destination->server, $application->uuid);
$application->fqdn = $fqdn;
$application->save();
if ($this->checkCoolifyConfig) {
// $config = loadConfigFromGit($this->repository_url, $this->git_branch, $this->base_directory, $this->query['server_id'], auth()->user()->currentTeam()->id);
// if ($config) {
// $application->setConfig($config);
// }
}
return redirect()->route('project.application.configuration', [
'application_uuid' => $application->uuid,
'environment_name' => $environment->name,

File diff suppressed because one or more lines are too long

View File

@@ -23,13 +23,17 @@ class EditDomain extends Component
public function updatedApplicationFqdn()
{
$this->application->fqdn = str($this->application->fqdn)->replaceEnd(',', '')->trim();
$this->application->fqdn = str($this->application->fqdn)->replaceStart(',', '')->trim();
$this->application->fqdn = str($this->application->fqdn)->trim()->explode(',')->map(function ($domain) {
return str($domain)->trim()->lower();
});
$this->application->fqdn = $this->application->fqdn->unique()->implode(',');
$this->application->save();
try {
$this->application->fqdn = str($this->application->fqdn)->replaceEnd(',', '')->trim();
$this->application->fqdn = str($this->application->fqdn)->replaceStart(',', '')->trim();
$this->application->fqdn = str($this->application->fqdn)->trim()->explode(',')->map(function ($domain) {
return str($domain)->trim()->lower();
});
$this->application->fqdn = $this->application->fqdn->unique()->implode(',');
$this->application->save();
} catch(\Throwable $e) {
return handleError($e, $this);
}
}
public function submit()

View File

@@ -34,6 +34,7 @@ class StackForm extends Component
$value = data_get($field, 'value');
$rules = data_get($field, 'rules', 'nullable');
$isPassword = data_get($field, 'isPassword', false);
$customHelper = data_get($field, 'customHelper', false);
$this->fields->put($key, [
'serviceName' => $serviceName,
'key' => $key,
@@ -41,6 +42,7 @@ class StackForm extends Component
'value' => $value,
'isPassword' => $isPassword,
'rules' => $rules,
'customHelper' => $customHelper,
]);
$this->rules["fields.$key.value"] = $rules;

View File

@@ -0,0 +1,41 @@
<?php
namespace App\Livewire\Project\Shared;
use App\Models\Application;
use Livewire\Component;
class UploadConfig extends Component
{
public $config;
public $applicationId;
public function mount() {
if (isDev()) {
$this->config = '{
"build_pack": "nixpacks",
"base_directory": "/nodejs",
"publish_directory": "/",
"ports_exposes": "3000",
"settings": {
"is_static": false
}
}';
}
}
public function uploadConfig()
{
try {
$application = Application::findOrFail($this->applicationId);
$application->setConfig($this->config);
$this->dispatch('success', 'Application settings updated');
} catch (\Exception $e) {
$this->dispatch('error', $e->getMessage());
return;
}
}
public function render()
{
return view('livewire.project.shared.upload-config');
}
}

View File

@@ -9,6 +9,7 @@ use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Process\InvokedProcess;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Process;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Str;
use OpenApi\Attributes as OA;
use RuntimeException;
@@ -1427,4 +1428,67 @@ class Application extends BaseModel
return $parsedCollection->toArray();
}
}
public function generateConfig($is_json = false)
{
$config = collect([]);
if ($this->build_pack = 'nixpacks') {
$config = collect([
'build_pack' => 'nixpacks',
'docker_registry_image_name' => $this->docker_registry_image_name,
'docker_registry_image_tag' => $this->docker_registry_image_tag,
'install_command' => $this->install_command,
'build_command' => $this->build_command,
'start_command' => $this->start_command,
'base_directory' => $this->base_directory,
'publish_directory' => $this->publish_directory,
'custom_docker_run_options' => $this->custom_docker_run_options,
'ports_exposes' => $this->ports_exposes,
'ports_mappings' => $this->ports_mapping,
'settings' => collect([
'is_static' => $this->settings->is_static,
]),
]);
}
$config = $config->filter(function ($value) {
return str($value)->isNotEmpty();
});
if ($is_json) {
return json_encode($config, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
}
return $config;
}
public function setConfig($config) {
$config = $config;
$validator = Validator::make(['config' => $config], [
'config' => 'required|json',
]);
if ($validator->fails()) {
throw new \Exception('Invalid JSON format');
}
$config = json_decode($config, true);
$deepValidator = Validator::make(['config' => $config], [
'config.build_pack' => 'required|string',
'config.base_directory' => 'required|string',
'config.publish_directory' => 'required|string',
'config.ports_exposes' => 'required|string',
'config.settings.is_static' => 'required|boolean',
]);
if ($deepValidator->fails()) {
throw new \Exception('Invalid data');
}
$config = $deepValidator->validated()['config'];
try {
$settings = data_get($config, 'settings', []);
data_forget($config, 'settings');
$this->update($config);
$this->settings()->update($settings);
} catch (\Exception $e) {
throw new \Exception('Failed to update application settings');
}
}
}

View File

@@ -39,13 +39,19 @@ class ScheduledDatabaseBackup extends BaseModel
public function server()
{
if ($this->database) {
if ($this->database->destination && $this->database->destination->server) {
$server = $this->database->destination->server;
if ($this->database instanceof ServiceDatabase) {
$destination = data_get($this->database->service, 'destination');
$server = data_get($destination, 'server');
} else {
$destination = data_get($this->database, 'destination');
$server = data_get($destination, 'server');
}
if ($server) {
return $server;
}
}
return null;
}
}

View File

@@ -288,6 +288,21 @@ class Service extends BaseModel
continue;
}
switch ($image) {
case $image->contains('castopod'):
$data = collect([]);
$disable_https = $this->environment_variables()->where('key', 'CP_DISABLE_HTTPS')->first();
if ($disable_https) {
$data = $data->merge([
'Disable HTTPS' => [
'key' => 'CP_DISABLE_HTTPS',
'value' => data_get($disable_https, 'value'),
'rules' => 'required',
'customHelper' => "If you want to use https, set this to 0. Variable name: CP_DISABLE_HTTPS",
],
]);
}
$fields->put('Castopod', $data->toArray());
break;
case $image->contains('label-studio'):
$data = collect([]);
$username = $this->environment_variables()->where('key', 'LABEL_STUDIO_USERNAME')->first();
@@ -982,8 +997,8 @@ class Service extends BaseModel
break;
case $image->contains('mysql'):
$userVariables = ['SERVICE_USER_MYSQL', 'SERVICE_USER_WORDPRESS', 'MYSQL_USER'];
$passwordVariables = ['SERVICE_PASSWORD_MYSQL', 'SERVICE_PASSWORD_WORDPRESS', 'MYSQL_PASSWORD'];
$rootPasswordVariables = ['SERVICE_PASSWORD_MYSQLROOT', 'SERVICE_PASSWORD_ROOT'];
$passwordVariables = ['SERVICE_PASSWORD_MYSQL', 'SERVICE_PASSWORD_WORDPRESS', 'MYSQL_PASSWORD','SERVICE_PASSWORD_64_MYSQL'];
$rootPasswordVariables = ['SERVICE_PASSWORD_MYSQLROOT', 'SERVICE_PASSWORD_ROOT','SERVICE_PASSWORD_64_MYSQLROOT'];
$dbNameVariables = ['MYSQL_DATABASE'];
$mysql_user = $this->environment_variables()->whereIn('key', $userVariables)->first();
$mysql_password = $this->environment_variables()->whereIn('key', $passwordVariables)->first();
@@ -1093,6 +1108,7 @@ class Service extends BaseModel
foreach ($fields as $field) {
$key = data_get($field, 'key');
$value = data_get($field, 'value');
ray($key, $value);
$found = $this->environment_variables()->where('key', $key)->first();
if ($found) {
$found->value = $value;

View File

@@ -2,6 +2,7 @@
use App\Enums\BuildPackTypes;
use App\Enums\RedirectTypes;
use App\Enums\StaticImageTypes;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Http\Request;
use Illuminate\Validation\Rule;
@@ -89,6 +90,7 @@ function sharedDataApplications()
'git_branch' => 'string',
'build_pack' => Rule::enum(BuildPackTypes::class),
'is_static' => 'boolean',
'static_image' => Rule::enum(StaticImageTypes::class),
'domains' => 'string',
'redirect' => Rule::enum(RedirectTypes::class),
'git_commit_sha' => 'string',
@@ -176,4 +178,5 @@ function removeUnnecessaryFieldsFromRequest(Request $request)
$request->offsetUnset('github_app_uuid');
$request->offsetUnset('private_key_uuid');
$request->offsetUnset('use_build_server');
$request->offsetUnset('is_static');
}

View File

@@ -40,6 +40,7 @@ const DATABASE_DOCKER_IMAGES = [
];
const SPECIFIC_SERVICES = [
'quay.io/minio/minio',
'minio/minio',
'svhd/logto',
];

View File

@@ -332,8 +332,12 @@ function fqdnLabelsForTraefik(string $uuid, Collection $domains, bool $is_force_
if (preg_match('/traefik\.http\.middlewares\.(.*?)(\.|$)/', $item, $matches)) {
return $matches[1];
}
if (preg_match('/coolify\.traefik\.middlewares=(.*)/', $item, $matches)) {
return explode(',', $matches[1]);
}
return null;
})->filter()
})->flatten()
->filter()
->unique();
}
foreach ($domains as $loop => $domain) {

View File

@@ -1174,10 +1174,10 @@ function check_domain_usage(ServiceApplication|Application|null $resource = null
if ($domains->contains($naked_domain)) {
if (data_get($resource, 'uuid')) {
if ($resource->uuid !== $app->uuid) {
throw new \RuntimeException("Domain $naked_domain is already in use by another resource called: <br><br>{$app->name}.");
throw new \RuntimeException("Domain $naked_domain is already in use by another resource: <br><br>Link: <a class='underline' target='_blank' href='{$app->link()}'>{$app->name}</a>");
}
} elseif ($domain) {
throw new \RuntimeException("Domain $naked_domain is already in use by another resource called: <br><br>{$app->name}.");
throw new \RuntimeException("Domain $naked_domain is already in use by another resource: <br><br>Link: <a class='underline' target='_blank' href='{$app->link()}'>{$app->name}</a>");
}
}
}
@@ -1193,10 +1193,10 @@ function check_domain_usage(ServiceApplication|Application|null $resource = null
if ($domains->contains($naked_domain)) {
if (data_get($resource, 'uuid')) {
if ($resource->uuid !== $app->uuid) {
throw new \RuntimeException("Domain $naked_domain is already in use by another resource called: <br><br>{$app->name}.");
throw new \RuntimeException("Domain $naked_domain is already in use by another resource: <br><br>Link: <a class='underline' target='_blank' href='{$app->service->link()}'>{$app->service->name}</a>");
}
} elseif ($domain) {
throw new \RuntimeException("Domain $naked_domain is already in use by another resource called: <br><br>{$app->name}.");
throw new \RuntimeException("Domain $naked_domain is already in use by another resource: <br><br>Link: <a class='underline' target='_blank' href='{$app->service->link()}'>{$app->service->name}</a>");
}
}
}
@@ -3181,6 +3181,7 @@ function newParser(Application|Service $resource, int $pull_request_id = 0, ?int
} elseif ($isService) {
$fqdn = generateFqdn($server, "$fqdnFor-$uuid");
}
$fqdn = str($fqdn)->replace('http://', '')->replace('https://', '');
$resource->environment_variables()->where('key', $key->value())->where($nameOfId, $resource->id)->firstOrCreate([
'key' => $key->value(),
$nameOfId => $resource->id,
@@ -3981,3 +3982,31 @@ function instanceSettings()
{
return InstanceSettings::get();
}
function loadConfigFromGit(string $repository, string $branch, string $base_directory, int $server_id, int $team_id) {
$server = Server::find($server_id)->where('team_id', $team_id)->first();
if (!$server) {
return;
}
$uuid = new Cuid2();
$cloneCommand = "git clone --no-checkout -b $branch $repository .";
$workdir = rtrim($base_directory, '/');
$fileList = collect([".$workdir/coolify.json"]);
$commands = collect([
"rm -rf /tmp/{$uuid}",
"mkdir -p /tmp/{$uuid}",
"cd /tmp/{$uuid}",
$cloneCommand,
'git sparse-checkout init --cone',
"git sparse-checkout set {$fileList->implode(' ')}",
'git read-tree -mu HEAD',
"cat .$workdir/coolify.json",
'rm -rf /tmp/{$uuid}',
]);
try {
return instant_remote_process($commands, $server);
} catch (\Exception $e) {
// continue
}
}

View File

@@ -7,7 +7,8 @@ return [
// The release version of your application
// Example with dynamic git hash: trim(exec('git --git-dir ' . base_path('.git') . ' log --pretty="%h" -n1 HEAD'))
'release' => '4.0.0-beta.357',
'release' => '4.0.0-beta.358',
// When left empty or `null` the Laravel environment will be used
'environment' => config('app.env'),

View File

@@ -1,3 +1,4 @@
<?php
return '4.0.0-beta.357';
return '4.0.0-beta.358';

View File

@@ -0,0 +1,34 @@
<?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('service_applications', function (Blueprint $table) {
$table->dropUnique(['fqdn']);
});
Schema::table('applications', function (Blueprint $table) {
$table->dropUnique(['fqdn']);
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('service_applications', function (Blueprint $table) {
$table->unique('fqdn');
});
Schema::table('applications', function (Blueprint $table) {
$table->unique('fqdn');
});
}
};

View File

@@ -14,7 +14,7 @@
"auth.register": "S'enregistrer",
"auth.registration_disabled": "L'enregistrement est désactivé. Merci de contacter l'administateur.",
"auth.reset_password": "Réinitialiser le mot de passe",
"auth.failed": "Aucune correspondance n'a été trouvé pour les informations d'identification renseignées.",
"auth.failed": "Aucune correspondance n'a été trouvée pour les informations d'identification renseignées.",
"auth.failed.callback": "Erreur lors du processus de retour de la plateforme de connexion.",
"auth.failed.password": "Le mot de passe renseigné est incorrect.",
"auth.failed.email": "Aucun utilisateur avec cette adresse email n'a été trouvé.",

View File

@@ -0,0 +1,25 @@
<svg version="1.1" id="prefix__Layer_1" xmlns="http://www.w3.org/2000/svg" x="0" y="0" viewBox="0 0 1235.7 1235.4"
xml:space="preserve">
<style>
.prefix__st0 {
fill: #fff
}
</style>
<g id="prefix__Layer_2_1_">
<g id="prefix__Layer_2-2">
<g id="prefix__Layer_4">
<circle class="prefix__st0" cx="618.6" cy="618.6" r="618.6" id="prefix__Layer_5" />
<linearGradient id="prefix__SVGID_1_" gradientUnits="userSpaceOnUse" x1="617.37" y1="1257.3" x2="617.37"
y2="61.44" gradientTransform="matrix(1 0 0 -1 0 1278)">
<stop offset=".32" stop-color="#cd9d49" />
<stop offset=".99" stop-color="#875d27" />
</linearGradient>
<circle cx="617.4" cy="618.6" r="597.9" fill="url(#prefix__SVGID_1_)" />
</g>
<path class="prefix__st0"
d="M1005.6 574.1c-4.8-4-12.4-10-22.6-17v-79.2c0-201.9-163.7-365.6-365.6-365.6-201.9 0-365.6 163.7-365.6 365.6v79.2c-10.2 7-17.7 13-22.6 17-4.1 3.4-6.5 8.5-6.5 13.9v94.9c0 5.4 2.4 10.5 6.5 14 11.3 9.4 37.2 29.1 77.5 49.3v9.2c0 24.9 16 45 35.8 45 19.8 0 35.8-20.2 35.8-45V527.8c0-24.9-16-45-35.8-45-19 0-34.5 18.5-35.8 41.9h-.1v-46.9c0-171.6 139.1-310.7 310.7-310.7C789 167.2 928 306.3 928 477.9v46.9c-1.3-23.4-16.8-41.9-35.8-41.9-19.8 0-35.8 20.2-35.8 45v227.6c0 24.9 16 45 35.8 45 19.8 0 35.8-20.2 35.8-45v-9.2c40.3-20.2 66.2-39.9 77.5-49.3 4.2-3.5 6.5-8.6 6.5-14v-95c.1-5.4-2.3-10.5-6.4-13.9z" />
<path class="prefix__st0"
d="M489.9 969.7c23.9 0 43.3-19.4 43.3-43.3V441.6c0-23.9-19.4-43.3-43.3-43.3h-44.7c-23.9 0-43.3 19.4-43.3 43.3v484.8c0 23.9 19.4 43.3 43.3 43.3h44.7zm-71.7-455.1h98.7v10.3h-98.7v-10.3zM639.7 969.7c23.9 0 43.3-19.4 43.3-43.3V441.6c0-23.9-19.4-43.3-43.3-43.3H595c-23.9 0-43.3 19.4-43.3 43.3v484.8c0 23.9 19.4 43.3 43.3 43.3h44.7zM568 514.6h98.7v10.3H568v-10.3zM789.6 969.7c23.9 0 43.3-19.4 43.3-43.3V441.6c0-23.9-19.4-43.3-43.3-43.3h-44.7c-23.9 0-43.3 19.4-43.3 43.3v484.8c0 23.9 19.4 43.3 43.3 43.3h44.7zm-71.7-455.1h98.7v10.3h-98.7v-10.3zM327.1 984.7h580.5c18 0 32.6 14.6 32.6 32.6s-14.6 32.6-32.6 32.6H327.1c-18 0-32.6-14.6-32.6-32.6s14.6-32.6 32.6-32.6z" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.2 KiB

BIN
public/svgs/azimutt.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

BIN
public/svgs/bookstack.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

5
public/svgs/castopod.svg Normal file
View File

@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 324 65">
<path fill="#009486" d="M26.6 40.2c-1.4 1.3-3 2.3-4.9 3.1-1.9.7-4 1.1-6.2 1.1-3 0-5.6-.6-8-1.9-2.3-1.3-4.2-3-5.5-5.2-1.3-2.2-2-4.7-2-7.5s.7-5.3 2-7.5 3.2-3.9 5.5-5.2c2.3-1.3 5-1.9 8-1.9 2.2 0 4.3.4 6.2 1.1 1.9.7 3.5 1.7 4.9 3.1l-5.7 5.4c-1.3-1.7-3.1-2.5-5.4-2.5-2.1 0-3.8.7-5.1 2.2-1.3 1.4-2 3.2-2 5.4s.7 4 2 5.4c1.3 1.4 3 2.2 5.1 2.2 2.2 0 4-.8 5.4-2.5l5.7 5.2ZM31.1 36.1c0-1.9.5-3.5 1.6-5s2.6-2.6 4.4-3.5c1.9-.9 4.1-1.3 6.5-1.3a23.36 23.36 0 0 1 5 .5c-.6-3.1-2.8-4.6-6.7-4.6-2.3 0-4.5.9-6.8 2.6L32.3 18c1.9-.9 3.9-1.6 5.8-2.1 1.9-.4 3.7-.7 5.4-.7 2.7 0 5.1.5 7.1 1.5s3.5 2.5 4.6 4.3c1.1 1.9 1.7 4 1.7 6.6v16.2h-6.8l-.5-3c-1 1.1-2.3 2-3.8 2.6-1.5.6-3.2 1-5 1-2.8 0-5.2-.8-7-2.3a7.42 7.42 0 0 1-2.7-6Zm8-1.8c0 .9.4 1.7 1.1 2.3.7.6 1.7.9 2.8.9 1.6 0 3-.5 4.1-1.5 1.1-1 1.6-2.2 1.6-3.6v-.6c-.7-.2-1.4-.4-2.2-.5-.8-.1-1.6-.2-2.3-.2-1.6 0-2.8.3-3.7.8-.9.5-1.4 1.3-1.4 2.4ZM61.9 40.3l3.8-6.1c1.6 1.1 3.1 1.9 4.4 2.5 1.4.6 2.6.9 3.6.9.8 0 1.5-.2 2-.6.5-.4.8-.9.8-1.4 0-.8-.5-1.5-1.4-2-.9-.5-2-1-3.3-1.5-1.3-.5-2.6-1.2-3.9-1.8-1.3-.7-2.4-1.6-3.3-2.7a6.4 6.4 0 0 1-1.3-4.2c0-2.4.9-4.3 2.8-5.9 1.9-1.5 4.5-2.3 8-2.3 1.7 0 3.5.2 5.3.6 1.9.4 3.6 1.1 5.1 2l-3.6 6.1c-.8-.5-1.9-1-3.2-1.4-1.3-.4-2.4-.6-3.4-.6-.5 0-1.1.1-1.7.3-.6.2-.9.6-.9 1.2 0 .7.4 1.3 1.3 1.7.9.4 1.9.9 3.1 1.4 1.3.5 2.6 1.1 4 1.8s2.5 1.6 3.5 2.7c.9 1.1 1.4 2.6 1.4 4.4 0 1.8-.5 3.4-1.5 4.7-1 1.3-2.4 2.3-4 3-1.7.7-3.5 1.1-5.6 1.1-1.9 0-3.9-.3-6-1-2.1-.5-4.1-1.5-6-2.9ZM88.6 15.8h4.6v-7h8.1v7h6.8v7h-6.8v10.3c0 1.3.4 2.4 1.3 3.1.9.8 1.9 1.1 3.2 1.1 1 0 2-.2 3-.6v6.6c-1.8.7-3.5 1-5.2 1-3.3 0-5.9-.9-7.7-2.7-1.8-1.8-2.7-4.3-2.7-7.7V22.5h-4.6v-6.7ZM113.1 29.8c0-2.8.6-5.3 2-7.5 1.3-2.2 3.1-3.9 5.3-5.2 2.3-1.3 4.8-1.9 7.7-1.9 2.9 0 5.4.6 7.7 1.9 2.2 1.3 4 3 5.3 5.2 1.3 2.2 2 4.7 2 7.5s-.7 5.3-2 7.5-3.1 3.9-5.3 5.2c-2.2 1.3-4.8 1.9-7.7 1.9-2.9 0-5.5-.6-7.7-1.9-2.3-1.3-4-3-5.3-5.2-1.4-2.2-2-4.7-2-7.5Zm7.8 0c0 2.2.7 4 2 5.4 1.3 1.4 3 2.2 5.1 2.2 2.1 0 3.8-.7 5.1-2.2 1.3-1.4 2-3.2 2-5.4s-.7-4-2-5.4a6.87 6.87 0 0 0-5.1-2.2c-2.1 0-3.8.7-5.1 2.2-1.3 1.4-2 3.2-2 5.4ZM148.4 15.8h7.6l.2 3c1.2-1.1 2.6-2 4.1-2.7 1.6-.6 3.3-.9 5.1-.9 2.6 0 5 .6 7 1.9 2.1 1.3 3.7 3 4.9 5.2 1.2 2.2 1.8 4.7 1.8 7.5s-.6 5.3-1.8 7.5c-1.2 2.2-2.8 3.9-4.9 5.2-2.1 1.3-4.4 1.9-7 1.9-1.8 0-3.4-.3-4.9-.9-1.5-.6-2.9-1.4-4-2.5v23.8h-8.1v-49Zm15.2 6.4c-2.1 0-3.8.7-5.1 2.2-1.3 1.4-2 3.2-2 5.4s.7 4 2 5.4c1.3 1.4 3 2.2 5.1 2.2 2.1 0 3.8-.7 5.1-2.2 1.3-1.4 2-3.2 2-5.4s-.7-4-2-5.4a6.67 6.67 0 0 0-5.1-2.2ZM182.4 29.8c0-2.8.6-5.3 2-7.5 1.3-2.2 3.1-3.9 5.3-5.2 2.3-1.3 4.8-1.9 7.7-1.9 2.9 0 5.4.6 7.7 1.9 2.2 1.3 4 3 5.3 5.2 1.3 2.2 2 4.7 2 7.5s-.7 5.3-2 7.5-3.1 3.9-5.3 5.2c-2.2 1.3-4.8 1.9-7.7 1.9-2.9 0-5.5-.6-7.7-1.9-2.3-1.3-4-3-5.3-5.2-1.3-2.2-2-4.7-2-7.5Zm7.9 0c0 2.2.7 4 2 5.4 1.3 1.4 3 2.2 5.1 2.2 2.1 0 3.8-.7 5.1-2.2 1.3-1.4 2-3.2 2-5.4s-.7-4-2-5.4a6.87 6.87 0 0 0-5.1-2.2c-2.1 0-3.8.7-5.1 2.2-1.3 1.4-2 3.2-2 5.4ZM215.8 29.8c0-2.8.6-5.3 1.8-7.5 1.2-2.2 2.8-3.9 4.9-5.2 2.1-1.3 4.4-1.9 7-1.9 1.8 0 3.4.3 4.9.9 1.5.6 2.9 1.4 4 2.5V0h8.1v43.9h-7.6l-.2-3c-1.2 1.1-2.6 2-4.1 2.7-1.6.6-3.3.9-5.1.9-2.6 0-5-.6-7-1.9-2.1-1.3-3.7-3-4.9-5.2-1.2-2.3-1.8-4.8-1.8-7.6Zm8.3 0c0 2.2.7 4 2 5.4 1.3 1.4 3 2.2 5.1 2.2 2.1 0 3.8-.7 5.1-2.2 1.3-1.4 2-3.2 2-5.4s-.7-4-2-5.4a6.87 6.87 0 0 0-5.1-2.2c-2.1 0-3.8.7-5.1 2.2-1.3 1.4-2 3.2-2 5.4ZM318.7 44h-10.82s-1.13-2.41-1.6-3.26c-.45-.86-1.55-.82-1.55-.82h-29.38s-1.07-.14-1.6.82c-.57.95-1.63 3.26-1.63 3.26h-10.65a4.47 4.47 0 0 1-4.47-4.44V4.47A4.47 4.47 0 0 1 261.44 0h57.23a4.47 4.47 0 0 1 4.47 4.44v35.09a4.45 4.45 0 0 1-4.43 4.47Z"></path>
<path fill="#E7F9E4" d="M274.95 9.51h30.2a9.34 9.34 0 0 1 9.4 9.44c0 5.18-4.22 9.4-9.4 9.4h-30.2a9.42 9.42 0 0 1 0-18.84Z"></path>
<path fill="#009486" d="M302.77 15.36a4.61 4.61 0 0 0-3.64 7.46s1.58-1.18 3.8-1.18c1.67 0 3.6 1.01 3.6 1.01a4.61 4.61 0 0 0-3.76-7.29ZM277.23 15.36a4.61 4.61 0 0 0-3.77 7.3s1.94-1.02 3.6-1.02c2.23 0 3.8 1.18 3.8 1.18a4.61 4.61 0 0 0-3.64-7.45Z"></path>
</svg>

After

Width:  |  Height:  |  Size: 3.9 KiB

10
public/svgs/dozzle.svg Normal file
View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="256px" height="256px" style="shape-rendering:geometricPrecision; text-rendering:geometricPrecision; image-rendering:optimizeQuality; fill-rule:evenodd; clip-rule:evenodd" xmlns:xlink="http://www.w3.org/1999/xlink">
<g><path style="opacity:1" fill="#222222" d="M -0.5,-0.5 C 84.8333,-0.5 170.167,-0.5 255.5,-0.5C 255.5,84.8333 255.5,170.167 255.5,255.5C 170.167,255.5 84.8333,255.5 -0.5,255.5C -0.5,170.167 -0.5,84.8333 -0.5,-0.5 Z"/></g>
<g><path style="opacity:1" fill="#fbda56" d="M 161.5,179.5 C 160.957,179.56 160.624,179.893 160.5,180.5C 184.157,181.5 207.824,181.833 231.5,181.5C 231.5,186.833 231.5,192.167 231.5,197.5C 199.167,197.5 166.833,197.5 134.5,197.5C 134.813,194.753 134.48,192.086 133.5,189.5C 132.893,189.624 132.56,189.957 132.5,190.5C 115.506,204.774 95.8393,210.94 73.5,209C 58.1984,207.118 42.8651,205.618 27.5,204.5C 32.8364,149.128 38.5031,93.795 44.5,38.5C 59.7916,40.3257 75.1249,41.8257 90.5,43C 113.794,44.8067 132.127,55.14 145.5,74C 173.165,74.5 200.831,74.6666 228.5,74.5C 228.91,80.6208 228.41,86.6208 227,92.5C 205.158,121.53 183.324,150.53 161.5,179.5 Z"/></g>
<g><path style="opacity:1" fill="#222222" d="M 64.5,58.5 C 74.4468,59.9949 84.4468,61.1616 94.5,62C 117.983,67.1515 131.483,81.6515 135,105.5C 135.624,124.968 132.958,143.968 127,162.5C 119.558,178.614 107.058,187.781 89.5,190C 76.8083,190.293 64.1416,189.793 51.5,188.5C 56.0225,145.186 60.3558,101.852 64.5,58.5 Z"/></g>
<g><path style="opacity:1" fill="#252422" d="M 153.5,93.5 C 169.328,92.3386 185.328,92.1719 201.5,93C 185,114.833 168.5,136.667 152,158.5C 155.973,140.11 157.307,121.443 156,102.5C 155.34,99.322 154.507,96.322 153.5,93.5 Z"/></g>
<g><path style="opacity:1" fill="#6d6133" d="M 161.5,179.5 C 185.167,180.167 208.833,180.833 232.5,181.5C 232.167,181.5 231.833,181.5 231.5,181.5C 207.824,181.833 184.157,181.5 160.5,180.5C 160.624,179.893 160.957,179.56 161.5,179.5 Z"/></g>
<g><path style="opacity:1" fill="#d6ba4d" d="M 231.5,181.5 C 231.833,181.5 232.167,181.5 232.5,181.5C 232.5,187.167 232.5,192.833 232.5,198.5C 199.5,198.5 166.5,198.5 133.5,198.5C 133.806,195.615 133.473,192.948 132.5,190.5C 132.56,189.957 132.893,189.624 133.5,189.5C 134.48,192.086 134.813,194.753 134.5,197.5C 166.833,197.5 199.167,197.5 231.5,197.5C 231.5,192.167 231.5,186.833 231.5,181.5 Z"/></g>
</svg>

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

1
public/svgs/forgejo.svg Normal file
View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 212 212" width="32" height="32"><style>circle,path{fill:none;stroke:#000;stroke-width:15}path{stroke-width:25}.orange{stroke:#f60}.red{stroke:#d40000}</style><g transform="translate(6 6)"><path d="M58 168V70a50 50 0 0 1 50-50h20" class="orange"/><path d="M58 168v-30a50 50 0 0 1 50-50h20" class="red"/><circle cx="142" cy="20" r="18" class="orange"/><circle cx="142" cy="88" r="18" class="red"/><circle cx="58" cy="180" r="18" class="red"/></g></svg>

After

Width:  |  Height:  |  Size: 503 B

BIN
public/svgs/joplin.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

55
public/svgs/keycloak.svg Normal file
View File

@@ -0,0 +1,55 @@
<svg viewBox="0 0 128 128" version="1.1" xmlns="http://www.w3.org/2000/svg">
<defs>
<clipPath id="clip-path">
<path class="cls-1" d="M.02-.02H128v127.98H.02z" />
</clipPath>
<clipPath id="clip-path-3">
<path class="cls-1" d="M428 245.69h-9.77a.42.42 0 0 1-.33-.17l-.76-1-2.14-2.82-5.68-7.7-3.18-4.28a.41.41 0 0 0-.63 0l-3.33 3.71-.38.43a.4.4 0 0 0-.1.27v11.16a.41.41 0 0 1-.41.41h-8.42a.41.41 0 0 1-.41-.41v-40.55a.4.4 0 0 1 .41-.41h8.42a.41.41 0 0 1 .41.41v15.53a.4.4 0 0 0 .7.28l4.65-5L414 208l3.24-3.52a.41.41 0 0 1 .3-.13h10.34a.4.4 0 0 1 .41.42.46.46 0 0 1-.1.25l-4.66 5.17-7.74 8.61-3.23 3.58a.4.4 0 0 0 0 .5l4 5.63 3.66 5.16.45.63 2.77 3.88 2.89 4.06 2 2.82a.41.41 0 0 1-.33.63zm-38.72-.57a.41.41 0 0 1-.37.57h-8.94a.4.4 0 0 1-.37-.25l-.18-.4-3.46-8a.4.4 0 0 0-.37-.25h-16.8a.41.41 0 0 0-.38.25l-.52 1.2-3.12 7.25a.41.41 0 0 1-.36.23h-8.94a.41.41 0 0 1-.37-.57l.62-1.44 4.22-9.76.15-.34.18-.41.08-.2 1.4-3.25 10.84-25.09a.41.41 0 0 1 .37-.25h8.4a.4.4 0 0 1 .37.25l5.64 13 2.79 6.44 3.12 7.21 5.9 13.66zm-17.16-17-.59-1.38-2-4.63-2-4.57a.41.41 0 0 0-.75 0l-3.51 8.11-1.07 2.48a.4.4 0 0 0 .37.56h9.13a.4.4 0 0 0 .37-.61zm-26.51 4.66a17.7 17.7 0 0 1-.83 1.84 20.76 20.76 0 0 1-4 5.37 22.08 22.08 0 0 1-2.26 1.94 21 21 0 0 1-11.68 4.14h-1.51a21.6 21.6 0 0 1-12.1-3.42 22 22 0 0 1-3.34-2.7c-.41-.41-.81-.82-1.18-1.24a20.43 20.43 0 0 1-5.1-14 23.47 23.47 0 0 1 .27-3.6l-.19-.28.3-.45a20.05 20.05 0 0 1 5.89-10.91A22 22 0 0 1 313 207a20.33 20.33 0 0 1 7.39-3.09 23.77 23.77 0 0 1 4.92-.49 21.25 21.25 0 0 1 15.45 6.13 20.25 20.25 0 0 1 6.17 12.94c.07.74.1 1.51.1 2.28a21.76 21.76 0 0 1-1.47 7.97zm-8-8a13.54 13.54 0 0 0-3.18-9 5.22 5.22 0 0 0-.36-.43 11.34 11.34 0 0 0-8.73-3.9 12.49 12.49 0 0 0-2.67.28 11.4 11.4 0 0 0-6.06 3.62 13.44 13.44 0 0 0-3.55 9.12v.32a13.41 13.41 0 0 0 3.56 9.41 11.78 11.78 0 0 0 1.07 1 11.35 11.35 0 0 0 2.33 1.6 12.09 12.09 0 0 0 10.81-.09 11.76 11.76 0 0 0 2.87-2.18l.36-.38a13.42 13.42 0 0 0 2-2.83 13.84 13.84 0 0 0 1.53-6.55zm-34.51 12.69h-16.85a.4.4 0 0 1-.41-.4v-32.33a.4.4 0 0 0-.23-.36.35.35 0 0 0-.17 0H277a.4.4 0 0 0-.41.41v40.55a.41.41 0 0 0 .41.41h26a.41.41 0 0 0 .41-.41v-7.42a.41.41 0 0 0-.34-.46zm-45.76-34c-.67-.05-1.34-.08-2-.08a21.24 21.24 0 0 0-15.42 6.15 22.18 22.18 0 0 0-2.08 2.35 20.67 20.67 0 0 0-4.22 13 22.27 22.27 0 0 0 1.35 7.89 19.26 19.26 0 0 0 2.08 4.05 20.42 20.42 0 0 0 2.74 3.28 20.93 20.93 0 0 0 4.13 3.14c.37.21.75.42 1.13.61.38.19.56.27.85.39a23.61 23.61 0 0 0 9.6 1.88 21.39 21.39 0 0 0 3.07-.22c.64-.09 1.27-.21 1.9-.36a21.44 21.44 0 0 0 9.63-5.32c.58-.54 1.16-1.12 1.73-1.74a.41.41 0 0 0 0-.56l-5.34-5.49a.39.39 0 0 0-.36-.12.44.44 0 0 0-.24.14 13.55 13.55 0 0 1-10.84 5 12.05 12.05 0 0 1-4.18-.71 11.73 11.73 0 0 1-4.28-2.79 11.29 11.29 0 0 1-2.7-4.3 14.68 14.68 0 0 1-.79-5 12 12 0 0 1 3.21-8.7l.49-.47a12.68 12.68 0 0 1 8.91-3.4 13.35 13.35 0 0 1 10.59 5.08.4.4 0 0 0 .61 0l5.19-5.89a.42.42 0 0 0 0-.55 21.73 21.73 0 0 0-14.78-7.27zm-23.34 4.2 1.57-2.74a.4.4 0 0 0-.35-.61h-9.07a.41.41 0 0 0-.35.2l-8.22 14.15-.44.32-.33.25a.42.42 0 0 1-.17-.16l-.14-.23-.21-.35-8.12-14a.41.41 0 0 0-.35-.2h-9.07a.41.41 0 0 0-.35.61l3.93 6.88 7.12 12.44 2.87 5a.41.41 0 0 1 .06.2v15.82a.41.41 0 0 0 .41.41h8.42a.41.41 0 0 0 .41-.41v-15.79a.41.41 0 0 1 .06-.2l2-3.55 7.7-13.46 1.57-2.74 1-1.83zm-38.85 29.85H174.7a.41.41 0 0 1-.41-.41v-7.77a.41.41 0 0 1 .41-.41h17.71a.41.41 0 0 0 .41-.41v-7.06a.41.41 0 0 0-.41-.41H174.7a.41.41 0 0 1-.41-.41V213a.41.41 0 0 1 .41-.41h19.78a.41.41 0 0 0 .41-.41v-7.41a.41.41 0 0 0-.41-.41h-29a.4.4 0 0 0-.41.41v40.55a.41.41 0 0 0 .41.41h29.66a.41.41 0 0 0 .41-.41v-7.36a.41.41 0 0 0-.42-.44zm-34.82 7-3.84-5.38-3.93-5.52-.14-.21q-5.38-7.57-7.54-10.58a.4.4 0 0 1 0-.5l3.69-4.09 3-3.37 2.92-3.24 6-6.66a.4.4 0 0 0-.3-.67h-10.31a.41.41 0 0 0-.3.13l-6.4 7-8.4 9.13a.4.4 0 0 1-.7-.28v-15.55a.4.4 0 0 0-.41-.4h-8.42a.4.4 0 0 0-.41.41v40.55a.41.41 0 0 0 .41.41h8.42a.41.41 0 0 0 .41-.41v-11.16a.4.4 0 0 1 .1-.27l1.75-2 2-2.17a.41.41 0 0 1 .63 0l5.84 7.85 4.19 5.65 1.68 2.27a.4.4 0 0 0 .32.17h9.78a.41.41 0 0 0 .33-.65zM120 204.28H33.93a.78.78 0 0 0-.66.37l-.43.74-5.27 9.13-5.82 10.09a.76.76 0 0 0 0 .76l1.25 2.21 10.25 17.76a.77.77 0 0 0 .67.39H120a.85.85 0 0 0 .85-.85v-39.74a.86.86 0 0 0-.85-.86Z" id="path1576" />
</clipPath>
<linearGradient id="linear-gradient" x1="20.71" y1="225.61" x2="430.83" y2="225.61" gradientUnits="userSpaceOnUse">
<stop offset="0" stop-color="#e6e6e6" id="stop1579" />
<stop offset="1" stop-color="#595959" id="stop1581" />
</linearGradient>
<style id="style2007">.cls-1{fill:none}</style>
</defs>
<g id="g2460" transform="translate(.714 .07)">
<path d="M105.69 41.25a.76.76 0 0 1-.66-.38l-11.51-20a.78.78 0 0 0-.67-.38h-47a.76.76 0 0 0-.66.38l-12 20.71 4.625 6.774c-.134.236-1.199 4.644-1.065 4.88L33.19 82.29l12 20.73a.76.76 0 0 0 .66.38h47a.78.78 0 0 0 .67-.38l11.52-20a.76.76 0 0 1 .66-.38H120a.86.86 0 0 0 .86-.86V42.11a.86.86 0 0 0-.86-.86z" id="path1588" style="fill:#4d4d4d;clip-path:url(#clip-path)" clip-path="url(#clip-path)" transform="matrix(1.2527 0 0 1.2527 -23.058 -13.67)" />
<g clip-path="url(#clip-path-3)" id="g1592" transform="matrix(1.2527 0 0 1.2527 -23.058 -217.896)" style="fill:#4d4d4d">
<path id="rect1590" style="display:inline;fill:url(#linear-gradient)" d="M20.71 197.91h99.111v52.823H20.71z" />
</g>
<path d="m21.876 61.343-16.122 5.85-1.591-2.743a.952.952 0 0 1 0-.952l7.29-12.64z" id="path1594" style="fill:#e1e1e1;stroke-width:1.2527" />
<path class="cls-62" id="polygon1794" transform="matrix(1.2527 0 0 1.2527 -23.058 -217.896)" style="fill:#c8c8c8" d="M120.89 225.43v9.83l-8.48-8.62z" />
<path class="cls-61" d="m117.757 66.016 10.623 10.798v12.039a1.065 1.065 0 0 1-1.064 1.065H114.95z" id="path1798" style="fill:#c2c2c2;stroke-width:1.2527" />
<path class="cls-63" id="polygon1802" transform="matrix(1.2527 0 0 1.2527 -23.058 -217.896)" style="fill:#c7c7c7" d="m112.41 226.64-2.24 19.08H98.31l-3.59-8.66z" />
<path class="cls-64" id="polygon1804" transform="matrix(1.2527 0 0 1.2527 -23.058 -217.896)" style="fill:#cecece" d="M120.89 216.31v9.12l-8.48 1.21z" />
<path class="cls-65" d="M128.38 39.083v13.993l-10.622 12.927-8.03-27.997h17.538a1.077 1.077 0 0 1 1.114 1.077z" id="path1808" style="fill:#d3d3d3;stroke-width:1.2527" />
<path class="cls-58" id="polygon1812" transform="matrix(1.2527 0 0 1.2527 -23.058 -217.896)" style="fill:#c6c6c6" d="M98.31 245.72h-6.26l-1.62-2.33 4.29-6.33z" />
<path class="cls-66" id="polygon1814" transform="matrix(1.2527 0 0 1.2527 -23.058 -217.896)" style="fill:#d5d5d5" d="m112.41 226.64-23.47-9.93 12.34-12.43h4.73z" />
<path class="cls-67" d="m88.357 53.577 7.24 25.492 22.16-13.066Z" id="path1816" style="fill:#d0d0d0;stroke-width:1.2527" />
<path class="cls-50" id="polygon1818" transform="matrix(1.2527 0 0 1.2527 -23.058 -217.896)" style="fill:#bfbfbf" d="m90.36 245.72.07-2.33 1.62 2.33z" />
<path class="cls-68" id="polygon1820" transform="matrix(1.2527 0 0 1.2527 -23.058 -217.896)" style="fill:#d9d9d9" d="m101.28 204.28-12.34 12.43-2.23-11.12 4.77-1.31z" />
<path class="cls-69" d="m88.357 53.577-35.69 8.23 37.581 25.192Z" id="path1822" style="fill:#d4d4d4;stroke-width:1.2527" />
<path class="cls-67" d="m88.357 53.577 1.866 33.422 5.362-7.93z" id="path1824" style="fill:#d0d0d0;stroke-width:1.2527" />
<path class="cls-68" d="m85.563 39.647-32.896 22.16 35.69-8.23Z" id="path1826" style="fill:#d9d9d9;stroke-width:1.2527" />
<path class="cls-70" id="polygon1828" transform="matrix(1.2527 0 0 1.2527 -23.058 -217.896)" style="fill:#d8d8d8" d="M60.45 223.28 48.1 245.72h-7.03l-5.2-22.81z" />
<path class="cls-71" d="M36.82 38.006 21.877 61.343 18.118 39.41l.538-.927a.977.977 0 0 1 .827-.464h17.338z" id="path1830" style="fill:#e2e2e2;stroke-width:1.2527" />
<path class="cls-70" d="M28.39 89.918h-8.944a.965.965 0 0 1-.84-.489L5.754 67.194l16.122-5.85Z" id="path1832" style="fill:#d8d8d8;stroke-width:1.2527" />
<path class="cls-72" id="polygon1834" transform="matrix(1.2527 0 0 1.2527 -23.058 -217.896)" style="fill:#e4e4e4" d="m27.56 214.53 5.27-9.13 3.04 17.51z" />
<path class="cls-73" id="polygon1836" transform="matrix(1.2527 0 0 1.2527 -23.058 -217.896)" style="fill:#dedede" d="m86.71 205.59-7.91-1.31H52.67l7.78 19z" />
<path class="cls-73" id="polygon1838" transform="matrix(1.2527 0 0 1.2527 -23.058 -217.896)" style="fill:#dedede" d="m60.45 223.28-7.78-19H47.8l-11.93 18.63z" />
<path class="cls-74" id="polygon1840" transform="matrix(1.2527 0 0 1.2527 -23.058 -217.896)" style="fill:#c5c5c5" d="M84.72 245.72H90.36l.07-2.33z" />
<path class="cls-67" id="polygon1842" transform="matrix(1.2527 0 0 1.2527 -23.058 -217.896)" style="fill:#d0d0d0" d="M73.47 245.72h11.25l5.71-2.33-29.98-20.11 5.4 22.44z" />
<path class="cls-75" id="polygon1844" transform="matrix(1.2527 0 0 1.2527 -23.058 -217.896)" style="fill:#d1d1d1" d="m65.85 245.72-5.4-22.44-12.35 22.44h17.15z" />
<path class="cls-78" id="polygon1856" transform="matrix(1.2527 0 0 1.2527 -23.058 -217.896)" style="fill:#ddd" d="m86.79 204.28-.08 1.31 4.77-1.31H89.3z" />
<path class="cls-79" id="polygon1858" transform="matrix(1.2527 0 0 1.2527 -23.058 -217.896)" style="fill:#e3e3e3" d="m86.71 205.59-.73-1.31H78.8z" />
<path class="cls-71" id="polygon1860" transform="matrix(1.2527 0 0 1.2527 -23.058 -217.896)" style="fill:#e2e2e2" d="m86.71 205.59.08-1.31h-.81z" />
<path class="cls-80" d="M58.58 38.457 44.074 63.573a.84.84 0 0 0-.1.414H33.851L53.757 29.5a.79.79 0 0 1 .3.288l4.51 7.842a.864.864 0 0 1 .013.827z" id="path1862" style="fill:#00b8e3;stroke-width:1.2527" />
<path class="cls-81" d="m58.567 90.394-4.51 7.804a.877.877 0 0 1-.3.288L33.84 63.962h10.122a.777.777 0 0 0 .1.388l14.481 25.054a.852.852 0 0 1 .025.99z" id="path1864" style="fill:#33c6e9;stroke-width:1.2527" />
<path class="cls-82" d="M53.757 29.5 33.852 63.962l-5.011 8.656-4.76-8.268a.777.777 0 0 1-.1-.388.84.84 0 0 1 .1-.414l4.835-8.355 14.67-25.38a.852.852 0 0 1 .738-.438h9.032a.89.89 0 0 1 .401.125z" id="path1866" style="fill:#008aaa;stroke-width:1.2527" />
<path class="cls-80" d="M53.757 98.486a.89.89 0 0 1-.426.113h-9.007a.852.852 0 0 1-.739-.439L30.181 74.948l-1.328-2.305 5.011-8.656Z" id="path1868" style="fill:#00b8e3;stroke-width:1.2527" />
<path class="cls-82" d="M93.793 63.962 73.875 98.46a.927.927 0 0 1-.3-.288l-4.51-7.817a.864.864 0 0 1 0-.802l14.481-25.129a.84.84 0 0 0 .126-.438h10.121Z" id="path1870" style="fill:#008aaa;stroke-width:1.2527" />
<path class="cls-80" d="M103.64 63.962a.84.84 0 0 1-.126.438L84.01 98.223a.852.852 0 0 1-.727.4h-8.982a.927.927 0 0 1-.438-.112l19.93-34.55 5.011-8.643 4.735 8.218a.84.84 0 0 1 .1.426z" id="path1872" style="fill:#00b8e3;stroke-width:1.2527" />
<path class="cls-80" d="M93.793 63.962H83.66a.84.84 0 0 0-.125-.426L69.053 38.482a.852.852 0 0 1 0-.865l4.51-7.817a.927.927 0 0 1 .3-.288z" id="path1874" style="fill:#00b8e3;stroke-width:1.2527" />
<path class="cls-81" d="m98.78 55.33-5.012 8.644L73.85 29.487a.927.927 0 0 1 .439-.112h9.007a.852.852 0 0 1 .726.4z" id="path1876" style="fill:#33c6e9;stroke-width:1.2527" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 11 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 10 KiB

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="256" height="256" viewBox="0 0 256 256" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" preserveAspectRatio="xMidYMid">
<g>
<path d="M6.79123171,86.9648684 C25.2351716,32.4823178 76.783459,-1.43234143 131.421839,0.0464773399 L131.421839,0.0464773399 L113.909757,20.739032 C81.4957329,26.5997669 53.5072568,48.7337413 42.5072761,81.2287969 C26.140539,129.576353 53.572705,182.545803 103.779303,199.543648 C153.985902,216.538377 207.952658,191.12264 224.319395,142.7782 C235.283535,110.390667 226.589826,75.9306053 204.563374,51.5978814 L204.563374,51.5978814 L203.21701,24.4290666 C247.371203,56.4768925 267.622761,114.633895 249.208429,169.029181 C226.546194,235.970273 153.909545,271.865521 86.9684532,249.204844 C20.0273609,226.542609 -15.8694453,153.905961 6.79123171,86.9648684 Z M165.185344,11.9237762 C165.839826,11.6401671 166.594039,11.5793938 167.321762,11.8256038 C168.035459,12.0671391 168.585536,12.5580009 168.936152,13.1595015 L168.936152,13.1595015 L169.007833,13.2763734 L169.071723,13.4103864 C169.240019,13.7313945 169.383381,14.0991514 169.450388,14.5510559 C169.582343,15.4417519 169.641535,17.5358595 169.665634,19.6808502 L169.671365,20.2662434 C169.677102,20.9486534 169.679633,21.6256073 169.680171,22.2599793 L169.680173,22.7924325 C169.678741,24.5267431 169.663874,25.8268542 169.663874,25.8268542 L169.663874,25.8268542 L170.167202,44.7600977 L170.910507,66.6151379 L171.837691,104.59538 C171.837691,104.59538 171.83785,104.602367 171.838064,104.616156 L171.838772,104.677745 C171.838883,104.691349 171.838983,104.706608 171.839058,104.723498 L171.839105,104.844231 C171.832023,107.013302 171.387173,122.892918 160.122454,133.928662 C148.009853,145.795053 133.131285,144.708923 123.451177,141.433394 C113.771069,138.154749 101.293828,129.979951 98.8800345,113.195592 C96.8283098,98.9302108 104.41287,86.9390787 106.734401,83.6627102 L106.889339,83.4459953 C107.205256,83.0081712 107.389865,82.7777388 107.389865,82.7777388 L107.389865,82.7777388 L131.197445,53.1717559 L145.064682,36.2627333 L156.965355,21.5275276 C156.965355,21.5275276 158.715313,19.1834331 160.51647,16.874806 L160.876881,16.4142586 C161.477025,15.6498178 162.070275,14.9069442 162.593713,14.2737698 L162.898895,13.907734 C163.342593,13.3805415 163.71955,12.9564826 163.983901,12.6998055 C164.292443,12.4006135 164.608776,12.205827 164.918876,12.0546727 L164.918876,12.0546727 L165.146386,11.9393591 Z" fill="#0058CC" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

17
public/svgs/mautic.svg Normal file
View File

@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="349.779px" height="349.779px" viewBox="0 0 349.779 349.779" enable-background="new 0 0 349.779 349.779"
xml:space="preserve">
<path fill="#FFFFFF" d="M174.89,349.779C78.612,349.779,0,271.462,0,174.89S78.612,0,174.89,0c23.26,0,45.931,4.417,67.129,13.543
c5.889,2.65,8.833,9.422,6.478,15.605c-2.649,5.888-9.421,8.833-15.604,6.477c-18.549-7.655-37.98-11.482-58.002-11.482
c-83.323,0-151.041,67.718-151.041,151.041S91.567,326.225,174.89,326.225c83.323,0,151.041-67.718,151.041-151.041
c0-17.96-2.944-35.332-9.127-51.819c-2.355-6.183,0.883-12.955,7.066-15.31c6.183-2.355,12.954,0.883,15.31,7.066
c7.066,19.138,10.6,39.453,10.6,60.063C349.779,271.167,271.462,349.779,174.89,349.779"/>
<g>
<polygon fill="#FDB933" points="251.44,156.93 224.354,185.194 239.369,248.496 273.522,248.496 "/>
</g>
<polygon fill="#FDB933" points="240.253,73.312 249.674,82.734 174.89,161.935 110.999,96.277 74.196,248.496 108.35,248.496
128.665,163.996 174.89,214.343 273.817,106.583 283.239,116.299 292.66,63.007 "/>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

51
public/svgs/onedev.svg Normal file
View File

@@ -0,0 +1,51 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
viewBox="200 200 630 630"
height="200"
width="200"
version="1.1">
<g
transform="matrix(1.969278,0,0,1.969278,522.1972,523.64867)">
<g
paint-order="stroke">
<g
transform="matrix(1.6226969,0,0,-1.6226969,2.4340454,49.894842)">
<path
stroke-linecap="round"
d="m 0,0 c 9.013,0 16.323,3.81 16.323,8.503 0,4.697 -7.31,4.663 -16.323,4.663 -9.015,0 -16.323,0.034 -16.323,-4.663 C -16.323,3.81 -9.015,0 0,0"
transform="translate(0,-6.5830035)"
paint-order="stroke"
style="opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0" />
</g>
<g
transform="scale(1.6226969,-1.6226969)">
<path
stroke-linecap="round"
d="m 0,0 c -10.7,0 -19.375,-8.674 -19.375,-19.375 0,-6.235 2.958,-11.768 7.533,-15.312 -9.205,-22.861 -31.582,-39.042 -57.699,-39.042 -13.013,0 -25.101,4.021 -35.1,10.876 2.549,4.364 4.016,9.436 4.016,14.853 0,16.292 -13.208,29.5 -29.5,29.5 -0.415,0 -0.827,-0.015 -1.238,-0.031 -0.261,2.309 -0.408,4.653 -0.408,7.031 0,10.383 2.57,20.171 7.084,28.784 10.565,22.164 33.744,37.56 60.658,37.56 24.747,0 46.31,-13.023 57.838,-32.347 -1.504,-1.553 -2.434,-3.665 -2.434,-5.997 0,-4.764 3.861,-8.625 8.625,-8.625 4.764,0 8.625,3.861 8.625,8.625 0,4.088 -2.848,7.504 -6.665,8.393 -1.01,1.971 -2.089,3.902 -3.251,5.776 3.102,3.499 5.018,8.066 5.018,13.106 0,10.953 -8.882,19.832 -19.834,19.832 -5.277,0 -10.033,-2.094 -13.581,-5.459 -11.75,6.755 -25.354,10.625 -39.853,10.625 -14.169,0 -27.485,-3.705 -39.051,-10.175 -3.497,3.109 -8.082,5.009 -13.128,5.009 -10.956,0 -19.834,-8.879 -19.834,-19.832 0,-4.643 1.598,-8.91 4.273,-12.285 -7.92,-12.438 -12.533,-27.18 -12.533,-42.99 0,-4.618 0.413,-9.14 1.166,-13.547 -6.693,-5.408 -10.977,-13.679 -10.977,-22.953 0,-16.292 13.208,-29.5 29.5,-29.5 4.15,0 8.097,0.86 11.68,2.407 13.551,-10.446 30.509,-16.68 48.904,-16.68 35.091,0 64.955,22.649 75.833,54.088 7.607,2.615 13.083,9.816 13.083,18.31 C 19.375,-8.674 10.7,0 0,0"
transform="translate(70.125,11.5)"
paint-order="stroke"
style="opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0" />
</g>
<g
transform="matrix(1.6226969,0,0,-1.6226969,-41.533257,-8.9250313)">
<path
stroke-linecap="round"
d="m 0,0 c 3.561,1.848 7.952,0.457 9.8,-3.105 0.127,-0.246 0.205,-0.503 0.304,-0.759 1.367,9.134 -1.382,17.072 -7.088,18.88 -6.791,2.152 -15.166,-5.181 -18.713,-16.372 -3.546,-11.195 -0.915,-22.012 5.873,-24.161 6.137,-1.944 13.562,3.878 17.552,13.287 -0.323,-0.247 -0.661,-0.482 -1.032,-0.674 -3.564,-1.85 -7.951,-0.463 -9.801,3.102 C -4.953,-6.239 -3.564,-1.85 0,0"
transform="translate(3.4126028,5.2498778)"
paint-order="stroke"
style="opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0" />
</g>
<g
transform="matrix(1.6226969,0,0,-1.6226969,46.400783,-8.9251198)">
<path
stroke-linecap="round"
d="M 0,0 C 6.789,2.148 9.42,12.966 5.873,24.16 2.326,35.352 -6.049,42.685 -12.84,40.532 c -5.705,-1.807 -8.455,-9.746 -7.088,-18.88 0.1,0.256 0.178,0.514 0.305,0.759 1.848,3.563 6.238,4.953 9.799,3.106 3.564,-1.85 4.953,-6.24 3.105,-9.802 -1.849,-3.566 -6.236,-4.952 -9.801,-3.103 -0.371,0.193 -0.709,0.428 -1.031,0.674 C -13.563,3.878 -6.137,-1.944 0,0"
transform="translate(6.411045,-20.266777)"
paint-order="stroke"
style="opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0" />
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.8 KiB

BIN
public/svgs/organizr.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

12
public/svgs/paperless.svg Normal file
View File

@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 27.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 1000 1000" style="enable-background:new 0 0 1000 1000;" xml:space="preserve">
<style type="text/css">
.st0{fill:#FFFFFF;}
</style>
<path class="st0" d="M299,891.7c-4.2-19.8-12.5-59.6-13.6-59.6c-176.7-105.7-155.8-288.7-97.3-393.4
c12.5,131.8,245.8,222.8,109.8,383.9c-1.1,2,6.2,27.2,12.5,50.2c27.2-46,68-101.4,65.8-106.7C208.9,358.2,731.9,326.9,840.6,73.7
c49.1,244.8-25.1,623.5-445.5,719.7c-2,1.1-76.3,131.8-79.5,132.9c0-2-31.4-1.1-27.2-11.5C290.7,908.4,294.8,900.1,299,891.7
L299,891.7z M293.8,793.4c53.3-61.8-9.4-167.4-47.1-201.9C310.5,701.3,306.3,765.1,293.8,793.4L293.8,793.4z"/>
</svg>

After

Width:  |  Height:  |  Size: 869 B

BIN
public/svgs/soketi.jpeg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

View File

@@ -0,0 +1,17 @@
<svg xmlns="http://www.w3.org/2000/svg" width="44.869" height="40.302" viewBox="0 0 44.869 40.302">
<g id="Group_10325" data-name="Group 10325" transform="translate(0.516)">
<path id="Exclusion_1" data-name="Exclusion 1" d="M18.621,36.98c-.1,0-.2,0-.305-.008a7.383,7.383,0,0,1-3.67-1.338c-.308-.207-.615-.429-.912-.644l-.027-.019a16.427,16.427,0,0,0-1.965-1.286,7.348,7.348,0,0,0-3.4-.847l-.165,0a5.86,5.86,0,0,0-1.338.135A1.959,1.959,0,0,0,5.934,34.7a3.214,3.214,0,0,0,.3,1.18,3.066,3.066,0,0,1,.274.709h0c-.034,0-.122-.108-.289-.313-.665-.82-2.428-2.995-4.791-3.458A1.76,1.76,0,0,1,.306,30.1C6.2,21.434,6.931,18.338,9.672,6.822l.238-1q.261-1.1.55-2.3A1.773,1.773,0,0,1,11.5,2.3L14.818.918a1.759,1.759,0,0,1,.676-.135,1.8,1.8,0,0,1,.275.021A14.322,14.322,0,0,1,20.989,0h2.3a14.32,14.32,0,0,1,5.219.8,1.77,1.77,0,0,0-1.017.539l-10,.758h0l-.7-.757A1.773,1.773,0,0,0,15.77.805a5.9,5.9,0,0,0-1.814,1.1c-1.308,1.2-1.972,3.351-1.972,6.406V20.836c0,3.056.664,5.213,1.972,6.408,1.377,1.262,3.743,1.9,7.033,1.9h2.3c3.29,0,5.656-.64,7.033-1.9,1.308-1.2,1.972-3.354,1.972-6.408V8.31c0-3.053-.664-5.208-1.972-6.406A5.912,5.912,0,0,0,28.508.8a1.825,1.825,0,0,1,.274-.021,1.749,1.749,0,0,1,.675.135L32.779,2.3a1.773,1.773,0,0,1,1.036,1.223c.613,2.556,1.133,4.837,1.511,6.5,2.1,9.24,2.891,12.7,8.2,20.511a1.759,1.759,0,0,1-1.115,2.718A8.073,8.073,0,0,0,37.9,36.443c-.108.139-.155.2-.168.2a2.225,2.225,0,0,1,.195-.49l.118-.273a3.243,3.243,0,0,0,.293-1.18,1.9,1.9,0,0,0-.657-1.524,10.157,10.157,0,0,0-2.225-.28q-.118,0-.237,0a3.506,3.506,0,0,0-2.887,1.172,5,5,0,0,0-.3.455l-.013.022a4.346,4.346,0,0,1-.365.543,1.328,1.328,0,0,1-1.083.532A4.472,4.472,0,0,1,28.737,35c-.242-.122-.44-.222-.632-.3a5.773,5.773,0,0,0-2.236-.523,3.7,3.7,0,0,0-.643.055,7.689,7.689,0,0,0-2.771,1.336c-.194.126-.386.252-.579.374A6.007,6.007,0,0,1,18.621,36.98Z" transform="translate(0 2.822)" fill="#f93" stroke="rgba(0,0,0,0)" stroke-width="1"/>
<g id="Group_4056" data-name="Group 4056" transform="translate(5.914 22.19)">
<path id="Path_14227" data-name="Path 14227" d="M698.042,466.44l.162-2.728,2.46-.713,1.006,3.181A4.743,4.743,0,0,0,698.042,466.44Z" transform="translate(-680.16 -451.111)" fill="#db902e"/>
<path id="Path_14229" data-name="Path 14229" d="M660.956,448.452c0,.064,0,1.019.007,1.1-1.971-.35-3.581.3-3.53,1.77h-.017V450.9c-.081-2.846,1.322-5.229,2.111-7.863.647-2.175.943-8.8,1.467-6.608a14.459,14.459,0,0,1-.037,5.614,23.229,23.229,0,0,0,0,3.2Z" transform="translate(-657.412 -435.988)" fill="#db902e"/>
<path id="Path_14231" data-name="Path 14231" d="M722.715,448.452c0,.064,0,1.019-.007,1.1,1.724.09,3.581.3,3.53,1.77h.017V450.9c.081-2.846-1.322-5.229-2.11-7.863-.647-2.175-.943-8.8-1.467-6.608a14.438,14.438,0,0,0,.038,5.614,23.287,23.287,0,0,1,0,3.2Z" transform="translate(-693.804 -435.988)" fill="#db902e"/>
</g>
<g id="Group_1803" data-name="Group 1803" transform="translate(9.16)">
<path id="Path_14233" data-name="Path 14233" d="M678.914,391.217c3.483,0,4.746.813,5.128,1.162.671.615,1.056,2.193,1.056,4.328v12.525c0,2.135-.385,3.712-1.057,4.328-.381.349-1.643,1.161-5.127,1.161h-2.3c-3.483,0-4.746-.812-5.129-1.163-.671-.614-1.055-2.191-1.055-4.326V396.707c0-2.135.385-3.713,1.056-4.328.382-.349,1.645-1.162,5.128-1.162h2.3m0-5.644h-2.3q-6.052,0-8.94,2.644t-2.888,8.49v12.525q0,5.846,2.888,8.49t8.94,2.644h2.3q6.054,0,8.94-2.644t2.888-8.49V396.707q0-5.846-2.888-8.49t-8.94-2.644Z" transform="translate(-664.788 -385.573)" fill="#1a1a1a"/>
</g>
<g id="Group_1804" data-name="Group 1804" transform="translate(19.692 15.337)">
<ellipse id="Ellipse_669" data-name="Ellipse 669" cx="2.445" cy="2.445" rx="2.445" ry="2.445" transform="translate(0 0)" fill="#1a1a1a"/>
<path id="Path_14234" data-name="Path 14234" d="M693.3,432.955h-2.286a.517.517,0,0,1-.514-.566l.47-4.836a.516.516,0,0,1,.514-.466h1.344a.516.516,0,0,1,.514.466l.47,4.836A.517.517,0,0,1,693.3,432.955Z" transform="translate(-689.717 -424.151)" fill="#1a1a1a"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.9 KiB

View File

@@ -184,10 +184,6 @@ export function initializeTerminalComponent() {
// Copy and paste functionality
this.term.attachCustomKeyEventHandler((arg) => {
if (arg.ctrlKey && arg.code === "KeyV" && arg.type === "keydown") {
navigator.clipboard.readText()
.then(text => {
this.socket.send(JSON.stringify({ message: text }));
});
return false;
}

View File

@@ -5,6 +5,13 @@
<x-forms.button type="submit">
Save
</x-forms.button>
{{--
<x-forms.button wire:click="downloadConfig">
Download Config
<x-modal-input buttonTitle="Upload Config" title="Upload Config" :closeOutside="false">
<livewire:project.shared.upload-config :applicationId="$application->id" />
</x-modal-input>
--}}
</div>
<div>General configuration for your application.</div>
<div class="flex flex-col gap-2 py-4">
@@ -56,7 +63,7 @@
@endif
@if ($application->build_pack !== 'dockercompose')
<div class="flex items-end gap-2">
<x-forms.input placeholder="https://coolify.io" id="application.fqdn" label="Domains"
<x-forms.input placeholder="https://coolify.io" wire:model.blur="application.fqdn" label="Domains"
helper="You can specify one domain with path or more with comma. You can specify a port to bind the domain to.<br><br><span class='text-helper'>Example</span><br>- http://app.coolify.io,https://cloud.coolify.io/dashboard<br>- http://app.coolify.io/api/v3<br>- http://app.coolify.io:3000 -> app.coolify.io will point to port 3000 inside the container. " />
<x-forms.button wire:click="getWildcardDomain">Generate Domain
</x-forms.button>

View File

@@ -52,15 +52,21 @@
helper="It is calculated together with the Base Directory:<br><span class='dark:text-warning'>{{ Str::start($base_directory . $docker_compose_location, '/') }}</span>" />
Compose file location in your repository:<span
class='dark:text-warning'>{{ Str::start($base_directory . $docker_compose_location, '/') }}</span>
@else
<x-forms.input wire:model="base_directory" label="Base Directory"
helper="Directory to use as root. Useful for monorepos." />
@endif
@if ($show_is_static)
<x-forms.input type="number" id="port" label="Port" :readonly="$isStatic || $build_pack === 'static'"
helper="The port your application listens on." />
<div class="w-52">
<div class="w-64">
<x-forms.checkbox instantSave id="isStatic" label="Is it a static site?"
helper="If your application is a static site or the final build assets should be served as a static site, enable this." />
</div>
@endif
{{-- <div class="w-64">
<x-forms.checkbox helper="If your repository contains a coolify.json file, it will be used to configure your application." instantSave id="checkCoolifyConfig" label="Use coolify.json if exists?" />
</div> --}}
{{-- @if ($build_pack === 'dockercompose' && isDev())
<div class="dark:text-warning">If you choose Docker Compose based deployments, you cannot
change it afterwards.</div>

View File

@@ -159,10 +159,11 @@
});
},
filterAndSort(items, isSort = true) {
if (this.search === '') {
const searchLower = this.search.trim().toLowerCase();
if (searchLower === '') {
return isSort ? Object.values(items).sort(sortFn) : Object.values(items);
}
const searchLower = this.search.toLowerCase();
const filtered = Object.values(items).filter(item => {
return (item.name?.toLowerCase().includes(searchLower) ||
item.description?.toLowerCase().includes(searchLower))

View File

@@ -24,8 +24,13 @@
<div class="grid grid-cols-2 gap-2">
@foreach ($fields as $serviceName => $field)
<div class="flex items-center gap-2"><span
class="font-bold">{{ data_get($field, 'serviceName') }}</span>{{ data_get($field, 'name') }}<x-helper
helper="Variable name: {{ $serviceName }}" /></div>
class="font-bold">{{ data_get($field, 'serviceName') }}</span>{{ data_get($field, 'name') }}
@if (data_get($field, 'customHelper'))
<x-helper helper="{{ data_get($field, 'customHelper') }}" />
@else
<x-helper helper="Variable name: {{ $serviceName }}" />
@endif
</div>
<x-forms.input type="{{ data_get($field, 'isPassword') ? 'password' : 'text' }}"
required="{{ str(data_get($field, 'rules'))?->contains('required') }}"
id="fields.{{ $serviceName }}.value"></x-forms.input>

View File

@@ -0,0 +1,6 @@
<form wire:submit="uploadConfig" class="flex flex-col gap-2 w-full">
<x-forms.textarea id="config" monacoEditorLanguage="json" useMonacoEditor />
<x-forms.button type="submit">
Upload
</x-forms.button>
</form>

View File

@@ -0,0 +1,23 @@
# documentation: https://www.audiobookshelf.org/
# slogan: Self-hosted audiobook, ebook, and podcast server
# tags: audiobooks, ebooks, podcasts, server, self-hosted
# logo: svgs/audiobookshelf.svg
# port: 80
services:
audiobookshelf:
image: ghcr.io/advplyr/audiobookshelf:latest
environment:
- SERVICE_FQDN_AUDIOBOOKSHELF_80
- TZ=${TIMEZONE:-America/Toronto}
volumes:
- audiobookshelf-audiobooks:/audiobooks
- audiobookshelf-podcasts:/podcasts
- audiobookshelf-config:/config
- audiobookshelf-metadata:/metadata
healthcheck:
test: ["CMD-SHELL", "curl -f http://localhost:80/ping || exit 1"]
interval: 30s
timeout: 10s
retries: 3
start_period: 15s

View File

@@ -5,9 +5,8 @@
# port: 9000
services:
authentik-server:
image: ghcr.io/goauthentik/server:${AUTHENTIK_TAG:-2024.2.2}
image: ghcr.io/goauthentik/server:${AUTHENTIK_TAG:-2024.8.0}
restart: unless-stopped
command: server
environment:
@@ -36,7 +35,7 @@ services:
redis:
condition: service_healthy
authentik-worker:
image: ghcr.io/goauthentik/server:${AUTHENTIK_TAG:-2024.2.2}
image: ghcr.io/goauthentik/server:${AUTHENTIK_TAG:-2024.8.0}
restart: unless-stopped
command: worker
environment:
@@ -73,7 +72,7 @@ services:
redis:
condition: service_healthy
postgresql:
image: docker.io/library/postgres:12-alpine
image: docker.io/library/postgres:16-alpine
restart: unless-stopped
healthcheck:
test: ["CMD-SHELL", "pg_isready -d $${POSTGRES_DB} -U $${POSTGRES_USER}"]
@@ -85,7 +84,7 @@ services:
environment:
- POSTGRES_PASSWORD=${SERVICE_PASSWORD_POSTGRESQL}
- POSTGRES_USER=${SERVICE_USER_POSTGRESQL}
- POSTGRES_DB=${POSTGRES_DB:-authentik}
- POSTGRES_DB=authentik
redis:
image: docker.io/library/redis:alpine
command: --save 60 1 --loglevel warning

View File

@@ -0,0 +1,103 @@
# ignore: true
# documentation: https://docs.azimutt.app/
# slogan: Next-Gen ERD: Design, Explore, Document and Analyze your database.
# tags: erd, entity-relationship diagram, database tool, database schema, diagram
# logo: svgs/azimutt.png
# port: 4000
services:
postgres:
image: postgres:15
environment:
- POSTGRES_PASSWORD=$SERVICE_PASSWORD_POSTGRES
- POSTGRES_USER=$SERVICE_USER_POSTGRES
- POSTGRES_DB=azimutt
volumes:
- azimutt-postgres-data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}"]
interval: 5s
timeout: 20s
retries: 10
minio:
image: minio/minio:latest
command: server /data --console-address ":9001"
environment:
- MINIO_SERVER_URL=$MINIO_SERVER_URL
- MINIO_BROWSER_REDIRECT_URL=$MINIO_BROWSER_REDIRECT_URL
- MINIO_ROOT_USER=$SERVICE_USER_MINIO
- MINIO_ROOT_PASSWORD=$SERVICE_PASSWORD_MINIO
volumes:
- azimutt-minio-data:/data
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"]
interval: 5s
timeout: 20s
retries: 10
createbuckets:
image: minio/mc:latest
restart: no
depends_on:
minio:
condition: service_healthy
entrypoint: >
/bin/sh -c "
/usr/bin/mc config host add myminio http://minio:9000 $SERVICE_USER_MINIO $SERVICE_PASSWORD_MINIO;
/usr/bin/mc mb -p myminio/azimutt;
/usr/bin/mc policy download myminio/azimutt;
exit 0;
"
smtp:
image: bytemark/smtp:latest
platform: linux/amd64
environment:
- SERVICE_FQDN_SMTP
- RELAY_HOST=$SERVICE_FQDN_SMTP
- RELAY_PORT=${RELAY_PORT:-587}
- RELAY_USERNAME=$SERVICE_EMAIL_SMTP
- RELAY_PASSWORD=$SERVICE_PASSWORD_SMTP
healthcheck:
test: ["CMD-SHELL", "bash -c ':> /dev/tcp/127.0.0.1/25' || exit 1"]
interval: 5s
timeout: 10s
retries: 20
backend:
container_name: azimutt-backend
platform: linux/amd64
image: ghcr.io/azimuttapp/azimutt:main
depends_on:
postgres:
condition: service_healthy
minio:
condition: service_healthy
environment:
- SERVICE_FQDN_AZIMUTT_4000
- SENTRY=false
- PHX_SERVER=true
- PHX_HOST=$SERVICE_URL_AZIMUTT
- PORT=${PORT:-4000}
- DATABASE_URL=ecto://$SERVICE_USER_POSTGRES:$SERVICE_PASSWORD_POSTGRES@postgres/azimutt
- SECRET_KEY_BASE=$SERVICE_BASE64_64_AZIMUTT
- FILE_STORAGE_ADAPTER=${FILE_STORAGE_ADAPTER:-s3}
- AUTH_PASSWORD=${AUTH_PASSWORD:-true}
- SKIP_ONBOARDING_FUNNEL=${SKIP_ONBOARDING_FUNNEL:-true}
- SKIP_EMAIL_CONFIRMATION=${SKIP_EMAIL_CONFIRMATION:-true}
- PUBLIC_SITE=${PUBLIC_SITE:-false}
- S3_BUCKET=${S3_BUCKET}
- S3_HOST=${S3_HOST}
- S3_KEY_ID=${S3_KEY_ID}
- S3_KEY_SECRET=${S3_KEY_SECRET}
- EMAIL_ADAPTER=${EMAIL_ADAPTER:-smtp}
- SMTP_RELAY=$SERVICE_FQDN_SMTP
- SMTP_USERNAME=$SERVICE_EMAIL_SMTP
- SMTP_PASSWORD=$SERVICE_PASSWORD_SMTP
- SMTP_PORT=${SMTP_PORT:-587}
healthcheck:
test: ["CMD-SHELL", "bash -c ':> /dev/tcp/127.0.0.1/4000' || exit 1"]
interval: 5s
timeout: 10s
retries: 20

View File

@@ -0,0 +1,59 @@
# documentation: https://www.bookstackapp.com/docs/
# slogan: BookStack is a simple, self-hosted, easy-to-use platform for organising and storing information
# tags: free-and-open-source,mfa,dark-light-themes,searchable,connected,simple-interface,diagramms,notes
# logo: svgs/bookstack.png
# port: 80
services:
bookstack:
image: lscr.io/linuxserver/bookstack:latest
environment:
- SERVICE_FQDN_BOOKSTACK_80
- APP_URL=${SERVICE_FQDN_BOOKSTACK}
- PUID=1000
- PGID=1000
- TZ=${TZ:-Europe/Berlin}
- DB_HOST=mariadb
- DB_PORT=3306
- DB_USER=${SERVICE_USER_MYSQL}
- DB_PASS=${SERVICE_PASSWORD_MYSQL}
- DB_DATABASE=${MYSQL_DATABASE:-bookstackapp}
- QUEUE_CONNECTION=${QUEUE_CONNECTION}
# You will need to set up an authentication provider as described at https://www.bookstackapp.com/docs/admin/third-party-auth/.
- GITHUB_APP_ID=${GITHUB_APP_ID}
- GITHUB_APP_SECRET=${GITHUB_APP_SECRET}
volumes:
- 'bookstack-data:/config'
healthcheck:
test:
- CMD-SHELL
- 'wget -qO- http://127.0.0.1:80/'
interval: 5s
timeout: 20s
retries: 10
depends_on:
mariadb:
condition: service_healthy
mariadb:
image: lscr.io/linuxserver/mariadb:latest
environment:
- PUID=1000
- PGID=1000
- TZ=${TZ:-Europe/Berlin}
- MYSQL_ROOT_PASSWORD=${SERVICE_PASSWORD_MYSQLROOT}
- MYSQL_DATABASE=${MYSQL_DATABASE:-bookstack}
- MYSQL_USER=${SERVICE_USER_MYSQL}
- MYSQL_PASSWORD=${SERVICE_PASSWORD_MYSQL}
volumes:
- 'bookstack-mariadb-data:/config'
healthcheck:
test:
- CMD
- mysqladmin
- ping
- '-h'
- 127.0.0.1
interval: 5s
timeout: 20s
retries: 10

View File

@@ -0,0 +1,63 @@
# documentation:https://docs.castopod.org/main/en/
# slogan: Castopod is a free & open-source hosting platform made for podcasters who want engage and interact with their audience.
# tags: podcast, media, audio, video, streaming, hosting, platform, castopod
# logo: svgs/castopod.svg
# port: 8000
services:
castopod:
image: castopod/castopod:latest
volumes:
- castopod-media:/var/www/castopod/public/media
environment:
- SERVICE_FQDN_CASTOPOD_8000
- MYSQL_DATABASE=castopod
- MYSQL_USER=$SERVICE_USER_MYSQL
- MYSQL_PASSWORD=$SERVICE_PASSWORD_MYSQL
- CP_DISABLE_HTTPS=${CP_DISABLE_HTTPS:-1}
- CP_BASEURL=$SERVICE_FQDN_CASTOPOD
- CP_ANALYTICS_SALT=$SERVICE_REALBASE64_64_SALT
- CP_CACHE_HANDLER=redis
- CP_REDIS_HOST=redis
- CP_REDIS_PASSWORD=$SERVICE_PASSWORD_REDIS
healthcheck:
test:
[
"CMD",
"curl",
"-f",
"http://localhost:8000/health"
]
interval: 5s
timeout: 20s
retries: 10
depends_on:
mariadb:
condition: service_healthy
redis:
condition: service_healthy
mariadb:
image: mariadb:11.2
volumes:
- castopod-db:/var/lib/mysql
environment:
- MYSQL_ROOT_PASSWORD=$SERVICE_PASSWORD_MYSQL
- MYSQL_DATABASE=castopod
- MYSQL_USER=$SERVICE_USER_MYSQL
- MYSQL_PASSWORD=$SERVICE_PASSWORD_MYSQL
healthcheck:
test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"]
interval: 5s
timeout: 20s
retries: 10
redis:
image: redis:7.2-alpine
command: --requirepass $SERVICE_PASSWORD_REDIS
volumes:
- castopod-cache:/data
healthcheck:
test: ["CMD-SHELL", "redis-cli -a $SERVICE_PASSWORD_REDIS ping | grep PONG"]
interval: 5s
timeout: 20s
retries: 10

View File

@@ -0,0 +1,32 @@
# ignore: true
# documentation: https://dozzle.dev/
# slogan: Dozzle is a simple and lightweight web UI for Docker logs.
# tags: dozzle,docker,logs,web-ui
# logo: svgs/dozzle.svg
# port: 8080
services:
dozzle:
image: amir20/dozzle:latest
environment:
- SERVICE_FQDN_DOZZLE_8080
- DOZZLE_AUTH_PROVIDER=simple
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- type: bind
source: /data/users.yml
target: /data/users.yml
content: |
users:
# "admin" here is username
admin:
name: "Admin"
# Just sha-256 which can be computed with "echo -n password | shasum -a 256"
password: "5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8"
email: me@email.net
healthcheck:
test: ["CMD", "/dozzle", "healthcheck"]
interval: 3s
timeout: 30s
retries: 5
start_period: 30s

View File

@@ -0,0 +1,19 @@
# documentation: https://dozzle.dev/guide/getting-started#running-with-docker
# slogan: Dozzle is a simple and lightweight web UI for Docker logs.
# tags: dozzle,docker,logs,web-ui
# logo: svgs/dozzle.svg
# port: 8080
services:
dozzle:
image: amir20/dozzle:latest
environment:
- SERVICE_FQDN_DOZZLE_8080
volumes:
- /var/run/docker.sock:/var/run/docker.sock
healthcheck:
test: ["CMD", "/dozzle", "healthcheck"]
interval: 3s
timeout: 30s
retries: 5
start_period: 30s

View File

@@ -0,0 +1,35 @@
# documentation: https://easyappointments.org/
# slogan: Schedule Anything. Let's start with easy! Get the best free online appointment scheduler on your server, today.
# tags: calendar, scheduling, database
# logo: svgs/easyappointments.png
# port: 80
services:
easyappointments:
image: alextselegidis/easyappointments:latest
environment:
- SERVICE_FQDN_EASYAPPOINTMENTS_80
- BASE_URL=${SERVICE_FQDN_EASYAPPOINTMENTS}
- DB_HOST=mysql
- DB_NAME=easyappointments
- DB_USERNAME=root
- DB_PASSWORD=${SERVICE_PASSWORD_EASYAPPOINTMENTS}
depends_on:
- mysql
healthcheck:
test: ["CMD", "curl", "-f", "http://127.0.0.1"]
interval: 2s
timeout: 10s
retries: 30
mysql:
image: mysql:8
volumes:
- easyappointments-mysql-data:/var/lib/mysql
environment:
- MYSQL_ROOT_PASSWORD=${SERVICE_PASSWORD_EASYAPPOINTMENTS}
- MYSQL_DATABASE=easyappointments
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "127.0.0.1"]
interval: 5s
timeout: 20s
retries: 10

View File

@@ -0,0 +1,51 @@
# ignore: true
# documentation: https://forgejo.org/docs
# slogan: Forgejo is a self-hosted lightweight software forge. Easy to install and low maintenance, it just does the job.
# tags: version control, collaboration, code, hosting, lightweight, mariadb
# logo: svgs/forgejo.svg
# port: 3000
services:
forgejo:
image: codeberg.org/forgejo/forgejo:8
environment:
- SERVICE_FQDN_FORGEJO_3000
- FORGEJO__server__ROOT_URL=${SERVICE_FQDN_FORGEJO_3000}
- FORGEJO__migrations__ALLOWED_DOMAINS=${FORGEJO__migrations__ALLOWED_DOMAINS}
- FORGEJO__migrations__ALLOW_LOCALNETWORKS=${FORGEJO__migrations__ALLOW_LOCALNETWORKS-false}
- USER_UID=1000
- USER_GID=1000
- FORGEJO__database__DB_TYPE=mysql
- FORGEJO__database__HOST=mariadb
- FORGEJO__database__NAME=${MYSQL_DATABASE-forgejo}
- FORGEJO__database__USER=$SERVICE_USER_MYSQL
- FORGEJO__database__PASSWD=$SERVICE_PASSWORD_MYSQL
volumes:
- forgejo-data:/data
- forgejo-timezone:/etc/timezone:ro
- forgejo-localtime:/etc/localtime:ro
ports:
- 22222:22
depends_on:
mariadb:
condition: service_healthy
healthcheck:
test: ["CMD", "curl", "-f", "http://127.0.0.1:3000"]
interval: 2s
timeout: 10s
retries: 15
mariadb:
image: mariadb:11
volumes:
- forgejo-mariadb-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}
healthcheck:
test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"]
interval: 5s
timeout: 20s
retries: 10

View File

@@ -0,0 +1,51 @@
# ignore: true
# documentation: https://forgejo.org/docs
# slogan: Forgejo is a self-hosted lightweight software forge. Easy to install and low maintenance, it just does the job.
# tags: version control, collaboration, code, hosting, lightweight, mysql
# logo: svgs/forgejo.svg
# port: 3000
services:
forgejo:
image: codeberg.org/forgejo/forgejo:8
environment:
- SERVICE_FQDN_FORGEJO_3000
- FORGEJO__server__ROOT_URL=${SERVICE_FQDN_FORGEJO_3000}
- FORGEJO__migrations__ALLOWED_DOMAINS=${FORGEJO__migrations__ALLOWED_DOMAINS}
- FORGEJO__migrations__ALLOW_LOCALNETWORKS=${FORGEJO__migrations__ALLOW_LOCALNETWORKS-false}
- USER_UID=1000
- USER_GID=1000
- FORGEJO__database__DB_TYPE=mysql
- FORGEJO__database__HOST=mysql
- FORGEJO__database__NAME=${MYSQL_DATABASE-forgejo}
- FORGEJO__database__USER=$SERVICE_USER_MYSQL
- FORGEJO__database__PASSWD=$SERVICE_PASSWORD_MYSQL
volumes:
- forgejo-data:/data
- forgejo-timezone:/etc/timezone:ro
- forgejo-localtime:/etc/localtime:ro
ports:
- 22222:22
depends_on:
mysql:
condition: service_healthy
healthcheck:
test: ["CMD", "curl", "-f", "http://127.0.0.1:3000"]
interval: 2s
timeout: 10s
retries: 15
mysql:
image: mysql:8
volumes:
- forgejo-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}
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "127.0.0.1"]
interval: 5s
timeout: 20s
retries: 10

View File

@@ -0,0 +1,50 @@
# ignore: true
# documentation: https://forgejo.org/docs
# slogan: Forgejo is a self-hosted lightweight software forge. Easy to install and low maintenance, it just does the job.
# tags: version control, collaboration, code, hosting, lightweight, postgresql
# logo: svgs/forgejo.svg
# port: 3000
services:
forgejo:
image: codeberg.org/forgejo/forgejo:8
environment:
- SERVICE_FQDN_FORGEJO_3000
- FORGEJO__server__ROOT_URL=${SERVICE_FQDN_FORGEJO_3000}
- FORGEJO__migrations__ALLOWED_DOMAINS=${FORGEJO__migrations__ALLOWED_DOMAINS}
- FORGEJO__migrations__ALLOW_LOCALNETWORKS=${FORGEJO__migrations__ALLOW_LOCALNETWORKS-false}
- USER_UID=1000
- USER_GID=1000
- FORGEJO__database__DB_TYPE=postgres
- FORGEJO__database__HOST=postgresql
- FORGEJO__database__NAME=${POSTGRESQL_DATABASE-forgejo}
- FORGEJO__database__USER=$SERVICE_USER_POSTGRESQL
- FORGEJO__database__PASSWD=$SERVICE_PASSWORD_POSTGRESQL
volumes:
- forgejo-data:/data
- forgejo-timezone:/etc/timezone:ro
- forgejo-localtime:/etc/localtime:ro
ports:
- 22222:22
depends_on:
postgresql:
condition: service_healthy
healthcheck:
test: ["CMD", "curl", "-f", "http://127.0.0.1:3000"]
interval: 2s
timeout: 10s
retries: 15
postgresql:
image: postgres:16-alpine
volumes:
- forgejo-postgresql-data:/var/lib/postgresql/data
environment:
- POSTGRES_USER=${SERVICE_USER_POSTGRESQL}
- POSTGRES_PASSWORD=${SERVICE_PASSWORD_POSTGRESQL}
- POSTGRES_DB=${POSTGRESQL_DATABASE}
healthcheck:
test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}"]
interval: 5s
timeout: 20s
retries: 10

View File

@@ -0,0 +1,137 @@
# ignore: true
# documentation: https://forgejo.org/docs
# slogan: Forgejo is a self-hosted lightweight software forge. Easy to install and low maintenance, it just does the job.
# tags: version control, collaboration, code, hosting, lightweight, runner, mariadb, actions, cicd, ci
# logo: svgs/forgejo.svg
# port: 3000
services:
forgejo:
image: codeberg.org/forgejo/forgejo:8
environment:
- SERVICE_FQDN_FORGEJO_3000
- FORGEJO__server__ROOT_URL=${SERVICE_FQDN_FORGEJO_3000}
- FORGEJO__migrations__ALLOWED_DOMAINS=${FORGEJO__migrations__ALLOWED_DOMAINS}
- FORGEJO__migrations__ALLOW_LOCALNETWORKS=${FORGEJO__migrations__ALLOW_LOCALNETWORKS-false}
- USER_UID=1000
- USER_GID=1000
- FORGEJO__database__DB_TYPE=mysql
- FORGEJO__database__HOST=mariadb
- FORGEJO__database__NAME=${MYSQL_DATABASE-forgejo}
- FORGEJO__database__USER=$SERVICE_USER_MYSQL
- FORGEJO__database__PASSWD=$SERVICE_PASSWORD_MYSQL
- RUNNER_SHARED_SECRET=${RUNNER_SHARED_SECRET-0000000000000000000000000000000000000000}
- FORGEJO__repository__ENABLE_PUSH_CREATE_USER=true
- FORGEJO__repository__DEFAULT_PUSH_CREATE_PRIVATE=false
- FORGEJO__repository__DEFAULT_REPO_UNITS=repo.code,repo.actions
volumes:
- forgejo-data:/data
- forgejo-timezone:/etc/timezone:ro
- forgejo-localtime:/etc/localtime:ro
ports:
- 22222:22
depends_on:
mariadb:
condition: service_healthy
healthcheck:
test: ["CMD", "curl", "-f", "http://127.0.0.1:3000"]
interval: 2s
timeout: 10s
retries: 15
command: >-
bash -c '
/bin/s6-svscan /etc/s6 &
sleep 10 ;
su -c "forgejo forgejo-cli actions register --secret ${RUNNER_SHARED_SECRET}" git ;
sleep infinity
'
mariadb:
image: mariadb:11
volumes:
- forgejo-mariadb-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}
healthcheck:
test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"]
interval: 5s
timeout: 20s
retries: 10
docker-in-docker:
image: docker:dind
hostname: docker
privileged: true
healthcheck:
test: ["CMD", "pgrep", "dockerd"]
interval: 10s
timeout: 30s
retries: 10
environment:
DOCKER_TLS_CERTDIR: /certs
DOCKER_HOST: docker-in-docker
volumes:
- forgejo-did-certs:/certs
runner-register:
image: code.forgejo.org/forgejo/runner:3.5.0
restart: 'no'
links:
- docker-in-docker
- forgejo
environment:
- DOCKER_HOST=tcp://docker-in-docker:2376
- RUNNER_SHARED_SECRET=${RUNNER_SHARED_SECRET}
volumes:
- forgejo-runner-data:/data
- forgejo-timezone:/etc/timezone:ro
- forgejo-localtime:/etc/localtime:ro
healthcheck:
disable: true
user: 0:0
command: >-
bash -ec '
while : ; do
forgejo-runner create-runner-file --connect --instance http://forgejo:3000 --name runner --secret ${RUNNER_SHARED_SECRET} && break ;
sleep 1 ;
done ;
sed -i -e "s|\"labels\": null|\"labels\": [\"docker:docker://node:20-bookworm\", \"ubuntu-22.04:docker://catthehacker/ubuntu:act-22.04\"]|" .runner ;
forgejo-runner generate-config > config.yml ;
sed -i -e "s|network: .*|network: host|" config.yml ;
sed -i -e "s|^ envs:$$| envs:\n DOCKER_HOST: tcp://docker:2376\n DOCKER_TLS_VERIFY: 1\n DOCKER_CERT_PATH: /certs/client|" config.yml ;
sed -i -e "s|^ options:| options: -v /certs/client:/certs/client|" config.yml ;
sed -i -e "s| valid_volumes: \[\]$$| valid_volumes:\n - /certs/client|" config.yml ;
chown -R 1000:1000 /data ;
exit 0
'
runner:
image: code.forgejo.org/forgejo/runner:3.5.0
links:
- docker-in-docker
- forgejo
depends_on:
docker-in-docker:
condition: service_started
environment:
- DOCKER_HOST=tcp://docker:2376
- DOCKER_CERT_PATH=/certs/client
- DOCKER_TLS_VERIFY=1
user: 1000:1000
volumes:
- forgejo-runner-data:/data
- forgejo-did-certs:/certs
- forgejo-timezone:/etc/timezone:ro
- forgejo-localtime:/etc/localtime:ro
healthcheck:
test: ["CMD", "pgrep", "forgejo-runner"]
interval: 10s
timeout: 30s
retries: 10
command: >-
bash -c '
while : ; do test -w .runner && forgejo-runner --config config.yml daemon ; sleep 1 ; done
'

View File

@@ -0,0 +1,137 @@
# ignore: true
# documentation: https://forgejo.org/docs
# slogan: Forgejo is a self-hosted lightweight software forge. Easy to install and low maintenance, it just does the job.
# tags: version control, collaboration, code, hosting, lightweight, runner, mysql, actions, cicd, ci
# logo: svgs/forgejo.svg
# port: 3000
services:
forgejo:
image: codeberg.org/forgejo/forgejo:8
environment:
- SERVICE_FQDN_FORGEJO_3000
- FORGEJO__server__ROOT_URL=${SERVICE_FQDN_FORGEJO_3000}
- FORGEJO__migrations__ALLOWED_DOMAINS=${FORGEJO__migrations__ALLOWED_DOMAINS}
- FORGEJO__migrations__ALLOW_LOCALNETWORKS=${FORGEJO__migrations__ALLOW_LOCALNETWORKS-false}
- USER_UID=1000
- USER_GID=1000
- FORGEJO__database__DB_TYPE=mysql
- FORGEJO__database__HOST=mysql
- FORGEJO__database__NAME=${MYSQL_DATABASE-forgejo}
- FORGEJO__database__USER=$SERVICE_USER_MYSQL
- FORGEJO__database__PASSWD=$SERVICE_PASSWORD_MYSQL
- RUNNER_SHARED_SECRET=${RUNNER_SHARED_SECRET-0000000000000000000000000000000000000000}
- FORGEJO__repository__ENABLE_PUSH_CREATE_USER=true
- FORGEJO__repository__DEFAULT_PUSH_CREATE_PRIVATE=false
- FORGEJO__repository__DEFAULT_REPO_UNITS=repo.code,repo.actions
volumes:
- forgejo-data:/data
- forgejo-timezone:/etc/timezone:ro
- forgejo-localtime:/etc/localtime:ro
ports:
- 22222:22
depends_on:
mysql:
condition: service_healthy
healthcheck:
test: ["CMD", "curl", "-f", "http://127.0.0.1:3000"]
interval: 2s
timeout: 10s
retries: 15
command: >-
bash -c '
/bin/s6-svscan /etc/s6 &
sleep 10 ;
su -c "forgejo forgejo-cli actions register --secret ${RUNNER_SHARED_SECRET}" git ;
sleep infinity
'
mysql:
image: mysql:8
volumes:
- forgejo-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}
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "127.0.0.1"]
interval: 5s
timeout: 20s
retries: 10
docker-in-docker:
image: docker:dind
hostname: docker
privileged: true
healthcheck:
test: ["CMD", "pgrep", "dockerd"]
interval: 10s
timeout: 30s
retries: 10
environment:
DOCKER_TLS_CERTDIR: /certs
DOCKER_HOST: docker-in-docker
volumes:
- forgejo-did-certs:/certs
runner-register:
image: code.forgejo.org/forgejo/runner:3.5.0
restart: 'no'
links:
- docker-in-docker
- forgejo
environment:
- DOCKER_HOST=tcp://docker-in-docker:2376
- RUNNER_SHARED_SECRET=${RUNNER_SHARED_SECRET}
volumes:
- forgejo-runner-data:/data
- forgejo-timezone:/etc/timezone:ro
- forgejo-localtime:/etc/localtime:ro
healthcheck:
disable: true
user: 0:0
command: >-
bash -ec '
while : ; do
forgejo-runner create-runner-file --connect --instance http://forgejo:3000 --name runner --secret ${RUNNER_SHARED_SECRET} && break ;
sleep 1 ;
done ;
sed -i -e "s|\"labels\": null|\"labels\": [\"docker:docker://node:20-bookworm\", \"ubuntu-22.04:docker://catthehacker/ubuntu:act-22.04\"]|" .runner ;
forgejo-runner generate-config > config.yml ;
sed -i -e "s|network: .*|network: host|" config.yml ;
sed -i -e "s|^ envs:$$| envs:\n DOCKER_HOST: tcp://docker:2376\n DOCKER_TLS_VERIFY: 1\n DOCKER_CERT_PATH: /certs/client|" config.yml ;
sed -i -e "s|^ options:| options: -v /certs/client:/certs/client|" config.yml ;
sed -i -e "s| valid_volumes: \[\]$$| valid_volumes:\n - /certs/client|" config.yml ;
chown -R 1000:1000 /data ;
exit 0
'
runner:
image: code.forgejo.org/forgejo/runner:3.5.0
links:
- docker-in-docker
- forgejo
depends_on:
docker-in-docker:
condition: service_started
environment:
- DOCKER_HOST=tcp://docker:2376
- DOCKER_CERT_PATH=/certs/client
- DOCKER_TLS_VERIFY=1
user: 1000:1000
volumes:
- forgejo-runner-data:/data
- forgejo-did-certs:/certs
- forgejo-timezone:/etc/timezone:ro
- forgejo-localtime:/etc/localtime:ro
healthcheck:
test: ["CMD", "pgrep", "forgejo-runner"]
interval: 10s
timeout: 30s
retries: 10
command: >-
bash -c '
while : ; do test -w .runner && forgejo-runner --config config.yml daemon ; sleep 1 ; done
'

View File

@@ -0,0 +1,136 @@
# ignore: true
# documentation: https://forgejo.org/docs
# slogan: Forgejo is a self-hosted lightweight software forge. Easy to install and low maintenance, it just does the job.
# tags: version control, collaboration, code, hosting, lightweight, runner, postresql, actions, cicd, ci
# logo: svgs/forgejo.svg
# port: 3000
services:
forgejo:
image: codeberg.org/forgejo/forgejo:8
environment:
- SERVICE_FQDN_FORGEJO_3000
- FORGEJO__server__ROOT_URL=${SERVICE_FQDN_FORGEJO_3000}
- FORGEJO__migrations__ALLOWED_DOMAINS=${FORGEJO__migrations__ALLOWED_DOMAINS}
- FORGEJO__migrations__ALLOW_LOCALNETWORKS=${FORGEJO__migrations__ALLOW_LOCALNETWORKS-false}
- USER_UID=1000
- USER_GID=1000
- FORGEJO__database__DB_TYPE=postgres
- FORGEJO__database__HOST=postgresql
- FORGEJO__database__NAME=${POSTGRESQL_DATABASE-forgejo}
- FORGEJO__database__USER=$SERVICE_USER_POSTGRESQL
- FORGEJO__database__PASSWD=$SERVICE_PASSWORD_POSTGRESQL
- RUNNER_SHARED_SECRET=${RUNNER_SHARED_SECRET-0000000000000000000000000000000000000000}
- FORGEJO__repository__ENABLE_PUSH_CREATE_USER=true
- FORGEJO__repository__DEFAULT_PUSH_CREATE_PRIVATE=false
- FORGEJO__repository__DEFAULT_REPO_UNITS=repo.code,repo.actions
volumes:
- forgejo-data:/data
- forgejo-timezone:/etc/timezone:ro
- forgejo-localtime:/etc/localtime:ro
ports:
- 22222:22
depends_on:
postgresql:
condition: service_healthy
healthcheck:
test: ["CMD", "curl", "-f", "http://127.0.0.1:3000"]
interval: 2s
timeout: 10s
retries: 15
command: >-
bash -c '
/bin/s6-svscan /etc/s6 &
sleep 10 ;
su -c "forgejo forgejo-cli actions register --secret ${RUNNER_SHARED_SECRET}" git ;
sleep infinity
'
postgresql:
image: postgres:16-alpine
volumes:
- forgejo-postgresql-data:/var/lib/postgresql/data
environment:
- POSTGRES_USER=${SERVICE_USER_POSTGRESQL}
- POSTGRES_PASSWORD=${SERVICE_PASSWORD_POSTGRESQL}
- POSTGRES_DB=${POSTGRESQL_DATABASE}
healthcheck:
test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}"]
interval: 5s
timeout: 20s
retries: 10
docker-in-docker:
image: docker:dind
hostname: docker
privileged: true
healthcheck:
test: ["CMD", "pgrep", "dockerd"]
interval: 10s
timeout: 30s
retries: 10
environment:
DOCKER_TLS_CERTDIR: /certs
DOCKER_HOST: docker-in-docker
volumes:
- forgejo-did-certs:/certs
runner-register:
image: code.forgejo.org/forgejo/runner:3.5.0
restart: 'no'
links:
- docker-in-docker
- forgejo
environment:
- DOCKER_HOST=tcp://docker-in-docker:2376
- RUNNER_SHARED_SECRET=${RUNNER_SHARED_SECRET}
volumes:
- forgejo-runner-data:/data
- forgejo-timezone:/etc/timezone:ro
- forgejo-localtime:/etc/localtime:ro
healthcheck:
disable: true
user: 0:0
command: >-
bash -ec '
while : ; do
forgejo-runner create-runner-file --connect --instance http://forgejo:3000 --name runner --secret ${RUNNER_SHARED_SECRET} && break ;
sleep 1 ;
done ;
sed -i -e "s|\"labels\": null|\"labels\": [\"docker:docker://node:20-bookworm\", \"ubuntu-22.04:docker://catthehacker/ubuntu:act-22.04\"]|" .runner ;
forgejo-runner generate-config > config.yml ;
sed -i -e "s|network: .*|network: host|" config.yml ;
sed -i -e "s|^ envs:$$| envs:\n DOCKER_HOST: tcp://docker:2376\n DOCKER_TLS_VERIFY: 1\n DOCKER_CERT_PATH: /certs/client|" config.yml ;
sed -i -e "s|^ options:| options: -v /certs/client:/certs/client|" config.yml ;
sed -i -e "s| valid_volumes: \[\]$$| valid_volumes:\n - /certs/client|" config.yml ;
chown -R 1000:1000 /data ;
exit 0
'
runner:
image: code.forgejo.org/forgejo/runner:3.5.0
links:
- docker-in-docker
- forgejo
depends_on:
docker-in-docker:
condition: service_started
environment:
- DOCKER_HOST=tcp://docker:2376
- DOCKER_CERT_PATH=/certs/client
- DOCKER_TLS_VERIFY=1
user: 1000:1000
volumes:
- forgejo-runner-data:/data
- forgejo-did-certs:/certs
- forgejo-timezone:/etc/timezone:ro
- forgejo-localtime:/etc/localtime:ro
healthcheck:
test: ["CMD", "pgrep", "forgejo-runner"]
interval: 10s
timeout: 30s
retries: 10
command: >-
bash -c '
while : ; do test -w .runner && forgejo-runner --config config.yml daemon ; sleep 1 ; done
'

View File

@@ -0,0 +1,114 @@
# ignore: true
# documentation: https://forgejo.org/docs
# slogan: Forgejo is a self-hosted lightweight software forge. Easy to install and low maintenance, it just does the job.
# tags: version control, collaboration, code, hosting, lightweight, runner, actions, cicd, ci
# logo: svgs/forgejo.svg
# port: 3000
services:
forgejo:
image: codeberg.org/forgejo/forgejo:8
environment:
- SERVICE_FQDN_FORGEJO_3000
- FORGEJO__server__ROOT_URL=${SERVICE_FQDN_FORGEJO_3000}
- FORGEJO__migrations__ALLOWED_DOMAINS=${FORGEJO__migrations__ALLOWED_DOMAINS}
- FORGEJO__migrations__ALLOW_LOCALNETWORKS=${FORGEJO__migrations__ALLOW_LOCALNETWORKS:-false}
- USER_UID=1000
- USER_GID=1000
- RUNNER_SHARED_SECRET=${RUNNER_SHARED_SECRET-0000000000000000000000000000000000000000}
- FORGEJO__repository__ENABLE_PUSH_CREATE_USER=true
- FORGEJO__repository__DEFAULT_PUSH_CREATE_PRIVATE=false
- FORGEJO__repository__DEFAULT_REPO_UNITS=repo.code,repo.actions
volumes:
- forgejo-data:/data
- forgejo-timezone:/etc/timezone:ro
- forgejo-localtime:/etc/localtime:ro
ports:
- 22222:22
healthcheck:
test: ["CMD", "curl", "-f", "http://127.0.0.1:3000"]
interval: 2s
timeout: 10s
retries: 15
command: >-
bash -c '
/bin/s6-svscan /etc/s6 &
sleep 10 ;
su -c "forgejo forgejo-cli actions register --secret ${RUNNER_SHARED_SECRET}" git ;
sleep infinity
'
docker-in-docker:
image: docker:dind
hostname: docker
privileged: true
healthcheck:
test: ["CMD", "pgrep", "dockerd"]
interval: 10s
timeout: 30s
retries: 10
environment:
DOCKER_TLS_CERTDIR=/certs
DOCKER_HOST=docker-in-docker
volumes:
- forgejo-did-certs:/certs
runner-register:
image: code.forgejo.org/forgejo/runner:3.5.0
restart: 'no'
links:
- docker-in-docker
- forgejo
environment:
- DOCKER_HOST=tcp://docker-in-docker:2376
- RUNNER_SHARED_SECRET=${RUNNER_SHARED_SECRET}
volumes:
- forgejo-runner-data:/data
- forgejo-timezone:/etc/timezone:ro
- forgejo-localtime:/etc/localtime:ro
healthcheck:
disable: true
user: 0:0
command: >-
bash -ec '
while : ; do
forgejo-runner create-runner-file --connect --instance ${SERVICE_FQDN_FORGEJO}:3000 --name runner --secret ${RUNNER_SHARED_SECRET} && break ;
sleep 1 ;
done ;
sed -i -e "s|\"labels\": null|\"labels\": [\"docker:docker://node:20-bookworm\", \"ubuntu-22.04:docker://catthehacker/ubuntu:act-22.04\"]|" .runner ;
forgejo-runner generate-config > config.yml ;
sed -i -e "s|network: .*|network: host|" config.yml ;
sed -i -e "s|^ envs:$$| envs:\n DOCKER_HOST: tcp://docker:2376\n DOCKER_TLS_VERIFY: 1\n DOCKER_CERT_PATH: /certs/client|" config.yml ;
sed -i -e "s|^ options:| options: -v /certs/client:/certs/client|" config.yml ;
sed -i -e "s| valid_volumes: \[\]$$| valid_volumes:\n - /certs/client|" config.yml ;
chown -R 1000:1000 /data ;
exit 0
'
runner:
image: code.forgejo.org/forgejo/runner:3.5.0
links:
- docker-in-docker
- forgejo
depends_on:
docker-in-docker:
condition: service_started
environment:
- DOCKER_HOST=tcp://docker:2376
- DOCKER_CERT_PATH=/certs/client
- DOCKER_TLS_VERIFY=1
user: 1000:1000
volumes:
- forgejo-runner-data:/data
- forgejo-did-certs:/certs
- forgejo-timezone:/etc/timezone:ro
- forgejo-localtime:/etc/localtime:ro
healthcheck:
test: ["CMD", "pgrep", "forgejo-runner"]
interval: 10s
timeout: 30s
retries: 10
command: >-
bash -c '
while : ; do test -w .runner && forgejo-runner --config config.yml daemon ; sleep 1 ; done
'

View File

@@ -0,0 +1,28 @@
# ignore: true
# documentation: https://forgejo.org/docs
# slogan: Forgejo is a self-hosted lightweight software forge. Easy to install and low maintenance, it just does the job.
# tags: version control, collaboration, code, hosting, lightweight
# logo: svgs/forgejo.svg
# port: 3000
services:
forgejo:
image: codeberg.org/forgejo/forgejo:8
environment:
- SERVICE_FQDN_FORGEJO_3000
- FORGEJO__server__ROOT_URL=${SERVICE_FQDN_FORGEJO_3000}
- FORGEJO__migrations__ALLOWED_DOMAINS=${FORGEJO__migrations__ALLOWED_DOMAINS}
- FORGEJO__migrations__ALLOW_LOCALNETWORKS=${FORGEJO__migrations__ALLOW_LOCALNETWORKS-false}
- USER_UID=1000
- USER_GID=1000
ports:
- 22222:22
volumes:
- forgejo-data:/data
- forgejo-timezone:/etc/timezone:ro
- forgejo-localtime:/etc/localtime:ro
healthcheck:
test: ["CMD", "curl", "-f", "http://127.0.0.1:3000"]
interval: 2s
timeout: 10s
retries: 15

View File

@@ -58,6 +58,7 @@ services:
- GITHUB_APP_ID=${GITHUB_APP_ID}
- GITHUB_APP_PRIVATE_KEY=${GITHUB_APP_PRIVATE_KEY}
- PGSSLMODE=${PGSSLMODE:-disable}
- FORCE_HTTPS=${FORCE_HTTPS:-true}
healthcheck:
disable: true

View File

@@ -0,0 +1,46 @@
# documentation: https://github.com/laurent22/joplin/blob/dev/packages/server/README.md
# slogan: Self-hosted sync server for Joplin
# tags: joplin
# logo: svgs/joplin.png
# port: 22300
services:
postgres:
image: 'postgres:16'
volumes:
- joplin-postgresql-data:/var/lib/postgresql/data'
environment:
- POSTGRES_PASSWORD=${SERVICE_PASSWORD_64_POSTGRES}
- POSTGRES_USER=${SERVICE_USER_POSTGRES}
- POSTGRES_DB=joplin
healthcheck:
test:
- CMD
- pg_isready
- -d
- joplin
interval: 10s
timeout: 5s
retries: 5
joplin:
image: 'joplin/server:latest'
platform: 'linux/amd64'
depends_on:
postgres:
condition: service_healthy
environment:
- SERVICE_FQDN_JOPLIN_22300
- APP_BASE_URL=${SERVICE_FQDN_JOPLIN}
- DB_CLIENT=pg
- POSTGRES_PASSWORD=${SERVICE_PASSWORD_64_POSTGRES}
- POSTGRES_DATABASE=joplin
- POSTGRES_USER=${SERVICE_USER_POSTGRES}
- POSTGRES_PORT=5432
- POSTGRES_HOST=postgres
# Default login is "admin@localhost" and password "admin"
healthcheck:
test: ["CMD-SHELL", "bash -c ':> /dev/tcp/127.0.0.1/22300' || exit 1"]
interval: 5s
timeout: 20s
retries: 3

View File

@@ -0,0 +1,54 @@
# documentation: https://www.keycloak.org
# slogan: Keycloak is an open-source Identity and Access Management tool.
# tags: keycloak,identity,access,management,iam,authentication,authorization,security,oauth2,openid-connect,sso,single-sign-on,saml,rbac,ldap,jwt,social-login
# logo: svgs/keycloak.svg
# port: 8080
services:
keycloak:
image: quay.io/keycloak/keycloak:25.0.2
command:
- start
environment:
- SERVICE_FQDN_KEYCLOAK_8080
- TZ=${TIMEZONE:-UTC}
- KEYCLOAK_ADMIN=${SERVICE_USER_ADMIN}
- KEYCLOAK_ADMIN_PASSWORD=${SERVICE_PASSWORD_ADMIN}
- KC_DB=postgres
- KC_DB_USERNAME=${SERVICE_USER_DATABASE}
- KC_DB_PASSWORD=${SERVICE_PASSWORD_64_DATABASE}
- KC_DB_URL_PORT=5432
- KC_DB_URL=jdbc:postgresql://postgres/${POSTGRESQL_DATABASE:-keycloak}
- KC_HOSTNAME=${SERVICE_FQDN_KEYCLOAK}
- KC_HTTP_ENABLED=${KC_HTTP_ENABLED:-true}
- KC_HEALTH_ENABLED=${KC_HEALTH_ENABLED:-true}
- KC_PROXY_HEADERS=${KC_PROXY_HEADERS:-xforwarded}
volumes:
- keycloak-data:/opt/keycloak/data
depends_on:
postgres:
condition: service_healthy
healthcheck:
test:
[
"CMD-SHELL",
"exec 3<>/dev/tcp/127.0.0.1/9000;echo -e 'GET /health/ready HTTP/1.1\r\nhost: http://localhost\r\nConnection: close\r\n\r\n' >&3;if [ $? -eq 0 ]; then echo 'Healthcheck Successful';exit 0;else echo 'Healthcheck Failed';exit 1;fi;",
]
interval: 5s
timeout: 20s
retries: 10
postgres:
image: postgres:16-alpine
volumes:
- keycloak-postgresql-data:/var/lib/postgresql/data
environment:
- POSTGRES_USER=${SERVICE_USER_DATABASE}
- POSTGRES_PASSWORD=${SERVICE_PASSWORD_64_DATABASE}
- POSTGRES_DB=${POSTGRESQL_DATABASE:-keycloak}
healthcheck:
test:
- CMD-SHELL
- pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}
interval: 5s
timeout: 20s
retries: 10

View File

@@ -0,0 +1,31 @@
# documentation: https://www.keycloak.org
# slogan: Keycloak is an open-source Identity and Access Management tool.
# tags: keycloak,identity,access,management,iam,authentication,authorization,security,oauth2,openid-connect,sso,single-sign-on,saml,rbac,ldap,jwt,social-login
# logo: svgs/keycloak.svg
# port: 8080
services:
keycloak:
image: quay.io/keycloak/keycloak:25.0.2
command:
- start
environment:
- SERVICE_FQDN_KEYCLOAK_8080
- TZ=${TIMEZONE:-UTC}
- KEYCLOAK_ADMIN=${SERVICE_USER_ADMIN}
- KEYCLOAK_ADMIN_PASSWORD=${SERVICE_PASSWORD_ADMIN}
- KC_HOSTNAME=${SERVICE_FQDN_KEYCLOAK}
- KC_HTTP_ENABLED=${KC_HTTP_ENABLED:-true}
- KC_HEALTH_ENABLED=${KC_HEALTH_ENABLED:-true}
- KC_PROXY_HEADERS=${KC_PROXY_HEADERS:-xforwarded}
volumes:
- keycloak-data:/opt/keycloak/data
healthcheck:
test:
[
"CMD-SHELL",
"exec 3<>/dev/tcp/127.0.0.1/9000;echo -e 'GET /health/ready HTTP/1.1\r\nhost: http://localhost\r\nConnection: close\r\n\r\n' >&3;if [ $? -eq 0 ]; then echo 'Healthcheck Successful';exit 0;else echo 'Healthcheck Failed';exit 1;fi;",
]
interval: 5s
timeout: 20s
retries: 10

View File

@@ -0,0 +1,21 @@
# documentation: https://docs.linuxserver.io/images/docker-libreoffice/
# slogan: LibreOffice is a free and powerful office suite.
# tags: office,document,spreadsheet,presentation,open-source
# logo: svgs/libreoffice.svg
# port: 3000
services:
libreoffice:
image: lscr.io/linuxserver/libreoffice:latest
environment:
- SERVICE_FQDN_LIBREOFFICE_3000
- PUID=${PUID:-1000}
- PGID=${PGID:-1000}
- TZ=${TZ:-Etc/UTC}
volumes:
- libreoffice-config:/config
healthcheck:
test: ["CMD", "wget", "-q", "--spider", "http://localhost:3000"]
interval: 30s
timeout: 10s
retries: 3

View File

@@ -1,22 +1,31 @@
# ignore: true
# documentation: https://docs.mattermost.com
# slogan: Mattermost is an open source, self-hosted Slack-alternative.
# tags: mattermost,slack,alternative
# logo: svgs/mattermost.svg
# port: 8065
services:
mattermost:
image: mattermost/mattermost-team-edition:9
image: mattermost/mattermost-team-edition:release-10
platform: linux/amd64
volumes:
- mattermost-data:/mattermost
environment:
- SERVICE_FQDN_MATTERMOST
- SERVICE_FQDN_MATTERMOST_8065
- MM_SERVICESETTINGS_SITEURL=${SERVICE_FQDN_MATTERMOST}
- TZ=${TZ:-UTC}
- MM_SQLSETTINGS_DRIVERNAME=postgres
- MM_SQLSETTINGS_DATASOURCE=postgres://$SERVICE_USER_POSTGRES:$SERVICE_PASSWORD_POSTGRES@postgres:5432/$POSTGRES_DB?sslmode=disable&connect_timeout=10
- MM_BLEVESETTINGS_INDEXDIR=/mattermost/bleve-indexes
- MM_SERVICESETTINGS_SITEURL=$SERVICE_FQDN_MATTERMOST
depends_on:
- postgres
postgres:
condition: service_healthy
healthcheck:
test: ["CMD", "curl", "-f", "http://127.0.0.1:8065"]
interval: 5s
timeout: 20s
retries: 10
postgres:
image: postgres:16-alpine
volumes:

View File

@@ -0,0 +1,120 @@
# documentation: https://www.mautic.org/
# slogan: Mautic v5 Open Source Marketing Automation
# tags: php,mautic,marketing,automation,email,service,5,open,source,crm
# logo: svgs/mautic.svg
# port: 80
services:
mysql:
image: 'mysql:8.0'
environment:
- 'MYSQL_ROOT_PASSWORD=${SERVICE_PASSWORD_64_MYSQLROOT}'
- 'MYSQL_DATABASE=${MYSQL_DATABASE:-mautic}'
- 'MYSQL_USER=${SERVICE_USER_MYSQL}'
- 'MYSQL_PASSWORD=${SERVICE_PASSWORD_64_MYSQL}'
volumes:
- 'mysql-data:/var/lib/mysql'
healthcheck:
test: 'mysqladmin ping --silent --user=$$SERVICE_USER_MYSQL --password=$$SERVICE_PASSWORD_64_MYSQL'
start_period: 30s
interval: 10s
timeout: 5s
retries: 5
rabbitmq:
image: 'rabbitmq:3'
environment:
- 'RABBITMQ_DEFAULT_VHOST=${RABBITMQ_DEFAULT_VHOST:-mautic}'
healthcheck:
test: rabbitmq-diagnostics -q ping
interval: 5s
timeout: 30s
retries: 10
volumes:
- 'rabbitmq-data:/var/lib/rabbitmq'
mautic_web:
image: 'mautic/mautic:latest'
volumes:
- 'mautic_data/config:/var/www/html/config:z'
- 'mautic_data/logs:/var/www/html/var/logs:z'
- 'mautic_data/media/files:/var/www/html/docroot/media/files:z'
- 'mautic_data/media/images:/var/www/html/docroot/media/images:z'
- 'mautic_data/plugins:/var/www/html/docroot/plugins:z'
- 'mautic_data/vendor:/var/www/html/vendor:z'
- 'mautic_data/bin:/var/www/html/bin:z'
- 'mautic_data/cron:/opt/mautic/cron:z'
environment:
- SERVICE_FQDN_MAUTIC_80
- 'DOCKER_MAUTIC_LOAD_TEST_DATA=${MAUTIC_LOAD_TEST_DATA:-false}'
- 'DOCKER_MAUTIC_RUN_MIGRATIONS=${MAUTIC_RUN_MIGRATIONS:-false}'
- 'MAUTIC_DB_HOST=${MYSQL_HOST:-mysql}'
- 'MAUTIC_DB_PORT=${MYSQL_PORT:-3306}'
- 'MAUTIC_DB_DATABASE=${MYSQL_DATABASE:-mautic}'
- 'MAUTIC_DB_USER=${SERVICE_USER_MYSQL}'
- 'MAUTIC_DB_PASSWORD=${SERVICE_PASSWORD_64_MYSQL}'
- 'MAUTIC_MESSENGER_DSN_EMAIL=${MAUTIC_MESSENGER_DSN_EMAIL:-amqp://guest:guest@rabbitmq:5672/mautic/messages}'
- 'MAUTIC_MESSENGER_DSN_HIT=${MAUTIC_MESSENGER_DSN_HIT:-amqp://guest:guest@rabbitmq:5672/mautic/messages}'
healthcheck:
test:
- CMD
- curl
- '-f'
- 'http://localhost'
interval: 15s
timeout: 10s
retries: 15
mautic_cron:
image: 'mautic/mautic:latest'
volumes:
- 'mautic_data/config:/var/www/html/config:z'
- 'mautic_data/logs:/var/www/html/var/logs:z'
- 'mautic_data/media/files:/var/www/html/docroot/media/files:z'
- 'mautic_data/media/images:/var/www/html/docroot/media/images:z'
- 'mautic_data/plugins:/var/www/html/docroot/plugins:z'
- 'mautic_data/vendor:/var/www/html/vendor:z'
- 'mautic_data/bin:/var/www/html/bin:z'
- 'mautic_data/cron:/opt/mautic/cron:z'
environment:
- DOCKER_MAUTIC_ROLE=mautic_cron
- 'MAUTIC_DB_HOST=${MYSQL_HOST:-mysql}'
- 'MAUTIC_DB_PORT=${MYSQL_PORT:-3306}'
- 'MAUTIC_DB_DATABASE=${MYSQL_DATABASE:-mautic}'
- 'MAUTIC_DB_USER=${SERVICE_USER_MYSQL}'
- 'MAUTIC_DB_PASSWORD=${SERVICE_PASSWORD_64_MYSQL}'
- 'MAUTIC_MESSENGER_DSN_EMAIL=${MAUTIC_MESSENGER_DSN_EMAIL:-amqp://guest:guest@rabbitmq:5672/mautic/messages}'
- 'MAUTIC_MESSENGER_DSN_HIT=${MAUTIC_MESSENGER_DSN_HIT:-amqp://guest:guest@rabbitmq:5672/mautic/messages}'
depends_on:
mautic_web:
condition: service_healthy
healthcheck:
test: ["CMD-SHELL", "exit 0"]
interval: 5s
timeout: 10s
retries: 15
mautic_worker:
image: 'mautic/mautic:latest'
volumes:
- 'mautic_data/config:/var/www/html/config:z'
- 'mautic_data/logs:/var/www/html/var/logs:z'
- 'mautic_data/media/files:/var/www/html/docroot/media/files:z'
- 'mautic_data/media/images:/var/www/html/docroot/media/images:z'
- 'mautic_data/plugins:/var/www/html/docroot/plugins:z'
- 'mautic_data/vendor:/var/www/html/vendor:z'
- 'mautic_data/bin:/var/www/html/bin:z'
- 'mautic_data/cron:/opt/mautic/cron:z'
environment:
- DOCKER_MAUTIC_ROLE=mautic_worker
- 'MAUTIC_DB_HOST=${MYSQL_HOST:-mysql}'
- 'MAUTIC_DB_PORT=${MYSQL_PORT:-3306}'
- 'MAUTIC_DB_DATABASE=${MYSQL_DATABASE:-mautic}'
- 'MAUTIC_DB_USER=${SERVICE_USER_MYSQL}'
- 'MAUTIC_DB_PASSWORD=${SERVICE_PASSWORD_64_MYSQL}'
- 'MAUTIC_MESSENGER_DSN_EMAIL=${MAUTIC_MESSENGER_DSN_EMAIL:-amqp://guest:guest@rabbitmq:5672/mautic/messages}'
- 'MAUTIC_MESSENGER_DSN_HIT=${MAUTIC_MESSENGER_DSN_HIT:-amqp://guest:guest@rabbitmq:5672/mautic/messages}'
depends_on:
mautic_web:
condition: service_healthy
healthcheck:
test: ["CMD-SHELL", "exit 0"]
interval: 5s
timeout: 10s
retries: 15

View File

@@ -0,0 +1,43 @@
# documentation: https://docs.onedev.io/
# slogan: Git server with CI/CD, kanban, and packages. Seamless integration. Unparalleled experience.
# tags: git, scm, ci, cd, kanban, packages, devops, collaboration, code, repository, management
# logo: svgs/onedev.svg
# port: 6610
services:
onedev:
image: 1dev/server:latest
volumes:
- onedev-docker-sock:/var/run/docker.sock
- onedev-data:/opt/onedev
environment:
- SERVICE_FQDN_ONEDEV_6610
- hibernate_dialect=io.onedev.server.persistence.PostgreSQLDialect
- hibernate_connection_driver_class=org.postgresql.Driver
- hibernate_connection_url=jdbc:postgresql://postgres:5432/${POSTGRESQL_DATABASE:-onedev}
- hibernate_connection_username=${SERVICE_USER_DATABASE}
- hibernate_connection_password=${SERVICE_PASSWORD_64_DATABASE}
- initial_user=${SERVICE_USER_ONEDEV}
- initial_password=${SERVICE_PASSWORD_ONEDEV}
- initial_email=${ONEDEV_EMAIL:-mail@example.com}
- initial_server_url=${SERVICE_FQDN_ONEDEV}
- initial_ssh_root_url=${SSH_ROOT_URL:-ssh://changeme:22}
depends_on:
postgres:
condition: service_healthy
healthcheck:
test: ["CMD", "true"]
postgres:
image: postgres:16-alpine
volumes:
- onedev-postgresql-data:/var/lib/postgresql/data
environment:
- POSTGRES_USER=${SERVICE_USER_DATABASE}
- POSTGRES_PASSWORD=${SERVICE_PASSWORD_64_DATABASE}
- POSTGRES_DB=${POSTGRESQL_DATABASE:-onedev}
healthcheck:
test: ["CMD-SHELL", "pg_isready"]
interval: 5s
timeout: 20s
retries: 10

View File

@@ -0,0 +1,19 @@
# documentation: https://docs.organizr.app/
# slogan: Homelab Services Organizer
# tags: tool
# logo: svgs/organizr.png
# port: 80
services:
organizr:
image: organizr/organizr:latest
environment:
- SERVICE_FQDN_ORGANIZR_80
- branch=${branch:-v2-master}
volumes:
- organizr-data:/config
healthcheck:
test: ["CMD-SHELL", "curl -sf http://localhost:80 || exit 1"]
interval: 10s
timeout: 1s
retries: 3

View File

@@ -0,0 +1,43 @@
# documentation: https://docs.paperless-ngx.com/configuration/
# slogan: Paperless-ngx is a community-supported open-source document management system that transforms your physical documents into a searchable online archive so you can keep, well, less paper.
# logo: svgs/paperless.svg
# port: 8000
services:
redis:
image: docker.io/library/redis:7.4
volumes:
- paperless-redis:/data
healthcheck:
test: ["CMD", "redis-cli", "ping"]
timeout: 10s
retries: 3
paperless:
image: paperlessngx/paperless-ngx:latest
depends_on:
redis:
condition: service_healthy
healthcheck:
test: ["CMD", "curl", "-fs", "-S", "--max-time", "2", "http://localhost:8000"]
interval: 30s
timeout: 10s
retries: 5
volumes:
- paperless-data:/usr/src/paperless/data
- paperless-media:/usr/src/paperless/media
- type: bind
source: ./export
target: /usr/src/paperless/export
is_directory: true
- type: bind
source: ./consume
target: /usr/src/paperless/consume
is_directory: true
environment:
- SERVICE_FQDN_PAPERLESS_8000
- PAPERLESS_URL=$SERVICE_FQDN_PAPERLESS_8000
- PAPERLESS_ADMIN_PASSWORD=${SERVICE_PASSWORD_PAPERLESS}
- PAPERLESS_ADMIN_USER=${SERVICE_USER_PAPERLESS}
- PAPERLESS_REDIS=redis://redis:6379
- PAPERLESS_SECRET_KEY=${SERVICE_REALBASE64_64_PAPERLESS}

View File

@@ -1940,6 +1940,7 @@ services:
- DEPLOYMENT=hobby
- SITE_URL=$SERVICE_FQDN_WEB
- SECRET_KEY=$SERVICE_BASE64_64_SECRETKEY
- 'ENCRYPTION_SALT_KEYS=${SERVICE_ENCRYPTION_SALT_KEYS:-00beef0000beef0000beef0000beef00}'
depends_on:
- db
- redis
@@ -1967,6 +1968,7 @@ services:
- DEPLOYMENT=hobby
- SITE_URL=$SERVICE_FQDN_WEB
- SECRET_KEY=$SERVICE_BASE64_64_SECRETKEY
- 'ENCRYPTION_SALT_KEYS=${SERVICE_ENCRYPTION_SALT_KEYS:-00beef0000beef0000beef0000beef00}'
depends_on:
- db
- redis
@@ -1998,6 +2000,7 @@ services:
- CLICKHOUSE_VERIFY=false
- SITE_URL=$SERVICE_FQDN_WEB
- SECRET_KEY=$SERVICE_BASE64_64_SECRETKEY
- 'ENCRYPTION_SALT_KEYS=${SERVICE_ENCRYPTION_SALT_KEYS:-00beef0000beef0000beef0000beef00}'
depends_on:
- db
- redis
@@ -2026,6 +2029,7 @@ services:
# - DEPLOYMENT=hobby
# - SITE_URL=$SERVICE_FQDN_WEB
# - SECRET_KEY=$SERVICE_BASE64_64_SECRETKEY
# - 'ENCRYPTION_SALT_KEYS=${SERVICE_ENCRYPTION_SALT_KEYS:-00beef0000beef0000beef0000beef00}'
# depends_on:
# - db
# - redis
@@ -2109,6 +2113,7 @@ services:
- DEPLOYMENT=hobby
- SITE_URL=$SERVICE_FQDN_WEB
- SECRET_KEY=$SERVICE_BASE64_64_SECRETKEY
- 'ENCRYPTION_SALT_KEYS=${SERVICE_ENCRYPTION_SALT_KEYS:-00beef0000beef0000beef0000beef00}'
- TEMPORAL_HOST=temporal
depends_on:
- db

View File

@@ -7,6 +7,7 @@
services:
rabbitmq:
image: rabbitmq:3-management
hostname: "rabbitmq"
environment:
- SERVICE_FQDN_RABBITMQ_15672
- RABBITMQ_DEFAULT_USER=$SERVICE_USER_RABBITMQ
@@ -19,3 +20,5 @@ services:
interval: 5s
timeout: 30s
retries: 10
volumes:
- rabbitmq-data:/var/lib/rabbitmq/

View File

@@ -10,12 +10,12 @@ services:
environment:
- SERVICE_FQDN_REACTIVERESUME_3000
- PUBLIC_URL=$SERVICE_FQDN_REACTIVERESUME
- STORAGE_URL=http://minio
- 'STORAGE_URL=${SERVICE_FQDN_MINIO}/default'
- DATABASE_URL=postgresql://$SERVICE_USER_POSTGRES:$SERVICE_PASSWORD_POSTGRES@postgres:5432/${POSTGRES_DB:-postgres}
- ACCESS_TOKEN_SECRET=$SERVICE_PASSWORD_ACCESSTOKEN
- REFRESH_TOKEN_SECRET=$SERVICE_PASSWORD_REFRESHTOKEN
- CHROME_TOKEN=$SERVICE_PASSWORD_CHROMETOKEN
- CHROME_URL=ws://chrome:3000
- CHROME_URL=ws://chrome:3000/chrome
- REDIS_URL=redis://redis:6379
- STORAGE_ENDPOINT=minio
- STORAGE_PORT=9000
@@ -24,8 +24,8 @@ services:
- STORAGE_ACCESS_KEY=$SERVICE_USER_MINIO
- STORAGE_SECRET_KEY=$SERVICE_PASSWORD_MINIO
- STORAGE_USE_SSL=false
- DISABLE_SIGNUPS=$SERVICE_DISABLE_SIGNUPS
- DISABLE_EMAIL_AUTH=$SERVICE_DISABLE_EMAIL_AUTH
- 'DISABLE_SIGNUPS=${SERVICE_DISABLE_SIGNUPS:-false}'
- 'DISABLE_EMAIL_AUTH=${SERVICE_DISABLE_EMAIL_AUTH:-false}'
depends_on:
- postgres
- minio
@@ -45,9 +45,10 @@ services:
retries: 10
minio:
image: quay.io/minio/minio:latest
image: minio/minio
command: server /data --console-address ":9001"
environment:
- SERVICE_FQDN_MINIO_9000
- MINIO_ROOT_USER=$SERVICE_USER_MINIO
- MINIO_ROOT_PASSWORD=$SERVICE_PASSWORD_MINIO
volumes:

View File

@@ -0,0 +1,23 @@
# documentation: https://docs.soketi.app
# slogan: Soketi is your simple, fast, and resilient open-source WebSockets server.
# tags: websockets,open,source,messaging
# logo: svgs/soketi.jpeg
# port: 6001
services:
soketi:
image: "quay.io/soketi/soketi:1.6-16-debian"
environment:
- SERVICE_FQDN_SOKETI_6001
- SOKETI_DEBUG=${DEBUG:-0}
- SOKETI_DEFAULT_APP_ID=${SERVICE_USER_SOKETI}
- SOKETI_DEFAULT_APP_KEY=${SERVICE_REALBASE64_64_SOKETIKEY}
- SOKETI_DEFAULT_APP_SECRET=${SERVICE_REALBASE64_64_SOKETISECRET}
- SOKETI_PUSHER_SCHEME=${SOKETI_PUSHER_SCHEME:-https}
- SOKETI_DEFAULT_APP_ENABLE_CLIENT_MESSAGES=${DEFAULT_APP_ENABLE_CLIENT_MESSAGES}
healthcheck:
test: ["CMD-SHELL", "bash -c ':> /dev/tcp/127.0.0.1/6001' || exit 1"]
interval: 5s
timeout: 20s
retries: 3

View File

@@ -0,0 +1,40 @@
# documentation: https://supertokens.com/docs/guides
# slogan: An open-source authentication solution that simplifies the implementation of secure user authentication and session management for web and mobile applications.
# tags: supertokens,login,authentication,authorization,oauth,user-management,session-management,access-control,otp,magic-link,passwordless
# logo: svgs/supertokens.svg
# port: 3567
services:
supertokens:
image: 'registry.supertokens.io/supertokens/supertokens-mysql:latest'
depends_on:
mysql:
condition: service_healthy
environment:
- SERVICE_FQDN_SUPERTOKENS_3567
- API_KEYS=${API_KEYS:-}
- MYSQL_CONNECTION_URI=mysql://$SERVICE_USER_MYSQL:$SERVICE_PASSWORD_MYSQL@mysql:3306/${MYSQL_DATABASE:-supertokens}
healthcheck:
test: "bash -c 'exec 3<>/dev/tcp/127.0.0.1/3567 && echo -e \"GET /hello HTTP/1.1\\r\\nhost: 127.0.0.1:3567\\r\\nConnection: close\\r\\n\\r\\n\" >&3 && cat <&3 | grep \"Hello\"'\n"
interval: 10s
timeout: 5s
retries: 5
mysql:
image: 'mysql:latest'
environment:
- MYSQL_ROOT_PASSWORD=$SERVICE_PASSWORD_MYSQL
- MYSQL_USER=$SERVICE_USER_MYSQL
- MYSQL_PASSWORD=$SERVICE_PASSWORD_MYSQL
- MYSQL_DATABASE=${MYSQL_DATABASE:-supertokens}
volumes:
- 'supertokens-mysql-data:/var/lib/mysql'
healthcheck:
test:
- CMD
- mysqladmin
- ping
- '-h'
- localhost
timeout: 20s
retries: 10

View File

@@ -0,0 +1,34 @@
# documentation: https://supertokens.com/docs/guides
# slogan: An open-source authentication solution that simplifies the implementation of secure user authentication and session management for web and mobile applications.
# tags: supertokens,login,authentication,authorization,oauth,user-management,session-management,access-control,otp,magic-link,passwordless
# logo: svgs/supertokens.svg
# port: 3567
services:
supertokens:
image: registry.supertokens.io/supertokens/supertokens-postgresql:latest
depends_on:
postgres:
condition: service_healthy
environment:
- SERVICE_FQDN_SUPERTOKENS_3567
- API_KEYS=${API_KEYS:-}
- POSTGRESQL_CONNECTION_URI="postgresql://$SERVICE_USER_POSTGRESQL:$SERVICE_PASSWORD_POSTGRESQL@postgres:5432/${POSTGRES_DB:-supertokens}"
healthcheck:
test: "bash -c 'exec 3<>/dev/tcp/127.0.0.1/3567 && echo -e \"GET /hello HTTP/1.1\\r\\nhost: 127.0.0.1:3567\\r\\nConnection: close\\r\\n\\r\\n\" >&3 && cat <&3 | grep \"Hello\"'\n"
interval: 10s
timeout: 5s
retries: 5
postgres:
image: postgres:16
environment:
- POSTGRES_USER=$SERVICE_USER_POSTGRESQL
- POSTGRES_PASSWORD=$SERVICE_PASSWORD_POSTGRESQL
- POSTGRES_DB=${POSTGRES_DB:-supertokens}
volumes:
- supertokens-postgres-data:/var/lib/postgresql/data
healthcheck:
test: ["CMD", "pg_isready", "-U", "$SERVICE_USER_POSTGRESQL", "-d", "${POSTGRES_DB:-supertokens}"]
interval: 5s
timeout: 5s
retries: 5

View File

@@ -1,98 +1,124 @@
# documentation: https://www.windmill.dev/docs/
# slogan: Windmill is a developer platform to build production-grade multi-steps automations and internal apps.\
# info: Login as admin@windmill.dev / changeme to setup the instance & accounts and give yourself super-admin privileges.
# slogan: Windmill is a developer platform to build production-grade multi-steps automations and internal apps.
# tags: windmill,workflow,automation,developer,platform
# logo: svgs/windmill.svg
# port: 8000
version: "3.7"
services:
db:
image: postgres:16
shm_size: 1g
restart: unless-stopped
volumes:
- db_data:/var/lib/postgresql/data
- db-data:/var/lib/postgresql/data
environment:
POSTGRES_PASSWORD: $SERVICE_PASSWORD_WINDMILL_POSTGRES
POSTGRES_DB: windmill
- POSTGRES_PASSWORD=$SERVICE_PASSWORD_POSTGRES
- POSTGRES_DB=${POSTGRES_DB:-windmill}
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 10s
timeout: 5s
retries: 5
windmill_server:
windmill-server:
image: ghcr.io/windmill-labs/windmill:main
environment:
- SERVICE_FQDN_WINDMILL
- DATABASE_URL=postgres://postgres:$SERVICE_PASSWORD_WINDMILL_POSTGRES@db/windmill
- MODE=server
- SERVICE_FQDN_WINDMILL_8000
- DATABASE_URL=postgres://postgres:$SERVICE_PASSWORD_POSTGRES@db/windmill
- MODE=${MODE:-server}
- BASE_URL=$SERVICE_FQDN_WINDMILL
depends_on:
db:
condition: service_healthy
volumes:
- worker_logs:/tmp/windmill/logs
- worker-logs:/tmp/windmill/logs
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8000/api/version || exit 1"]
interval: 30s
timeout: 10s
retries: 3
windmill_worker_1:
windmill-worker-1:
image: ghcr.io/windmill-labs/windmill:main
environment:
- DATABASE_URL=postgres://postgres:$SERVICE_PASSWORD_WINDMILL_POSTGRES@db/windmill
- MODE=worker
- WORKER_GROUP=default
- DATABASE_URL=postgres://postgres:$SERVICE_PASSWORD_POSTGRES@db/windmill
- MODE=${MODE:-worker}
- WORKER_GROUP=${WORKER_GROUP:-default}
depends_on:
db:
condition: service_healthy
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- worker_dependency_cache:/tmp/windmill/cache
- worker_logs:/tmp/windmill/logs
- worker-dependency-cache:/tmp/windmill/cache
- worker-logs:/tmp/windmill/logs
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8000/api/version || exit 1"]
interval: 30s
timeout: 10s
retries: 3
windmill_worker_2:
windmill-worker-2:
image: ghcr.io/windmill-labs/windmill:main
environment:
- DATABASE_URL=postgres://postgres:$SERVICE_PASSWORD_WINDMILL_POSTGRES@db/windmill
- MODE=worker
- WORKER_GROUP=default
- DATABASE_URL=postgres://postgres:$SERVICE_PASSWORD_POSTGRES@db/windmill
- MODE=${MODE:-worker}
- WORKER_GROUP=${WORKER_GROUP:-default}
depends_on:
db:
condition: service_healthy
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- worker_dependency_cache:/tmp/windmill/cache
- worker_logs:/tmp/windmill/logs
- worker-dependency-cache:/tmp/windmill/cache
- worker-logs:/tmp/windmill/logs
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8000/api/version || exit 1"]
interval: 30s
timeout: 10s
retries: 3
windmill_worker_3:
windmill-worker-3:
image: ghcr.io/windmill-labs/windmill:main
environment:
- DATABASE_URL=postgres://postgres:$SERVICE_PASSWORD_WINDMILL_POSTGRES@db/windmill
- MODE=worker
- WORKER_GROUP=default
- DATABASE_URL=postgres://postgres:$SERVICE_PASSWORD_POSTGRES@db/windmill
- MODE=${MODE:-worker}
- WORKER_GROUP=${WORKER_GROUP:-default}
depends_on:
db:
condition: service_healthy
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- worker_dependency_cache:/tmp/windmill/cache
- worker_logs:/tmp/windmill/logs
- worker-dependency-cache:/tmp/windmill/cache
- worker-logs:/tmp/windmill/logs
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8000/api/version || exit 1"]
interval: 30s
timeout: 10s
retries: 3
windmill_worker_native:
windmill-worker-native:
image: ghcr.io/windmill-labs/windmill:main
environment:
- DATABASE_URL=postgres://postgres:$SERVICE_PASSWORD_WINDMILL_POSTGRES@db/windmill
- MODE=worker
- WORKER_GROUP=native
- NUM_WORKERS=8
- SLEEP_QUEUE=200
- DATABASE_URL=postgres://postgres:$SERVICE_PASSWORD_POSTGRES@db/windmill
- MODE=${MODE:-worker}
- WORKER_GROUP=${WORKER_GROUP:-native}
- NUM_WORKERS=${NUM_WORKERS:-8}
- SLEEP_QUEUE=${SLEEP_QUEUE:-200}
depends_on:
db:
condition: service_healthy
volumes:
- worker_logs:/tmp/windmill/logs
- worker-logs:/tmp/windmill/logs
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8000/api/version || exit 1"]
interval: 30s
timeout: 10s
retries: 3
lsp:
image: ghcr.io/windmill-labs/windmill-lsp:latest
volumes:
- lsp_cache:/root/.cache
- lsp-cache:/root/.cache
healthcheck:
test: ["CMD-SHELL", "exit 0"]
interval: 30s
timeout: 10s
retries: 3

File diff suppressed because one or more lines are too long

View File

@@ -1,10 +1,9 @@
<?php
use App\Actions\Service\DeleteService;
use App\Jobs\DeleteResourceJob;
use App\Models\Application;
use App\Models\ApplicationPreview;
use App\Models\GithubApp;
use App\Models\Server;
use App\Models\Service;
use App\Models\StandaloneDocker;
use Illuminate\Support\Collection;
@@ -93,6 +92,7 @@ services:
environment:
- SERVICE_FQDN_ACTIVEPIECES
- AP_API_KEY=$SERVICE_PASSWORD_64_APIKEY
- AP_URL=$SERVICE_URL_ACTIVEPIECES
- AP_ENCRYPTION_KEY=$SERVICE_PASSWORD_ENCRYPTIONKEY
- AP_ENGINE_EXECUTABLE_PATH=dist/packages/engine/main.js
- AP_ENVIRONMENT=prod
@@ -165,7 +165,7 @@ services:
afterEach(function () {
// $this->applicationPreview->forceDelete();
$this->application->forceDelete();
DeleteService::run($this->service);
DeleteResourceJob::dispatchSync($this->service);
$this->service->forceDelete();
});

View File

@@ -1,10 +1,10 @@
{
"coolify": {
"v4": {
"version": "4.0.0-beta.357"
"version": "4.0.0-beta.358"
},
"nightly": {
"version": "4.0.0-beta.358"
"version": "4.0.0-beta.359"
},
"helper": {
"version": "1.0.2"