Skip to main content

Detailed Start

This comprehensive guide walks you through setting up your own oryelle instance, covering all available configuration options in detail.

oryelle's architecture consists of two main Docker containers: a frontend for the user interface and a backend for processing. This containerized approach provides flexibility for deployment across various platforms. For this guide, we'll demonstrate local deployment using Docker Compose.

In addition to the core oryelle containers, the setup requires:

  • A reverse proxy to handle routing - we'll use Traefik in this guide, though other reverse proxies will work
  • A PostgreSQL database with the pgvector extension for vector operations and storage

To begin, let's create a dedicated directory for your oryelle installation:

mkdir setup
cd setup

1. Creating the docker compose file

Let's create a Docker Compose configuration file that includes all available environment variables for both oryelle containers. We documented each option, including optional settings (only for the two oryelle containers), to help you understand and customize your deployment.

docker-compose.yml
services:
traefik:
image: traefik:v2.10
command:
- "--api.insecure=false"
- "--providers.docker=true"
- "--providers.docker.exposedbydefault=false"
- "--entrypoints.web.address=:80"
networks:
- frontend_proxy
- backend_proxy
ports:
- "3000:80" # Expose oryelle on port 3000 (of the host).
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
frontend:
container_name: frontend
image: ghcr.io/oryelle/oryelle-frontend:latest
restart: always
depends_on:
- backend
networks:
- frontend_proxy
labels:
- "traefik.enable=true"
- "traefik.http.routers.frontend.rule=PathPrefix(`/`) && !PathPrefix(`/api/v1`)" # Route traffic not going to /api/v1 to the frontend.
- "traefik.http.routers.frontend.entrypoints=web"
- "traefik.http.services.frontend.loadbalancer.server.port=3000" # The frontend listens on port 3000 (of the container).
backend:
container_name: backend
image: ghcr.io/oryelle/oryelle-backend:latest
restart: always
environment:
- DB_USER=postgres # The database user to use for the backend. Required.
- DB_PASSWORD=password # The password for the database user. Required. (Make sure to change this in production!)
- DB_HOST=db # The host of the database. Required.
- DB_PORT=5432 # The port of the database. Required.
- DB_NAME=oryelle # The name of the database. Required.
- DB_SSL=false # Whether to use SSL for the database connection.
- SESSION_SECRET=*** # The session secret to use for express user sessions. Generate yours with `openssl rand -hex 32`
- COOKIE_MAX_AGE=2592000000 # The maximum age of the cookie in milliseconds. Required.
- COOKIE_SAMESITE=lax # The same site attribute of the cookie. Required.
- LOG_LEVEL=error # The log level to use for the backend. Can be "error", "warn", "info" or "debug".
- LOG_FILES=false # Can be "true" or "false". Whether to create log files.
- ENABLE_SENTRY=true # Optional. Whether to send reports to sentry. Default is true. This helps the oryelle team fix bugs.
networks:
- backend_db
- backend_proxy
volumes:
- file_data:/app/data/files # The volume for the file (uploaded to oryelle) data. Required, so oryelle can persist the files.
- log_data:/app/data/logs # The volume for the log data. Only necessary if you want to persist the logs.
- ./:/app/config:ro # Map the current folder of the host to the config folder of the backend. Required, so oryelle can find the config file.
labels:
- "traefik.enable=true"
- "traefik.http.routers.backend.rule=PathPrefix(`/api/v1`)" # Route traffic going to /api/v1 to the backend.
- "traefik.http.routers.backend.entrypoints=web"
- "traefik.http.services.backend.loadbalancer.server.port=3333" # The backend listens on port 3333 (of the container).
depends_on:
db:
condition: service_healthy
db:
image: pgvector/pgvector:pg17
restart: always
shm_size: 128mb
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}"]
interval: 30s
timeout: 60s
retries: 5
start_period: 20s
volumes:
- postgres_data:/var/lib/postgresql/data # The volume for the database data. Required.
networks:
- backend_db
environment: # The following variables need to match the values in the backend environment variables.
POSTGRES_PASSWORD: password # The password for the database user. Required. (Make sure to change this in production!)
POSTGRES_USER: postgres # The database user to use for the backend. Required.
POSTGRES_DB: oryelle # The name of the database. Required.
networks:
backend_db:
internal: true
frontend_proxy:
internal: true
backend_proxy:
internal: false
volumes:
file_data:
postgres_data:
log_data:
Important Security Notice

