Write your own SFTP server in C#

Why would anyone want to write their own SFTP server?
Why not choose one of many existing SFTP servers, you may ask.

Why

Some of reasons for not using a ready-made SFTP server include:

  • Simple installation. Just copy an .exe, run it, and see it working.

  • Less external dependencies. The server is compiled into your application and there is exactly zero chance that someone will forget to install the SFTP server when your application is installed on production servers.

  • Keep your user database in one place. Easily share user database between your application and the SFTP server.

  • Advanced access rights based on your application's business logic. Imagine offering access to a specific file only when it has been purchased and a related record exists in your sales database.

  • Licensing. Many SFTP servers are licensed on per-server basis. On the other hand, Rebex components are licensed on per-developer basis with royalty-free distribution. When you use the following code to develop a custom SFTP server and purchase a Rebex File Server license, you will be able to install it on unlimited number of servers and add any number of users for free.

How

Creating a custom SFTP server is simply using Rebex File Server .NET component.
Just use the following code:

static void Main(string[] args)
{
  var serverPort = 22;
  var privateKeyPassword = "myVerySecurePassword";
  var rsaPrivateKeyFilename = "server-private-key-rsa.ppk";
  var dsaPrivateKeyFilename = "server-private-key-dsa.ppk";
  var rootFolder = @"c:\data\";
  var userName = "tester";
  var userPassword = "password";

  var server = new FileServer();

  // add one or more users
  var user = new FileServerUser(userName, userPassword, rootFolder);
  server.Users.Add(user);

  // add RSA private key for communication encryption
  server.Keys.Add(LoadOrCreatePrivateKey(rsaPrivateKeyFilename, privateKeyPassword, useRsa: true));
  // add DSA private key for communication encryption
  server.Keys.Add(LoadOrCreatePrivateKey(dsaPrivateKeyFilename, privateKeyPassword, useRsa: false));

  // bind SFTP protocol and start the server
  server.Bind(serverPort, FileServerProtocol.Sftp);
  server.Start();

  Console.WriteLine("SFTP server started. Listening on port {0}.", serverPort);
  Console.WriteLine("Press <enter> to stop.");
  Console.ReadLine();
}

static SshPrivateKey LoadOrCreatePrivateKey(string filename, string password, bool useRsa)
{
  if (!File.Exists(filename))
  {
    // generate server key if it doesn't exist yet

    SshPrivateKey key;
    if (useRsa)
    {
      // generate a 2048-bit RSA key
      key = SshPrivateKey.Generate(SshHostKeyAlgorithm.RSA, 2048);
    }
    else
    {
      // generate a 1024-bit DSA key
      key = SshPrivateKey.Generate(SshHostKeyAlgorithm.DSS, 1024);
    }
    key.Save(filename, password, SshPrivateKeyFormat.Putty);

    return key;
  }

  return new SshPrivateKey(filename, password);
}

Further reading