Add local server by saeedvaziry · Pull Request #1046 · vitodeploy/vito · GitHub
Skip to content

Add local server#1046

Open
saeedvaziry wants to merge 4 commits into4.xfrom
feat/local-server
Open

Add local server#1046
saeedvaziry wants to merge 4 commits into4.xfrom
feat/local-server

Conversation

@saeedvaziry
Copy link
Copy Markdown
Member

@saeedvaziry saeedvaziry commented Mar 13, 2026

Summary

  • Registers the host machine Vito runs on as a managed "local" server, so users can deploy sites to the same server
  • Adds is_vito_service flag on services (nginx, php 8.4, redis, supervisor) to identify services Vito depends on — these cannot be uninstalled, but can be restarted/managed with a warning alert
  • The local server cannot be deleted, rebooted, or transferred
  • The Local provider is hidden from the create-server UI
  • php artisan server:setup-local bootstraps the local server (idempotent, called during install and update)
  • Install script now supports VITO_CHANNEL=branch to install directly from a branch

Test from branch

curl -s https://raw.githubusercontent.com/vitodeploy/vito/feat/local-server/scripts/install.sh |V_ADMIN_EMAIL=admin@example.com V_ADMIN_PASSWORD=password VITO_VERSION=feat/local-server VITO_CHANNEL=branch bash

Changes

New files

  • app/ServerProviders/Local.php — minimal provider, copies Vito's SSH keys
  • app/Console/Commands/SetupLocalServerCommand.phpserver:setup-local artisan command
  • database/migrations/..._add_is_vito_service_to_services_table.php
  • tests/Feature/LocalServerTest.php — 11 tests

Backend

  • Server::isLocal() helper
  • Service model — is_vito_service column
  • RegisterServerProviderhidden() support
  • ServerPolicy::delete() — blocks local server deletion
  • CreateServerRule::notIn(['local'])
  • RebootServer / TransferServer — validation errors for local server
  • Uninstall — blocks uninstall of vito services
  • ServerResource / ServiceResource — expose is_local / is_vito_service

Frontend

  • Create server dropdown filters hidden providers
  • Services table shows "vito" badge, hides uninstall for vito services
  • Action dialogs show warning alert for vito services
  • Server settings hides delete/transfer cards for local server

Scripts

  • install.sh — calls server:setup-local, supports VITO_CHANNEL=branch
  • update.sh — calls server:setup-local after migrations

@saeedvaziry saeedvaziry changed the title Add local server feature Add local server Mar 13, 2026
@saeedvaziry saeedvaziry requested a review from Copilot March 22, 2026 22:45
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds first-class support for managing the host machine as a special “local” server, including provider registration, backend enforcement (non-deletable/non-transferable), service protection via is_vito_service, UI affordances/warnings, and install/update automation via server:setup-local.

Changes:

  • Introduces a hidden Local server provider plus an artisan bootstrap command (server:setup-local) and tests.
  • Adds is_vito_service to services (DB/model/resource/UI) and blocks uninstall while still allowing management actions with warnings.
  • Updates install/update scripts to bootstrap the local server and support installing directly from a branch.

Reviewed changes

Copilot reviewed 22 out of 25 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
tests/Feature/LocalServerTest.php Adds feature coverage for local server restrictions and server:setup-local.
scripts/update.sh Runs server:setup-local during updates and attempts to authorize the app SSH key.
scripts/reset-server.sh Adds a full reset script for wiping a Vito installation and related packages.
scripts/install.sh Adds branch-install flow and bootstraps local server + SSH key authorization.
resources/js/types/service.d.ts Exposes is_vito_service on Service type.
resources/js/types/server.d.ts Exposes is_local on Server type.
resources/js/types/index.d.ts Adds optional hidden to provider config typing.
resources/js/pages/services/components/columns.tsx Adds “vito” badge and hides uninstall action for Vito services.
resources/js/pages/services/components/action.tsx Adds warning alert when managing a Vito service.
resources/js/pages/servers/components/create-server.tsx Filters hidden server providers out of the provider dropdown.
resources/js/pages/server-settings/index.tsx Hides delete/transfer UI for local server.
database/migrations/2026_03_13_221643_add_is_vito_service_to_services_table.php Adds is_vito_service column to services.
app/ServerProviders/Local.php Implements minimal “Local” provider that copies Vito SSH keys.
app/Providers/ServerProviderServiceProvider.php Registers the Local provider as hidden.
app/Policies/ServerPolicy.php Prevents deleting local server via policy.
app/Plugins/RegisterServerProvider.php Adds hidden() support and persists hidden into provider config.
app/Models/Service.php Adds fillable/cast/phpdoc for is_vito_service.
app/Models/Server.php Adds isLocal() helper.
app/Http/Resources/ServiceResource.php Exposes is_vito_service to frontend.
app/Http/Resources/ServerResource.php Exposes is_local to frontend.
app/Console/Commands/SetupLocalServerCommand.php Implements server:setup-local bootstrap logic.
app/Actions/Service/Uninstall.php Blocks uninstall of Vito services with validation error.
app/Actions/Server/TransferServer.php Adds guard preventing transfer of local server.
app/Actions/Server/RebootServer.php Adds guard preventing reboot of local server.
app/Actions/Server/CreateServer.php Disallows creating a server using the local provider via the normal flow.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread scripts/update.sh
Comment on lines +44 to +50
if [ -f /home/vito/vito/storage/ssh-public.key ] && [ -f /home/vito/.ssh/authorized_keys ]; then
if ! grep -qF "$(cat /home/vito/vito/storage/ssh-public.key)" /home/vito/.ssh/authorized_keys 2>/dev/null; then
cat /home/vito/vito/storage/ssh-public.key >> /home/vito/.ssh/authorized_keys
chown vito:vito /home/vito/.ssh/authorized_keys
chmod 600 /home/vito/.ssh/authorized_keys
fi
fi
Copy link

