PlayerServers
Search
K
Comment on page

Setting up plugins mount

Learn how to setup plugins repository as a mount for your Pterodactyl servers.

Introduction

In order for your players to be able to install plugins via plugin management GUI, we need to mount the plugins repository folder to each of your virtualised containers (servers).
Unfortunately, Pterodactyl doesn't provide an API for that at the moment (until v2 is out), so we will need to perform a quick modification on your Pterodactyl's code.
You will need to perform these modifications every time you update Pterodactyl.

Instructions

  1. 1.
    Navigate to your Pterodactyl folder, preferably via some kind of SFTP file manager, like WinSCP or CyberDuck. The directory is usually /var/www/pterodactyl.
  2. 2.
    Open up app/Http/Controllers/Api/Application/Servers/ServerManagementController.php preferably using some sort of text editor, like VSCode or Notepad++.
    1. 1.
      If you're a more advanced user, just making sure to merge this differences will be enough. For everyone else, please carefully follow the instructions below.
    2. 2.
      Below all imports, paste use Pterodactyl\Models\MountServer; Your imports should look like the following:
      ServerManagementController.php
      1
      <?php
      2
      3
      namespace Pterodactyl\Http\Controllers\Api\Application\Servers;
      4
      5
      use Illuminate\Http\Response;
      6
      use Pterodactyl\Models\Server;
      7
      use Pterodactyl\Services\Servers\SuspensionService;
      8
      use Pterodactyl\Services\Servers\ReinstallServerService;
      9
      use Pterodactyl\Http\Requests\Api\Application\Servers\ServerWriteRequest;
      10
      use Pterodactyl\Http\Controllers\Api\Application\ApplicationApiController;
      11
      use Pterodactyl\Models\MountServer; # This is the line we added
    3. 3.
      Below reinstall function, paste the following code block:
      ServerManagementController.php
      public function mount(ServerWriteRequest $request, Server $server): Response
      {
      $mountServer = (new MountServer())->forceFill([
      'mount_id' => $request->input('mount_id'),
      'server_id' => $server->id,
      ]);
      $mountServer->saveOrFail();
      return $this->returnNoContent();
      }
    4. 4.
      The end result will be the following file (which you may as well just copy and replace your whole file contents with, but a more manual approach like in steps 1 and 2 is recommended):
      ServerManagementController.php
      1
      <?php
      2
      3
      namespace Pterodactyl\Http\Controllers\Api\Application\Servers;
      4
      5
      use Illuminate\Http\Response;
      6
      use Pterodactyl\Models\Server;
      7
      use Pterodactyl\Services\Servers\SuspensionService;
      8
      use Pterodactyl\Services\Servers\ReinstallServerService;
      9
      use Pterodactyl\Http\Requests\Api\Application\Servers\ServerWriteRequest;
      10
      use Pterodactyl\Http\Controllers\Api\Application\ApplicationApiController;
      11
      use Pterodactyl\Models\MountServer; # This is the line we added
      12
      13
      class ServerManagementController extends ApplicationApiController
      14
      {
      15
      /**
      16
      * ServerManagementController constructor.
      17
      */
      18
      public function __construct(
      19
      private ReinstallServerService $reinstallServerService,
      20
      private SuspensionService $suspensionService
      21
      ) {
      22
      parent::__construct();
      23
      }
      24
      25
      /**
      26
      * Suspend a server on the Panel.
      27
      *
      28
      * @throws \Throwable
      29
      */
      30
      public function suspend(ServerWriteRequest $request, Server $server): Response
      31
      {
      32
      $this->suspensionService->toggle($server);
      33
      34
      return $this->returnNoContent();
      35
      }
      36
      37
      /**
      38
      * Unsuspend a server on the Panel.
      39
      *
      40
      * @throws \Throwable
      41
      */
      42
      public function unsuspend(ServerWriteRequest $request, Server $server): Response
      43
      {
      44
      $this->suspensionService->toggle($server, SuspensionService::ACTION_UNSUSPEND);
      45
      46
      return $this->returnNoContent();
      47
      }
      48
      49
      /**
      50
      * Mark a server as needing to be reinstalled.
      51
      *
      52
      * @throws \Pterodactyl\Exceptions\DisplayException
      53
      * @throws \Pterodactyl\Exceptions\Model\DataValidationException
      54
      * @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
      55
      */
      56
      public function reinstall(ServerWriteRequest $request, Server $server): Response
      57
      {
      58
      $this->reinstallServerService->handle($server);
      59
      60
      return $this->returnNoContent();
      61
      }
      62
      63
      # Our mount function
      64
      public function mount(ServerWriteRequest $request, Server $server): Response
      65
      {
      66
      $mountServer = (new MountServer())->forceFill([
      67
      'mount_id' => $request->input('mount_id'),
      68
      'server_id' => $server->id,
      69
      ]);
      70
      71
      $mountServer->saveOrFail();
      72
      73
      return $this->returnNoContent();
      74
      }
      75
      }
  3. 3.
    Now navigate to app/routes/api-application.php and open it.
    1. 1.
      Below the following line:
      Route::post('/{server:id}/reinstall', [Application\Servers\ServerManagementController::class, 'reinstall'])->name('api.application.servers.reinstall');
      Paste this line
      Route::post('/{server:id}/mount', [Application\Servers\ServerManagementController::class, 'mount'])->name('api.application.servers.mount');
    2. 2.
      The end result should look like the following. You can also just use it to completely copy-paste the content to your api-application.php, but a more manual approach like in step 1 is preferred as Pterodactyl may do additional modifications to this file in the future.
      api-application.php
      1
      <?php
      2
      3
      use Illuminate\Support\Facades\Route;
      4
      use Pterodactyl\Http\Controllers\Api\Application;
      5
      6
      /*
      7
      |--------------------------------------------------------------------------
      8
      | User Controller Routes
      9
      |--------------------------------------------------------------------------
      10
      |
      11
      | Endpoint: /api/application/users
      12
      |
      13
      */
      14
      15
      Route::group(['prefix' => '/users'], function () {
      16
      Route::get('/', [Application\Users\UserController::class, 'index'])->name('api.application.users');
      17
      Route::get('/{user:id}', [Application\Users\UserController::class, 'view'])->name('api.application.users.view');
      18
      Route::get('/external/{external_id}', [Application\Users\ExternalUserController::class, 'index'])->name('api.application.users.external');
      19
      20
      Route::post('/', [Application\Users\UserController::class, 'store']);
      21
      Route::patch('/{user:id}', [Application\Users\UserController::class, 'update']);
      22
      23
      Route::delete('/{user:id}', [Application\Users\UserController::class, 'delete']);
      24
      });
      25
      26
      /*
      27
      |--------------------------------------------------------------------------
      28
      | Node Controller Routes
      29
      |--------------------------------------------------------------------------
      30
      |
      31
      | Endpoint: /api/application/nodes
      32
      |
      33
      */
      34
      Route::group(['prefix' => '/nodes'], function () {
      35
      Route::get('/', [Application\Nodes\NodeController::class, 'index'])->name('api.application.nodes');
      36
      Route::get('/deployable', Application\Nodes\NodeDeploymentController::class);
      37
      Route::get('/{node:id}', [Application\Nodes\NodeController::class, 'view'])->name('api.application.nodes.view');
      38
      Route::get('/{node:id}/configuration', Application\Nodes\NodeConfigurationController::class);
      39
      40
      Route::post('/', [Application\Nodes\NodeController::class, 'store']);
      41
      Route::patch('/{node:id}', [Application\Nodes\NodeController::class, 'update']);
      42
      43
      Route::delete('/{node:id}', [Application\Nodes\NodeController::class, 'delete']);
      44
      45
      Route::group(['prefix' => '/{node:id}/allocations'], function () {
      46
      Route::get('/', [Application\Nodes\AllocationController::class, 'index'])->name('api.application.allocations');
      47
      Route::post('/', [Application\Nodes\AllocationController::class, 'store']);
      48
      Route::delete('/{allocation:id}', [Application\Nodes\AllocationController::class, 'delete'])->name('api.application.allocations.view');
      49
      });
      50
      });
      51
      52
      /*
      53
      |--------------------------------------------------------------------------
      54
      | Location Controller Routes
      55
      |--------------------------------------------------------------------------
      56
      |
      57
      | Endpoint: /api/application/locations
      58
      |
      59
      */
      60
      Route::group(['prefix' => '/locations'], function () {
      61
      Route::get('/', [Application\Locations\LocationController::class, 'index'])->name('api.applications.locations');
      62
      Route::get('/{location:id}', [Application\Locations\LocationController::class, 'view'])->name('api.application.locations.view');
      63
      64
      Route::post('/', [Application\Locations\LocationController::class, 'store']);
      65
      Route::patch('/{location:id}', [Application\Locations\LocationController::class, 'update']);
      66
      67
      Route::delete('/{location:id}', [Application\Locations\LocationController::class, 'delete']);
      68
      });
      69
      70
      /*
      71
      |--------------------------------------------------------------------------
      72
      | Server Controller Routes
      73
      |--------------------------------------------------------------------------
      74
      |
      75
      | Endpoint: /api/application/servers
      76
      |
      77
      */
      78
      Route::group(['prefix' => '/servers'], function () {
      79
      Route::get('/', [Application\Servers\ServerController::class, 'index'])->name('api.application.servers');
      80
      Route::get('/{server:id}', [Application\Servers\ServerController::class, 'view'])->name('api.application.servers.view');
      81
      Route::get('/external/{external_id}', [Application\Servers\ExternalServerController::class, 'index'])->name('api.application.servers.external');
      82
      83
      Route::patch('/{server:id}/details', [Application\Servers\ServerDetailsController::class, 'details'])->name('api.application.servers.details');
      84
      Route::patch('/{server:id}/build', [Application\Servers\ServerDetailsController::class, 'build'])->name('api.application.servers.build');
      85
      Route::patch('/{server:id}/startup', [Application\Servers\StartupController::class, 'index'])->name('api.application.servers.startup');
      86
      87
      Route::post('/', [Application\Servers\ServerController::class, 'store']);
      88
      Route::post('/{server:id}/suspend', [Application\Servers\ServerManagementController::class, 'suspend'])->name('api.application.servers.suspend');
      89
      Route::post('/{server:id}/unsuspend', [Application\Servers\ServerManagementController::class, 'unsuspend'])->name('api.application.servers.unsuspend');
      90
      Route::post('/{server:id}/reinstall', [Application\Servers\ServerManagementController::class, 'reinstall'])->name('api.application.servers.reinstall');
      91
      # The line we added (below)
      92
      Route::post('/{server:id}/mount', [Application\Servers\ServerManagementController::class, 'mount'])->name('api.application.servers.mount');
      93
      94
      Route::delete('/{server:id}', [Application\Servers\ServerController::class, 'delete']);
      95
      Route::delete('/{server:id}/{force?}', [Application\Servers\ServerController::class, 'delete']);
      96
      97
      // Database Management Endpoint
      98
      Route::group(['prefix' => '/{server:id}/databases'], function () {
      99
      Route::get('/', [Application\Servers\DatabaseController::class, 'index'])->name('api.application.servers.databases');
      100
      Route::get('/{database:id}', [Application\Servers\DatabaseController::class, 'view'])->name('api.application.servers.databases.view');
      101
      102
      Route::post('/', [Application\Servers\DatabaseController::class, 'store']);
      103
      Route::post('/{database:id}/reset-password', [Application\Servers\DatabaseController::class, 'resetPassword']);
      104
      105
      Route::delete('/{database:id}', [Application\Servers\DatabaseController::class, 'delete']);
      106
      });
      107
      });
      108
      109
      /*
      110
      |--------------------------------------------------------------------------
      111
      | Nest Controller Routes
      112
      |--------------------------------------------------------------------------
      113
      |
      114
      | Endpoint: /api/application/nests
      115
      |
      116
      */
      117
      Route::group(['prefix' => '/nests'], function () {
      118
      Route::get('/', [Application\Nests\NestController::class, 'index'])->name('api.application.nests');
      119
      Route::get('/{nest:id}', [Application\Nests\NestController::class, 'view'])->name('api.application.nests.view');
      120
      121
      // Egg Management Endpoint
      122
      Route::group(['prefix' => '/{nest:id}/eggs'], function () {
      123
      Route::get('/', [Application\Nests\EggController::class, 'index'])->name('api.application.nests.eggs');
      124
      Route::get('/{egg:id}', [Application\Nests\EggController::class, 'view'])->name('api.application.nests.eggs.view');
      125
      });
      126
      });
  4. 4.
    Now cd into your Pterodactyl folder via the following command: cd /var/www/pterodactyl
  5. 5.
    Execute the following commands:
    root@pterodactyl:/var/www/pterodactyl# php artisan optimize:clear
    INFO Clearing cached bootstrap files.
    events .................................................................................................................................. 5ms DONE
    views ................................................................................................................................... 6ms DONE
    cache ................................................................................................................................... 6ms DONE
    route ................................................................................................................................... 1ms DONE
    config .................................................................................................................................. 1ms DONE
    compiled ................................................................................................................................ 2ms DONE
    root@pterodactyl:/var/www/pterodactyl# php artisan optimize
    INFO Caching the framework bootstrap files.
    config ................................................................................................................................. 25ms DONE
    routes ................................................................................................................................. 59ms DONE
  6. 6.
    After that's done, we can now create our mount. Go to the mounts tab on your Pterodactyl admin panel and click the Create New and fill the fields as in the following example. Make sure to name Target folder as /plugins-repo. Source folder should be set to the path of your plugins folder.
    Mount creation example