NBD is short for Linux’s “network block device”. On the client side, an NBD looks like any other block device, however, all data is stored on a server and reads and writes will be sent across the network. NBD does not offer any security beyond IP-whitelisting, which is why I want to send my data through an SSH tunnel.
Usually it will be best to install NBD from your distribution’s repository. The Gentoo package is called sys-block/nbd and will install both the client and server userland-tools, Ubuntu has separate packages called nbd-server and nbd-client. If you want to install manually, you can download the source via the NBD homepage. The server is a pure user space application, while the client application handles only connection/disconnection and hands over to the kernel for normal operation. If you compile your own kernel, make sure to activate NBD support on the client (set CONFIG_BLK_DEV_NBD to “m” or “y”).
The storage space for the NBD can be an image file or any other block device (real partition, LVM logical volume or whatever). Once you have that, you’ll just need to start the server. The server does not need to run as root (unless you want to use a privileged port), read/write access to the storage is enough. Create a small image file for testing and start the server:
# dd if=/dev/zero bs=1M count=0 seek=80 of=/tmp/nbd-test.img
# nbd-server 127.0.0.1:10000 /tmp/nbd-test.img
The first argument tells the server which IP and port to bind to, the second which device to use. There are bunch of other options, like “-r” to export read-only. Just take a look at the man page. 😉 Binding to 127.0.0.1 will prevent anyone who can’t log in to the server from connecting to the NBD. The path to the storage file or device must be absolute.
Connecting to the NBD
The server is up, so the next step is to connect the client. If you haven’t already, load the NBD kernel module:
# modprobe nbd
Now we have to set up the SSH tunnel. My server in this example is called yukari:
# ssh -N -L 10001:127.0.0.1:10000 yukari
“-L 10001:127.0.0.1:10000” is the key part: TCP connections to port 10001 on the local host will be forwarded to the remote host and sent to 127.0.0.1:10000. You could use “-L 10001:example.com:80” to access the example.com website through your tunnel. Fun fact: this works even if the tunnel is IPv4 and the endpoint IPv6, as long as the SSH gateway has IPv6 connectivity (or the other way around – just the TCP connection is forwarded, after all).
“-N” tells SSH not to run any command on the server (like open a shell). Without -N you’ll get a shell as usual, and the tunnel will be gone as soon as you exit.
Let’s connect the NBD using the local tunnel endpoint:
# nbd-client localhost 10001 /dev/nbd0
Negotiation: ..size = 81920KB
/dev/nbd0 can be used like any other block device. Create a filesystem, mount it, put some data on it, unmount. If you worry about an attacker getting access to the storage: encrypt it. Once you’re done, disconnect the NBD:
# nbd-client -d /dev/nbd0
Disconnecting: que, disconnect, sock, done
- Never have two or more clients accessing the NBD read/write at the same time (exceptions apply for some cluster file systems).
- Exporting the NBD to localhost only and accessing via SSH protects against attackers on the network, but not on the local machine. Users on the server will be able to read your data (unless it’s encrypted) and even overwrite it (unless your NBD is read-only).
- NBD homepage
- Network Block Devices: Using Hardware Over a Network (Linux Magazine)