In this section, we will run the finished tutorial app and set up a gRPC client for programmatic access to our lnd nodes.

Setting up our web development workspace

Let’s set up our news site. Before beginning, ensure that you are running Python 2.7 and that you have pip and virtualenv installed.

# Create a new workspace which will hold both the repo and the virtualenv. We
# recommend running this in a new terminal window.
mkdir ln-workspace
cd ln-workspace

# Clone the repo
git clone

# Create virtualenv and activate it. Make sure to activate this environment
# whenever you are working with the coindesk app.
virtualenv deskenv
source deskenv/bin/activate

# Install webapp Python requirements
cd lightning-coindesk
pip install -r requirements.txt

Now, let’s set up Python gRPC so that we can run our website

# Install the dependencies required for gRPC
pip install grpcio grpcio-tools googleapis-common-protos

# Run our webserver
python runserver

Notice that in coindesk/ we have set LND_RPCHOST = "localhost:10002". In other words, your server is connected to the “Bob” lnd node, and making payments to it is equivalent to making payments to Bob.

Testing the app

If everything went smoothly, you should now have a web server exposed at port

  1. lightning coindesk homepage

Feel free to click around the site. You will soon find that you need to log in and make a payment to view the articles.

login page

To prevent lnd users from having to go through the hassle of signing up with an email address and password, we created an authentication scheme based on the user’s lnd identity pubkey and logging in by signing an arbitrary message. In particular, we are signing the CSRF token sent along with the login POST request. This scheme is secure against replay attacks because Django generates a unique CSRF token for every login attempt, and never uses CSRF tokens.

Let’s create a new account for Alice by logging in and supplying a username. Copy down the generated message (in the screenshot, it is VcccAuMC...)

alice$ lncli-alice signmessage <GENERATED_MESSAGE>
    "signature": <SIGNATURE>

Paste <SIGNATURE> into the corresponding field and set alice as the desired username. You should now be logged in as Alice.

logged in homepage

Navigate to the sweet article and make a payment from the Alice node (you can use either the command line or the web GUI). Clicking “Complete” will prompt the webserver to check that the payment has been complete, and you can now enjoy reading through this sweet article.

Setting up gRPC

Let’s practice running some commands on gRPC. Open up a new terminal window then proceed as follows:

# Enter the development environment
cd ln-workspace

# Activate Python virtualenv
source deskenv/bin/activate

# Clone the Google API repository, which is required due to the use of
# google/api/annotations.proto
git clone

# Download the lnd rpc.proto file
curl -o rpc.proto -s

# Compile the proto file
python -m grpc_tools.protoc --proto_path=googleapis:. --python_out=. --grpc_python_out=. rpc.proto

We have now generated the two files and, which you’ll need to import into your Python code in order to use it with lnd. Let’s move it into the coindesk folder for easy access

mv rpc* lightning-coindesk/coindesk

We will now try a few commands with the Python gRPC client from the command line.

# Optionally install ipython for prettier command line output
pip install ipython

# Open the Django shell. This is a standard Python shell that also allows access to Django objects.
cd lightning-coindesk
python shell
# Import rpc files and grpc
In [1]: from coindesk import rpc_pb2 as ln, rpc_pb2_grpc as lnrpc
In [2]: import grpc

# Establish a secure connection with our RPC server. We will first have to
# gather our cert. Lnd cert is at ~/.lnd/tls.cert on Linux and
# ~/Library/Application Support/Lnd/tls.cert on Mac
In [3]: cert = open('~/.lnd/tls.cert').read()
In [4]: creds = grpc.ssl_channel_credentials(cert)
In [5]: channel = grpc.secure_channel('localhost:10009', creds)
# Create a new 'stub' object that will allow us to interact with our "Bob" lnd node.
In [6]: stub = lnrpc.LightningStub(channel)

# Make a call to the ListChannels API.
In [7]: listchannels_resp = stub.ListChannels(ln.ListChannelsRequest())
channels {
  active: true
  remote_pubkey: "02244b8eff01be9f7b4ec1d73ab10fc36da48b01a685ac90ed09a63fe94ec08d0a"
  channel_point: "2622b779a8acca471a738b0796cd62e4457b79b33265cbfa687aadccc329023a:0"
  chan_id: 495879744192512
  capacity: 1000000
  local_balance: 21001
  remote_balance: 970311
  commit_fee: 8688
  commit_weight: 724
  fee_per_kw: 12000
  total_satoshis_received: 21001
  num_updates: 8
channels {
  active: true
  remote_pubkey: "032eed260ef71110a02a5da44d82fef9628ffa51113a2d0b9524e7d3bff615a1cf"
  channel_point: "028088c354b26c33cfd5a5b2d4cca27c6e3a73b6752b5beff6f67ce779af5656:1"
  chan_id: 554153860464641
  capacity: 800000
  local_balance: 190000
  remote_balance: 601312
  commit_fee: 8688
  commit_weight: 724
  fee_per_kw: 12000
  total_satoshis_sent: 10000
  num_updates: 2

What happened here? We constructed the request object for the list channels command with ln.ListChannelsRequest(), and passed it into the ListChannels function exposed by our stub.

The response was saved into a listchannels_resp variable that holds all the information returned by the listchannels command. You can now access the individual properties of this object; for example, you can access the chan_id of Bob’s first channel with listchannels_resp.channels[0].chan_id.

Playing with gRPC

To get a hang of the RPC documentation, try running a slightly more complex command like GetChanInfo, which requires passing in some parameters. The API docs are not yet complete, but you can refer to the RPC documentation in lnd.

Hint: look at the GetChanInfo object and the associated requests and responses.

Moving on to Step 4

By now, you should have at least a basic understanding of how to work with lnd from a gRPC client. In Stage 4, we will finally integrate lnd into our news site.