Install Directus 7 on web host

Installing Directus 7 on a webhost is quite a hassle. This document explains how it works.

Structure

All folders are relative to the root of your domain!

Folder Purpose URL
api api rest calls https://api.yourdomain.com
api7.server Directus server instance You can place this also behind the visible folders in the public area in something like 'private_server', but then you have to modify the relative paths as mentioned in the code below to that same level
directus Directus standalone app https://www.yourdomain.com/directus

URL's

The server at api7.server is never directly called in your browser (therefor you should hide it behind the public part of your website)

Installation of the app (directus)

To install the app (directus) just follow the documentation.

Standalone app

which mainly is:

git clone -b build https://github.com/directus/app.git directus

You can also install it local on a disk an move it with ftp to directus folder in the root of your domain.

Install API

The API installation is in fact the installation of the server itself, containing a public folder that will end up to be our api (api.yourhost.com).

Standalone API

which in fact is:

git clone -b build https://github.com/directus/api.git

but it is better to do:

git clone -b build https://github.com/directus/api.git api7.server

which clones this git into folder api7.server. Later on you can move it to a hidden place behind the public folder.

Install the api for the subdomain api.yourdomain.com

For the api there is not much to install. It is in fact not more than creating an 'api' subdomain at your host.
This process will likely create a 'api' subfolder in the root of your public folders automatically.

Don't forget to install a SSL certificate for your api.yourdomain.com domain.

Now when that is done, copy the contents of the public folder in the api7.server folder into the root of the the api.yourhost.com subdomain, which is likely the 'api' folder in the root.

Configuration

api (subdomain folder contents)

index.php

<?php
$app = require dirname(__DIR__, 1) . '/api7.server/src/web.php';
$app->run();

thumbnail/index.php

<?php

require dirname(__DIR__, 2) . '/api7.server/vendor/autoload.php';

use Directus\Util\ArrayUtils;
use Directus\Filesystem\Thumbnailer;

and somewhat later in the file:

