---
title: "Managed Elasticsearch and OpenSearch on Fly.io with Bonsai"
author: "Mo Omer"
date: 2025-09-12
canonical_url: https://bonsai.io/blog/managed-elasticsearch-and-opensearch-on-fly-io-with-bonsai/
license: CC BY-SA 4.0
license_url: https://creativecommons.org/licenses/by-sa/4.0/
copyright: Bonsai.io, 2026
---

**Fast search closes deals; slow search closes tabs. At [Bonsai.io](https://bonsai.io), we're opinionated about search. Even our free (forever) sandbox clusters get distributed to 3 nodes and managed by the same team of search engineers that manage our enterprise customers' deployments. We've been keeping our customers' tabs open from search to purchase since 2008.**

Deploying fantastic search experiences on Fly.io with Bonsai.io's managed search is as easy as dropping an environment variable into your application's secrets.

In this post, we'll take that basic deployment a step further by deploying what we like to call an _interleaving_ proxy. It's a pass-through, or _reverse_, proxy which will sit in-front of our search cluster, forwarding requests from our application hosted on Fly.io to our search cluster hosted, and fully managed, on Bonsai.io.

To follow along by deploying to your Fly.io account, get your own Bonsai managed cluster by signing up at [Bonsai.io](https://bonsai.io) - we've got detailed instructions on getting started with the Sandbox cluster at [this page](https://bonsai.io/ai-powered-search).

For this post, we put together a little sample API web service to demonstrate interacting with Elasticsearch and OpenSearch. It puts some static book data into an Elasticsearch index and responds to requests at `/api/books` with results fetched from our search cluster.

Clone or fork it at [GitHub](https://github.com/omc/bonsai-examples/tree/feat/add-fly-io-examples/deployments/fly.io).

**Info**

OpenSearch and Elasticsearch can do a whole heckuva lot more than handle your website's search these days.

The things that make it a world-class search database also make it a fantastic vector/embedding database for AI-powered apps. We've written more about that at our [blog](https://bonsai.io/blog/)!

Since our Books API server is configured to deploy on Elasticsearch, it expects an environment variable, `ELASTICSEARCH_NODE`, to be populated with a connection URL, with optional embedded credentials. Deploying the server with that env variable set to the full-access URL from our cluster's management page would work just fine.

But we aspire to more. Pointing our application to a proxy server has some security and quality-of-life benefits that are, well, pretty nice.

For starters, when credentials are set and managed in our proxy application, our API server doesn't need to blink when it comes time to rotate them out, because with a [Bluegreen](https://fly.io/docs/blueprints/seamless-deployments/) Fly deployment, the proxy will update, and the application can automatically retry any failed queries - transparent to the user.

We can also configure our proxy to maintain connections across requests, potentially reducing the frequency (and overhead) of opening/closing new connections from your application onto the search cluster. If we really want to dive-in, the proxy can also help isolate audit logs and control, making rate limiting, logging, and query shaping much easier to do.

Since we're deploying with a _managed_ database, however, we're mainly focused on credential isolation (out of our web-app) and rotation. Connection pooling can _probably_ be configured in our code (via the Elasticsearch/OpenSearch clients). And for the rest, well, we'll leave that to Bonsai.

Let's get deploying.

## Install flyctl

First, you'll need [flyctl](https://fly.io/docs/flyctl/install/), Fly.io's command-line application that allows you to deploy and manage applications, secrets, and more.

## Log-in with flyctl

Once [flyctl](https://fly.io/docs/flyctl/install/) is installed, log-in by running

```sh
fly auth login
```

and following the prompts!

## Really, clone the sample code to follow along!

If you haven't yet, make sure you clone or fork the post's [example code](https://github.com/omc/bonsai-examples/tree/feat/add-fly-io-examples/deployments/fly.io)!

## Deploying an interleaving (reverse) proxy on Fly.io

We've put together a couple of examples of reverse-proxies, based on Nginx and Node.js, available in the [GitHub](https://github.com/omc/bonsai-examples/tree/feat/add-fly-io-examples/deployments/fly.io) repo. Most languages/run-times have standard libraries or community packages that make writing your own TCP proxy pretty easy. Since our Bonsai.io server will deploy with SSL support, we want to deploy a [TLS termination proxy](https://en.wikipedia.org/wiki/TLS_termination_proxy), meaning that while our application will communicate with our proxy over an unencrypted or encrypted protocol (HTTP or HTTPS), communication between the proxy and our Elasticsearch cluster will always be encrypted using Bonsai.io's SSL certificates, and our application won't need to know about those keys or certificates at all.

**Info**

Our application will only be using _one_ proxy type at a time. Deploying both at the same time will allow you to switch between them by updating a `fly secret` associated with the API server!

### Deploying an Nginx proxy on Fly.io

Head into the [nginx-proxy](https://github.com/omc/bonsai-examples/tree/feat/add-fly-io-examples/deployments/fly.io/nginx-proxy) directory.

Configure the proxy's Fly app by running

```sh
fly launch --no-deploy --flycast
```

and following along with the prompts.

**Info**

The `--flycast` flag lets [flyctl](https://fly.io/docs/flyctl/install/) know that we're deploying a private application that should only be accessible via the [Flycast private proxy](https://fly.io/docs/networking/flycast/)

Next, set the Fly app's secrets by replacing the values in the command below with the credentials from your Bonsai.io cluster's credentials page (details on how to find them [here](https://bonsai.io/ai-powered-search)).

```sh
fly secrets set \
  BONSAI_HOST="REPLACE-ME-1234567890.us-east-1.bonsaisearch.net:443" \
  BONSAI_USERNAME="<from your bonsai cluster's credentials page>" \
  BONSAI_PASSWORD="<from your bonsai cluster's credentials page>"
```

Finally, deploy the proxy to Fly.io with

```sh
fly deploy --flycast
```

Once deployed, the Nginx proxy will be deployed into your Fly organization's internal network, available via the [Flycast private proxy](https://fly.io/docs/networking/flycast/) at `<nginx-proxy-app-name>.flycast:9200`.

### Deploying a Node.js proxy on Fly.io

Head into the [node-proxy](https://github.com/omc/bonsai-examples/tree/feat/add-fly-io-examples/deployments/fly.io/node-proxy) directory.

Configure the proxy's Fly app by running

```sh
fly launch --no-deploy --flycast
```

and following along with the prompts.

**Info**

The `--flycast` flag lets [flyctl](https://fly.io/docs/flyctl/install/) know that we're deploying a private application that should only be accessible via the [Flycast private proxy](https://fly.io/docs/networking/flycast/)

Next, set the Fly app's secrets by replacing the `ELASTICSEARCH_NODE` value in the command below with the full (credentials-embedded) URL from your Bonsai.io cluster's credentials page (details on how to find them [here](https://bonsai.io/ai-powered-search)).

```sh
fly secrets set \
  ELASTICSEARCH_NODE="https://<user>:<password>@<your-cluster-name>.bonsaisearch.net"
```

Finally, deploy the proxy to Fly.io with

```sh
fly deploy --flycast
```

Once deployed, the Node.js proxy will be deployed into your Fly organization's internal network, available via the [Flycast private proxy](https://fly.io/docs/networking/flycast/) at `<node-proxy-app-name>.flycast:9200`.

## Deploy our Books API service

Now that our proxy is up and ready, we can deploy our application configured to use the live proxy!

**Note**

Since our API service will be publicly accessible, we've dropped the `--flycast` flags from our `flyctl` commands.

First, configure the app with `fly launch`:

```sh
fly launch --no-deploy
```

Then, grab the application name of our proxy with `fly apps list`. Here's what mine looked like:

```sh
# NAME                            OWNER           STATUS          LATEST DEPLOY 
# nginx-proxy-polished-dawn-4849  personal        deployed        2m2s ago
```

With the app name, we can set our `ELASTICSEARCH_NODE` URL to point to the internal, `flycast` proxy, URL on Fly.io.

**Tip**

Don't forget to replace my app's name with yours in the next command!

```sh
fly secrets set ELASTICSEARCH_NODE="http://nginx-proxy-polished-dawn-4849.flycast:9200"
```

Deploy:

```sh
fly deploy
```

And finally, test our Proxy! My app deployed with the name `bonsai-book-server`, yours will probably be different. Replace the next command with your app's public URL:

```
curl https://bonsai-book-server.fly.dev/api/books
```

You should see JSON data similar to

```json
[{"id":1,"title":"The Hobbit","author":"J.R.R. Tolkien","year":1937},{"id":2,"title":"The Lord of the Rings",...}]
```

## Next steps

You're probably planning on using search with a bit more functionality than returning a small, static, set of books over an API.

We'd love to help. Send one of us (that's right, a real, non-LLM, person) a note at [support@bonsai.io](mailto:support@bonsai.io).

_Copyright ©️ Bonsai.io, 2026 · By Mo Omer · Originally published at https://bonsai.io/blog/managed-elasticsearch-and-opensearch-on-fly-io-with-bonsai/ · CC BY-SA 4.0_
