diff --git a/nixos/modules/private-storage.nix b/nixos/modules/private-storage.nix
index 39972965909f6566051ecd3cd39e8dbe00e7fb45..d2db7dd661a8a923c04e245e45cad30305ebfe68 100644
--- a/nixos/modules/private-storage.nix
+++ b/nixos/modules/private-storage.nix
@@ -48,6 +48,14 @@ in
         An IPv4 address to advertise for this storage service.
       '';
     };
+    services.private-storage.introducerFURL = lib.mkOption
+    { default = null;
+      type = lib.types.nullOr lib.types.str;
+      example = lib.literalExample "pb://<tubid>@<location hint>/<swissnum>";
+      description = ''
+        A Tahoe-LAFS introducer node fURL at which this storage node should announce itself.
+      '';
+    };
     services.private-storage.publicStoragePort = lib.mkOption
     { default = 8898;
       type = lib.types.int;
@@ -78,7 +86,10 @@ in
       # We just populate this according to policy/preference of Private
       # Storage.
       sections =
-      { node =
+      { client = if cfg.introducerFURL == null then {} else
+        { "introducer.furl" = cfg.introducerFURL;
+        };
+        node =
         # XXX Should try to name that is unique across the grid.
         { nickname = "storage";
           # We have the web port active because the CLI uses it.  We may
diff --git a/nixos/modules/tests/private-storage.nix b/nixos/modules/tests/private-storage.nix
index 0838de10b1e794824a3cfea63e1c75ac81776286..89e63a858728722c006297e024facde686dd74e5 100644
--- a/nixos/modules/tests/private-storage.nix
+++ b/nixos/modules/tests/private-storage.nix
@@ -1,31 +1,136 @@
+let
+  pkgs = import <nixpkgs> { };
+  # Here are the preconstructed secrets which we can assign to the introducer.
+  # This is a lot easier than having the introducer generate them and then
+  # discovering and configuring the other nodes with them.
+  pemFile = pkgs.writeTextFile {
+    name = "node.pem";
+    text = ''
+-----BEGIN CERTIFICATE-----
+MIICojCCAYoCAQEwDQYJKoZIhvcNAQELBQAwFzEVMBMGA1UEAwwMbmV3cGJfdGhp
+bmd5MB4XDTE5MDkyMDE4NDkzNloXDTIwMDkxOTE4NDkzNlowFzEVMBMGA1UEAwwM
+bmV3cGJfdGhpbmd5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA1zK4
+wH0ZvjFCnFo+PvT/ANBJ2H7pZQDRHFHmhW28VeQ4nCqlifjxJ/MOWpqKYK6rxHOK
+DNTDR5MbkFO7l0yquB0/FArP9RErezKakXz8qSLhipDZk7y+0fKWMPxcgdSzm28Z
+817Yzp1naXPHQRcno3M3eo58FyoTDAOXP3hiS+bFm8RGVINLSBJtILKoplvgSdyD
+/1Xg4zbh2FK+gS0f92jel5JyAaebt3EQPiIxwUrvi5a1w5EQKi13sJ22RK5H6sch
+Xg76GMMBCckLs+g8xza5uHLbotMnWb7ddW+pC0SQsrihUxz902lQoUuxq2aJig6o
+Ti6wsetUcxtOErfy6wIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQC7ciESyktDoAus
+ni6zW30AXnoTxD/LNCf2HMUFcyFF57p5dcaTsAUhUd+aKX/iJyhy6bfgo8GGI5xN
+LvhvNQ6Cb6Z9qiCWDvEll+nbfuJNEanEd6bkR06/TX5bK5iDMYZD4Z+SSHsNDNEF
+DXJ96zp42UfQTdimxXHmZidAYvtYeLe4EDoJGhpuryEAIUwPdTvsPX+pLfCdtdyP
+595zbHkUPPnA3feWckcmN0FWiXisaE4ERXdPrcBnMB5TqY7KI0j2TjW59l1TnNFD
+dEKMyBD89ndBXvZq8JO8nzdM0WF32jSM/Yb+clS6PHoypHGo4jBTE3AEIXMUe//x
+MSwj51gz
+-----END CERTIFICATE-----
+-----BEGIN PRIVATE KEY-----
+MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDXMrjAfRm+MUKc
+Wj4+9P8A0EnYfullANEcUeaFbbxV5DicKqWJ+PEn8w5amopgrqvEc4oM1MNHkxuQ
+U7uXTKq4HT8UCs/1ESt7MpqRfPypIuGKkNmTvL7R8pYw/FyB1LObbxnzXtjOnWdp
+c8dBFyejczd6jnwXKhMMA5c/eGJL5sWbxEZUg0tIEm0gsqimW+BJ3IP/VeDjNuHY
+Ur6BLR/3aN6XknIBp5u3cRA+IjHBSu+LlrXDkRAqLXewnbZErkfqxyFeDvoYwwEJ
+yQuz6DzHNrm4ctui0ydZvt11b6kLRJCyuKFTHP3TaVChS7GrZomKDqhOLrCx61Rz
+G04St/LrAgMBAAECggEAfRKjwmxzK9Fhj5H7n4exNf3ZDZUlfWiuILGRM3eGAL22
+ET3QHJKtRrTDYPF0/6BFgNZOJAr8vHrJiGbCHruWdY+5+6IVH7As/1t37psgFgWJ
+5Ikvi+glV8yQckQaV/MRuIMoKAS2Kc/eLLH32uLkTOFIG1j40lXH4DGuFFuZddbH
+Ie2TsgUmI3LXTSGSq4qSgXyB46uGuGOn4WKIAKp7O4kN2jBB5y3q9C2YltQ+Dv+k
+T64wBNK3ZnHHNKli0A86kzPLVQJfHgjzC76QRlC+guKgRoV9Kut3LLfoi6ep5yJr
+RT6Pr/hTNKCluIZUTPhmB0u3xGr9gj6vDsMCanvrsQKBgQD5y7ZJqFvgh9MlhSLN
+20p7jlyu+cYSDWktUjA4109ior8oaCVUXziSuPsr9JfwYRaYsJTUpCYKECFYLibA
+qI+Jj/auJljuCmrfWuS9Z08sAmVoU+O4FZt2UVbui5l5spU41Ze09f81DpzkHhZ0
+SEVH2SgChdy7KdPPhxcVhJHqJQKBgQDciwameP0WaazTY77ZRE4Yt+dPyPFkpSer
+bibeMmss5d+QVo4B4YEL20CrmaJq+FB9u99nL1d6VsvtWuovvHKMmoM//D8Si7PW
+ieAm9mN0L+2Xf25UVFBewQkzNuJJG+z1OtHFfIDDGnNzL2yx//3YFJnR/ehftsK7
+lIlXUElzzwKBgGUW1cx1P8lb7k0u1ejtJ/VcpZGCL3A60SewLSezqsLGDgoyK3k7
+l8944Nzm/V4gTF66h2COlX5ZDMV819372SrYggH0LuUWfi2pwQwNdPLgfV19JZjn
+1aRKQp4DDLc9WDpJ5j0rmH5GTaPbsUaZwL/U1+Y9ehicUsWXa/YfUlWpAoGBAJCZ
+7yBTj82UOCbZ7ZZS/MmkOtvLKssMpnf2XzGs6SylA/KFbdK54ny9oydgMmfkrBHk
+jtP+7GJgapET3RyzeH/MB2Z6o3grdRyjhf7F6euSSTvd558PMSsPclLMF45L6w/X
+IxdTTLGftDa/z4reB7gXucs/qY6oLAIFoA9Jqv9tAoGAIpw4GDw5IQFZhcHuHCOZ
+Xrq9L1fR5rYBQa6xcPHkMbWzigcNJz7FnLg0tB1SvF23egpmj5VAcnWyjyj883pn
+h2wuwJUFy8LALtjJwqhjUtQfv5LLiT5061/CUrhD3GEBNlYbOO4FA1Z0SIhFYn40
+VzowmHAqdxYvlfJsWe91UI0=
+-----END PRIVATE KEY-----
+'';
+  };
+  tubID = "rr7y46ixsg6qmck4jkkc7hke6xe4sv5f";
+  swissnum = "2k6p3wrabat5jrj7otcih4cjdema4q3m";
+  introducerPort = 35151;
+  location = "tcp:introducer:${toString introducerPort}";
+  introducerFURL = "pb://${tubID}@${location}/${swissnum}";
+  introducerFURLFile = pkgs.writeTextFile {
+    name = "introducer.furl";
+    text = introducerFURL;
+  };
+in
 # https://nixos.org/nixos/manual/index.html#sec-nixos-tests
 import <nixpkgs/nixos/tests/make-test.nix> {
 
-  # Configure a single machine as a PrivateStorage storage node.
-  machine =
-    { config, pkgs, ... }:
-    { imports =
-      [ ../private-storage.nix
-      ];
-      services.private-storage.enable = true;
-    };
+  nodes = rec {
+    # Get a machine where we can run a Tahoe-LAFS client node.
+    client =
+      { config, pkgs, ... }:
+      { environment.systemPackages = [
+          pkgs.tahoe-lafs
+          pkgs.daemonize
+        ];
+      };
+
+    # Get another machine where we can run a Tahoe-LAFS introducer node.  It has the same configuration as the client.
+    introducer = client;
+
+    # Configure a single machine as a PrivateStorage storage node.
+    storage =
+      { config, pkgs, ... }:
+      { imports =
+        [ ../private-storage.nix
+        ];
+        services.private-storage.enable = true;
+        services.private-storage.publicIPv4 = "storage";
+        services.private-storage.introducerFURL = introducerFURL;
+      };
+  };
 
   # Test the machine with a Perl program (sobbing).
   testScript =
     ''
-      # Boot the VM.
-      $machine->start;
+      #
+      # Set up a Tahoe-LAFS introducer.
+      #
+      $introducer->start;
+      $introducer->succeed('tahoe create-introducer --hostname introducer /tmp/introducer');
+      $introducer->copyFileFromHost('${pemFile}', '/tmp/introducer/private/node.pem');
+      $introducer->copyFileFromHost('${introducerFURLFile}', '/tmp/introducer/private/introducer.furl');
+      $introducer->succeed('daemonize $(type -p tahoe) run /tmp/introducer');
+      $introducer->waitForOpenPort(${toString introducerPort});
+
+      #
+      # Get a Tahoe-LAFS storage server up.
+      #
+
+      # Boot the storage VM.
+      $storage->start;
 
       # The systemd unit should reach the running state.
-      $machine->waitForUnit("tahoe.storage.service");
+      $storage->waitForUnit('tahoe.storage.service');
 
       # Some while after that the Tahoe-LAFS node should listen on the web API
       # port. The port number here has to agree with the port number set in
       # the private-storage.nix module.
-      $machine->waitForOpenPort(3456);
+      $storage->waitForOpenPort(3456);
 
       # Once the web API is listening it should be possible to scrape some
       # status from the node if it is really working.
-      $machine->succeed("tahoe -d /var/db/tahoe-lafs/storage status");
+      $storage->succeed('tahoe -d /var/db/tahoe-lafs/storage status');
+
+      #
+      # Storage appears to be working so try to get a client to speak with it.
+      #
+
+      # Boot another VM.
+      $client->start;
+
+      # Create a Tahoe-LAFS client on it.
+      $client->succeed('tahoe create-client --shares-needed 1 --shares-happy 1 --shares-total 1 --introducer ${introducerFURL}');
     '';
 }