The Lightning Network: How to install and (hopefully) make money

Note: This document was written in July 2018. Lightning is new and improving fast. If you find any out-of-date information or omissions, please leave a comment.

Lightning is an intriguing new technology that promises (lightning) fast transactions at a scale that is unheard of for Bitcoin. And now that Lightning is live on the Bitcoin mainnet, it is also a potential money maker.

Unfortunately, I’ve also found that Lightning is extremely hard to install, and I’ve wasted many hours setting up a node. I’m sharing my experiences so others will hopefully have a smoother experience.

This blogpost only describes the installation process, and assumes the reader is proficient in setting up a server. To learn more about Lightning itself, check the excellent white paper. To learn more about the economics behind Lightning, see The Economics of Lightning Network Fees. LnRoute lists many helpful resources.
Warning: Lightning is not for the faint of heart. There are known and unknown issues. The wallet’s private key will be stored on the Lightning node, and the node will have to be online 24/7 to route transactions. As always with crypto, do not experiment with more btc than you’re prepared to lose. (Or experiment on Testnet. But where’s the fun in that?).


In the cloud on a Virtual Private Server (VPS), or on your own hardware. This tutorial shows how to install Lightning on a Digital Ocean VPS. I am considering installing and documenting Lightning on a ODROID-HC1 (leave a comment if you’re interested).

This tutorial assumes you’re using a Mac to connect to the VPS. Using Linux or Windows shouldn’t be too different though.
Your Lightning node has to be always online to forward payments.

Setup Digital Ocean

Setting up a VPS on Digital Ocean will take about 30 minutes to complete.

  1. Create an account
  2. Create a new droplet
  3. Create SSH key pair
  4. Log in

Use the following referral link to create an account on Digital Ocean and receive $10 (I will receive $25).

Create a new droplet

On the Create Droplet page, select the One-click apps tab and the Docker option, and select the 320GB option on the same page.

Next, we’re going to create a new SSH key pair by entering the following command in the Terminal:

# 1. Create SSH key pair. "lightning" will be the filename
# Enter a passphrase to secure the file
$ ssh-keygen -f ~/.ssh/lightning -t rsa -b 4096

# 2. Backup lightning and files
$ cd ~/.ssh
$ (Make a safe backup)
# 3. Copy the public key to the clipboard
$ pbcopy < ~/.ssh/

Back in the browser, click on the New SSH Key button and paste the public key (copied to the clipboard in step 3 above) into the text box, and click the Create button to create the droplet.

Once the droplet is created, copy the ip-address of the droplet.

# Log in.
$ ssh root@<droplet's ip-address> -i ~/.ssh/lightning

Install bitcoind

Lightning requires a locally running full bitcoin node (that will change in the future with the Neutrino light client). This step will download the full Bitcoin blockchain and will take about 12 to 24 hours to complete.

I followed the steps in Doug von Kohorn’s Lightning post.

  1. Make sure to be logged in on your server.
  2. Install Bitcoind Docker image.
  3. Download the Bitcoin blockchain.
  4. Create a convenience script for easy access to the bitcoind container
  5. Wait while the blockchain is downloading.

Log in if you’re not logged in already.

# Log in.
$ ssh root@<droplet's ip-address> -i ~/.ssh/lightning

Create a bitcoind Docker container using the dockerfile which is (confusingly) located in a repo called lightning-node.

Bitcoind will save the blockchain and all settings on the disk, not in the container itself. This way, all data will persist, even if we replace the bitcoind container with an updated version.

# 1. Clone the bitcoind repo. (don't let the lightning 
# node project name fool you, this will install bitcoind)
$ git clone
# 2. Build the bitcoind Docker container.
$ cd lightning-node
$ docker build . -t dougvk/bitcoind
# 3. Create a working directory outside of the Docker image,
# so the working directory won't be overwritten when you
# update the Docker image with a new bitcoind version.
$ mkdir -p /scratch/bitcoin/mainnet/bitcoind
# 4. Run bitcoind and start downloading the blockchain.
$ docker run --name bitcoind -d -v /scratch/bitcoin/mainnet/bitcoind:/data -p 8333:8333 -p 9735:9735 dougvk/bitcoind:latest

Add a convenience script to access the bitcoind container:

# 1. Create script.
$ touch /bin/bitcoin-cli
# 2. Make script executable.
$ chmod +x /bin/bitcoin-cli
# 3. Edit script (See below).
$ nano /bin/bitcoin-cli
# 4. Confirm script is working. This command shows the wallet info.
$ bitcoin-cli getwalletinfo

In Nano (step 3 above), edit the bitcoin-cli script as follows:

#!/usr/bin/env bash
docker run --rm --network container:bitcoind -v /scratch/bitcoin/mainnet/bitcoind:/data dougvk/bitcoind:latest bitcoin-cli "$@"