try {
    $app = require dirname(__DIR__, 2) . '/api7.server/src/web.php';
//  $app = \Directus\create_app_with_project_name($basePath, $projectName);
} catch (\Exception $e) {

correcting the thumbnailer custom configuration settings

There is a bug or it is very poorly documented, which makes it hard to find how the thumbnail feature of Directus
can handle custom settings, like f.e. other image formats. This can easily be corrected.

Again we edit the same thumbnail/index.php file. Just after the try catch we have modified just a minute ago we add another modification:

try {

    $app = require dirname(__DIR__, 2) . '/api7.server/src/web.php';
//    $app = \Directus\create_app_with_project_name($basePath, $projectName);

} catch (\Exception $e) {
    http_response_code(404);
    header('Content-Type: application/json');
    echo json_encode([
        'error' => [
            'error' => 8,
            'message' => 'API Project Configuration Not Found: ' . $projectName
        ]
    ]);
    exit;
}

// ------ modification starts here --------

$customSettings = [];
if (file_exists(dirname(__FILE__) . '/configuration.php')) {
    $customSettings = require_once(dirname(__FILE__) . '/configuration.php');
    if (is_array($customSettings) === false) {
       $customSettings = [];
    }
}

$defaultSettings = \Directus\get_directus_thumbnail_settings();

$settings = array_merge_recursive($defaultSettings, $customSettings);

// ------- modification ends here ----------

try {
    $app = require dirname(__DIR__, 2) . '/api7.server/src/web.php';

Now we can add a file to the same folder with the name configuration.php, here is a sample

<?php
return [
    'thumbnail_not_found_location' => __DIR__ . '/img-not-found.png',
    'thumbnail_dimensions' => [
        // width x height
        '100x100',
        '100x200',
        '300x300',
        '500x500',
        '640x480',
        '1024x1024'
    ],
    'thumbnail_quality_tags' => [
        'poor' => 25,
        'good' => 50,
        'better' => 75,
        'best' => 100,
    ],
    'thumbnail_actions' => [
        'contain' => [
            'options' => [
                'resizeCanvas' => false, // http://image.intervention.io/api/resizeCanvas
                'position' => 'center',
                'resizeRelative' => false,
                'canvasBackground' => 'ccc', // http://image.intervention.io/getting_started/formats
            ]
        ],
        'crop' => [
            'options' => [
                'position' => 'center', // http://image.intervention.io/api/fit
            ]
        ],
    ]
];

Sample:

https://api.thuiskunst.nl/thumbnail/_/300/300/crop/best/IMG_7240.JPG

Result

You can download this image and put it in the api/thumbnail folder as well.

api7.server contents

config/api.php

Storage section (notice the <-- important)

<?php

return [
    ...

    'storage' => [
        'adapter' => 'local',
        // The storage root is the directus root directory.
        // All path are relative to the storage root when the path is not starting with a forward slash.
        // By default the uploads directory is located at the directus public root
        // An absolute path can be used as alternative.
        'root' => dirname(__FILE__, 3) . '/api/uploads/_/originals',   // <--- important
        // This is the url where all the media will be pointing to
        // here is where Directus will assume all assets will be accessed
        // Ex: (yourdomain)/uploads/_/originals
        'root_url' => 'https://api.thuiskunst.nl/uploads/_/originals',   // <--- important
        // Same as "root", but for the thumbnails
        'thumb_root' => dirname(__FILE__, 3) . '/api/uploads/_/thumbnails',   // <--- important
        //   'key'    => 's3-key',
        //   'secret' => 's3-secret',
        //   'region' => 's3-region',
        //   'version' => 's3-version',
        //   'bucket' => 's3-bucket',
        //   'options' => ['ACL' => 'public-read', 'Cache-Control' => 'max-age=604800']
        // Set custom S3 endpoint
        //   'endpoint' => 's3-endpoint',
    ],
    ...
];

Cors section

return [
    ...

'cors' => [
        'enabled' => true, // <--- important
        'origin' => ['*'],
        'methods' => [
            'GET',
            'POST',
            'PUT',
            'PATCH',
            'DELETE',
            'HEAD',
        ],
        'headers' => [], // <-- leave this empty (1)
        'exposed_headers' => [],
        'max_age' => null, // in seconds
        'credentials' => false,
    ],    
    ...
]

(1) Follow the directions from the .htaccess chapter in the directus folder at the end of this article

Directus app (directus folder)

config.js

/* eslint-disable */

(function directusConfig() {
  const config = {
    // The API URLs the user can connect to using this instance of the application.
    // Object values are used as project name in the app
    // Don't forget to add the API environment!
    api: {
      "https://api.yourhost.com/_/": "Your app name"
    },

    // Allow the user to connect to any API by entering a URL in a text field
    //   instead of selecting from a dropdown
    allowOtherAPI: false,

    // Controls the way the application routes. By default, routing is done using
    //   hashes (#) to ensure the app works without any server url rewrites.
    //
    // If you're using the application and have the correct URL rewrites in place
    //   (everything to /index.html), you can change this to "history" to make
    //   the urls in the app a little prettier
    routerMode: "hash", // hash | history

    // When using history mode, the application will make all the routes "pretty"
    // by using absolute paths. If you are serving the application from a folder
    // like /admin, this will cause the routes to be wrong (eg /collection instead
    // of /admin/collections). To combat this, set the routerBaseUrl to the path
    // you're serving the application from
    routerBaseUrl: "/directus"  // <--- important
  };

  window.__DirectusConfig__ = config;
})();

.htaccess

I had an error with the cross domain loading (CORS) from the api subdomain (where the media is stored) to the directus app.

Add this to the .htaccess file in the directus app root folder. It allows traffic coming from the 'api' subdomain on the same host.

<IfModule mod_headers.c>
   SetEnvIfNoCase Origin "https?://(api\.)?(yourdomain\.com)(:\d+)?$" ACAO=$0
   Header set Access-Control-Allow-Origin %{ACAO}e env=ACAO
</IfModule>
Last update: Tue, 13 Sep 2022 14:32:15