3 releases

0.0.2 Oct 27, 2021
0.0.1 Aug 14, 2021
0.0.0 Aug 5, 2021

#5 in #agora


Used in agora

CC0 license

38KB
490 lines

Agora


crate build chat on telegram

agora serves the contents of a local directory, providing file listings and downloads over HTTP. For example, you can point it at a directory full of PDFs, allowing users to browse and view the PDFs in their web browser. If agora is connected to an LND node, it can be configured to require Lightning Network payments for downloads.

Public Agora instances:

Agora is free software developed by @casey and @soenkehahn.

Support, Feedback, and Discussion

If you have a question, want to request a feature, or find a bug, please feel free to open an issue or join our Telegram group.

The developers, Casey and Sönke, can also be reached via email.

Running

$ mkdir files
$ echo 'amazing content' > files/file.txt
$ agora --directory files --http-port 1234
$ curl http://localhost:1234/files/file.txt

See agora --help for more configuration options.

Installation

Pre-built binaries for Linux, MacOS, and Windows can be found on the releases page.

Building from Source

agora is written in Rust and built with cargo. You can install Rust with rustup.

Inside the checked out repository, running cargo build --release will build agora and copy the binary to ./target/release/agora.

From within the repository, you can also run, e.g., cargo install --locked --path . --root /usr/local, which will copy agora to /usr/local/bin/agora.

Running with Docker

The agora Docker image can be pulled from ghcr.

Building Agora Docker Image

The Docker image can also be built directly from within the repository.

Building the image:

docker build --tag agora:latest .

Running Agora in Docker

The Docker image can used to serve files from your host machine, and connect to your existing LND node.

To run agora with a local directory ~/my-files:

docker run \
  --network="host" \
  -e FILES_DIR=/files \
  -e AGORA_PORT=8080 \
  -v ~/my-files:/files \
  agora:latest

To run agora with a Lightning instance connected (assuming that LND RPC is running on localhost and port 10009 and the data dir is located in ~/.lnd).

docker run \
  --network="host" \
  -e FILES_DIR=/files \
  -e AGORA_PORT=8080 \
  -e LND_RPC_AUTHORITY=localhost:10009 \
  -e TLS_CERT_PATH=/.lnd/tls.cert \
  -e INVOICES_MACAROON_PATH=/.lnd/data/chain/bitcoin/testnet/invoice.macaroon \
  -v ~/my-files:/files \
  -v ~/.lnd:/.lnd \
  agora:latest

Releases Notifications

To receive release notifications on GitHub, you can watch this repository with custom notification settings.

Additionally, an RSS feed of agora releases is published here.

Deployment

The agora binary contains its static assets, so it can be copied and run from anywhere on the filesystem. By default cargo links to system libraries dynamically. You can avoid this by using the x86_64-unknown-linux-musl target: cargo build --target=x86_64-unknown-linux-musl --release. This produces a statically linked binary that runs on, e.g., Alpine and CentOS Linux.

Configuration

You can configure the network port and address agora listens on, and the directory it serves. See agora --help for details.

HTTPS Configuration

If you're running agora on a public domain it can be configured to automatically request TLS certificates for HTTPS from Let's Encrypt via the ACME protocol. See the --acme-* and --https-* flags in agora --help for details.

LND Configuration

By default agora serves files for free. To charge for downloads, agora must be connected to an LND instance. There are multiple command line flags to configure this connection, see agora --help for details.

To configure which files are free and which are paid, see Access Configuration below.

Access Configuration

You can put a .agora.yaml configuration file into directories served by agora to configure access to files in that directory.

An example configuration is:

# whether or not to charge for files
paid: true
# price for files in satoshis
base-price: 1000 sat

Access configuration applies recursively to files in subdirectories. For example you can put this configuration in your base directory:

paid: false
base-price: 500 sat

Then in some subdirectories you can charge for file downloads by creating an subdir/.agora.yaml like this:

paid: true

The default configuration is:

paid: false
# `base-price` does not have a default. Setting `paid` to `true`
# while not having a `base-price` causes an error.
base-price: null

Custom Index Pages

agora serves directory file listings. If a .index.md file is present in a directory, agora will render the contained Markdown as HTML and include it with the file listing. agora expects Commonmark Markdown, extended with footnotes, strikethrough, tables, and task lists.

Buying Files from an Agora Instance