Proper security configuration of your reverse proxy is critical for production deployments. Pay special attention to:

  • Header handling: Configure proxy headers securely - The oryelle-backend trusts X-Forwarded-For, X-Forwarded-Host, and X-Forwarded-Proto headers by default (express trust proxy is set to true). Ensure these headers are properly configured and validated in your reverse proxy to prevent spoofing.
  • SSL/TLS settings: Ensure proper HTTPS configuration

We recommend thoroughly reviewing your chosen reverse proxy's security documentation (e.g. Traefik's security guide) before deploying to production. Additionally, follow Docker security best practices to harden your compose configuration.

2. Creating the oryelle configuration file

The oryelle configuration file serves multiple essential purposes:

  • Specifies initial user accounts to be created during first launch
  • Configures authentication method (email/password or SSO, with SSO pending future support)
  • Controls initial Multi-Factor Authentication (MFA) settings
  • Defines available Model Context Protocol (MCP) Servers
  • Manages Large Language Model (LLM) configurations and their capabilities
  • Designates which LLM handles chat name generation
  • Specifies the model responsible for file embedding creation
  • Determines which MCP server and LLM settings can be configured through the UI (known as "requirements", useful for managing items like API keys)
  • Sets license parameters and associated limitations (optional; default license is used if not specified)

We will now go over each of these points one by one. Before we get started, we create the following (almost empty) configuration file:

config.json
{
"version": "1",
"authentication": "",
"users": [],
"requireMFA": false,
"mcpServers": [],
"models": [],
"chatNameGenerationModel": {},
"embeddingModel": {}
}
info

The file must be called config.json and it must be located in the host folder that is mapped to the /app/config/ folder in the docker container.

Authentication Method

The "authentication" property specifies how users will authenticate with oryelle. Currently, it only accepts "password" as a valid value, which enables email + password based authentication. This is a required property that must be set. While only password authentication is supported today, we plan to add Single Sign-On (SSO) capabilities in future releases.

"authentication": "password"

Initial Users

The "users" property defines the initial set of user accounts created during first launch. You must specify at least one administrator account during setup. This array only affects the initial user creation - once the application has started and users are stored in the database, modifying this configuration will have no effect. Below, we'll demonstrate how to configure both an administrator and a standard user account.

"users": [
{
"name": "Initial Admin",
"role": "admin",
"email": "[email protected]",
"password": "password1234"
},
{
"name": "Initial Non-Admin",
"role": "user",
"email": "[email protected]",
"password": "password4321"
}
]

Initial MFA Policy

The "requireMFA" property determines whether Multi-Factor Authentication (MFA) should be mandatory for all users from the start. While this can be enabled later through the web interface, setting it to true in the initial configuration ensures MFA is required immediately upon launch. Note that this property only affects the initial setup - once oryelle is running, the setting is stored in the database and subsequent changes to this property in the configuration file will not take effect. For this example we will set it to false.

"requireMFA": false

Requirements

Let's explore the concept of requirements in oryelle. Requirements can be configured for both MCP Servers and models to specify what data should be passed to them during execution. There are four types of requirements:

  • "default": These are global requirements that can only be configured by administrators through the web interface library. They're ideal for scenarios where all users need access to the same resource - for example, a shared API key for a web search MCP Server. These keys can be securely stored so they're never exposed to end users.

  • "userID": When enabled, oryelle will automatically pass the internal user ID to any resource with this requirement. This enables fine-grained access control based on user identity.

  • "email": Similar to userID, this requirement tells oryelle to pass the user's email address to the resource. This is particularly useful for access control in corporate environments where email addresses are used to authenticate access to internal resources.

  • "individual": These requirements are configured separately for each user through the web interface library. This is perfect for scenarios where each user needs their own unique credentials - for example, personal repository access tokens or API keys.

