Warning

The reseller functionality in Fleio will be deprecated and removed from Fleio in the following months. We recommend that you do not use this feature any more.

How to configure the reseller panel on different subdomains

Enable reseller feature

First, we will need to enable the reseller feature.

To do that please check How to enable reseller feature in docker deployment.

Fleio settings.py changes

In settings.py we need to allow the reseller’s subdomains to connect to the Fleio backend.

For this guide, we will use the following setup:

Fleio installation URL:

  • portal.fleio.com

Reseller urls:

  • reseller.fleio.com

  • reseller2.fleio.com

Notice that the cookie domain will be the top level domain (in our case fleio.com).

Run the fleio edit settings.py command and add the following code at the end of your settings.py file.

NEW_MIDDLEWARE = list(MIDDLEWARE)
NEW_MIDDLEWARE.insert(1, 'corsheaders.middleware.CorsMiddleware')
MIDDLEWARE = tuple(NEW_MIDDLEWARE)
RESELLER_DOMAINS = {
    'reseller.fleio.com': {
        'url': 'http://reseller.fleio.com',
        'cookie_domain': 'fleio.com',
     },
    'portal.fleio.com': {
        'url': 'http://reseller.fleio.com',
        'cookie_domain': 'fleio.com',
     },
    'reseller2.fleio.com': {
        'url': 'http://reseller2.fleio.com',
        'cookie_domain': 'fleio.com',
     },
    'portal.fleio.com': {
        'url': 'http://reseller2.fleio.com',
        'cookie_domain': 'fleio.com',
     },
}
CORS_ORIGIN_WHITELIST = (
    'http://portal.fleio.com',
    'http://reseller.fleio.com',
    'http://reseller2.fleio.com',
)
CORS_ALLOW_CREDENTIALS = True
for domain in RESELLER_DOMAINS:
   CORS_ORIGIN_WHITELIST += (RESELLER_DOMAINS[domain]['url'],)
   ALLOWED_HOSTS.append(domain)

For each new domain you will have to add a new entry in the RESELLER_DOMAINS dictionary, with the following syntax:

...
'reseller3.fleio.com': {
    'url': 'http://reseller3.fleio.com',
    'cookie_domain': 'fleio.com',
 },
'portal.fleio.com': {
    'url': 'http://reseller3.fleio.com',
    'cookie_domain': 'fleio.com',
 },

Additionally, you need to add the reseller domains in the ALLOWED_HOSTS list.

On exit, when you will be asked to restart Fleio, answer with “N”. We will restart later.

Fleio web configuration

Before digging into adding custom configuration to the fleio_web_1 container, please read the following docs:

First we will create a new directory where we will place our updated web.conf.template file. All these needs to be done while using the fleio user:

sudo -i -u fleio
mkdir /home/fleio/compose/custom-web

Create the custom-web Dockerfile and add the updated file

touch /home/fleio/compose/custom-web/Dockerfile
touch /home/fleio/compose/custom-web/web.conf.template

In the Dockerfile add the following:

ARG FLEIO_DOCKER_HUB
ARG FLEIO_RELEASE_SUFFIX

FROM ${FLEIO_DOCKER_HUB}/fleio_web${FLEIO_RELEASE_SUFFIX}

COPY web.conf.template /etc/nginx/templates/web.conf.template

The web.conf.template must be configured different, depending on the FLEIO_SSL_OPTION. Please check the variable in /home/fleio/compose/.env and use the proper template:

Important

Notice that all resellers have different and unused ports. Reseller 1 will use the 9001 port, while reseller 2 will use 9002 port Remember the ports because we will need them in the next step.

no_ssl