You can navigate to any Agora instance and browse the hosted files. Agora instances can host a mix of free and paid files. For paid files, Agora will present you a Lightning Network invoice that you must pay before downloading the file. These invoices can be paid with a Lightning Network wallet. Popular wallets include:

  • Wallet of Satoshi, a hosted wallet for Android and iOS.
  • Strike, a hosted wallet for Android, iOS, and Google Chrome.
  • Phoenix, a self-custodial wallet for iOS and Android.
  • Breez, a self-custodial wallet for iOS and Android.
  • River Financial, a Bitcoin financial services platform with the ability to buy and sell bitcoin for USD, and make and receive Lightning Payments, for the web, iOS, and Android.

Selling Files with Agora

Agora is not a hosted platform. If you want to sell files through it, you'll have to host your own Agora instance. Agora instances require access to an LND instance to create invoices and query their payment status. LND in turn needs access to a bitcoin node -- e.g. bitcoind -- to query the state of the bitcoin blockchain.

Setting up bitcoind and LND

Setting up bitcoind and LND is a complex topic, and many different approaches are possible. An excellent guide to setting up LND on Linux is available here, and a companion guide to setting up bitcoind, to supply the Lightning Network node with information about the blockchain, is here.

Processing Payments with Agora

In order to process payments, Agora needs to be connected to an LND instance. See the --lnd-* flags in agora --help.

Additionally, LND nodes can only receive payments if they have sufficient inbound liquidity.

Inbound Liquidity

Liquidity management is one of the most complicated aspects of the Lightning Network, and certainly one of the most counter-intuitive.

The basic primitive that makes up the Lightning Network is the "payment channel", commonly referred to as just a "channel". A channel is between two Lightning Network nodes, has a fixed capacity, is opened by making a on-chain Bitcoin transaction, and is closed by making an on-chain Bitcoin transaction.

While the channel is open, the two parties to the channel can make payments between themselves, but do not have to publish a Bitcoin transaction for each one of these payments. They only have to publish a Bitcoin transaction when they want to close the channel, which nets-out the intermediate transactions made since it was opened.

As a concrete example, let's say Alice and Bob open a channel, with Alice contributing 1 BTC when the channel is opened, and Bob contributing 0 BTC. Initially, their balances on the channel are:

Alice: 1 BTC
Bob:   0 BTC

In this state, Alice can send a 0.1 BTC payment to Bob, and the channel balances will be:

Alice: 0.9 BTC
Bob:   0.1 BTC

Alice and Bob can send each other money, but only up to the amount that they have on their side of the channel. At this point, Alice can send Bob up to 0.9 BTC, and Bob can send Alice up to 0.1 BTC.

However, at the very beginning, when Bob's balance was 0 BTC, Alice could not have received any money from Bob. Due to a lack of inbound liquidity, which is, quite simply, money on the other side of a channel, which can be sent to you.

This is an aspect of the Lightning Network that is very different from other payment systems, and from on-chain Bitcoin payments. You must arrange to have sufficient inbound liquidity to receive payments.

A question you might ask is, What if I just want to assume that the customer is good for the money and queue it up myself for settlement once I have the liquidity to spare?

Let's imagine that we were in the initial state, Alice had 1 BTC in the channel, Bob 0 BTC, and Alice let Bob make a payment to her of 1 BTC. The new balance would be:

Alice:  2 BTC
Bob:   -1 BTC

However! When a Lightning Network channel is closed, you divide up the funds from the funding transaction between the parties to the channel. The channel was funded with an on-chain Bitcoin transaction of 1 BTC, so there is no way to pay out 2 BTC to Alice from the initial funding transaction. Since both parties to a payment channel can close the channel at any time, Alice would be trusting Bob to keep the channel open until he no longer had a negative balance. This is not scalable or secure, and avoiding the need for trust is the whole purpose of the Lightning Network in the first place, otherwise we could all just trade unenforceable IOUs back and forth.

Inbound liquidity can be sourced in a number of ways, and in-development proposals should make it even easier in the future. For now, we recommend purchasing inbound liquidity from Bitrefill. Bitrefill offers a service where a Lightning Node operator can pay Bitrefill to open a channel with that operator's Lightning Node. The operator pays Bitrefill a small amount of bitcoin and receives a channel with a much greater amount of inbound liquidity in return.

Development

You can run the tests locally with cargo test. Pull requests are tested on github actions, with the workflow defined in .github/workflows/build.yaml. You can run approximately the same tests locally with just all. (See just.)

License

Agora is licensed under the CC0 with the exception of third-party components listed in ATTRIBUTION.md.

Dependencies

~11–23MB
~355K SLoC