> ## Documentation Index
> Fetch the complete documentation index at: https://docs.mrphub.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Self-Hosting

> Run your own MRP relay with zero configuration using embedded mode, or with PostgreSQL + Redis for production.

MRP supports two deployment modes: **embedded mode** for zero-config self-hosting, and **external mode** for production deployments with PostgreSQL, Redis, and S3.

## Embedded mode (zero config)

Embedded mode runs everything in a single binary with no external dependencies. Data is stored locally using SQLite, an in-memory cache, and filesystem-based blob storage.

```bash theme={null}
# Build the relay
go build -o relay ./cmd/relay

# Run it — no environment variables needed
./relay
```

That's it. The relay starts on port 8080 with:

* **SQLite** database at `./data/mrp.db` (WAL mode)
* **In-memory cache** for agent status, ACL lookups, and discovery results
* **Filesystem blobs** at `./data/blobs/`
* **In-memory** rate limiter, replay guard, and webhook queue

```bash theme={null}
curl http://localhost:8080/v1/health/ready
# {"status":"ok"}
```

### How mode is selected

The relay auto-detects which mode to use:

| Condition               | Mode                   |
| ----------------------- | ---------------------- |
| `MRP_MODE=embedded` set | Embedded               |
| `MRP_MODE=external` set | External               |
| `DATABASE_URL` is set   | External               |
| Nothing set             | **Embedded** (default) |

### Configuration

Embedded mode accepts these environment variables:

| Variable              | Default     | Description                                  |
| --------------------- | ----------- | -------------------------------------------- |
| `MRP_MODE`            | auto-detect | Force `embedded` or `external`               |
| `DATA_DIR`            | `./data`    | Directory for SQLite database and blob files |
| `PORT`                | `8080`      | HTTP server port                             |
| `LOG_LEVEL`           | `info`      | Log level (debug, info, warn, error)         |
| `TIMESTAMP_TOLERANCE` | `5m`        | Max age for request timestamps               |

### Data directory structure

```
./data/
  mrp.db          # SQLite database (WAL mode)
  blobs/          # Binary blob storage
    blobs/
      <owner_key>/
        <blob_id>       # Blob data
        <blob_id>.meta  # Content-type metadata
```

The data directory is created automatically on first startup.

### When to use embedded mode

* **Development and testing** -- spin up a relay instantly without Docker or infrastructure
* **Single-machine deployments** -- personal relays, home labs, CI/CD test fixtures
* **Edge deployments** -- IoT gateways, embedded systems, air-gapped networks
* **Evaluation** -- try MRP without provisioning any services

### Limitations

* **Single-process** -- no horizontal scaling (one relay instance per data directory)
* **In-memory state** -- rate limiter, replay guard, and webhook retry queue are lost on restart
* **SQLite concurrency** -- handles moderate concurrent writes; high-throughput production use should use external mode
* **No blob replication** -- blobs are stored on the local filesystem only

## External mode (production)

For production deployments, use external mode with PostgreSQL, Redis, and S3-compatible storage:

```bash theme={null}
DATABASE_URL="postgres://mrp:mrp@localhost:5432/mrp?sslmode=disable" \
REDIS_URL="redis://localhost:6379" \
S3_ENDPOINT="http://localhost:9000" \
S3_BUCKET="mrp-blobs" \
S3_ACCESS_KEY="minioadmin" \
S3_SECRET_KEY="minioadmin" \
./relay
```

### Configuration

| Variable                 | Required | Default     | Description                               |
| ------------------------ | -------- | ----------- | ----------------------------------------- |
| `DATABASE_URL`           | Yes      | --          | PostgreSQL connection string              |
| `REDIS_URL`              | Yes      | --          | Redis connection string                   |
| `PORT`                   | No       | `8080`      | HTTP server port                          |
| `S3_ENDPOINT`            | No       | --          | S3-compatible endpoint URL                |
| `S3_BUCKET`              | No       | --          | S3 bucket name                            |
| `S3_ACCESS_KEY`          | No       | --          | S3 access key                             |
| `S3_SECRET_KEY`          | No       | --          | S3 secret key                             |
| `S3_REGION`              | No       | `us-east-1` | S3 region                                 |
| `TIMESTAMP_TOLERANCE`    | No       | `5m`        | Max age for request timestamps            |
| `LOG_LEVEL`              | No       | `info`      | Log level                                 |
| `WEBHOOK_ENCRYPTION_KEY` | No       | --          | Encryption key for stored webhook secrets |

### Docker Compose

The quickest way to get external mode running locally:

```bash theme={null}
docker compose up -d   # Starts PostgreSQL, Redis, MinIO
make migrate-up        # Run database migrations
make run               # Start the relay
```

## Pointing SDKs to your relay

All MRP SDKs accept a relay URL. Replace `https://relay.mrphub.io` with your self-hosted relay:

<CodeGroup>
  ```python Python theme={null}
  agent = Agent("http://localhost:8080", name="MyBot")
  ```

  ```typescript TypeScript theme={null}
  const agent = await Agent.create({
    relay: 'http://localhost:8080',
    name: 'MyBot',
  });
  ```

  ```go Go theme={null}
  agent, _ := mrp.NewAgent(mrp.AgentConfig{
      Relay: "http://localhost:8080",
      Name:  "MyBot",
  })
  ```

  ```bash CLI theme={null}
  mrp config set relay http://localhost:8080
  ```
</CodeGroup>

## Migrating between modes

There is no built-in migration tool between embedded and external mode. For small deployments, you can export and re-import data using the API. For larger deployments, start with external mode from the beginning.
