chore(seeding): seed railpack examples from new repo layout

Move all git examples into ApplicationSeeder on railpack, using the
reorganized coollabsio/coolify-examples main branch, and drop the
separate Railpack Examples project. Add DEV_SEED_IP to set the IP for
seeded sslip.io domains (e.g. a Tailscale IP).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Andras BacsaiandClaude Opus 5.5 committed 2026-10-12 14:26:19 +02:00
1 parent a7e1cecfa7
commit b13ecb0542
11 files changed
+194 -867

No files matched your search

+3
View File
@@ -9,6 +9,9 @@ APP_DEBUG=true
SSH_MUX_ENABLED=true
COOLIFY_CONTAINER_ROLE=all
DEV_SENTINEL_URL=
# IPv4 address for seeded sslip.io domains (server wildcard domain and example apps). Empty uses 127.0.0.1.
# Set it to a LAN or Tailscale IP to reach seeded deployments from other devices, then reseed.
DEV_SEED_IP=
# PostgreSQL Database Configuration
DB_DATABASE=coolify
+2
View File
@@ -14,6 +14,8 @@ return [
// devHostDockerPath() uses them only for that server. The defaults are the legacy docker-compose.dev.yml names.
'dev_data_volume' => env('DEV_COOLIFY_DATA_VOLUME', 'coolify_dev_coolify_data'),
'dev_backups_volume' => env('DEV_COOLIFY_BACKUPS_VOLUME', 'coolify_dev_backups_data'),
// Development only: IP for the seeded sslip.io wildcard domain and application domains (for example a Tailscale IP).
'dev_seed_ip' => env('DEV_SEED_IP') ?: '127.0.0.1',
'registry_url' => env('REGISTRY_URL', 'docker.io'),
'helper_image' => env('HELPER_IMAGE', env('REGISTRY_URL', 'docker.io').'/coollabsio/coolify-helper'),
'is_windows_docker_desktop' => env('IS_WINDOWS_DOCKER_DESKTOP', false),
+90 -70
View File
@@ -10,18 +10,24 @@ use Illuminate\Database\Seeder;
class ApplicationSeeder extends Seeder
{
public const EXAMPLES_REPOSITORY = 'coollabsio/coolify-examples';
public const EXAMPLES_REPOSITORY_PROJECT_ID = 603035348;
/**
* Run the database seeds.
*/
public function run(): void
{
$sslipHost = ServerSettingSeeder::sslipHost();
Application::create([
'uuid' => 'docker-compose',
'name' => 'Docker Compose Example',
'repository_project_id' => 603035348,
'git_repository' => 'coollabsio/coolify-examples',
'repository_project_id' => self::EXAMPLES_REPOSITORY_PROJECT_ID,
'git_repository' => self::EXAMPLES_REPOSITORY,
'git_branch' => 'main',
'base_directory' => '/docker-compose',
'base_directory' => '/internal/compose',
'docker_compose_location' => '/docker-compose-test.yaml',
'build_pack' => 'dockercompose',
'ports_exposes' => '80',
@@ -31,30 +37,14 @@ class ApplicationSeeder extends Seeder
'source_id' => 1,
'source_type' => GithubApp::class,
]);
Application::create([
'uuid' => 'nodejs',
'name' => 'NodeJS Fastify Example',
'fqdn' => 'http://nodejs.127.0.0.1.sslip.io',
'repository_project_id' => 603035348,
'git_repository' => 'coollabsio/coolify-examples',
'git_branch' => 'main',
'base_directory' => '/nodejs',
'build_pack' => 'nixpacks',
'ports_exposes' => '3000',
'environment_id' => 1,
'destination_id' => 0,
'destination_type' => StandaloneDocker::class,
'source_id' => 1,
'source_type' => GithubApp::class,
]);
Application::create([
'uuid' => 'dockerfile',
'name' => 'Dockerfile Example',
'fqdn' => 'http://dockerfile.127.0.0.1.sslip.io',
'repository_project_id' => 603035348,
'git_repository' => 'coollabsio/coolify-examples',
'fqdn' => "http://dockerfile.{$sslipHost}",
'repository_project_id' => self::EXAMPLES_REPOSITORY_PROJECT_ID,
'git_repository' => self::EXAMPLES_REPOSITORY,
'git_branch' => 'main',
'base_directory' => '/dockerfile',
'base_directory' => '/dockerfile/single-stage',
'build_pack' => 'dockerfile',
'ports_exposes' => '80',
'environment_id' => 1,
@@ -66,7 +56,7 @@ class ApplicationSeeder extends Seeder
Application::create([
'uuid' => 'dockerfile-pure',
'name' => 'Pure Dockerfile Example',
'fqdn' => 'http://pure-dockerfile.127.0.0.1.sslip.io',
'fqdn' => "http://pure-dockerfile.{$sslipHost}",
'git_repository' => 'coollabsio/coolify',
'git_branch' => 'main',
'git_commit_sha' => 'HEAD',
@@ -99,51 +89,81 @@ CMD ["nginx", "-g", "daemon off;"]
CMD ["sh", "-c", "echo Crashing in 5 seconds... && sleep 5 && exit 1"]
',
]);
Application::create([
'uuid' => 'github-deploy-key',
'name' => 'GitHub Deploy Key Example',
'fqdn' => 'http://github-deploy-key.127.0.0.1.sslip.io',
'git_repository' => 'git@github.com:coollabsio/coolify-examples-deploy-key.git',
'git_branch' => 'main',
'build_pack' => 'nixpacks',
'ports_exposes' => '80',
'environment_id' => 1,
'destination_id' => 0,
'destination_type' => StandaloneDocker::class,
'source_id' => 0,
'source_type' => GithubApp::class,
'private_key_id' => 1,
]);
Application::create([
'uuid' => 'gitlab-deploy-key',
'name' => 'GitLab Deploy Key Example',
'fqdn' => 'http://gitlab-deploy-key.127.0.0.1.sslip.io',
'git_repository' => 'git@gitlab.com:coollabsio/php-example.git',
'git_branch' => 'main',
'build_pack' => 'nixpacks',
'ports_exposes' => '80',
'environment_id' => 1,
'destination_id' => 0,
'destination_type' => StandaloneDocker::class,
'source_id' => 1,
'source_type' => GitlabApp::class,
'private_key_id' => 1,
]);
Application::create([
'uuid' => 'gitlab-public-example',
'name' => 'GitLab Public Example',
'fqdn' => 'http://gitlab-public.127.0.0.1.sslip.io',
'git_repository' => 'https://gitlab.com/andrasbacsai/coolify-examples.git',
'base_directory' => '/astro/static',
'publish_directory' => '/dist',
'git_branch' => 'main',
'build_pack' => 'nixpacks',
'ports_exposes' => '80',
'environment_id' => 1,
'destination_id' => 0,
'destination_type' => StandaloneDocker::class,
'source_id' => 1,
'source_type' => GitlabApp::class,
]);
foreach (self::railpackExamples() as $example) {
$application = Application::create([
'uuid' => $example['uuid'],
'name' => $example['name'],
'fqdn' => "http://{$example['uuid']}.{$sslipHost}",
'repository_project_id' => isset($example['git_repository']) ? null : self::EXAMPLES_REPOSITORY_PROJECT_ID,
'git_repository' => $example['git_repository'] ?? self::EXAMPLES_REPOSITORY,
'git_branch' => 'main',
'base_directory' => $example['base_directory'] ?? '/',
'publish_directory' => $example['publish_directory'] ?? null,
'build_command' => $example['build_command'] ?? null,
'start_command' => $example['start_command'] ?? null,
'build_pack' => 'railpack',
'static_image' => 'nginx:alpine',
'ports_exposes' => $example['ports_exposes'],
'environment_id' => 1,
'destination_id' => 0,
'destination_type' => StandaloneDocker::class,
'source_id' => $example['source_id'] ?? 0,
'source_type' => $example['source_type'] ?? GithubApp::class,
'private_key_id' => $example['private_key_id'] ?? null,
]);
$application->settings->update([
'is_static' => $example['is_static'] ?? false,
'is_spa' => $example['is_spa'] ?? false,
]);
}
}
/**
* Railpack examples from coollabsio/coolify-examples (main branch) and the deploy key / GitLab examples.
*
* @return array<int, array<string, mixed>>
*/
public static function railpackExamples(): array
{
return [
// JavaScript runtimes
['uuid' => 'nodejs', 'name' => 'Node.js Fastify Example', 'base_directory' => '/javascript/runtimes/nodejs', 'ports_exposes' => '3000', 'source_id' => 1],
['uuid' => 'bun', 'name' => 'Bun Example', 'base_directory' => '/javascript/runtimes/bun', 'ports_exposes' => '3000'],
// JavaScript frameworks (server)
['uuid' => 'nestjs', 'name' => 'NestJS Example', 'base_directory' => '/javascript/frameworks/nestjs', 'ports_exposes' => '3000', 'start_command' => 'npm run start:prod'],
['uuid' => 'adonisjs', 'name' => 'AdonisJS Example', 'base_directory' => '/javascript/frameworks/adonisjs/simple', 'ports_exposes' => '3333'],
['uuid' => 'remix', 'name' => 'Remix Example', 'base_directory' => '/javascript/frameworks/remix', 'ports_exposes' => '3000'],
['uuid' => 'nextjs-ssr', 'name' => 'Next.js SSR Example', 'base_directory' => '/javascript/frameworks/nextjs/ssr', 'ports_exposes' => '3000'],
['uuid' => 'nuxt-server', 'name' => 'Nuxt Server Example', 'base_directory' => '/javascript/frameworks/nuxt/server', 'ports_exposes' => '3000'],
['uuid' => 'nuxt-nitro', 'name' => 'Nuxt Nitro Example', 'base_directory' => '/javascript/frameworks/nuxt/nitro', 'ports_exposes' => '3000'],
['uuid' => 'astro-server', 'name' => 'Astro Server Example', 'base_directory' => '/javascript/frameworks/astro/server', 'ports_exposes' => '4321', 'start_command' => 'HOST=0.0.0.0 node dist/server/entry.mjs'],
['uuid' => 'vue-ssr', 'name' => 'Vue SSR Example', 'base_directory' => '/javascript/frameworks/vue/ssr', 'ports_exposes' => '3000'],
// JavaScript frameworks and build tools (static)
['uuid' => 'nextjs-static', 'name' => 'Next.js Static Example', 'base_directory' => '/javascript/frameworks/nextjs/spa', 'ports_exposes' => '80', 'publish_directory' => '/out', 'is_static' => true],
['uuid' => 'nuxt-static', 'name' => 'Nuxt Static Example', 'base_directory' => '/javascript/frameworks/nuxt/static', 'ports_exposes' => '80', 'build_command' => 'npm run generate', 'publish_directory' => '/.output/public', 'is_static' => true],
['uuid' => 'astro-static', 'name' => 'Astro Static Example', 'base_directory' => '/javascript/frameworks/astro/static', 'ports_exposes' => '80', 'publish_directory' => '/dist', 'is_static' => true],
['uuid' => 'vue-spa', 'name' => 'Vue SPA Example', 'base_directory' => '/javascript/frameworks/vue/spa', 'ports_exposes' => '80', 'publish_directory' => '/dist', 'is_static' => true, 'is_spa' => true],
['uuid' => 'vue-spa-router', 'name' => 'Vue SPA Router Example', 'base_directory' => '/javascript/frameworks/vue/spa-router', 'ports_exposes' => '80', 'publish_directory' => '/dist', 'is_static' => true, 'is_spa' => true],
['uuid' => 'vite-vanilla-js', 'name' => 'Vite Vanilla JS Example', 'base_directory' => '/javascript/build-tools/vite/vanilla-js', 'ports_exposes' => '80', 'publish_directory' => '/dist', 'is_static' => true],
['uuid' => 'vite-vanilla-ts', 'name' => 'Vite Vanilla TS Example', 'base_directory' => '/javascript/build-tools/vite/vanilla-ts', 'ports_exposes' => '80', 'publish_directory' => '/dist', 'is_static' => true],
['uuid' => 'static', 'name' => 'Static HTML Example', 'base_directory' => '/static', 'ports_exposes' => '80', 'publish_directory' => '/', 'is_static' => true],
// PHP
['uuid' => 'laravel', 'name' => 'Laravel Example', 'base_directory' => '/php/laravel', 'ports_exposes' => '80'],
['uuid' => 'laravel-pure', 'name' => 'Laravel Pure Example', 'base_directory' => '/php/laravel-pure', 'ports_exposes' => '80'],
['uuid' => 'laravel-inertia', 'name' => 'Laravel Inertia Example', 'base_directory' => '/php/laravel-inertia', 'ports_exposes' => '80'],
['uuid' => 'symfony', 'name' => 'Symfony Example', 'base_directory' => '/php/symfony', 'ports_exposes' => '80'],
// Other languages
['uuid' => 'python-flask', 'name' => 'Python Flask Example', 'base_directory' => '/python/flask', 'ports_exposes' => '5000', 'start_command' => 'flask run --host=0.0.0.0 --port=5000'],
['uuid' => 'go-gin', 'name' => 'Go Gin Example', 'base_directory' => '/go/gin', 'ports_exposes' => '3000'],
['uuid' => 'rust-rocket', 'name' => 'Rust Rocket Example', 'base_directory' => '/rust/rocket', 'ports_exposes' => '8000'],
['uuid' => 'ruby-rails', 'name' => 'Ruby on Rails Example', 'base_directory' => '/ruby/rails', 'ports_exposes' => '3000'],
['uuid' => 'elixir-phoenix', 'name' => 'Elixir Phoenix Example', 'base_directory' => '/elixir/phoenix', 'ports_exposes' => '4000'],
// Deploy keys and GitLab
['uuid' => 'github-deploy-key', 'name' => 'GitHub Deploy Key Example', 'git_repository' => 'git@github.com:coollabsio/coolify-examples-deploy-key.git', 'ports_exposes' => '80', 'private_key_id' => 1],
['uuid' => 'gitlab-deploy-key', 'name' => 'GitLab Deploy Key Example', 'git_repository' => 'git@gitlab.com:coollabsio/php-example.git', 'ports_exposes' => '80', 'source_id' => 1, 'source_type' => GitlabApp::class, 'private_key_id' => 1],
['uuid' => 'gitlab-public-example', 'name' => 'GitLab Public Example', 'git_repository' => 'https://gitlab.com/andrasbacsai/coolify-examples.git', 'base_directory' => '/astro/static', 'ports_exposes' => '80', 'publish_directory' => '/dist', 'source_id' => 1, 'source_type' => GitlabApp::class, 'is_static' => true],
];
}
}
@@ -15,12 +15,5 @@ class ApplicationSettingsSeeder extends Seeder
$application_1 = Application::find(1)->load(['settings']);
$application_1->settings->is_debug_enabled = false;
$application_1->settings->save();
$gitlabPublic = Application::where('uuid', 'gitlab-public-example')->first();
if ($gitlabPublic) {
$gitlabPublic->load(['settings']);
$gitlabPublic->settings->is_static = true;
$gitlabPublic->settings->save();
}
}
}
-6
View File
@@ -31,11 +31,5 @@ class DatabaseSeeder extends Seeder
CaSslCertSeeder::class,
PersonalAccessTokenSeeder::class,
]);
if (in_array(config('app.env'), ['local', 'development', 'dev'], true)) {
$this->call([
DevelopmentRailpackExamplesSeeder::class,
]);
}
}
}
@@ -1,604 +0,0 @@
<?php
namespace Database\Seeders;
use App\Enums\ProxyStatus;
use App\Enums\ProxyTypes;
use App\Models\Application;
use App\Models\Environment;
use App\Models\GithubApp;
use App\Models\GitlabApp;
use App\Models\PrivateKey;
use App\Models\Project;
use App\Models\Server;
use App\Models\StandaloneDocker;
use App\Models\Team;
use Illuminate\Database\Seeder;
use RuntimeException;
class DevelopmentRailpackExamplesSeeder extends Seeder
{
public const PROJECT_UUID = 'railpack-examples';
public const GIT_REPOSITORY = 'coollabsio/coolify-examples';
public const GIT_BRANCH = 'next';
public const REPOSITORY_PROJECT_ID = 603035348;
public function run(): void
{
if (! $this->isDevelopmentEnvironment()) {
$this->command?->warn('Skipping DevelopmentRailpackExamplesSeeder outside development mode.');
return;
}
$this->ensureDevelopmentPrerequisitesExist();
if (! StandaloneDocker::query()->find(0)) {
throw new RuntimeException('StandaloneDocker with id=0 is required before running DevelopmentRailpackExamplesSeeder.');
}
$this->cleanupLegacyLimaProjects();
$this->cleanupLegacyProductionExamples();
$this->seedEnvironment(StandaloneDocker::query()->findOrFail(0));
}
/**
* @return array<int, array<string, mixed>>
*/
public static function examples(): array
{
return [
[
'uuid' => 'railpack-simple-webserver',
'name' => 'Railpack Simple Webserver Example',
'base_directory' => '/node/simple-webserver',
'ports_exposes' => '3000',
'start_command' => 'npm run start',
],
[
'uuid' => 'railpack-expressjs',
'name' => 'Railpack Express.js Example',
'base_directory' => '/node/expressjs',
'ports_exposes' => '3000',
'start_command' => 'npm run start',
],
[
'uuid' => 'railpack-fastify',
'name' => 'Railpack Fastify Example',
'base_directory' => '/node/fastify',
'ports_exposes' => '3000',
'start_command' => 'npm run start',
],
[
'uuid' => 'railpack-nestjs',
'name' => 'Railpack NestJS Example',
'base_directory' => '/node/nestjs',
'ports_exposes' => '3000',
'build_command' => 'npm run build',
'start_command' => 'npm run start:prod',
],
[
'uuid' => 'railpack-adonisjs',
'name' => 'Railpack AdonisJS Example',
'base_directory' => '/node/adonisjs',
'ports_exposes' => '3333',
'build_command' => 'npm run build',
'start_command' => 'npm run start',
],
[
'uuid' => 'railpack-hono',
'name' => 'Railpack Hono Example',
'base_directory' => '/node/hono',
'ports_exposes' => '3000',
'build_command' => 'npm run build',
'start_command' => 'npm run start',
],
[
'uuid' => 'railpack-koa',
'name' => 'Railpack Koa Example',
'base_directory' => '/node/koa',
'ports_exposes' => '3000',
'start_command' => 'npm run start',
],
[
'uuid' => 'railpack-nextjs-ssr',
'name' => 'Railpack Next.js SSR Example',
'base_directory' => '/node/nextjs/ssr',
'ports_exposes' => '3000',
'build_command' => 'npm run build',
'start_command' => 'npm run start',
],
[
'uuid' => 'railpack-nuxtjs-ssr',
'name' => 'Railpack NuxtJS SSR Example',
'base_directory' => '/node/nuxtjs/ssr',
'ports_exposes' => '3000',
'build_command' => 'npm run build',
'start_command' => 'npm run preview -- --host 0.0.0.0 --port 3000',
],
[
'uuid' => 'railpack-astro-ssr',
'name' => 'Railpack Astro SSR Example',
'base_directory' => '/node/astro/ssr',
'ports_exposes' => '4321',
'build_command' => 'npm run build',
'start_command' => 'npm run start',
],
[
'uuid' => 'railpack-sveltekit-ssr',
'name' => 'Railpack SvelteKit SSR Example',
'base_directory' => '/node/sveltekit/ssr',
'ports_exposes' => '3000',
'build_command' => 'npm run build',
'start_command' => 'npm run start',
],
[
'uuid' => 'railpack-tanstack-start-ssr',
'name' => 'Railpack TanStack Start SSR Example',
'base_directory' => '/node/tanstack-start/ssr',
'ports_exposes' => '3000',
'build_command' => 'npm run build',
'start_command' => 'npm run start',
],
[
'uuid' => 'railpack-angular-ssr',
'name' => 'Railpack Angular SSR Example',
'base_directory' => '/node/angular/ssr',
'ports_exposes' => '4000',
'build_command' => 'npm run build',
'start_command' => 'npm run start',
],
[
'uuid' => 'railpack-vue-ssr',
'name' => 'Railpack Vue SSR Example',
'base_directory' => '/node/vue/ssr',
'ports_exposes' => '3000',
'build_command' => 'npm run build',
'start_command' => 'npm run start',
],
[
'uuid' => 'railpack-qwik-ssr',
'name' => 'Railpack Qwik SSR Example',
'base_directory' => '/node/qwik/ssr',
'ports_exposes' => '3000',
'build_command' => 'npm run build',
'start_command' => 'npm run serve',
],
[
'uuid' => 'railpack-react-static',
'name' => 'Railpack React Static Example',
'base_directory' => '/node/react',
'ports_exposes' => '80',
'build_command' => 'npm run build',
'publish_directory' => '/dist',
'is_static' => true,
'is_spa' => true,
],
[
'uuid' => 'railpack-vite-static',
'name' => 'Railpack Vite Static Example',
'base_directory' => '/node/vite',
'ports_exposes' => '80',
'build_command' => 'npm run build',
'publish_directory' => '/dist',
'is_static' => true,
'is_spa' => true,
],
[
'uuid' => 'railpack-eleventy-static',
'name' => 'Railpack Eleventy Static Example',
'base_directory' => '/node/eleventy',
'ports_exposes' => '80',
'build_command' => 'npm run build',
'publish_directory' => '/_site',
'is_static' => true,
],
[
'uuid' => 'railpack-gatsby-static',
'name' => 'Railpack Gatsby Static Example',
'base_directory' => '/node/gatsby',
'ports_exposes' => '80',
'build_command' => 'npm run build',
'publish_directory' => '/public',
'is_static' => true,
],
[
'uuid' => 'railpack-nextjs-static',
'name' => 'Railpack Next.js Static Example',
'base_directory' => '/node/nextjs/static',
'ports_exposes' => '80',
'build_command' => 'npm run build',
'publish_directory' => '/out',
'is_static' => true,
'is_spa' => true,
],
[
'uuid' => 'railpack-nuxtjs-static',
'name' => 'Railpack NuxtJS Static Example',
'base_directory' => '/node/nuxtjs/static',
'ports_exposes' => '80',
'build_command' => 'npm run build',
'publish_directory' => '/.output/public',
'is_static' => true,
'is_spa' => true,
],
[
'uuid' => 'railpack-astro-static',
'name' => 'Railpack Astro Static Example',
'base_directory' => '/node/astro/static',
'ports_exposes' => '80',
'build_command' => 'npm run build',
'publish_directory' => '/dist',
'is_static' => true,
],
[
'uuid' => 'railpack-sveltekit-static',
'name' => 'Railpack SvelteKit Static Example',
'base_directory' => '/node/sveltekit/static',
'ports_exposes' => '80',
'build_command' => 'npm run build',
'publish_directory' => '/build',
'is_static' => true,
'is_spa' => true,
],
[
'uuid' => 'railpack-tanstack-start-static',
'name' => 'Railpack TanStack Start Static Example',
'base_directory' => '/node/tanstack-start/static',
'ports_exposes' => '80',
'build_command' => 'npm run build',
'publish_directory' => '/.output/public',
'is_static' => true,
'is_spa' => true,
],
[
'uuid' => 'railpack-angular-static',
'name' => 'Railpack Angular Static Example',
'base_directory' => '/node/angular/static',
'ports_exposes' => '80',
'build_command' => 'npm run build',
'publish_directory' => '/dist/static/browser',
'is_static' => true,
'is_spa' => true,
],
[
'uuid' => 'railpack-vue-static',
'name' => 'Railpack Vue Static Example',
'base_directory' => '/node/vue/static',
'ports_exposes' => '80',
'build_command' => 'npm run build',
'publish_directory' => '/dist',
'is_static' => true,
'is_spa' => true,
],
[
'uuid' => 'railpack-qwik-static',
'name' => 'Railpack Qwik Static Example',
'base_directory' => '/node/qwik/static',
'ports_exposes' => '80',
'build_command' => 'npm run build',
'publish_directory' => '/dist',
'is_static' => true,
'is_spa' => true,
],
// Multi-language examples on the main branch.
[
'uuid' => 'railpack-python-flask',
'name' => 'Railpack Python Flask Example',
'base_directory' => '/flask',
'ports_exposes' => '5000',
'git_branch' => 'main',
'start_command' => 'flask run --host=0.0.0.0 --port=5000',
],
[
'uuid' => 'railpack-go-gin',
'name' => 'Railpack Go Gin Example',
'base_directory' => '/go/gin',
'ports_exposes' => '3000',
'git_branch' => 'main',
],
[
'uuid' => 'railpack-rust',
'name' => 'Railpack Rust Example',
'base_directory' => '/rust',
'ports_exposes' => '8000',
'git_branch' => 'main',
],
[
'uuid' => 'railpack-laravel',
'name' => 'Railpack Laravel Example',
'base_directory' => '/laravel',
'ports_exposes' => '80',
'git_branch' => 'main',
],
[
'uuid' => 'railpack-laravel-pure',
'name' => 'Railpack Laravel Pure Example',
'base_directory' => '/laravel-pure',
'ports_exposes' => '80',
'git_branch' => 'main',
],
[
'uuid' => 'railpack-laravel-inertia',
'name' => 'Railpack Laravel Inertia Example',
'base_directory' => '/laravel-inertia',
'ports_exposes' => '80',
'git_branch' => 'main',
],
[
'uuid' => 'railpack-symfony',
'name' => 'Railpack Symfony Example',
'base_directory' => '/symfony',
'ports_exposes' => '80',
'git_branch' => 'main',
],
[
'uuid' => 'railpack-rails',
'name' => 'Railpack Ruby on Rails Example',
'base_directory' => '/rails-example',
'ports_exposes' => '3000',
'git_branch' => 'main',
],
[
'uuid' => 'railpack-elixir-phoenix',
'name' => 'Railpack Elixir Phoenix Example',
'base_directory' => '/elixir-phoenix',
'ports_exposes' => '4000',
'git_branch' => 'main',
],
[
'uuid' => 'railpack-bun',
'name' => 'Railpack Bun Example',
'base_directory' => '/bun',
'ports_exposes' => '3000',
'git_branch' => 'main',
],
[
'uuid' => 'railpack-github-deploy-key',
'name' => 'Railpack GitHub Deploy Key Example',
'git_repository' => 'git@github.com:coollabsio/coolify-examples-deploy-key.git',
'git_branch' => 'main',
'ports_exposes' => '80',
'private_key_id' => 1,
],
[
'uuid' => 'railpack-gitlab-deploy-key',
'name' => 'Railpack GitLab Deploy Key Example',
'git_repository' => 'git@gitlab.com:coollabsio/php-example.git',
'git_branch' => 'main',
'ports_exposes' => '80',
'source_id' => 1,
'source_type' => GitlabApp::class,
'private_key_id' => 1,
],
[
'uuid' => 'railpack-gitlab-public-example',
'name' => 'Railpack GitLab Public Example',
'git_repository' => 'https://gitlab.com/andrasbacsai/coolify-examples.git',
'git_branch' => 'main',
'base_directory' => '/astro/static',
'publish_directory' => '/dist',
'ports_exposes' => '80',
'source_id' => 1,
'source_type' => GitlabApp::class,
'is_static' => true,
],
];
}
private function ensureDevelopmentPrerequisitesExist(): void
{
Team::query()->firstOrCreate(
['id' => 0],
[
'name' => 'Root Team',
'description' => 'The root team',
'personal_team' => true,
],
);
PrivateKey::query()->firstOrCreate(
['id' => 1],
[
'uuid' => 'ssh',
'team_id' => 0,
'name' => 'Testing Host Key',
'description' => 'This is a test docker container',
'private_key' => <<<'KEY'
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
QyNTUxOQAAACBbhpqHhqv6aI67Mj9abM3DVbmcfYhZAhC7ca4d9UCevAAAAJi/QySHv0Mk
hwAAAAtzc2gtZWQyNTUxOQAAACBbhpqHhqv6aI67Mj9abM3DVbmcfYhZAhC7ca4d9UCevA
AAAECBQw4jg1WRT2IGHMncCiZhURCts2s24HoDS0thHnnRKVuGmoeGq/pojrsyP1pszcNV
uZx9iFkCELtxrh31QJ68AAAAEXNhaWxANzZmZjY2ZDJlMmRkAQIDBA==
-----END OPENSSH PRIVATE KEY-----
KEY,
],
);
Server::query()->firstOrCreate(
['id' => 0],
[
'uuid' => 'localhost',
'name' => 'localhost',
'description' => 'This is a test docker container in development mode',
'ip' => 'coolify-testing-host',
'team_id' => 0,
'private_key_id' => 1,
'proxy' => [
'type' => ProxyTypes::TRAEFIK->value,
'status' => ProxyStatus::EXITED->value,
],
],
);
StandaloneDocker::query()->firstOrCreate(
['id' => 0],
[
'uuid' => 'docker',
'name' => 'Standalone Docker 1',
'network' => 'coolify',
'server_id' => 0,
],
);
$this->ensurePublicGithubSourceExists();
$this->ensurePublicGitlabSourceExists();
}
private function ensurePublicGithubSourceExists(): void
{
GithubApp::query()->firstOrCreate(
['id' => 0],
[
'uuid' => 'github-public',
'name' => 'Public GitHub',
'api_url' => 'https://api.github.com',
'html_url' => 'https://github.com',
'is_public' => true,
'team_id' => 0,
],
);
}
private function ensurePublicGitlabSourceExists(): void
{
GitlabApp::query()->firstOrCreate(
['id' => 1],
[
'uuid' => 'gitlab-public',
'name' => 'Public GitLab',
'api_url' => 'https://gitlab.com/api/v4',
'html_url' => 'https://gitlab.com',
'is_public' => true,
'team_id' => 0,
],
);
}
private function isDevelopmentEnvironment(): bool
{
return in_array(config('app.env'), ['local', 'development', 'dev'], true);
}
private function cleanupLegacyLimaProjects(): void
{
Project::query()
->whereIn('uuid', [
'railpack-examples-lima-ubuntu-2404',
'railpack-examples-lima-ubuntu-2604',
])
->get()
->each(function (Project $project): void {
Application::withTrashed()
->whereIn('environment_id', $project->environments()->pluck('id'))
->get()
->each
->forceDelete();
$project->delete();
});
}
private function cleanupLegacyProductionExamples(): void
{
$project = Project::query()->where('uuid', self::PROJECT_UUID)->first();
if (! $project) {
return;
}
Application::withTrashed()
->whereIn('environment_id', $project->environments()->pluck('id'))
->whereIn('uuid', collect(self::examples())->pluck('uuid'))
->get()
->each
->forceDelete();
}
private function seedEnvironment(StandaloneDocker $destination): void
{
$environment = $this->prepareEnvironment();
foreach (self::examples() as $example) {
$this->upsertApplication($environment, $destination, $example);
}
}
private function prepareEnvironment(): Environment
{
$project = Project::query()->firstOrNew(['uuid' => self::PROJECT_UUID]);
$project->fill([
'name' => 'Railpack Examples',
'description' => 'Development-only Railpack examples from coollabsio/coolify-examples@next.',
'team_id' => 0,
]);
$project->save();
$environment = $project->environments()->firstOrCreate(['name' => 'production']);
$project->environments()
->whereKeyNot($environment->id)
->get()
->each(function (Environment $obsoleteEnvironment): void {
Application::withTrashed()
->where('environment_id', $obsoleteEnvironment->id)
->get()
->each
->forceDelete();
$obsoleteEnvironment->delete();
});
return $environment;
}
/**
* @param array<string, mixed> $example
*/
private function upsertApplication(Environment $environment, StandaloneDocker $destination, array $example): void
{
$uuid = $example['uuid'];
$name = $example['name'];
$application = Application::withTrashed()->firstOrNew(['uuid' => $uuid]);
$application->fill([
'name' => $name,
'description' => $name,
'fqdn' => "http://{$uuid}.127.0.0.1.sslip.io",
'repository_project_id' => $example['repository_project_id'] ?? self::REPOSITORY_PROJECT_ID,
'git_repository' => $example['git_repository'] ?? self::GIT_REPOSITORY,
'git_branch' => $example['git_branch'] ?? self::GIT_BRANCH,
'build_pack' => 'railpack',
'ports_exposes' => $example['ports_exposes'],
'base_directory' => $example['base_directory'] ?? '/',
'publish_directory' => $example['publish_directory'] ?? null,
'static_image' => 'nginx:alpine',
'install_command' => $example['install_command'] ?? null,
'build_command' => $example['build_command'] ?? null,
'start_command' => $example['start_command'] ?? null,
'environment_id' => $environment->id,
'destination_id' => $destination->id,
'destination_type' => StandaloneDocker::class,
'source_id' => $example['source_id'] ?? 0,
'source_type' => $example['source_type'] ?? GithubApp::class,
'private_key_id' => $example['private_key_id'] ?? null,
]);
$application->save();
if ($application->trashed()) {
$application->restore();
}
$application->settings()->updateOrCreate(
['application_id' => $application->id],
[
'is_static' => $example['is_static'] ?? false,
'is_spa' => $example['is_spa'] ?? false,
],
);
}
}
+16 -1
View File
@@ -4,6 +4,7 @@ namespace Database\Seeders;
use App\Models\Server;
use Illuminate\Database\Seeder;
use InvalidArgumentException;
class ServerSettingSeeder extends Seeder
{
@@ -13,10 +14,24 @@ class ServerSettingSeeder extends Seeder
public function run(): void
{
$server_2 = Server::find(0)->load(['settings']);
$server_2->settings->wildcard_domain = 'http://127.0.0.1.sslip.io';
$server_2->settings->wildcard_domain = 'http://'.self::sslipHost();
$server_2->settings->is_build_server = false;
$server_2->settings->is_usable = true;
$server_2->settings->is_reachable = true;
$server_2->settings->save();
}
/**
* The sslip.io host for seeded domains, based on DEV_SEED_IP (default 127.0.0.1).
*/
public static function sslipHost(): string
{
$ip = config('constants.coolify.dev_seed_ip');
if (! filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) {
throw new InvalidArgumentException("DEV_SEED_IP must be an IPv4 address, got: {$ip}");
}
return "{$ip}.sslip.io";
}
}
+16 -16
View File
@@ -2,22 +2,22 @@
#
# Railpack end-to-end deploy smoke test against the local dev stack.
#
# Walks a curated set of railpack-* example apps from
# DevelopmentRailpackExamplesSeeder, triggers a deploy via the Coolify API,
# Walks a curated set of Railpack example apps from
# ApplicationSeeder, triggers a deploy via the Coolify API,
# waits for the deployment queue to finish, then exec()s into the resulting
# container and checks that COOLIFY_*, SOURCE_COMMIT, and any RAILPACK_*
# build inputs landed correctly. Optionally curls the FQDN.
#
# Requires:
# - Dev stack running: docker compose -f docker-compose.yml -f docker-compose.dev.yml up -d
# - Seeder run: php artisan db:seed --class=DevelopmentRailpackExamplesSeeder
# - Seeder run: php artisan migrate:fresh --seed
# - Personal token: PersonalAccessTokenSeeder run (creates Bearer 'root')
# - jq, curl available on host
#
# Usage:
# scripts/railpack-smoke.sh # default subset
# scripts/railpack-smoke.sh --app railpack-laravel # single app
# scripts/railpack-smoke.sh --all # every seeded railpack-* app
# scripts/railpack-smoke.sh --app laravel # single app
# scripts/railpack-smoke.sh --all # every seeded Railpack app
# scripts/railpack-smoke.sh --timeout 900 # build wait per app, seconds
# scripts/railpack-smoke.sh --no-curl # skip FQDN curl
# scripts/railpack-smoke.sh --extra-env KEY=VALUE # build+runtime env (alias of --both-env)
@@ -37,16 +37,16 @@ BOTH_ENVS=()
APPS=()
DEFAULT_APPS=(
railpack-expressjs
railpack-nestjs
railpack-nextjs-ssr
railpack-vite-static
railpack-astro-static
railpack-python-flask
railpack-go-gin
railpack-rust
railpack-symfony
railpack-bun
nodejs
nestjs
nextjs-ssr
vite-vanilla-js
astro-static
python-flask
go-gin
rust-rocket
symfony
bun
)
while (( $# > 0 )); do
@@ -87,7 +87,7 @@ if (( ${#APPS[@]} == 0 )); then
fi
if [[ "${APPS[0]}" == "__ALL__" ]]; then
mapfile -t APPS < <(curl_api GET /applications | jq -r '.[].uuid' | grep '^railpack-' || true)
mapfile -t APPS < <(curl_api GET /applications | jq -r '.[] | select(.build_pack == "railpack") | .uuid' || true)
fi
log() { printf '[%s] %s\n' "$(date +%H:%M:%S)" "$*"; }
+67 -18
View File
@@ -1,11 +1,16 @@
<?php
use App\Models\Application;
use App\Models\GitlabApp;
use App\Models\Project;
use App\Models\Server;
use Database\Seeders\ApplicationSeeder;
use Database\Seeders\GithubAppSeeder;
use Database\Seeders\GitlabAppSeeder;
use Database\Seeders\PrivateKeySeeder;
use Database\Seeders\ProjectSeeder;
use Database\Seeders\ServerSeeder;
use Database\Seeders\ServerSettingSeeder;
use Database\Seeders\StandaloneDockerSeeder;
use Database\Seeders\TeamSeeder;
use Database\Seeders\UserSeeder;
@@ -13,8 +18,9 @@ use Illuminate\Foundation\Testing\RefreshDatabase;
uses(RefreshDatabase::class);
it('seeds the default applications without railpack examples', function () {
$this->seed([
function seedApplicationSeederPrerequisites(): void
{
test()->seed([
UserSeeder::class,
TeamSeeder::class,
PrivateKeySeeder::class,
@@ -22,22 +28,65 @@ it('seeds the default applications without railpack examples', function () {
ProjectSeeder::class,
StandaloneDockerSeeder::class,
GithubAppSeeder::class,
ApplicationSeeder::class,
GitlabAppSeeder::class,
]);
}
$nixpacksExample = Application::where('uuid', 'nodejs')->first();
expect($nixpacksExample)
->not->toBeNull()
->and($nixpacksExample->name)->toBe('NodeJS Fastify Example')
->and($nixpacksExample->build_pack)->toBe('nixpacks')
->and($nixpacksExample->base_directory)->toBe('/nodejs')
->and($nixpacksExample->ports_exposes)->toBe('3000');
expect(Application::query()->where('build_pack', 'railpack')->exists())->toBeFalse();
expect(Application::query()->whereIn('uuid', ['railpack-nodejs', 'railpack-static'])->exists())->toBeFalse();
expect(Application::query()
->whereIn('git_repository', ['coollabsio/coolify-examples', 'coollabsio/coolify'])
->pluck('git_branch')->unique()->all())->toBe(['main']);
beforeEach(function () {
config()->set('constants.coolify.dev_seed_ip', '127.0.0.1');
});
it('seeds every git example as railpack in the default project', function () {
seedApplicationSeederPrerequisites();
$this->seed(ApplicationSeeder::class);
$railpackUuids = collect(ApplicationSeeder::railpackExamples())->pluck('uuid')->sort()->values()->all();
expect(Application::query()->where('build_pack', 'railpack')->pluck('uuid')->sort()->values()->all())->toBe($railpackUuids)
->and(Application::query()->whereNotIn('build_pack', ['railpack', 'dockerfile', 'dockercompose'])->exists())->toBeFalse()
->and(Project::query()->count())->toBe(1)
->and(Application::query()->pluck('environment_id')->unique()->all())->toBe([1])
->and(Application::query()->whereNotNull('git_branch')->pluck('git_branch')->unique()->all())->toBe(['main']);
});
it('seeds railpack examples with the new example repository layout', function () {
seedApplicationSeederPrerequisites();
$this->seed(ApplicationSeeder::class);
$nodejs = Application::query()->where('uuid', 'nodejs')->sole();
$astroServer = Application::query()->where('uuid', 'astro-server')->sole();
$vueSpa = Application::query()->where('uuid', 'vue-spa')->with('settings')->sole();
$gitlabPublic = Application::query()->where('uuid', 'gitlab-public-example')->with('settings')->sole();
$compose = Application::query()->where('uuid', 'docker-compose')->sole();
expect($nodejs->git_repository)->toBe(ApplicationSeeder::EXAMPLES_REPOSITORY)
->and($nodejs->base_directory)->toBe('/javascript/runtimes/nodejs')
->and($nodejs->fqdn)->toBe('http://nodejs.127.0.0.1.sslip.io')
->and($astroServer->start_command)->toBe('HOST=0.0.0.0 node dist/server/entry.mjs')
->and($vueSpa->publish_directory)->toBe('/dist')
->and($vueSpa->settings->is_static)->toBeTrue()
->and($vueSpa->settings->is_spa)->toBeTrue()
->and($gitlabPublic->source_type)->toBe(GitlabApp::class)
->and($gitlabPublic->repository_project_id)->toBeNull()
->and($gitlabPublic->settings->is_static)->toBeTrue()
->and($compose->base_directory)->toBe('/internal/compose');
});
it('uses DEV_SEED_IP for the server wildcard domain and application domains', function () {
config()->set('constants.coolify.dev_seed_ip', '100.64.1.2');
seedApplicationSeederPrerequisites();
$this->seed([ServerSettingSeeder::class, ApplicationSeeder::class]);
expect(Server::query()->find(0)->settings->wildcard_domain)->toBe('http://100.64.1.2.sslip.io')
->and(Application::query()->where('uuid', 'nodejs')->value('fqdn'))->toBe('http://nodejs.100.64.1.2.sslip.io')
->and(Application::query()->where('uuid', 'dockerfile')->value('fqdn'))->toBe('http://dockerfile.100.64.1.2.sslip.io')
->and(Application::query()->whereNotNull('fqdn')->where('fqdn', 'not like', '%.100.64.1.2.sslip.io')->exists())->toBeFalse();
});
it('rejects a DEV_SEED_IP that is not an IPv4 address', function (string $value) {
config()->set('constants.coolify.dev_seed_ip', $value);
ServerSettingSeeder::sslipHost();
})->with(['hostname' => 'devserver.ts.net', 'ipv6' => 'fd7a:115c:a1e0::1', 'injection' => '1.2.3.4; rm -rf /'])
->throws(InvalidArgumentException::class);
@@ -1,9 +0,0 @@
<?php
it('runs the normal development database seeder without v5 seeders', function () {
$databaseSeeder = file_get_contents(database_path('seeders/DatabaseSeeder.php'));
$developmentSeederBlock = str($databaseSeeder)->after("if (in_array(config('app.env'), ['local', 'development', 'dev'], true)) {")->before(' }')->toString();
expect($developmentSeederBlock)->toContain('DevelopmentRailpackExamplesSeeder::class')
->and($developmentSeederBlock)->not->toContain('V5DevLimaSeeder::class');
});
@@ -1,136 +0,0 @@
<?php
use App\Models\Application;
use App\Models\GithubApp;
use App\Models\GitlabApp;
use App\Models\PrivateKey;
use App\Models\Project;
use App\Models\Server;
use App\Models\StandaloneDocker;
use App\Models\Team;
use Database\Seeders\DevelopmentRailpackExamplesSeeder;
use Database\Seeders\GithubAppSeeder;
use Database\Seeders\PrivateKeySeeder;
use Database\Seeders\ProjectSeeder;
use Database\Seeders\ServerSeeder;
use Database\Seeders\StandaloneDockerSeeder;
use Database\Seeders\TeamSeeder;
use Database\Seeders\UserSeeder;
use Illuminate\Foundation\Testing\RefreshDatabase;
uses(RefreshDatabase::class);
function seedRailpackExamplePrerequisites(): void
{
test()->seed([
UserSeeder::class,
TeamSeeder::class,
PrivateKeySeeder::class,
ServerSeeder::class,
ProjectSeeder::class,
StandaloneDockerSeeder::class,
GithubAppSeeder::class,
]);
}
it('can seed the railpack examples directly on a clean development database', function () {
config()->set('app.env', 'local');
$this->seed(DevelopmentRailpackExamplesSeeder::class);
expect(Team::query()->find(0))->not->toBeNull()
->and(PrivateKey::query()->find(1))->not->toBeNull()
->and(Server::query()->count())->toBe(1)
->and(Server::query()->find(0)?->uuid)->toBe('localhost')
->and(StandaloneDocker::query()->find(0))->not->toBeNull()
->and(GithubApp::query()->find(0))->not->toBeNull()
->and(GitlabApp::query()->find(1))->not->toBeNull()
->and(Application::query()->count())->toBe(count(DevelopmentRailpackExamplesSeeder::examples()));
$project = Project::query()->where('uuid', DevelopmentRailpackExamplesSeeder::PROJECT_UUID)->firstOrFail();
expect($project->environments)->toHaveCount(1)
->and($project->environments->first()->name)->toBe('production')
->and($project->applications()->whereRelation('destination.server', 'uuid', 'localhost')->count())
->toBe(count(DevelopmentRailpackExamplesSeeder::examples()));
});
it('seeds every railpack example in the production environment on testing-host', function () {
config()->set('app.env', 'local');
seedRailpackExamplePrerequisites();
$this->seed(DevelopmentRailpackExamplesSeeder::class);
$project = Project::query()->where('uuid', DevelopmentRailpackExamplesSeeder::PROJECT_UUID)->firstOrFail();
$environment = $project->environments()->sole();
$applications = $environment->applications()->with('settings', 'destination.server')->orderBy('uuid')->get();
expect($environment->name)->toBe('production')
->and($applications)->toHaveCount(count(DevelopmentRailpackExamplesSeeder::examples()))
->and($applications->every(fn (Application $application) => $application->build_pack === 'railpack'))->toBeTrue()
->and($applications->every(fn (Application $application) => $application->destination->server->uuid === 'localhost'))->toBeTrue()
->and($applications->pluck('uuid')->sort()->values()->all())
->toBe(collect(DevelopmentRailpackExamplesSeeder::examples())->pluck('uuid')->sort()->values()->all());
$nestjs = $applications->firstWhere('uuid', 'railpack-nestjs');
$angularStatic = $applications->firstWhere('uuid', 'railpack-angular-static');
$githubDeployKey = $applications->firstWhere('uuid', 'railpack-github-deploy-key');
$gitlabDeployKey = $applications->firstWhere('uuid', 'railpack-gitlab-deploy-key');
expect($applications->where('git_repository', DevelopmentRailpackExamplesSeeder::GIT_REPOSITORY)
->pluck('git_branch')->unique()->sort()->values()->all())->toBe(['main', 'next'])
->and($applications->firstWhere('uuid', 'railpack-python-flask')->git_branch)->toBe('main')
->and($nestjs->git_branch)->toBe('next');
expect($nestjs->base_directory)->toBe('/node/nestjs')
->and($nestjs->build_command)->toBe('npm run build')
->and($nestjs->start_command)->toBe('npm run start:prod')
->and($angularStatic->publish_directory)->toBe('/dist/static/browser')
->and($angularStatic->settings->is_static)->toBeTrue()
->and($githubDeployKey->private_key_id)->toBe(1)
->and($githubDeployKey->source_type)->toBe(GithubApp::class)
->and($gitlabDeployKey->source_type)->toBe(GitlabApp::class);
});
it('consolidates legacy railpack environments into production', function () {
config()->set('app.env', 'local');
seedRailpackExamplePrerequisites();
$project = Project::query()->create([
'uuid' => DevelopmentRailpackExamplesSeeder::PROJECT_UUID,
'name' => 'Railpack Examples',
'team_id' => 0,
]);
$project->environments()->first()->update(['name' => 'ubuntu24', 'uuid' => 'railpack-examples-ubuntu24']);
$project->environments()->create(['name' => 'ubuntu26', 'uuid' => 'railpack-examples-ubuntu26']);
$this->seed(DevelopmentRailpackExamplesSeeder::class);
$project->refresh();
expect($project->environments)->toHaveCount(1)
->and($project->environments->first()->name)->toBe('production')
->and($project->applications)->toHaveCount(count(DevelopmentRailpackExamplesSeeder::examples()));
});
it('skips the railpack examples outside development mode', function () {
config()->set('app.env', 'testing');
seedRailpackExamplePrerequisites();
$this->seed(DevelopmentRailpackExamplesSeeder::class);
expect(Project::query()->where('uuid', DevelopmentRailpackExamplesSeeder::PROJECT_UUID)->exists())->toBeFalse();
});
it('is idempotent when run multiple times', function () {
config()->set('app.env', 'local');
seedRailpackExamplePrerequisites();
$this->seed(DevelopmentRailpackExamplesSeeder::class);
$this->seed(DevelopmentRailpackExamplesSeeder::class);
$project = Project::query()->where('uuid', DevelopmentRailpackExamplesSeeder::PROJECT_UUID)->firstOrFail();
expect($project->environments)->toHaveCount(1)
->and($project->applications)->toHaveCount(count(DevelopmentRailpackExamplesSeeder::examples()));
});