At the time of writing, the Bitcoin blockchain is 175GB in size. The blockchain download should already be in progress and will take up to 24 hours to complete. Take a break, a nap or a short vacation while the blockchain is downloading.

Check the status of the download by entering the following command. When the download is complete, the latest downloaded block should have today’s date.

# Check the blockchain download progress.
$ docker logs bitcoind --tail "10"

Install C-Lightning

Next, install the Lightning client. There are multiple Lightning implementations, such as C-Lightning and lnd. It shouldn’t matter which implementation you use, as all implementations should be interoperable.

I found this step more complicated than I expected and wasted time trying to use the lnd implementation. In the end I gave up on lnd and switched to C-Lightning. (Since the software and documentation is updated on an almost daily basis, it is entirely possible that lnd will be easier to install by the time you read this.) Installing C-Lightning should take about 30 minutes.

  1. Make sure to be logged in on your server.
  2. Create a C-Lightning docker image and sync the Lightning network.
  3. Create a convenience script for easy access to the bitcoind container.
  4. Set name and other options

Log in if you’re not logged in already.

# Log in.
$ ssh root@<droplet's ip-address> -i ~/.ssh/lightning

Create the C-Lighting docker image and a scratch directory on disk so the data will persist even if we replace the lightning docker container.

# 1. Create a working directory outside of the Docker image,
# so the working directory won't be overwritten when you
# update the Docker image with a newer C Lightning version.
$ mkdir -p /scratch/bitcoin/mainnet/clightning
# 2. Create the Lighting docker image.
docker run --rm --name lightning --network container:bitcoind -v /scratch/bitcoin/mainnet/bitcoind:/root/.bitcoin -v /scratch/bitcoin/mainnet/clightning:/root/.lightning --entrypoint /usr/bin/lightningd elementsproject/lightningd --network=bitcoin --log-level=debug

The Lightining node should now be downloading the Lightning network, which should take about 10 minutes.

Since the last command doesn’t return to the command prompt, open a new Terminal window or tab and log in again.

# Log in.
$ ssh root@<droplet's ip-address> -i ~/.ssh/<filename>

Next, we’ll create a convenience script to access the Lightning client.

# 1. Create script.
$ touch /bin/lightning-cli
# 2. Make script executable.
$ chmod +x /bin/lightning-cli
# 3. Edit script (See below).
$ nano /bin/lightning-cli
# 4. Confirm script is working. 
$ lightning-cli getinfo

In Nano (step 3 above), edit the lightning-cli script as follows:

#!/usr/bin/env bash
docker run --rm -v /scratch/bitcoin/mainnet/clightning:/root/.lightning --entrypoint /usr/bin/lightning-cli
elementsproject/lightningd "$@"

I haven’t found the complete documentation of all config file options. If you’ve found one, please leave a comment. A basic config file sets the name of the Lightning node and the color the name appears in Lightning explorers, such as Recksplorer.

# 1. Create config file
$ touch /scratch/bitcoin/mainnet/clightning/config
# 2. Edit and save config file (see below)
$ nano /scratch/bitcoin/mainnet/clightning/config

My config file is as follows. I’ve named my node Punchbeef✅ (yes, a Mystery Science Theater 3000 reference) and set its color to orange. The color is used various Lightning explorers and provides an way to stand out.You obviously want to change the alias and the color (unless you like orange). To ensure more stable channels, Chang Li of FirstBlock suggested to add bind-addr and announce-addr to the config file. However, bind-addr didn’t seem to work as expected.

alias=Punchbeef✅           # Change the alias, obviously
#bind-addr= This doesn't seem to work yet
announce-addr=<droplet's ip-address>:9735

Restart the Lightning node to the update the changes.

# 1. Stop the Lightning node
$ lightning-cli stop
# 2. Start the Lightning node
# Note: this creates a new container. How do we restart
# the existing one? Any Docker experts here?
$ docker run --rm --name lightning --network container:bitcoind_mainnet -v /scratch/bitcoin/mainnet/bitcoind:/root/.bitcoin -v /scratch/bitcoin/mainnet/clightning:/root/.lightning --entrypoint /usr/bin/lightningd elementsproject/lightningd --network=bitcoin --log-level=debug

We now have a fully functional Lightning node running on mainnet.

Note: If you prefer to use lnd over C-Lightning, the undocumented command to install lnd on mainnet is as follows. For support, check their active Slack.
# Don't use unless you want to install LND, instead of C-Lightning!
$ docker create --name=lnd lightninglabs/lnd --bitcoin.mainnet

Setting fees

The way to make money on the Lightning network is to forward transactions from other nodes via your node. The sending node will choose the optimal path, based on the fees nodes have set. So we want to set the fees to a price that’s low enough so that traffic will flow through our node, yet high enough to make a profit. That at least is the theory.