In addition to specifying the type of requirement, you can configure two important properties that control how requirements behave:

  • "secure": A boolean flag (true or false) that controls value visibility. When set to true, the requirement value will never be sent back to users via HTTP. When false, users can view the value that is set for a requirement in the library interface. This property is particularly relevant for "default" and "individual" requirements.
  • "required": A boolean flag (true or false) that indicates whether the requirement must be satisfied for the resource to function. Resources with unfulfilled required requirements will be unavailable. Note that this setting has no impact on "email" and "userID" requirements since these values are always present.
Important Security Notice

Please note that once a requirement value is passed to an MCP Server or model, oryelle cannot control how that value is handled, even if "secure" is set to true. To prevent potential data leaks, carefully verify that any MCP Servers and models you use implement proper security measures for handling requirement values.

Let's examine how to define requirements in practice. We'll demonstrate this using an MCP Server example, though the same principles apply when configuring requirements for models. Since we haven't covered MCP Servers in detail yet, we'll focus specifically on the "requirements" property and its configuration.

You can configure a default requirement as follows:

config.json
"mcpServers": [
{
. . .
"requirements": {
"ALLOWED_FILES": { // The requirement key. Must be unique for this mcpServer. Required.
"title": "Allowed Files", // Define a title for your requirement. Required.
"shortDescription": "The directory the plugin can access.", // Give it a short description. Required.
"description": "The directory the plugin can access.", // Give it a long description (e.g. explain why it is needed, or how to obtain an API Key for a service). Required (but can be the same as the short description).
"secure": false, // Whether the requirement is secure or not. Required.
"required": true, // Whether the requirement is required or not. Required.
"type": "string", // The type of the requirement. Currently "string" is supported. Required.
"category": "default" // Tells oryelle that this is a default type requirement. Required.
}
},
"config": {
"transport": "stdio",
"command": "npx",
"args": [
"-y",
"@modelcontextprotocol/server-filesystem",
"${{ALLOWED_FILES}}" // The value of the requirement set by an admin will be inserted here when the MCP Server is loaded.
],
"restart": { "enabled": true, "maxAttempts": 3, "delayMs": 1000 }
}
}
],

When the mcpServer config is loaded by oryelle, it will replace ${{ALLOWED_FILES}} with the value that was set for the requirement via the web interface. You can use the ${{<requirement-key>}} syntax anywhere in the "config" section, to insert a requirement value. For more details have a look at the models and MCP Server section of this guide.

info

You can of course also add more than one requirement to a resource. Please note that Chat Name Generation and Embedding Models do not support requirements.

MCP Servers

The "mcpServer" property accepts an array of Model Context Protocol (MCP) servers that oryelle will utilize. Each server in this array represents a distinct service or capability that can be integrated into your oryelle instance.

info

For detailed information about MCP and creating custom servers, visit modelcontextprotocol.io. While oryelle currently focuses on MCP Server-defined tools, we're actively expanding support for additional resource types. Most tools are already compatible, though some advanced return formats are still in development.

Let's haver a look at how to configure an MCP server. Before we look at how to connect to the server, we will define some necessary metadata and optional requirements. We'll use a database server as an illustrative example to demonstrate the configuration process:

config.json
"mcpServers": [
{
// Metadata - everything is required!
"id": "plugins.oryelle.dev/customer_database/", // The id of the plugin. Needs to be unique for every MCP Server. Must be in the following format: plugins.<your-domain>.<your-tld>/<plugin-name>/ (can be chosen freely otherwise). We do not enforce this format (yet!!!), but features might break if you don't follow it.
"name": "Customer Database Plugin", // The name of the plugin. Can be freely chosen.
"description": "A plugin that allows access to the customer database.", // The short description of the plugin. Can be freely chosen.
"shortDescription": "A plugin that allows access to the customer database. It can perform CRUD operations on the database.", // The description of the plugin. Can be freely chosen.
"type": "Local", // The type that should be displayed for the MCP Server. Can be "Local" or "Online". This is solely for informative reasons for your organization members.
"schemaVersion": "1.0.0", // Version of the schema. Currently only "1.0.0" is supported.
"version": "1.0.0", // Version of the plugin. This is useful if you have multiple versions of your plugin. Can be freely chosen.

// Requirements - We define two example requirements
"requirements": {
"EMAIL": {
"title": "User Email",
"shortDescription": "The Email of the User.",
"description": "The Email of the User.",
"secure": false,
"required": true,
"type": "string",
"category": "email"
},
"ACCESS_TOKEN": {
"title": "Database Access Token",
"shortDescription": "The Access Token for the Database.",
"description": "The Access Token for the Database.",
"secure": true,
"required": true,
"type": "string",
"category": "default"
}
},
"config": {} // We will look at this later!
},
]

