> For the complete documentation index, see [llms.txt](https://docs.trmnl.com/go/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.trmnl.com/go/diy/byos.md).

# BYOS (Build Your Own Server)

Buy a TRMNL device, then point it at your own server.

### Why

TRMNL intends to ensure that **every device is un-brickable and can run with zero external dependencies**. BYOS is one aspect of making this possible for you.

### Quick Start

1. Purchase a TRMNL from our [store](https://trmnl.com).
2. Choose a BYOS implementation for your stack (see below). Our flagship implementation is [Terminus](https://github.com/usetrmnl/terminus), so we recommend you get started there.

### Audience

This page is primarily for BYOS maintainers but might also be helpful for anyone wanting to get a high level overview of what each implementation can do before spinning up on your own network.

### Implementations

We support multiple implementations developed by us and the community at large. The goal isn't for BYOS to match parity with our hosted solution but to provide enough of a pleasant solution for your own customized experience. There are trade offs either way but we've got you covered for whatever path you wish to travel.

**Legend**

Use this legend to understand the matrix of features below.

* 🟢 Supported.
* 🟡 Partially supported.
* 🔴 Not supported or not implemented.
* ⚪️ Unknown.

**Matrix**

Below is a list of all implementations in various languages/frameworks you can use to self-host and manage your devices with:

<table><thead><tr><th width="150.58984375">Implementation</th><th>Stack</th><th width="121.6953125">Dashboard</th><th width="172.37109375">Auto-Provisioning</th><th width="111.859375">Devices</th><th>JSON Data API</th><th>Image Previews</th><th>Playlists</th><th>Plugins</th><th>Recipes</th><th>Sensors</th><th>Docker</th><th>Test Suite</th><th>Maintained</th><th>Semantic Versioning</th></tr></thead><tbody><tr><td><a href="https://github.com/usetrmnl/terminus"><strong>Terminus</strong></a></td><td>Ruby/Hanami</td><td>🟢</td><td>🟢</td><td>🟢</td><td>🟢</td><td>🟢</td><td>🟢</td><td>🟢</td><td>🟢</td><td>🟢</td><td>🟢</td><td>🟢</td><td>🟢</td><td>🟢</td></tr><tr><td><a href="https://github.com/usetrmnl/larapaper"><strong>LaraPaper</strong></a></td><td>PHP/Laravel</td><td>🟢</td><td>🟢</td><td>🟢</td><td>🟢</td><td>🟢</td><td>🟢</td><td>🟢</td><td>🟢</td><td>🔴</td><td>🟢</td><td>🟢</td><td>🟢</td><td>🔴</td></tr><tr><td><a href="https://github.com/usetrmnl/inker"><strong>Inker</strong></a></td><td>JavaScript</td><td>🟢</td><td>🟢</td><td>🟢</td><td>🟢</td><td>🟢</td><td>🟢</td><td>🟢</td><td>🟢</td><td>🔴</td><td>🟢</td><td>🟢</td><td>🟢</td><td>⚪️</td></tr><tr><td><a href="https://github.com/usetrmnl/byos_next"><strong>BYOS Next.js</strong></a></td><td>JavaScript/Next.js</td><td>🟢</td><td>🟢</td><td>🟢</td><td>🟢</td><td>🟢</td><td>🟢</td><td>🔴</td><td>🟢</td><td>🔴</td><td>🟢</td><td>🔴</td><td>🟢</td><td>🟢</td></tr><tr><td><a href="https://github.com/usetrmnl/byos_fastapi"><strong>BYOS Fast API</strong></a></td><td>Python/FastAPI</td><td>🟢</td><td>⚪️</td><td>🟢</td><td>🔴</td><td>🟢</td><td>🟢</td><td>🟢</td><td>⚪️</td><td>🔴</td><td>🔴</td><td>🔴</td><td>🔴</td><td>⚪️</td></tr><tr><td><a href="https://github.com/usetrmnl/byos_django"><strong>BYOS Django</strong></a></td><td>Python/Django</td><td>🔴</td><td>🔴</td><td>🟢</td><td>🟢</td><td>🟢</td><td>🔴</td><td>🔴</td><td>🔴</td><td>🔴</td><td>🟢</td><td>🔴</td><td>🔴</td><td>⚪️</td></tr><tr><td><a href="https://github.com/usetrmnl/byos_phoenix"><strong>BYOS Phoenix</strong></a></td><td>Elixir/Phoenix</td><td>🔴</td><td>🔴</td><td>🟢</td><td>🟢</td><td>🟢</td><td>🟢</td><td>🔴</td><td>🔴</td><td>🔴</td><td>🔴</td><td>🔴</td><td>🔴</td><td>⚪️</td></tr></tbody></table>

The following provides a detailed breakdown of each of the above features:

* **Dashboard**: Provides a high level overview of information mostly in terms of quick links, statistics, charts, graphs, system health, etc.
* **Auto-Provisioning**: Devices can be automatically provisioned once added to your network. This includes the automatic provisioning of new and existing devices.
* **Devices**: Provides device management in terms of updating each device, viewing current image, viewing logs, and more.
* **JSON Data API**: Provides full API support using a JSON Data API for device management, image generation, logging, and more.
* **Image Previews**: Provides a UI for quickly, and dynamically, generating new device screens.
* **Playlists**: Supports playlist configuration and management in terms of timing, order, and display of screens on devices. This can also include proxying to our Core server.
* **Plugins**: Supports installation and hosting of custom plugins. This can also include proxying to our Core server.
* **Recipes**: Supports installation and hosting of custom plugins. This can also include proxying to our Core server.
* **Sensors**: Supports sensors connected via [Qwiic Cables](https://www.sparkfun.com/flexible-qwiic-cable-50mm.html) either to the server (via Raspberry Pi) or via a TRMNL compatible device. Please see the [TRMNL Sensor Scanner](https://github.com/usetrmnl/sensor_scanner) project for further details.
* **Docker**: Supports Docker for both local development and production deployment.
* **Test Suite**: Has a test suite with near 100% test coverage, is fully runnable locally, and is wired up with automatic Continuous Integration (CI) builds.
* **Maintained**: Project is maintained and kept up-to-date on a weekly (or monthly) basis in terms of dependencies, firmware updates, and keeping up-to-date with any/all Core changes.
* **Semantic Versioning**: Supports [strict semantic versioning](https://alchemists.io/articles/strict_semantic_versioning).

### API

At a minimum, the following API endpoints should be supported for all BYOS implementations. The headers below are the ones our firmware sends.

#### Setup

The device calls this once, after WiFi setup, to trade its MAC address for an API key.

```shell
curl "http://byos.local/api/setup" \
    -H 'ID: <device_mac_address>' \
    -H 'FW-Version: 1.8.16' \
    -H 'Model: og' \
    -H 'Content-Type: application/json'
```

The firmware reads `status`, `api_key`, `friendly_id`, `image_url` + `message`, and stores `api_key` for every request after this one. Any `status` other than `200` counts as a failed setup.

Example response:

```json
{
  "status": 200,
  "api_key": "<device_api_key>",
  "friendly_id": "ABC123",
  "image_url": "http://byos.local/images/setup-logo.bmp",
  "message": "Register at byos.local with Device ID 'ABC123'"
}
```

#### Display

The device calls this on every wake. It also sends battery, WiFi + screen details as headers (`Battery-Voltage`, `RSSI`, `Width`, `Height`, `Refresh-Rate` and more); see [Screens](/go/private-api/screens.md) for the full list.

```bash
curl "http://byos.local/api/display" \
     -H 'ID: <device_mac_address>' \
     -H 'Access-Token: <device_api_key>' \
     -H 'FW-Version: 1.8.16' \
     -H 'Content-Type: application/json'
```

The firmware reads these fields:

* `status` -- `0` draws `image_url`; `202` means "not registered yet" and the device polls again in a few seconds
* `image_url` + `filename` -- `filename` is a cache key, so the device only downloads `image_url` when `filename` changes
* `refresh_rate` -- seconds to sleep before the next request
* `reset_firmware` -- `true` makes the device erase its WiFi credentials + API key
* `update_firmware` + `firmware_url` -- `true` + a `.bin` URL triggers an OTA update
* `special_function` -- what a button press does (e.g. `identify`, `sleep`, `rewind`)

#### Logs

When something goes wrong (a failed download, a bad image), the device posts its logs here:

```bash
curl -X POST "http://byos.local/api/log" \
     -H 'ID: <device_mac_address>' \
     -H 'Access-Token: <device_api_key>' \
     -H 'Content-Type: application/json' \
     -d '{"logs": [{"message": "..."}]}'
```

💡 For a detailed breakdown of all API endpoints and what they can do, please refer to the [Terminus API Documentation](https://github.com/usetrmnl/terminus?tab=readme-ov-file#api) or the [TRMNL API](https://github.com/usetrmnl/trmnl-api) gem which provides a Ruby API client for talking to our servers.

### Securing With HTTPS

Most BYOS implementations serve up content over plain HTTP. If you prefer TLS connections, you can put a reverse proxy in front of the server. Caddy is a popular option. You can use self-signed certificates, or real ones from Let's Encrypt. See [this community issue](https://github.com/usetrmnl/trmnl-firmware/issues/58#issue-2826999580) for details on how to set it up yourself.
