Skip to main content

Remote Captive Core

As briefly alluded to in the Installation page, there is a way to decouple the Horizon instance from its Captive Core ingesting instance by configuring Captive Core to operate remotely.

This allows for greater flexibility in architectural scaling: you can scale your request-serving Horizon, ingesting Horizon, and Captive Core instances separately. There's also nothing wrong with running Horizon and Remote Captive Core on the same machine, e.g. if you just want them to be in different processes or are running a containerized setup.


This architecture is still considered experimental. While we expect to continue to support this architecture moving forward, the implementation itself is subject to changes. You will have to build the package from source, and the JSON API responses should not be considered stable: though Horizon will stay up-to-date and be compatible with the response format, it's not recommended to build custom functionality on top of the API.

Getting Started

As noted above, this setup requires building packages from source. It will eventually make its way into the unstable SDF repository, then into the stable one. For now, though, we will build the package directly.

The requirements here are the same as for building Horizon: a Unix-like OS, Golang, and git. With those set up,

git clone monorepo && cd monorepo
go install -v ./exp/services/captivecore
sudo cp $(go env GOPATH)/bin/captivecore /usr/bin/stellar-captive-core-api

(You should refer to the list of Horizon releases and git checkout accordingly before building if you're looking for a stable release rather than the bleeding edge master branch.)

Running Captive Core

Running the API requires some familiar parameters:


These should be self-explanatory if you've read the earlier sections. There are a few others that you can see under the --help text that may be of interest, particularly the ones related to ports if you want to expose the underlying Stellar Core or ensure the Remote Captive Core and Horizon ports don't conflict (both default to 8000).

If you wanted to rely on SDF for history archives and connect to the test network, you might prepare your environment and run the Remote Captive Core API as follows:

stellar-captive-core-api \
--stellar-core-binary-path=$(which stellar-core) \
--captive-core-config-append-path=/etc/default/stellar-captive-core-stub.toml \
--history-archive-urls="" \

# INFO[...] Starting Captive Core server on 8001 pid=9450

After this, you should be able to hit endpoints locally and see results, e.g.:

curl http://localhost:8001/latest-sequence
PrepareRange must be called before any other operations

For using pubnet, refer to the earlier section on Configuring Captive Core that outlines considerations about quorum sets and choosing who you trust.

Running Horizon

With the Captive Core API server running, you can now point Horizon to this remote instance for ingestion. Rather than passing the configuration and binary paths described earlier, you instead point Horizon to the remote instance:


The remote URL should point to a running Captive Core API like the one we set up above, while the Core URL should point to the underlying Stellar Core port that the remote node exposes. In our case, we'll assume that both Horizon and Remote Captive Core are running on the same machine for simplicity; otherwise, you should fill in the hostnames and ports accordingly:

stellar-horizon-cmd serve \
--remote-captive-core-url=http://localhost:8001 \

After ingestion catches up, you should be able to query Horizon's endpoints just like before.