SFTP test server options for .NET developers
Where do I point my SFTP client while testing?
You've added Rebex SFTP to your project, written the first Sftp.Connect() / Login / Upload() / Download() sequence, and now you need something on the other end of the wire. Preferably something you can break, restart, and fill with junk files without anybody noticing.
This post walks through some options, from "you already have one" to "spin up a fresh server per test run", with the trade-offs of each.
Option 1: The SFTP server you already have
If your organization already runs an SFTP server - OpenSSH on a Linux box, a vendor appliance, whatever - the fastest path is to get a test account on it and move on. Nothing to install, nothing to explain to anyone.
It works, but be aware of what you're signing up for:
- Shared state. Someone else's test run deletes the directory yours depends on. Test ordering suddenly matters.
- You don't control the config. Want to check how your code behaves with a different key exchange algorithm, an expired host key, or a server that rejects
SSH_FXP_RENAME? You'll be filing a ticket with whoever owns the box. - It's not there when you are. Working on the train, on a plane, or from a coffee shop with a captive-portal Wi-Fi means no tests.
- Reset is manual. No easy way to say "put the filesystem back the way it was" between test runs.
- CI is awkward. Your build agents now need network access and credentials to a real server.
Fine for a smoke test. Might be painful as the backbone of an automated test suite.
Option 2: test.rebex.net - zero setup, read-only
We run a public test server at test.rebex.net. Credentials, ports and the list of supported protocols are on that page - SFTP is on port 22, and the login is the usual demo / password combination.
var client = new Sftp();
client.Connect("test.rebex.net", 22);
client.Login("demo", "password");
foreach (var item in client.GetList("/"))
Console.WriteLine(item.Name);
client.Disconnect();
That's a working SFTP session in under a minute, which is exactly what it's for: confirming your connection code, your credentials handling, and your fingerprint verification logic actually do something before you go hunting for bugs elsewhere.
Limitations you need to know about:
- It's read-only. You cannot upload, delete or rename anything. Half of what you probably want to test is off the table.
- It's shared and rate-limited. Please don't point a CI pipeline at it. It's a courtesy service, not infrastructure.
- It's remote. Same offline problem as option 1.
Use it to answer "does my code speak SFTP at all?" Then move to something local.
Option 3: Rebex Tiny SFTP Server - unzip, click Start
Rebex Tiny SFTP Server is a minimalist single-user SFTP server for Windows. It started life as a sample application for the Rebex File Server library and turned out to be useful enough on its own that we ship it as a standalone download.
The workflow is about as simple as it gets: download the ZIP, unpack it, run RebexTinySftpServer.exe, press Start. You now have an SFTP server on localhost serving a directory of your choice, with full read/write access.
Configuration lives in RebexTinySftpServer.exe.config - plain XML, where you set the port, the user name and password, and the root directory.
Licensing: running the pre-built binary is free, for commercial and non-commercial use alike. No strings.
Where it falls short:
- It's a GUI application. You start and stop it by hand. There's no service mode and no command-line control, so wiring it into an automated pipeline means either leaving it running permanently or scripting a window.
- Single user. Testing permission boundaries between accounts isn't possible.
- Changing the configuration means editing XML and restarting the app.
Perfect for interactive development: leave it running in the background on your dev box and hammer it from the debugger.
Option 4: Rebex File Server .NET library - run the server in-process
Tiny SFTP Server is not magic. Under the hood it's a thin GUI wrapped around the Rebex File Server library - and if you already own the library, you can skip the wrapper entirely and start the server from inside your own test process.
Setup is a handful of lines: create a FileServer, give it a host key and a user, and start it.
// nuget Microsoft.NET.Test.Sdk
// nuget NUnit
// nuget NUnit3TestAdapter
// nuget Rebex.FileServer
// nuget Rebex.Sftp
using System.Net;
using NUnit.Framework;
using Rebex.Net;
using Rebex.Net.Servers;
[TestFixture]
public class SftpTests
{
private static readonly Lazy<SshPrivateKey> ServerKeyLazy = new(SshPrivateKey.Generate);
private const string Username = "user01";
private const string Password = "password";
[Test]
public async Task Test()
{
// prepare
await using FileServer server = await CreateServer();
// contains the actual port used by the server
IPEndPoint serverEndpoint = (IPEndPoint)server.Bindings.First().EndPoint;
TestContext.WriteLine("Server endpoint: {0}", serverEndpoint);
using Sftp client = new();
await client.ConnectAsync(serverEndpoint.Address.ToString(), serverEndpoint.Port);
await client.LoginAsync(Username, Password);
// test
Assert.That(client.IsAuthenticated, Is.True);
await client.DisconnectAsync();
}
// CreateServer can be parameterized to customize the testing environment
private static async Task<FileServer> CreateServer()
{
FileServer fs = new();
try
{
// port 0 will instruct the server to use a random, unused port, so the test can be parallelized
await fs.BindAsync(new IPEndPoint(IPAddress.Loopback, 0), FileServerProtocol.Sftp);
fs.Keys.Add(ServerKeyLazy.Value);
fs.Users.Add(Username, Password, Path.GetTempPath());
await fs.StartAsync();
return fs;
}
catch
{
await fs.DisposeAsync();
throw;
}
}
}
Why this is attractive for testing:
- No external process, no orchestration. No ZIP to unpack on the build agent, no process to launch and reap, no port conflict with something a previous run left behind.
dotnet testis the whole story. - Each test can get its own server. Pick a free port, point a temp directory at it, tear it down afterwards. Tests can run in parallel without stepping on each other.
- You can make the server misbehave on purpose. This is the real payoff. The library exposes a virtual file system you can implement yourself, plus events for uploads and downloads. That makes it possible to simulate the failures you'd otherwise never reproduce: a read that throws halfway through a large file, a directory with 50,000 entries, filenames with awkward Unicode, a server that drops the connection mid-transfer, permissions that change between two calls. Testing your retry and resume logic against a server that actually fails beats hoping it works.
- Restrict the algorithms. Narrow down the supported key exchange and encryption algorithms to check how your client behaves against an old or hardened server.
Where to look for a working example: Tiny SFTP Server itself. The source is on GitHub at github.com/rebexnet/RebexTinySftpServer - a few hundred readable lines around the FileServer class, showing key loading, user setup and lifecycle handling. Fork it, strip out the WinForms parts, and you have the skeleton of a test fixture.
Licensing: Rebex File Server is a commercial component, sold separately or as part of the File Transfer Pack and Total Pack. A trial key is enough to find out whether the approach suits you.
The trade-off: this is the only option here that costs money if you're building commercially, and it's the one that requires you to write code rather than run an executable. In return you get complete control over the server's behaviour from within your test suite.
Option 5: Buru SFTP Server - the one you can script
When you want the same convenience as Tiny SFTP Server but with automation, use Buru SFTP Server. It's a full SFTP/FTP/SSH server for Windows, and it happens to be the same core that powers test.rebex.net - so behaviour you see locally matches what you saw online.
Two things make it a good fit for testing.
First, it runs portable. There's a portable mode - download the Portable ZIP, unpack, and run it as a normal console application from any folder, USB stick, or network drive. No installer, no admin rights, no leftover Windows service. (It can run as a service when you want it to; you're just not forced into it.)
Second, everything can be driven from the command line. Creating an instance, adding users, starting the server:
# initialize an instance in the current directory
burusftp init
# add a user
burusftp user add john --password mypassword --root-dir "C:\temp\sftp-test-root"
# run the server
burusftp run
Which means your test fixture can do this:
- Copy a clean instance directory into a temp folder (or run
burusftp initfresh). - Add exactly the users your test needs, with exactly the root directories and permissions it needs.
- Start the server on a free port.
- Run the tests.
- Kill the process and delete the folder.
Every run starts from a known state. No shared server, no leftover files from yesterday, no "works on my machine".
The configuration is a text file in YAML format, so you can keep a set of purpose-built configs in your repository next to the tests that use them - one that only allows a weak set of algorithms, one with a tiny transfer limit, one with a specific host key. Diffable, reviewable, versioned.
It also serves FTP, FTP/S and SSH shell, which is handy if your application talks more than one protocol and you'd rather not run three different test servers.
Licensing: free for non-commercial use; see pricing for the details of what each tier includes.
This is the option we'd recommend for anything resembling a real test suite.
Option 6: Third-party servers, when you need the weird ones
Sooner or later you'll integrate with a server that does something surprising - an unusual path format, a non-standard permission string in directory listings, an SFTP v3 implementation with opinions, a SSH_FXP_STAT response that omits fields everyone else sends.
If you want to test against a specific implementation, sftp.net/servers maintains a list of SFTP server software with notes on each. Pick the one your customer uses, install it locally, and reproduce the problem.
That said - you probably don't need to do this as often as you think. We run regular regression tests of Rebex SFTP against a large set of third-party server implementations precisely so that this class of incompatibility gets caught on our side rather than yours. If you do hit a server that Rebex SFTP misbehaves against, that's a bug report we want: send us a communication log and we'll look at it.
Quick summary
| Setup | Write access | Automatable | Offline | Cost | |
|---|---|---|---|---|---|
| Your own server | already done | yes | varies | no | – |
| test.rebex.net | none | no | no (please don't) | no | free |
| Tiny SFTP Server | unzip + click | yes | not really | yes | free, incl. commercial use |
| File Server (in-process) | write a fixture | yes | yes, fully | yes | commercial license |
| Buru SFTP Server | unzip + 3 commands | yes | yes, fully | yes | free for non-commercial use |
| Third-party servers | varies | yes | varies | varies | varies |
A reasonable progression for most projects:
- Start with test.rebex.net to prove your connection code works.
- Move to Tiny SFTP Server for day-to-day development against a local, writable server.
- Adopt Buru SFTP Server once you want tests that run unattended from a clean state.
- Host Rebex File Server in-process when you need the server to fail in specific, repeatable ways - or simply want zero moving parts in CI.
- Reach for specific third-party servers only when you're chasing a compatibility issue with a particular implementation.
Questions? Rebex support and the forum are both open.