With our requirements and metadata in place, let's explore how to establish connections to MCP Servers. oryelle supports two transport protocols:

  • stdio - For local connections using standard input/output streams
  • sse - For remote connections over HTTP using Server-Sent Events

Let's see how to implement both transport methods with our database example:

config.json
"mcpServers": [
{
. . .
"config": {
"transport": "stdio", // We set the transport to "stdio"
"command": "node", // Here we use node to start a js MCP Server, you can use any command here, for example pip to start a python MCP Server or docker.
"args": [ // We specify some arguments for our MCP Server. The details will depend on the MCP Server you are trying to use - this is just an example.
"/mcp/database-mcp.js", // We assume that the MCP Server was installed in this directory in advance.
"--accessToken=${{ACCESS_TOKEN}}", // Pass the Access Token to it
"--userEmail=${{EMAIL}}" // Pass the user email to it
],
"restart": { "enabled": true, "maxAttempts": 3, "delayMs": 1000 }
}
}
]

When a user attempts to interact with the MCP Server, oryelle automatically handles the startup process, ensuring a seamless experience.

info

The specific command (node), path (/mcp/database-mcp.js), and flags (--userEmail) shown above are just examples. The actual values you'll use depend on:

  1. The programming language and runtime of your MCP Server implementation
  2. Where you installed or built your MCP Server
  3. What configuration options your specific MCP Server accepts

For example, a Python-based MCP Server might use python as the command and accept different flag names. Always refer to your MCP Server's documentation for the correct configuration values.

Other available config options

oryelle leverages the langchainjs-mcp-adapters package for MCP Server connections. Any configuration options specified in the "config" section of your MCP Server definitions are passed directly to the underlying MultiServerMCPClient from @langchain/mcp-adapters. Please note: OAuth is currently not supported.

To illustrate how this works, let's examine a sample configuration:

config.json
"mcpServers": [
{
. . .
"config": {
"transport": "sse",
"url": "https://mcp.example.com/database",
"headers": {
"Authorization": "Bearer token1234",
"Your-Custom-Header": "[email protected]"
},
"useNodeEventSource": true,
"reconnect": { "enabled": true, "maxAttempts": 3, "delayMs": 2000 }
}
}
]

This configuration is transformed internally by oryelle into a MultiServerMCPClient instance, structured as follows:

tools-oryelle.js
import { MultiServerMCPClient } from "@langchain/mcp-adapters";

// ...

const client = new MultiServerMCPClient({
// ...
mcpServers: {
<generated-id>: {
transport: "sse",
url: "https://mcp.example.com/database",
headers: {
Authorization: "Bearer token1234",
"Your-Custom-Header": "[email protected]"
},
useNodeEventSource: true,
reconnect: {
enabled: true,
maxAttempts: 5,
delayMs: 2000,
},
},
},
});

Similarly, for stdio transports, you can configure options like command, args, and other stdio-specific settings. oryelle fully supports all configuration options available in MultiServerMCPClient, allowing you to customize both SSE and stdio transports according to your needs.

Models

The "models" property allows you to configure an array of LLMs for your application. oryelle provides seamless integration with:

  • Ollama models for local inference
  • OpenAI API compatible models, including (but not limited to):
    • Official OpenAI API
    • Cloudflare Workers AI
    • Self-hosted OpenAI API compatible models

Let's haver a look at how to configure a model. Before we look at how to connect to the model, we will define some necessary metadata and optional requirements. We'll use an example to demonstrate the configuration process:

config.json
  "models": [
{
// Metadata - Everything is required!
"id": "models.oryelle.dev/Qwen2.5/", // The id of the model. Needs to be unique for every model. Must be in the following format: models.<your-domain>.<your-tld>/<model-name>/ (can be chosen freely otherwise). We do not enforce this format (yet!!!), but features might break if you don't follow it.
"name": "Qwen 2.5", // The name that will be displayed for the model. Can be freely chosen (but it makes sense to chose the name of the model).
"description": "Qwen2.5 72B Model - A powerful open source LLM.", // The model description. Can be used to describe the models capabilities or to describe to your members, what they can use it for best.
"shortDescription": "An advanced model by Qwen", // A short description. Can be freely chosen.
"supportsTools": true, // Whether the model supports tools (MCP Servers). Changing this value has no effect whether the model actually supports tools, it will only enable tool related capabilities in oryelle. You need to check whether a model supports tool calling or not.
"supportsImages": false, // Whether the model supports image inputs. Changing this value has no effect whether the model actually supports images. You need to check whether a model supports OpenAI compatible image inputs.
"type": "Cloud", // The type that should be displayed for the model. Can be "Cloud" or "Local". This is solely for informative reasons for your organization members.
"version": "1.0.0", // Version of the model. This is useful if you have multiple versions of your model. Can be freely chosen.
"schemaVersion": "1.0.0", // Version of the schema. Currently only "1.0.0" is supported.
"graph": "react", // Currently only "react" is supported.

// Requirements
"requirements": {
"API_KEY": {
"title": "API Key",
"shortDescription": "API Key for the model.",
"description": "The API key for the model.",
"secure": true,
"required": true,
"type": "string",
"category": "default"
}
},

// Connection Details
"adapter": "", // We will look at this later
"adapterConfig": {} // We will look at this later
}
]

Now that we have configured the required metadata and a requirement, let's explore how to set up the adapter to connect to different types of models:

config.json
  "models": [
{
...
// Connection Details
"adapter": "openai", // We set this value to "openai"
"adapterConfig": {
"model": "qwen2.5", // Here we specify the model we want to use - the value here is given by the OpenAI API provider used by you
"openAIApiKey": "${{API_KEY}}", // The API key for the API provider
"configuration": {
"baseURL": "https://api.your-provider.com/v1/" // The baseURL for your API provider
}
}
}
]

Chat Name Generation Model (optional)

The "chatNameGenerationModel" property allows you to specify a model for automatically generating concise chat titles based on conversation context. For instance, a discussion about calculations might receive the title "Calculation". While optional, this feature enhances the user experience by providing meaningful conversation labels.

You can configure either an ollama or openai adapter for this purpose, similar to regular models. The setup follows the same pattern as standard models, though it's simpler since metadata and requirements are not supported. We recommend using a lightweight, efficient model to ensure quick title generation without consuming excessive resources.

Here an example with an ollama adapter:

config.json
"chatNameGenerationModel": {
"adapter": "ollama", // Specify the ollama adapter
"adapterConfig": {
"model": "gemma3:1b", // Specify the model
"temperature": 0.7, // Optionally set the temperature
"baseUrl": "http://host.docker.internal:11434" // Specify the baseUrl
}
}

Embedding Model

The "embeddingModel" property specifies the model used to generate vector embeddings for files uploaded to oryelle. These embeddings enable semantic search and similarity matching across your documents. oryelle supports both ollama and openai adapters for embedding models:

config.json
"embeddingModel": {
"adapter": "openai", // Set the adapter to openai
"adapterConfig": {
"openAIApiKey": "<your-api-key>", // Replace this with the API key for your API provider
"configuration": {
"baseURL": "https://api.openai.com/v1/" // Replace this with the baseURL of your API provider
}
}
}

License

oryelle comes with a default license that includes basic functionality and standard usage limits. To use this default license, you don't need to change anything in your setup. For expanded capabilities, custom limits, or enterprise features, please contact our team to discuss licensing options that best fit your needs. You will receive instructions on how to add a license, after obtaining one.

3. Start oryelle

With both your docker-compose.yml and config.json files properly configured, you're ready to launch oryelle. Start the service by running the following command:

Terminal
docker compose up -d

Congratulations! Your oryelle instance should now be running and accessible at https://localhost:3000 (unless you specified a different port in your configuration). You can access the platform using the admin credentials you defined in your configuration file.

For security purposes, we recommend changing your password after your first login.

Important Security Notice

Before deploying oryelle to the internet, please ensure you:

  1. Follow best practices in our Security Considerations documentation
  2. Consider implementing Cloudflare Zero Trust to secure your instance with enterprise-grade protection

Proper security configuration is essential for protecting your oryelle deployment and its data from unauthorized access and potential threats.