Copilot AI Mar 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the update path, the public key is only appended when /home/vito/.ssh/authorized_keys already exists. On installs where that file is missing (common), this block becomes a no-op, so the local server won’t be able to SSH using Vito’s app key after server:setup-local. Create the file (and .ssh dir if needed) with correct permissions before the grep/append logic.

Copilot uses AI. Check for mistakes.
Comment thread scripts/install.sh
chown -R vito:vito /home/vito/vito/storage/ssh-public.key

# authorize vito's app key for local SSH access
cat /home/vito/vito/storage/ssh-public.key >> /home/vito/.ssh/authorized_keys
Copy link

Copilot AI Mar 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This unconditionally appends the app public key to authorized_keys. If the install script is re-run (or partially re-run), it will duplicate entries and can also concatenate keys if the existing file doesn’t end with a newline. Consider ensuring the file exists, checking for the key before appending (similar to update.sh), and appending with a guaranteed newline.

Suggested change
cat /home/vito/vito/storage/ssh-public.key >> /home/vito/.ssh/authorized_keys
mkdir -p /home/vito/.ssh
touch /home/vito/.ssh/authorized_keys
APP_SSH_KEY="$(cat /home/vito/vito/storage/ssh-public.key)"
if ! grep -qxF "$APP_SSH_KEY" /home/vito/.ssh/authorized_keys 2>/dev/null; then
printf '%s\n' "$APP_SSH_KEY" >> /home/vito/.ssh/authorized_keys
fi

Copilot uses AI. Check for mistakes.
Comment on lines +27 to +38
/** @var ?User $user */
$user = User::query()->first();

if (! $user) {
$this->error('No admin user found. Please create a user first.');

return self::FAILURE;
}

/** @var ?\App\Models\Project $project */
$project = $user->currentProject ?? $user->allProjects()->first();

Copy link

Copilot AI Mar 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

server:setup-local currently picks User::first(), which can be a non-admin user in existing installations and could attach the local server to the wrong user/project. It would be safer to explicitly select an admin user (e.g., where('is_admin', true) / role === ADMIN) and/or allow specifying the target user/project via options.

Copilot uses AI. Check for mistakes.
Comment on lines +21 to +70
if (Server::query()->where('provider', 'local')->exists()) {
$this->info('Local server already exists. Skipping.');

return self::SUCCESS;
}

/** @var ?User $user */
$user = User::query()->first();

if (! $user) {
$this->error('No admin user found. Please create a user first.');

return self::FAILURE;
}

/** @var ?\App\Models\Project $project */
$project = $user->currentProject ?? $user->allProjects()->first();

if (! $project) {
$this->error('No project found. Please create a project first.');

return self::FAILURE;
}

$os = $this->detectOS();

$server = new Server([
'project_id' => $project->id,
'user_id' => $user->id,
'name' => 'Vito',
'ssh_user' => 'vito',
'ip' => '127.0.0.1',
'port' => 22,
'os' => $os,
'provider' => 'local',
'authentication' => [
'user' => 'vito',
'pass' => Str::random(15),
'root_pass' => Str::random(15),
],
'status' => ServerStatus::READY,
'progress' => 100,
]);
$server->save();

$server->provider()->create();

if (file_exists('/home/vito/.ssh/id_rsa.pub')) {
$server->public_key = trim(file_get_contents('/home/vito/.ssh/id_rsa.pub'));
$server->save();
Copy link

Copilot AI Mar 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The command returns early as soon as a local server row exists. If a previous run partially created the server (missing SSH key copy, missing services, or missing is_vito_service flags), subsequent runs won’t repair it even though the command is intended to be idempotent. Consider making the command reconcile state (create missing services/keys, update flags) rather than skipping entirely.

Suggested change

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants