Architecture & Routing

Glue2 is the central reverse proxy that sits in front of every HolaCloud service. All incoming traffic — whether from browser users, API clients, or internal services — passes through Glue2 before reaching its destination.

Glue2 Architecture

Reverse Proxy

Glue2 operates as a Layer-7 reverse proxy. It terminates TLS, inspects each request, authenticates the caller, and then forwards the request to the appropriate backend service. No external traffic reaches HolaCloud services directly; Glue2 is the single entry point.

1Client ──▶ Glue2 (auth check) ──▶ Backend Service
2              │
3              ├──▶ InceptionDB
4              ├──▶ Lambda
5              ├──▶ Files
6              ├──▶ Config
7              ├──▶ KVNode
8              ├──▶ Scheduler
9              └──▶ Logs

Virtual Host Routing

Glue2 routes requests based on the Host header. Each HolaCloud project is assigned a unique subdomain (<project>.hola.cloud), and Glue2 maps that subdomain to the project's backend service.

Built-in platform services use reserved subdomains:

Host Service
inceptiondb.hola.cloud InceptionDB
api.hola.cloud Public API (Lambda, Files, Config, etc.)
console.hola.cloud HolaCloud Console
auth.hola.cloud Authentication / Session service
logs.hola.cloud InstantLogs

When a request arrives for my-project.hola.cloud, Glue2 looks up the project with that slug, resolves its primary backend service, and forwards the request.

The Proxy Flow

  1. Client sends an HTTP request to <project>.hola.cloud.
  2. Glue2 terminates the TLS connection and reads the Host header.
  3. Glue2 checks authentication (session cookie, API key, or OAuth token). If the endpoint requires auth and none is provided, the request is rejected with 401 Unauthorized.
  4. Glue2 resolves the virtual host to a project ID and backend service target.
  5. Glue2 injects authentication and project headers into the request.
  6. The request is forwarded to the backend service.
  7. The backend response is streamed back to the client, and Glue2 logs the transaction.

Injected Headers

When forwarding to a backend, Glue2 injects:

Header Description
X-Glue-Authentication Plain JSON authentication context
X-Holacloud-Project-Id The UUID of the project derived from the virtual host
X-Holacloud-Tenant-Project-Id Tenant-scoped project ID for multi-tenant isolation
X-Forwarded-For Original client IP address
X-Forwarded-Proto Original protocol (http or https)

Backend services use these headers to identify the caller and enforce authorization. X-Glue-Authentication is plain JSON.

V0 Admin Endpoints

Glue2 exposes a set of admin endpoints under /v0/:

List Virtual Hosts

curl "https://api.hola.cloud/v0/virtualhosts" \
GET /v0/virtualhosts HTTP/1.1
Host: api.hola.cloud
// Go 1.21+, standard library only. Save as main.go and run: go run main.go
package main

import (
	"fmt"
	"io"
	"net/http"
)

func main() {
	req, err := http.NewRequest("GET", "https://api.hola.cloud/v0/virtualhosts", nil)
	if err != nil {
		panic(err)
	}

	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		panic(err)
	}
	defer resp.Body.Close()

	responseBody, err := io.ReadAll(resp.Body)
	if err != nil {
		panic(err)
	}
	fmt.Println(resp.Status)
	fmt.Println(string(responseBody))
}
<?php
// PHP 8+ with the curl extension. Save as example.php and run: php example.php

$ch = curl_init();

curl_setopt_array($ch, [
    CURLOPT_URL => 'https://api.hola.cloud/v0/virtualhosts',
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST => 'GET',
]);

$response = curl_exec($ch);
if ($response === false) {
    throw new Exception(curl_error($ch));
}
echo curl_getinfo($ch, CURLINFO_RESPONSE_CODE), "\n", $response, "\n";
curl_close($ch);
# Python 3.8+. Install: pip install requests. Save as example.py and run: python example.py
import requests

response = requests.request(
    "GET",
    "https://api.hola.cloud/v0/virtualhosts"
)

print(response.status_code)
print(response.text)
// Node.js 18+. Save as example.mjs and run: node example.mjs
const response = await fetch("https://api.hola.cloud/v0/virtualhosts", {
  method: "GET"
});

console.log(response.status);
console.log(await response.text());
const response = await fetch("https://api.hola.cloud/v0/virtualhosts", {
  method: "GET"
});

console.log(response.status);
console.log(await response.text());
// Java 17+, standard library only. Save as Main.java and run: java Main.java
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;

public class Main {
    public static void main(String[] args) throws Exception {
        var request = HttpRequest.newBuilder()
            .uri(URI.create("https://api.hola.cloud/v0/virtualhosts"))
            .method("GET", HttpRequest.BodyPublishers.noBody())
            .build();

        var response = HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString());
        System.out.println(response.statusCode());
        System.out.println(response.body());
    }
}
1["my-project.hola.cloud", "api.my-project.hola.cloud"]