server {
  listen 8080;
  client_max_body_size 5000m;
  add_header X-Frame-Options "SAMEORIGIN";
  server_name ${FLEIO_DOMAIN};

  gzip on;
  gzip_min_length 1000;
  gzip_proxied expired no-cache no-store private auth;
  gzip_types text/plain text/css application/json application/javascript application/x-javascript text/xml application/xml application/xml+rss text/javascript;

  location /backend {
    include /etc/nginx/uwsgi_params;
    proxy_pass http://backend:8000;
    proxy_redirect http://$host:8000 http://$host;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_buffering off;
    proxy_request_buffering off;
    proxy_read_timeout 150s;
  }

  location / {
    proxy_pass http://frontend:9000;
    proxy_redirect http://$host:9000 http://$host;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  }
}

# reseller 1

server {
  listen 8080;
  client_max_body_size 5000m;
  add_header X-Frame-Options "SAMEORIGIN";
  server_name reseller.fleio.com;

  gzip on;
  gzip_min_length 1000;
  gzip_proxied expired no-cache no-store private auth;
  gzip_types text/plain text/css application/json application/javascript application/x-javascript text/xml application/xml application/xml+rss text/javascript;

  location /backend {
    include /etc/nginx/uwsgi_params;
    proxy_pass http://backend:8000;
    proxy_redirect http://$host:8000 http://$host;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_buffering off;
    proxy_request_buffering off;
    proxy_read_timeout 150s;
  }

  location / {
    proxy_pass http://reseller:9001;
    proxy_redirect http://$host:9001 http://$host;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  }
}

# reseller 2

server {
  listen 8080;
  client_max_body_size 5000m;
  add_header X-Frame-Options "SAMEORIGIN";
  server_name reseller2.fleio.com;

  gzip on;
  gzip_min_length 1000;
  gzip_proxied expired no-cache no-store private auth;
  gzip_types text/plain text/css application/json application/javascript application/x-javascript text/xml application/xml application/xml+rss text/javascript;

  location /backend {
    include /etc/nginx/uwsgi_params;
    proxy_pass http://backend:8000;
    proxy_redirect http://$host:8000 http://$host;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_buffering off;
    proxy_request_buffering off;
    proxy_read_timeout 150s;
  }

  location / {
    proxy_pass http://reseller2:9002;
    proxy_redirect http://$host:9002 http://$host;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  }
}

own_ssl

server {
  listen 8080;

  server_name ${FLEIO_DOMAIN};

  location / {
    return 301 https://$host$request_uri;
  }
}

server {
  listen 4430 ssl;
  client_max_body_size 5000m;
  add_header X-Frame-Options "SAMEORIGIN";
  server_name ${FLEIO_DOMAIN};

  ssl_certificate /var/webapps/fleio/ssl/${FLEIO_DOMAIN}/ssl.crt;
  ssl_certificate_key /var/webapps/fleio/ssl/${FLEIO_DOMAIN}/ssl.key;

  gzip on;
  gzip_min_length 1000;
  gzip_proxied expired no-cache no-store private auth;
  gzip_types text/plain text/css application/json application/javascript application/x-javascript text/xml application/xml application/xml+rss text/javascript;

  location /backend {
    include /etc/nginx/uwsgi_params;
    proxy_pass http://backend:8000;
    proxy_redirect http://$host:8000 http://$host;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  }

  location / {
    proxy_pass http://frontend:9000;
    proxy_redirect http://$host:9000 http://$host;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_buffering off;
    proxy_request_buffering off;
    proxy_read_timeout 150s;
  }
}

# reseller 1

server {
  listen 4430 ssl;
  client_max_body_size 5000m;
  add_header X-Frame-Options "SAMEORIGIN";
  server_name reseller.fleio.com;

  ssl_certificate /var/webapps/fleio/ssl/reseller.fleio.com/ssl.crt;
  ssl_certificate_key /var/webapps/fleio/ssl/reseller.fleio.com/ssl.key;

  gzip on;
  gzip_min_length 1000;
  gzip_proxied expired no-cache no-store private auth;
  gzip_types text/plain text/css application/json application/javascript application/x-javascript text/xml application/xml application/xml+rss text/javascript;

  location /backend {
    include /etc/nginx/uwsgi_params;
    proxy_pass http://backend:8000;
    proxy_redirect http://$host:8000 http://$host;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  }

  location / {
    proxy_pass http://reseller:9001;
    proxy_redirect http://$host:9001 http://$host;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_buffering off;
    proxy_request_buffering off;
    proxy_read_timeout 150s;
  }
}

# reseller 2

server {
  listen 4430 ssl;
  client_max_body_size 5000m;
  add_header X-Frame-Options "SAMEORIGIN";
  server_name reseller2.fleio.com;

  ssl_certificate /var/webapps/fleio/ssl/reseller2.fleio.com/ssl.crt;
  ssl_certificate_key /var/webapps/fleio/ssl/reseller2.fleio.com/ssl.key;

  gzip on;
  gzip_min_length 1000;
  gzip_proxied expired no-cache no-store private auth;
  gzip_types text/plain text/css application/json application/javascript application/x-javascript text/xml application/xml application/xml+rss text/javascript;

  location /backend {
    include /etc/nginx/uwsgi_params;
    proxy_pass http://backend:8000;
    proxy_redirect http://$host:8000 http://$host;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  }

  location / {
    proxy_pass http://reseller2:9002;
    proxy_redirect http://$host:9002 http://$host;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_buffering off;
    proxy_request_buffering off;
    proxy_read_timeout 150s;
  }
}

lets_encrypt

server {
  listen 8080;

  server_name ${FLEIO_DOMAIN};

  location / {
    return 301 https://$host$request_uri;
  }
}

server {
  listen 4430 ssl;
  client_max_body_size 5000m;
  add_header X-Frame-Options "SAMEORIGIN";
  server_name ${FLEIO_DOMAIN};

  ssl_certificate /etc/letsencrypt/live/${FLEIO_DOMAIN}/ssl.crt;
  ssl_certificate_key /etc/letsencrypt/live/${FLEIO_DOMAIN}/ssl.key;

  gzip on;
  gzip_min_length 1000;
  gzip_proxied expired no-cache no-store private auth;
  gzip_types text/plain text/css application/json application/javascript application/x-javascript text/xml application/xml application/xml+rss text/javascript;

  location /backend {
    include /etc/nginx/uwsgi_params;
    proxy_pass http://backend:8000;
    proxy_redirect http://$host:8000 http://$host;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  }

  location / {
    proxy_pass http://frontend:9000;
    proxy_redirect http://$host:9000 http://$host;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_buffering off;
    proxy_request_buffering off;
    proxy_read_timeout 150s;
  }
}

# reseller 1

server {
  listen 4430 ssl;
  client_max_body_size 5000m;
  add_header X-Frame-Options "SAMEORIGIN";
  server_name reseller.fleio.com;

  ssl_certificate /var/webapps/fleio/ssl/reseller.fleio.com/ssl.crt;
  ssl_certificate_key /var/webapps/fleio/ssl/reseller.fleio.com/ssl.key;

  gzip on;
  gzip_min_length 1000;
  gzip_proxied expired no-cache no-store private auth;
  gzip_types text/plain text/css application/json application/javascript application/x-javascript text/xml application/xml application/xml+rss text/javascript;

  location /backend {
    include /etc/nginx/uwsgi_params;
    proxy_pass http://backend:8000;
    proxy_redirect http://$host:8000 http://$host;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  }

  location / {
    proxy_pass http://reseller:9001;
    proxy_redirect http://$host:9001 http://$host;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_buffering off;
    proxy_request_buffering off;
    proxy_read_timeout 150s;
  }
}

# reseller 2

server {
  listen 4430 ssl;
  client_max_body_size 5000m;
  add_header X-Frame-Options "SAMEORIGIN";
  server_name reseller2.fleio.com;

  ssl_certificate /var/webapps/fleio/ssl/reseller2.fleio.com/ssl.crt;
  ssl_certificate_key /var/webapps/fleio/ssl/reseller2.fleio.com/ssl.key;

  gzip on;
  gzip_min_length 1000;
  gzip_proxied expired no-cache no-store private auth;
  gzip_types text/plain text/css application/json application/javascript application/x-javascript text/xml application/xml application/xml+rss text/javascript;

  location /backend {
    include /etc/nginx/uwsgi_params;
    proxy_pass http://backend:8000;
    proxy_redirect http://$host:8000 http://$host;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  }

  location / {
    proxy_pass http://reseller2:9002;
    proxy_redirect http://$host:9002 http://$host;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_buffering off;
    proxy_request_buffering off;
    proxy_read_timeout 150s;
  }
}

Resellers configuration

Now we will need to create a new directory for each reseller, in the /home/fleio/compose directory:

# if you're not using the fleio user:
sudo -i -u fleio
mkdir /home/fleio/compose/reseller.fleio.com
mkdir /home/fleio/compose/reseller2.fleio.com

In these new directories, we will have to:

  • create new directories which will contain the enduser and reseller configuration files (these will be mapped as volumes)

  • define a new reseller image

  • add the nginx configuration file for the reseller’s domain

Create the needed directories:

#if you're not using the fleio user:
sudo -i -u fleio
mkdir -p /home/fleio/compose/reseller.fleio.com/enduser/assets/config/
mkdir -p /home/fleio/compose/reseller.fleio.com/reseller/assets/config/
mkdir -p /home/fleio/compose/reseller.fleio.com/site/constants/

Create the Dockerfile and the reseller.fleio.com.conf file:

#if you're not using the fleio user:
sudo -i -u fleio
touch /home/fleio/compose/reseller.fleio.com/Dockerfile
touch /home/fleio/compose/reseller.fleio.com/reseller.fleio.com.conf

Add the following code in the Dockerfile:

ARG FLEIO_DOCKER_HUB
ARG FLEIO_RELEASE_SUFFIX

FROM ${FLEIO_DOCKER_HUB}/fleio_frontend${FLEIO_RELEASE_SUFFIX}

COPY reseller.fleio.com.conf "/etc/nginx/conf.d/reseller.fleio.com.conf"

Add the following code in the reseller.fleio.com.conf file. Make sure to configure the proper port on the listen 9001 line:

server {
    listen 9001;
    client_max_body_size 5000m;
    add_header X-Frame-Options "SAMEORIGIN";
    server_name reseller.fleio.com;

    location /images {
        alias /var/webapps/fleio/frontend/site/images/;
        break;
    }

    location /js {
        alias /var/webapps/fleio/frontend/site/js/;
        expires max;
        break;
    }

    location /vendor {
        alias /var/webapps/fleio/frontend/site/vendor/;
        expires max;
        break;
    }

    location /styles {
        alias /var/webapps/fleio/frontend/site/styles/;
        expires max;
        break;
    }

    location /reseller {
        alias /var/webapps/fleio/frontend/reseller/;
        expires -1;
        try_files $uri $uri/ /../reseller/index.html;
    }


    location /tinymce {
        alias /var/webapps/fleio/frontend/staff/tinymce/;
        break;
    }

    location /static {
        alias /var/webapps/fleio/frontend/backendstatic/;
        break;
    }

    location /new {
        alias /var/webapps/fleio/frontend/enduser/;
        expires -1;
        try_files $uri $uri/ /../enduser/index.html;
    }

    location / {
        alias /var/webapps/fleio/frontend/site/;
        expires -1;
        try_files $uri $uri/ /index.html;
    }
}

Now we need to add the enduser / reseller panel configuration files:

Important

Notice that the backendApiUrl is the main Fleio URL.

Angular enduser:

vi /home/fleio/compose/reseller.fleio.com/enduser/assets/config/enduser.config.json

And add the code from bellow.

{
  "urls": {
    "backendApiUrl": "//panel.fleio.com/backend/api/",
    "homeName": "enduser",
    "angularJsPanelUrl": "//reseller.fleio.com/",
    "resellerUrl": "/reseller"
  },
  "settings": {
    "defaultLanguage": "en",
    "imagesPath": "assets/img/enduser/",
    "logoDark": null,
    "logoLight": null,
    "defaultTheme": "spring",
    "availableThemes": [
      "spring",
      "navy",
      "dusk"
    ],
    "instanceForm": {
      "hideNetworksIfOnlyOneAvailable": true,
      "preselectPublicNetworks": true,
      "showUserData": true,
      "flavorsAsCards": false,
      "showRootPasswordField": true,
      "rootPasswordFieldMandatory": false,
      "hideVolumeSelectionForFlavorsWithDisk": false,
      "defaultVolumeType": null,
      "reseller_client_id": null
    },
    "logoutRedirect": null,
    "usernameInputLabel": null
  }
}

Angular JS enduser (will be removed soon, but as of 2021.06.1 this is still needed):

vi /home/fleio/compose/reseller.fleio.com/site/constants/constants.js
// Global end-user panel configuration
'use strict';

var user_config = {
    api_url: 'http://fleio.reseller.com/backend/api',
  language: 'en', // default language
  base_url: '/',
  home_url: '/',
  angularPanelUrl: 'http://reseller.fleio.com/new/',
  // logo_light: 'https://fleio.com/images/logo.png',
  // logo_dark: 'https://fleio.com/images/logo.png',
  // shutdown_instance_note: "NOTE: The instance will continue to be charged even if it's shutdown. Delete the instance if you want to no longer be charged.",
  // toast_hide_delay: 3000, // bottom-left toast message animation delay in milliseconds
  items_display_mode: 'cardview', //cardview || listview
  enable_debug: true,  // set to true in development to enable angular debug
  flavors_as_cards: false, // used on instance creation for flavors selector layout
  local_compute_storage_enabled: true, // used on instance create on boot source selection
  preselect_public_networks: true, // preselects networks with public tag on instance creation form
  hide_networks_if_only_one_available: true, // if there is only one network available on the instance creation form, preselect it and hide the input field
  show_root_password_field_on_new_instance_form: true,
  root_password_mandatory_on_new_instance_form: false,
  show_userdata_on_new_instance_form: true,
  hide_volume_selection_for_flavors_with_disk: false,
  default_volume_type_on_new_instance_form: null,  // dict, with keys as region names and value as volume type names
  // example default_volume_type_on_new_instance_form
  // default_volume_type_on_new_instance_form: {
  //   'RegionOne': 'SSD',
  // },
  customThemesCallback: function(mdThemingProvider) {
    // read the docs on how to define new themes
  },
  registeredThemes: ['Spring', 'Navy', 'Dusk'], // list of themes that can be used by a user
  new_object_arrow_img_source: 'images/arrow.png',
  logout_redirect: null,
  username_input_label: null,
  reseller_client_id: null,
};

try {
  angular.module('fleio.config').constant('CONFIG', user_config);
}
catch (err) {
  angular.module('fleiostaff.config').constant('USER_CONFIG', user_config);
}

Reseller panel:

vi /home/fleio/compose/reseller.fleio.com/reseller/assets/config/reseller.config.json

Add the code from bellow:

{
  "urls": {
    "backendApiUrl": "//fleio.reseller.com/backend/resellerapi/",
    "homeName": "reseller"
  },
  "settings": {
    "defaultLanguage": "en",
    "imagesPath": "assets/img/reseller/",
    "logoDark": null,
    "logoLight": null,
    "defaultTheme": "spring",
    "availableThemes": [
      "spring",
      "navy",
      "dusk"
    ],
    "instanceForm": {
      "hideNetworksIfOnlyOneAvailable": true,
      "preselectPublicNetworks": true,
      "showUserData": true,
      "flavorsAsCards": false,
      "showRootPasswordField": true,
      "rootPasswordFieldMandatory": false,
      "hideVolumeSelectionForFlavorsWithDisk": false,
      "defaultVolumeType": null
    },
    "logoutRedirect": null,
    "usernameInputLabel": null
  }
}

Repeat the previous steps for as many resellers as you want.

Define docker-compose services and map volumes

Lastly, we need to define the new docker-compose services and we need to map the configuration files in the reseller service:

#if you're not using the fleio user:
sudo -i -u fleio
cd /home/fleio/compose

Add this to the docker-compose.override.yml file:

services:
# redefine web service to include the custom web.conf.template file
  web:
    build:
      context: ./custom-web/
      dockerfile: Dockerfile
      args:
        - FLEIO_DOCKER_HUB
        - FLEIO_RELEASE_SUFFIX
    image: fleio_custom_web

# define a new reseller service for each of your resellers

  reseller:
    build:
      context: ./reseller.fleio.com/
      dockerfile: Dockerfile
      args:
        - FLEIO_DOCKER_HUB
        - FLEIO_RELEASE_SUFFIX
    image: fleio_reseller_1
    restart: always
    volumes:
      - /home/fleio/compose/reseller.fleio.com/site/constants:/var/webapps/fleio/frontend/site/constants
      - /home/fleio/compose/reseller.fleio.com/enduser/assets/config:/var/webapps/fleio/frontend/enduser/assets/config/
      - /home/fleio/compose/reseller.fleio.com/reseller/assets/config:/var/webapps/fleio/frontend/reseller/assets/config/

  reseller2:
    build:
      context: ./reseller2.fleio.com/
      dockerfile: Dockerfile
      args:
        - FLEIO_DOCKER_HUB
        - FLEIO_RELEASE_SUFFIX
    image: fleio_reseller2_1
    restart: always
    volumes:
      - /home/fleio/compose/reseller2.fleio.com/site/constants:/var/webapps/fleio/frontend/site/constants
      - /home/fleio/compose/reseller2.fleio.com/enduser/assets/config:/var/webapps/fleio/frontend/enduser/assets/config/
      - /home/fleio/compose/reseller2.fleio.com/reseller/assets/config:/var/webapps/fleio/frontend/reseller/assets/config/

Build and publish

Finally, we will need to build all our changes and to create the new containers based on the changes added in the docker-compose-override file.

fleio build
fleio recreate

If you run the fleio status command you should now see the new reseller services up and running. The reseller panel should also be available at the configured domains.