I was expecting to be able to set fees to optimize for more traffic. Unfortunately, I haven’t found a way to do that yet and am currently using the default settings. If anyone knows the solution or has suggestions, please leave a comment.

Connecting to nodes and creating Channels

Note: If you’re not familiar with the concept of Lightning channels, please see the original Lightning white paper or this introduction to Lightning.

Funding channels is a two step process: you first send btc from your current wallet to the node’s wallet, and then you fund the channel with btc from the node’s wallet. Creating and funding channels will take about two hours and will involve the following steps:

  1. Create a Bitcoin address for the node’s wallet.
  2. Send btc to the address created in step 1 and wait for six confirmations.
  3. Connect to any Lightning node of your choosing to create a channel.
  4. Fund the channel with btc from step 2 and wait for six confirmations.

As with any other Bitcoin wallet, you can create multiple addresses for a single wallet. Send a small amount of btc to the Lightning wallet, like so:

# 1. Create new address. 
$ lightning-cli newaddr
# 2. Send btc to the address generated above and wait for six 
# confirmations. Check status at:
# 3. Confirm the funds have been received.
$ lightning-cli listfunds

When needed, use the dev-listaddrs command to list all addresses of your Lightning wallet:

# List all addresses of your Lightning wallet.
$ lightning-cli dev-listaddrs

Next, connect to one or more other Lightning nodes.

# 1. Connect to another Lightning node. The parameters are 
# the Lightning id, and optional ip-address and port.
# The command below connects to the author's Punchbeef✅ node.
$ lightning-cli connect 02060d0c8577cfc2a1962220a1cde4f623ca55ef80bd25e4be5a8b15fed78b11a3@
# 2. Confirm your node is connected to the node in step 4, and 
# the state is "GOSSIPING".
$ lightning-cli listpeers
Looking for nodes to connect to? Recksplorer is a live Lightning network map that can be used to find other nodes you might want to connect to. Other great resources are the Lightning Network Stores list, and the Y’alls list. 1ml maintains a list of the largest nodes in terms of btc and nodes with most channels.

I funded most channels with 318 kSatoshi (approx. 20 USD). Some hosts required a higher minimum, to which I conformed. I also checked the prices of the goods the merchants sold and made sure the channel had enough satoshi for a purchase of at least the cheaper items in the store.

Funding a channel is a channel is an on-chain event and needs to be confirmed.
# 1. If needed, list connections. Unfunded channels will have 
# state set to 'GOSSIPING'
$ lightning-cli listpeers
# 2. Fund the channel to peer ID 02060... belonging to Punchbeef✅
# with 400 kSat
$ lightning-cli fundchannel 02060d0c8577cfc2a1962220a1cde4f623ca55ef80bd25e4be5a8b15fed78b11a3 400000

And boom. We’re live.


To test Lightning payments, you could buy a sticker or T-shirt at various merchants, but you can also buy an inbound channel from the Y’alls node for about $4.62. Why not? Browse to the about page of the Y’alls site and follow the steps below.

# 1. Connect to the Y'alls node
$ lightning-cli connect
# 2. Fund outbound channel with 1 mSat and wait for confirmation
$ lightning-cli fundchannel 03e50492eab4107a773141bb419e107bda3de3d55652e6e1a41225f06a0bbf2d56 1000000
# 3. Confirm the channel state is CHANNELD_NORMAL
$ lightning-cli listpeers 03e50492eab4107a773141bb419e107bda3de3d55652e6e1a41225f06a0bbf2d56
# 4. Browse to, locate the 'Join
# the Y'alls Community' box and select your node from the
# dropdown list and click 'Attempt Channel Open'.
# 5. Copy the invoice starting with "lnbc" from the bottom box
# 6. Pay Y'alls node to create inbound channel using the invoice 
# copied in step 5.
$ lightning-cli pay <lnbc...>

Closing channels and withdraw funds

To withdraw btc from a channel to the node’s wallet, you will need to close the channel. This step will take about one hour.

  1. Find the id of the channel you want to close
  2. Close channel
  3. Profit!
Just like funding a channel, closing one is also an on-chain event and needs to be confirmed.
# 1. Show funded channels to look up channel id.
$ lightning-cli listfunds
# 2. Close channel. Command should return a txid, which is
# verifiable on
$ lightning-cli close xxxxx:xxx:x
# 3. After about one hour, the channel should be removed 
# from the list, and a utxo should be added to the utxo list.
# You may need to rescan the outputs to see the latest updates.
$ lightning-cli dev-rescan-outputs
$ lightning-cli listfunds


With real btc stored on your node, you definitely want to have a backup, just in case. However, backing up a Lightning isn’t straightforward.