Traffic Stats

curl "https://api.hola.cloud/v0/stats" \
GET /v0/stats HTTP/1.1
Host: api.hola.cloud
// Go 1.21+, standard library only. Save as main.go and run: go run main.go
package main

import (
	"fmt"
	"io"
	"net/http"
)

func main() {
	req, err := http.NewRequest("GET", "https://api.hola.cloud/v0/stats", nil)
	if err != nil {
		panic(err)
	}

	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		panic(err)
	}
	defer resp.Body.Close()

	responseBody, err := io.ReadAll(resp.Body)
	if err != nil {
		panic(err)
	}
	fmt.Println(resp.Status)
	fmt.Println(string(responseBody))
}
<?php
// PHP 8+ with the curl extension. Save as example.php and run: php example.php

$ch = curl_init();

curl_setopt_array($ch, [
    CURLOPT_URL => 'https://api.hola.cloud/v0/stats',
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST => 'GET',
]);

$response = curl_exec($ch);
if ($response === false) {
    throw new Exception(curl_error($ch));
}
echo curl_getinfo($ch, CURLINFO_RESPONSE_CODE), "\n", $response, "\n";
curl_close($ch);
# Python 3.8+. Install: pip install requests. Save as example.py and run: python example.py
import requests

response = requests.request(
    "GET",
    "https://api.hola.cloud/v0/stats"
)

print(response.status_code)
print(response.text)
// Node.js 18+. Save as example.mjs and run: node example.mjs
const response = await fetch("https://api.hola.cloud/v0/stats", {
  method: "GET"
});

console.log(response.status);
console.log(await response.text());
const response = await fetch("https://api.hola.cloud/v0/stats", {
  method: "GET"
});

console.log(response.status);
console.log(await response.text());
// Java 17+, standard library only. Save as Main.java and run: java Main.java
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;

public class Main {
    public static void main(String[] args) throws Exception {
        var request = HttpRequest.newBuilder()
            .uri(URI.create("https://api.hola.cloud/v0/stats"))
            .method("GET", HttpRequest.BodyPublishers.noBody())
            .build();

        var response = HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString());
        System.out.println(response.statusCode());
        System.out.println(response.body());
    }
}

Backend Health Status

curl "https://api.hola.cloud/v0/status" \
GET /v0/status HTTP/1.1
Host: api.hola.cloud
// Go 1.21+, standard library only. Save as main.go and run: go run main.go
package main

import (
	"fmt"
	"io"
	"net/http"
)

func main() {
	req, err := http.NewRequest("GET", "https://api.hola.cloud/v0/status", nil)
	if err != nil {
		panic(err)
	}

	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		panic(err)
	}
	defer resp.Body.Close()

	responseBody, err := io.ReadAll(resp.Body)
	if err != nil {
		panic(err)
	}
	fmt.Println(resp.Status)
	fmt.Println(string(responseBody))
}
<?php
// PHP 8+ with the curl extension. Save as example.php and run: php example.php

$ch = curl_init();

curl_setopt_array($ch, [
    CURLOPT_URL => 'https://api.hola.cloud/v0/status',
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST => 'GET',
]);

$response = curl_exec($ch);
if ($response === false) {
    throw new Exception(curl_error($ch));
}
echo curl_getinfo($ch, CURLINFO_RESPONSE_CODE), "\n", $response, "\n";
curl_close($ch);
# Python 3.8+. Install: pip install requests. Save as example.py and run: python example.py
import requests

response = requests.request(
    "GET",
    "https://api.hola.cloud/v0/status"
)

print(response.status_code)
print(response.text)
// Node.js 18+. Save as example.mjs and run: node example.mjs
const response = await fetch("https://api.hola.cloud/v0/status", {
  method: "GET"
});

console.log(response.status);
console.log(await response.text());
const response = await fetch("https://api.hola.cloud/v0/status", {
  method: "GET"
});

console.log(response.status);
console.log(await response.text());
// Java 17+, standard library only. Save as Main.java and run: java Main.java
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;

public class Main {
    public static void main(String[] args) throws Exception {
        var request = HttpRequest.newBuilder()
            .uri(URI.create("https://api.hola.cloud/v0/status"))
            .method("GET", HttpRequest.BodyPublishers.noBody())
            .build();

        var response = HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString());
        System.out.println(response.statusCode());
        System.out.println(response.body());
    }
}
1[
2  {
3    "id": "project-123",
4    "name": "My Project",
5    "host": "my-project.hola.cloud",
6    "status": 200,
7    "statusText": "200 OK"
8  }
9]

Next Steps

Comments

Leave a comment