# How the CasaOS Relay Service Works for Data Relay: A Technical Deep Dive

> Discover how the CasaOS relay service functions as a data-access layer, using GORM to link custom identifiers with Docker containers for efficient data relay.

- Repository: [IceWhale/CasaOS](https://github.com/IceWhaleTech/CasaOS)
- Tags: deep-dive
- Published: 2026-06-28

---

**The CasaOS relay service is a thin data-access layer that stores and retrieves relationships between user-defined custom identifiers and their underlying Docker containers using GORM.**

The CasaOS relay service (implemented as `RelyService` in the IceWhaleTech/CasaOS repository) provides a lightweight persistence mechanism for mapping high-level application identifiers to actual Docker container IDs. This architectural component enables the rest of the system to locate and interact with containers using stable, user-friendly names rather than volatile container hashes. By leveraging GORM as its database abstraction layer, the service automatically inherits transaction handling, connection pooling, and support for both SQLite and MySQL backends.

## Core Architecture and Interface Design

The relay service follows a clean interface-based design that separates the contract definition from the concrete implementation.

### The RelyService Interface Definition

In [`service/rely.go`](https://github.com/IceWhaleTech/CasaOS/blob/main/service/rely.go) (lines 18-22), the `RelyService` interface defines the three core operations available to callers:

```go
type RelyService interface {
    Create(rely model.RelyDBModel)
    GetInfo(id string) model.RelyDBModel
    Delete(id string)
}

```

This minimal interface provides everything needed to manage the lifecycle of a relay mapping: creating records, retrieving container information by custom ID, and cleaning up obsolete entries.

### Database Model Structure

The underlying data structure is defined in [`service/model/o_rely.go`](https://github.com/IceWhaleTech/CasaOS/blob/main/service/model/o_rely.go) (lines 7-22) as the `RelyDBModel` struct:

```go
type RelyDBModel struct {
    ID                uint `gorm:"primarykey"`
    CustomId          string
    ContainerCustomId string
    ContainerId       string
    Type              int
    CreatedAt         time.Time
    UpdatedAt         time.Time
    DeletedAt         gorm.DeletedAt `gorm:"index"`
}

```

This GORM model maps directly to the `o_rely` table, storing the custom identifier (`CustomId`), the actual Docker container ID (`ContainerId`), and a computed container custom ID (`ContainerCustomId`). The `Type` field supports future extensibility, with available constants defined in [`types/rely.go`](https://github.com/IceWhaleTech/CasaOS/blob/main/types/rely.go) (line 3), including `RELY_TYPE_MYSQL` for potential multi-backend support.

## Data Flow and CRUD Operations

The `relyService` implementation (lines 24-51 in [`service/rely.go`](https://github.com/IceWhaleTech/CasaOS/blob/main/service/rely.go)) wraps a `*gorm.DB` instance and executes standard CRUD operations against the `o_rely` table.

### Service Initialization and Dependency Injection

When CasaOS bootstraps its service layer via `NewService` in [`service/service.go`](https://github.com/IceWhaleTech/CasaOS/blob/main/service/service.go) (lines 59-61), the relay service is instantiated with the same database connection used throughout the application:

```go
rely: NewRelyService(db),

```

This ensures the relay service participates in the same connection pool and transaction context as other data services.

### Creating Relay Records

The `Create` method receives a populated `RelyDBModel` and persists it using GORM's `Create` method:

```go
func (r *relyService) Create(rely model.RelyDBModel) {
    r.db.Create(&rely)
}

```

This inserts a new row into the `o_rely` table, establishing the mapping between the user-defined custom ID and the Docker container identifier.

### Querying and Deleting Mappings

Retrieval operations use the `GetInfo` method, which queries by `custom_id` and returns the first matching record:

```go
func (r *relyService) GetInfo(id string) model.RelyDBModel {
    var m model.RelyDBModel
    r.db.Where("custom_id = ?", id).First(&m)
    return m
}

```

Deletion is handled similarly via the `Delete` method, which removes rows matching the provided custom ID:

```go
func (r *relyService) Delete(id string) {
    var c model.RelyDBModel
    r.db.Where("custom_id = ?", id).Delete(&c)
}

```

## Integration with the Repository Pattern

The relay service is exposed to the rest of the application through the central `Repository` interface defined in [`service/service.go`](https://github.com/IceWhaleTech/CasaOS/blob/main/service/service.go) (lines 33-40 and 109-111). This aggregation pattern allows higher-level components—such as REST API controllers in `route/v2`—to access relay functionality via `MyService.Rely()`.

The repository structure (lines 59-61) shows how the service is wired:

```go
type repository struct {
    // ... other services
    rely RelyService
}

func (r *repository) Rely() RelyService {
    return r.rely
}

```

This design decouples the persistence logic from the HTTP handlers, ensuring that controllers only interact with the interface contract rather than direct database implementations.

## Working with the Relay Service: Code Examples

Below are practical examples demonstrating how to interact with the CasaOS relay service programmatically.

### Initializing the Service

Normally instantiated by the main application bootstrap, but can be created manually for testing:

```go
import (
    "gorm.io/driver/sqlite"
    "gorm.io/gorm"
    "github.com/IceWhaleTech/CasaOS/service"
)

func initRelyService() service.RelyService {
    db, _ := gorm.Open(sqlite.Open("casaos.db"), &gorm.Config{})
    // Migrate the schema (ensures o_rely exists)
    db.AutoMigrate(&service.model.RelyDBModel{}) // model path is service/model
    return service.NewRelyService(db)
}

```

### Creating a Relay Mapping

```go
func addRelay(svc service.RelyService, customID, containerID string) {
    relay := service.model.RelyDBModel{
        CustomId:          customID,
        ContainerCustomId: "casaos-" + customID,
        ContainerId:       containerID,
        Type:              service.types.RELY_TYPE_MYSQL, // currently 0
    }
    svc.Create(relay)
}

```

### Retrieving Relay Information

```go
func getRelay(svc service.RelyService, customID string) *service.model.RelyDBModel {
    info := svc.GetInfo(customID)
    return &info
}

```

### Deleting a Relay Record

```go
func deleteRelay(svc service.RelyService, customID string) {
    svc.Delete(customID)
}

```

### Accessing via Global Repository

```go
// Assume MyService has been initialised by the main application
relayInfo := MyService.Rely().GetInfo("my-custom-app")
fmt.Printf("Container ID: %s\n", relayInfo.ContainerId)

```

## Summary

- The **CasaOS relay service** acts as a thin data-access layer between user-defined identifiers and Docker container IDs, implemented in [`service/rely.go`](https://github.com/IceWhaleTech/CasaOS/blob/main/service/rely.go).
- It exposes **three core operations** (`Create`, `GetInfo`, `Delete`) through a clean interface definition located at lines 18-22 of [`service/rely.go`](https://github.com/IceWhaleTech/CasaOS/blob/main/service/rely.go).
- Data persistence uses **GORM** with the `RelyDBModel` struct (defined in [`service/model/o_rely.go`](https://github.com/IceWhaleTech/CasaOS/blob/main/service/model/o_rely.go) lines 7-22) mapping to the `o_rely` table.
- The service is **integrated via the Repository pattern** in [`service/service.go`](https://github.com/IceWhaleTech/CasaOS/blob/main/service/service.go) (lines 59-61), allowing access through `MyService.Rely()`.
- It supports **extensible relay types** through constants in [`types/rely.go`](https://github.com/IceWhaleTech/CasaOS/blob/main/types/rely.go) (line 3), though currently the default type is used for standard Docker container mappings.

## Frequently Asked Questions

### What is the primary purpose of the CasaOS relay service?

The CasaOS relay service provides a persistent mapping layer that links user-defined custom identifiers to actual Docker container IDs. This allows the system and API consumers to reference containers using stable, human-readable names rather than volatile Docker hashes, while the service handles the translation to physical container references.

### Which database table stores the relay mappings?

All relay records are stored in the **`o_rely`** table, defined by the `RelyDBModel` struct in [`service/model/o_rely.go`](https://github.com/IceWhaleTech/CasaOS/blob/main/service/model/o_rely.go) (lines 7-22). This table includes fields for `CustomId`, `ContainerId`, `ContainerCustomId`, and a `Type` field for future extensibility, along with standard GORM timestamps.

### How does the relay service handle different database types?

The relay service itself is database-agnostic, relying on GORM for all persistence operations. It accepts a `*gorm.DB` instance during initialization (as seen in [`service/service.go`](https://github.com/IceWhaleTech/CasaOS/blob/main/service/service.go) lines 59-61), which means it automatically inherits whatever database driver the main CasaOS application configures—whether SQLite for local deployments or MySQL for distributed setups. The `RELY_TYPE_MYSQL` constant in [`types/rely.go`](https://github.com/IceWhaleTech/CasaOS/blob/main/types/rely.go) (line 3) suggests future support for type-specific relay logic, though currently the service uses a unified approach.

### Where is the relay service initialized in the CasaOS architecture?

The relay service is instantiated within the **`NewService`** factory function in [`service/service.go`](https://github.com/IceWhaleTech/CasaOS/blob/main/service/service.go) (lines 59-61), where it receives the shared database connection. It is then exposed through the `Repository` interface at lines 109-111, making it available to HTTP controllers and other services via the `Rely()` method on the global service instance.