My first instinct was to back up the state of the channels themselves. But that turned out to be a bad idea, according to this Github issue, which is probably the best resource on Lightning backups.

To understand why you should never back up channel states, you have to understand how the Lightning protocol punishes dishonest nodes. One attack vector is to propagate an old state of a channel, which is exactly what could happen if you back up channel states. The punishment for propagating an old state is confiscation of all funds in a channel by the peer. In other words: you risk losing all your funds in the channels if you try to backup and restore an a channel state.

The channel states are saved in the lightning.sqlite3 file in the /scratch/bitcoin/mainnet/clightning/ directory. Never back up the lightning.sqlite3 file.

Instead, backup the hsm_secret file in the /scratch/bitcoin/mainnet/clightning/ directory. The following command copies the hsm_secret file to your local home directory.

# Run from your local computer. <filename> is the ssh file on 
# your local drive, <ip-address> is your lightning
# server's IP address.
$ scp -i <filename> root@<droplet's ip-address>:/scratch/bitcoin/mainnet/clightning/hsm_secret ~

The steps to recover the funds are copied from the GitHub issue metioned above: Copy hsm_secret on a clean install and start lightningd with the--port=0 option. Do not connect or fund any channel. Run lightning-cli newaddr a few times, then shut down lightning with lightningd stop. Run sqlite3 /scratch/bitcoin/mainnet/clightning/lightningd.sqlite3 "UPDATE vars SET val= 500000 WHERE name='last_processed_block';" Run lightningd again with the --port=0 option. Recover on-chain funds to your personal wallet by running lightning-cli withdraw all. Then wait up to a few months for the peers to close your old channels. Once all channels are closed, recover your funds that were previously stuck in the channels with lightning-cli withdraw all.

Since you’re not able to create or fund new channels without disrupting the recovery process, you will need to set up a second server to continue running a lightning node.

Errors and solutions

As with any technology, and particular a new one, you will encounter errors.

No address known, giving up

This happens when trying to connect to a node when the lightning node hasn’t finished syncing yet. Wait until your node has fully synced and try again.

Not enough funds to open channel

After funding several channels, it’s possible Lighting will complain that not enough funds are available. The first time I encountered the error, I thought I’d lost my money. It turns out the funds are still there, and all you have to do is have C-Lightning rescan the utxos:

# 1. Rescan outputs if funds are 'missing'
$ lightning-cli dev-rescan-outputs
# 2. Confirm all bitcoins are still there.
$ lightning-cli listfunds

Connection refused

When trying to connect to some popular nodes with many channels, I sometimes encountered a -1, Connection establishment: Connection refused error. I assume there is some limit to the number of channels a node can maintain and that there is no solution besides regularly retrying.

Unable to fund a channel

Sometimes you’re able to connect to a node, but unable to fund a channel to that peer for various reasons. These peers will be in a perpetual GOSSIPING state. To check if peers are in GOSSIPING state, run:

# Outputs the nodes in Gossiping state
$ lightning-cli listpeers | jq '.peers[] | select(.state == "GOSSIPING") | .'

Fund each nodes returned:

# Fund channel
$ lightning-cli fundchannel <peer-id> <amount>


I encountered a multiple more serious issues where channels were stuck in a state after funding for several days. So the funds are tied up, but the channel doesn’t become active. The channel is either awaiting a lock-in (Peer already CHANNELD_AWAITING_LOCKIN), or is in a perpetual state of shutting down (Peer already CHANNELD_SHUTTING_DOWN), instead of the expected CHANNELD_NORMAL. C-Lightning don’t seem to be able to resolve these stuck states automatically yet, even though the listpeers info suggests funds will automatically be returned after 144 confirmations, which equals 24 hours.

# List all channels that were not opened correctly
$ lightning-cli listpeers | jq '.peers[].channels[] | select(.state != "CHANNELD_NORMAL") | .'

Ignore channels with status CHANNELD_AWAITING_LOCKIN:Funding needs more confirmations.

The issue is discussed in this GitHub issue, I‘m currently still waiting to see if it will resolve eventually, even though the channels are stuck in these states for about a week already.


Chang Li of Firstblock Capital for setup advise and config file tips, Shane Vitarana for proofreading. Doug von Kohorn‘s Run Your Own Mainnet Lightning Node blogpost was extremely helpful, as well many Stack Overflow answers, GitHub issues, and the lnd Slack community.

Was this post helpful?

Consider creating a channel to punchbeef✅

# 1. Connect to punchbeef✅
$ lightning-cli connect 02060d0c8577cfc2a1962220a1cde4f623ca55ef80bd25e4be5a8b15fed78b11a3@
# 2. Fund channel
$ lightning-cli fundchannel
02060d0c8577cfc2a1962220a1cde4f623ca55ef80bd25e4be5a8b15fed78b11a3 400000