Panel Installation

Step 1: Copy the new files

The panel/new-files/ folder is laid out to match your panel's root folder by folder: app/ goes over your app/, database/ over your database/, resources/ over your resources/. Nothing needs to be renamed or rearranged.

Option A: drag and drop (recommended if you use FileZilla, WinSCP, or similar):

  1. Connect to your server/panel over SFTP.
  2. In the left panel (your computer) open panel/new-files/.
  3. Drag the app folder from the left onto the app folder on the right (your panel's root) and choose merge when the client asks what to do with folders that already exist (never "replace all"), it only needs to add new files inside subfolders you already have.
  4. Repeat the same with database and resources.

Option B: over SSH/terminal, if you prefer the command line:

bash
cp -r panel/new-files/app/*        /path/to/panel/app/
cp -r panel/new-files/database/*   /path/to/panel/database/
cp -r panel/new-files/resources/*  /path/to/panel/resources/

Files that get copied (28 in total, all of them new files, none overwrite an existing file in your panel):

  • app/Services/Domains/WingsProxyClient.php
  • app/Services/Domains/DomainService.php
  • app/Jobs/Domains/ApplyDomainProxy.php
  • app/Jobs/Domains/RevokeDomainProxy.php
  • app/Models/Domain.php
  • app/Models/NodeProxySetting.php
  • app/Transformers/Api/Client/DomainTransformer.php
  • app/Http/Controllers/Api/Client/Servers/DomainController.php
  • app/Http/Controllers/Admin/Nodes/NodeProxyController.php
  • app/Http/Requests/Admin/Node/NodeProxyFormRequest.php
  • app/Http/Requests/Api/Client/Servers/Domains/StoreDomainRequest.php
  • app/Http/Requests/Api/Client/Servers/Domains/GetDomainsRequest.php
  • app/Http/Requests/Api/Client/Servers/Domains/DeleteDomainRequest.php
  • app/Http/Requests/Api/Client/Servers/Domains/VerifyDomainRequest.php
  • database/migrations/2025_05_04_000001_create_server_domains_table.php
  • database/migrations/2025_05_04_000002_create_node_proxy_settings_table.php
  • database/migrations/2026_05_29_000001_fix_server_domains_unique_index.php
  • database/migrations/2026_09_16_000001_add_custom_ssl_and_allocation_to_server_domains.php
  • database/migrations/2026_09_17_000001_add_verification_to_server_domains.php
  • database/migrations/2026_09_18_000001_add_show_conf_path_to_node_proxy_settings.php
  • resources/scripts/components/server/domains/DomainsContainer.tsx
  • resources/scripts/components/server/domains/AddDomainModal.tsx
  • resources/scripts/components/server/domains/DomainRow.tsx
  • resources/scripts/api/swr/getServerDomains.ts
  • resources/scripts/api/server/domains/createServerDomain.ts
  • resources/scripts/api/server/domains/deleteServerDomain.ts
  • resources/scripts/api/server/domains/verifyServerDomain.ts
  • resources/views/admin/nodes/view/proxy.blade.php

Step 2: Apply the 6 injected fragments

This part isn't dragged over: these are files that already exist in your panel, and you need to open them with a text editor (or your panel/hPanel/whatever file editor you use) to paste a block of code at the exact spot. Every file in panel/injected-code/ starts with a DESTINO:/UBICACIÓN: comment that tells you which file and where exactly it goes. Summary:

FragmentTarget fileWhere
routes__api-client.phproutes/api-client.phpinside the /servers/{server} group, right before the /startup group
routes__admin.phproutes/admin.phpinside the prefix('nodes') group, alongside the other GET/POST routes of /view/{node}
app_Models__Permission.phpapp/Models/Permission.phpconstants alongside the other ACTION_* ones, and the 'domain' => [...] entry as the last key of the $permissions array
app_Models__Node.phpapp/Models/Node.phpalongside the other relations (after allocations()); no extra use needed
resources_scripts_routers__routes.tsresources/scripts/routers/routes.tsimport of the DomainsContainer component + entry in the server.routes array, after Backups
resources_views_admin_nodes_view__TABS.blade.phpthe 5 blades in admin/nodes/view/ (index.blade.php, settings.blade.php, configuration.blade.php, allocation.blade.php, servers.blade.php)as the last <li> of the <ul class="nav nav-tabs">

Step 3: Migrate the database

bash
cd /path/to/panel
php artisan migrate

This creates the server_domains and node_proxy_settings tables, applies the fix for the unique index (2026_05_29_000001_fix_server_domains_unique_index.php), adds the custom certificate and allocation columns (2026_09_16_000001_...), and adds the domain verification column and state (2026_09_17_000001_...).

Don't skip the fix migration. Without it, deleting a domain and creating it again (even on a different server) can collide with the table's UNIQUE(domain) constraint and throw a duplicate error. See Troubleshooting.

Step 4: Regenerate Composer's autoloader

bash
composer dump-autoload -o

If your panel was installed with the optimized autoloader (composer install --optimize-autoloader, the recommended mode for production), Laravel builds a fixed class → file map on install. That map doesn't automatically pick up the new classes you just copied: if you skip this step, VerifyDomainRequest and friends throw "Class not found" the moment something tries to use them, even though the file is in the right place. If your panel doesn't use the optimized autoloader you can skip this step, but running it anyway doesn't break anything.

Step 5: Build the frontend

bash
yarn install
yarn run build:production

On a server with little RAM (under 1-2 GB free) the build can fail with an out-of-memory error before finishing. If that happens, run:

bash
NODE_OPTIONS="--max-old-space-size=2048" yarn run build:production

Step 6: Clear caches and restart the queue

bash
php artisan config:clear
php artisan route:clear
php artisan view:clear
php artisan queue:restart

If you use supervisor or systemd for queue:work, confirm the process restarts on its own (Restart=always or equivalent). queue:restart only tells the worker to finish its current cycle, it doesn't bring it back up by itself.

Verification

  1. Go to any server in the panel → the Proxy tab should show up.
  2. Go to Admin → Nodes → (a node) → Proxy → the configuration view should load with no 404 or 500 error.

Next: Installation: Wings →