Jump to content
Jump to navigation

Jump to heading Architecture

Jump to heading Overview

Scotty provides a simple REST API to interact with your apps. For that, it traverses a directory structure on the server and reads the docker-compose.yml files in each found directory. If the same directory contains a .scotty file, it reads the settings for that app from that file.

Scotty uses the information from the .scotty.yml file to create a docker-compose.override.yml file to instruct a load balancer on how to reach the exposed services of the app. Scotty does not touch any other files in the directory besides the docker-compose.override.yml and .scotty.yml files.

Scotty also tracks how long an app has been running and stops it after a given lifetime. It can add basic auth to the app and prevent robots from indexing the app if needed.

Jump to heading The anatomy of an app

Every folder with a docker-compose.yml file is considered an app. The folder needs to reside in the apps directory of Scotty (see configuration).

Every app has a unique name which derives from the folder the docker-compose.yml is in. The name is used to identify the app in the UI and CLI. An app has numerous services, which are defined in the docker-compose.yml file. Some of the services are exposed to the public, some are not. Every service gets a unique hostname, which is derived from the app name and service name, but this can be overridden in the .scotty.yml file or while creating a new app.

Ideally the docker-compose references pre-built docker images, but it can also build images on the fly from Dockerfiles.

Example layout of the apps directory:

.
├── feat-preview-apps-using-scotty-test
│   ├── docker-compose.override.yml
│   └── docker-compose.yml
├── main-test-app
│   ├── docker-compose.override.yml
│   ├── docker-compose.yml
│   ├── private
│   ├── redis.conf
│   └── web
└── nginx-test
    ├── docker-compose.override.yml
    ├── docker-compose.yml
    └── html
        ├── index.html
        └── static
            ├── app.5a03541a7bda648594c1.js
            └── app.b77a84840a9e3574131f2ed36a54aa86.css

Jump to heading Types of apps

Scotty does not support all possible docker-compose settings. docker-compose.yml is validated and categorized into three types: owned, supported and unsupported:

Unsupported features are:

  • Exposing ports directly, as this might conflict with other running apps
  • Using environment-variable expansion inside the docker-compose.yml file. This is not supported, as Scotty can't know the values of the environment variables at runtime. You can adopt these types of apps manually and provide the values for the environment variables in the .scotty.yml file.

Scotty will also try to handle apps found in the apps directory or its subdirectories. That means you can have other apps running on the server which won't be visible or interfered with by Scotty.

Jump to heading Owned apps

Owned apps are either created by Scotty, or adopted manually. Scotty is allowed to manage the whole lifecycle of the app, even destroying the app and all its data.

Jump to heading Supported apps

Supported apps are docker-compose-based applications which can be handled by Scotty. They do not have any side-effects in their docker-compose file like exposed ports or needed environment variables. Scotty can handle the complete lifecycle of the app, but won't allow destroying the app and all its data.

Jump to heading Unsupported apps

Unsupported apps are docker-compose-based applications which need environment variables to interact with docker-compose or are exposing ports directly. Scotty won't touch these apps but will show them in the UI and CLI. You can use the cli-command app:adopt to make the app compatible with Scotty.

Jump to heading Blueprints

Owned apps can adopt blueprints to provide additional functionality. Blueprints store common tasks to execute on certain events like app:create, app:run or app:destroy.

These scripts are stored in the blueprints directory of Scotty. The scripts are executed in the running service container of the app. Common tasks could be, for example, running the deploy command for Drupal applications, or clearing the cache for other apps.

Blueprints can be provided when creating a new app via app:create.

Jump to heading Server-Architecture

Scotty traverses a dedicated folder on the server to find possible apps. If there is a folder with a valid docker-compose.yml file, Scotty will add the app to its internal database. If there is a corresponding .scotty.yml file, Scotty will also read the settings for that particular app.

When Scotty creates a new app, it will save the settings in the .scotty.yml file and create a docker-compose.override.yml file to instruct the load balancer on what domain should be used to reach each public service of an app.

Jump to heading Overview

Server Architecture

Scotty works well with the following load balancers:

Jump to heading Traefik

Scotty will create the necessary labels for Traefik to route the traffic to the public services of each app. Depending on the settings, Scotty will also create configuration to enable basic auth or to prevent robots from indexing the app.

An example docker-compose.override.yml file for Traefik:

services:
  nginx:
    labels:
      traefik.http.routers.nginx--nginx-again.middlewares: nginx--nginx-test--robots
      traefik.http.routers.nginx--nginx-again.rule: Host(`nginx.nginx-test.example.com`)
      traefik.enable: 'true'
      traefik.http.services.nginx--nginx-again.loadbalancer.server.port: '80'
      traefik.http.routers.nginx--nginx-again.tls: 'true'
      traefik.http.routers.nginx--nginx-again.tls.certresolver: myresolver
      traefik.http.middlewares.nginx--nginx-again--robots.headers.customresponseheaders.X-Robots-Tags: none, noarchive, nosnippet, notranslate, noimageindex
    environment: {}
    networks:
    - default
    - proxy
networks:
  proxy:
    external: true

Jump to heading Haproxy-Config

Scotty supports the legacy setup called haproxy-config. It will create the necessary docker-compose.override.yml to instruct haproxy-config to route the traffic to the public services of each app. Haproxy-config does not support preventing robots from indexing the app. The support for haproxy-config won't be continued in the future, as haproxy-config is deprecated.

An example docker-compose.override.yml file for haproxy-config:

services:
  nginx:
    environment:
      VHOST: nginx.test-nginx.example.com
      HTTPS_ONLY: '1'
      VPORT: '80'
      HTTP_AUTH_USER: nginx
      HTTP_AUTH_PASS: nginx

Jump to heading Domain-Setup

Best practice is to have a wildcard domain pointing to the server where Scotty is running and giving Scotty a subdomain to manage the apps. This way Scotty can create new domains for apps without further DNS configuration being necessary. It is also advised to use Let's Encrypt to provide SSL certificates for the domains and apps. Both proxy types support Let's Encrypt.

An example setup:

apps.example.com   A     1.2.34
*.apps.example.com CNAME apps.example.com.

Then you can assign scotty.apps.example.com to Scotty and let Scotty manage the apps.

Jump to heading Caveats and pitfalls

  • If you are running the Scotty server inside a Docker container, you need to make sure that the path to the apps folder is the same on both the host and the Docker container, as Scotty is using docker-compose to manage the apps. Otherwise mounted binds of your apps would not work as expected, since bind mount paths need to be identical on the host and container. It's a bit complicated, but as a rule of thumb: when using Scotty, make sure to mount the apps folder to the same path!