How Spite Drove Me to Build My Own FTP Server

I didn’t want to write an FTP server. Nobody wants to write an FTP server. That’s like trying to fix a broken lightbulb with a hammer. You only do it when everything else has failed and you’re out of better options.

And yet here I am.

All I needed was a simple, anonymous file drop. A network scanner that sends invoices to a server over FTP. No passwords. No secrets. Not exposed to the internet. Deep inside a private IPv6 network where no sunlight reaches. The kind of setup that should take about twenty minutes and a cup of coffee.

But no.

Every FTP daemon out there—vsftpd, ProFTPD, Pure-FTPd, Wu-FTPD (yes, that’s real and yes, I tried it)—all of them, every last one, decided that my use case was morally reprehensible.

  • You want to run as Root?
    Sorry, that’s forbidden.
  • You want to accept anonymous uploads and save them as Root?
    That’s a security violation.
  • You want to do this in a controlled environment where the threat model is “literally nothing”?
    Sorry, no can do. We have principles.

It’s like trying to rent a bouncy castle for a party and being told you first have to take a safety course, sign a 14-page liability waiver, and promise not to bounce.

So after several hours of failed containers, contradictory documentation, and seething rage, I made a decision that permanently altered the trajectory of my life:

I wrote my own FTP server.

Not because it’s a good idea.
Not because I wanted to.
But because nothing else would just do the thing.

It started with a .NET TCP Listener. Within two hours, I had a core that could accept connections and trick my ancient network scanner into thinking it was talking to a Real Boy™ FTP server. From there, the darkness took me.

Yes, I implemented all the core FTP commands.
Yes, I added UTF-8 support.
Yes, I handled extended passive and active modes because, surprise, IPv6 hates fun.
Yes, it jails users to a directory like a proper little warden.
Yes, there’s a full config system. Strongly typed, naturally.
And yes, there is an unholy suite of unit tests for every file upload, download, resume, deletion, and escape attempt.

I didn’t just build a server. I built a vengeful monument.

And now, because I am technically a functioning member of society, I will be releasing binaries.
Not the source code.
I’m not doing this for the open-source glory. Linus already took all of that.

I’m doing this for spite. For people like me. For the ones broken by legacy protocols and self-righteous daemons.

You want to use it? Great. It’ll work. You’ll weep tears of joy as your scanner finally delivers its precious little invoices into your file system.
You want the code?

Pay me.
Or better yet, try writing your own. See how deep the rabbit hole goes.


What Do I Call This Monster?

It’s called vIsftpd.

Not to be confused with its uptight cousin, vsftpd—the so-called Very Secure FTP Daemon, which treats anonymous uploads like a war crime and panics at the idea of running as Root.

No. Mine is vIsftpdVery InSecure FTP Daemon.

The name is a deliberate mutation. A surgical insertion of IN, slipped right into the acronym like a virus. A quiet rebellion against decades of paranoid FTP design. It doesn’t come with a moral compass. It doesn’t demand certificates. It doesn’t ask for your fingerprints.

It does what it’s told.

Run it in a private subnet. Let your ancient network scanner live its best life. And rest easy knowing that finally—finally—someone wrote an FTP daemon that trusts you to be reckless on purpose.

“vIsftpd: Run it as root, or don’t run it at all.”

—RFC 959, probably, if you read it upside down while angry


The Protocols That Trust Me (and the One That Doesn’t)

Let me get one thing straight: I'm not new here. I know the risks. I’ve read the horror stories. I understand the implications of running services as Root in a local network. And so do the rest of the protocols.

SMB? It grumbles a little, but it lets me run as Root, lets me drop files as Root, and then minds its own business.
Nginx, Apache? Same story. "Are you sure?" they ask politely. And then they let me do my thing.
NFS? Please. NFS doesn't even pretend. It’s the drunk uncle of network protocols—no authentication, no shame, just raw access and a smile.
rsync? It’s basically a teleportation spell for files. No lecture, no judgment.

And then there’s FTP. Sweet, broken, judgmental FTP.

Every FTP server I tried was like a bouncer with a God complex. “Oh you want to run as Root? Upload files as Root? Hah. That's not allowed here, peasant.” And this, mind you, on a locked-down subnet, with no sensitive data, just a lonely scanner sending invoices like a bureaucratic bottle in the ocean.

So why is FTP the only protocol that acts like it’s guarding the nuclear launch keys?

Honestly, I don’t know. Maybe it's guilt. Maybe it's insecurity. Maybe it just wants to be loved in a world that forgot it after SCP moved in next door. But I do know one thing: I’m done asking for permission.

That’s why vIsftpd exists.


Concurrency and the Art of Not Crashing Everything

I could’ve cut corners. I didn’t need to support multiple clients. In fact, this entire FTP server exists just to serve one—one single, lonely network scanner living somewhere in my local IPv6 swamp, quietly trying to send PDFs to the promised land.

But I built multi-connection support anyway. Because deep down, I knew someone—maybe future me, maybe a desperate sysadmin—would eventually say, “Hey, can it handle more than one connection at a time?” And I wanted the answer to be “yes,” not “please don’t touch it.”

So the moment a client connects, vIsftpd does what all emotionally distant services should: it hands off the connection to a background task and keeps listening.

No global locks. No weird thread pools. No FIFO queues like it’s a print server from 1997. Just clean, parallel processing like a civilized modern daemon—each connection living its own sad little life, reading its own sad little FTP commands, and uploading its sad little invoices.

Does it scale? Sure.
Do I care? Not really.
But it works. And it doesn't crash. And that, in the world of DIY protocol servers, is enough to call it art.


What It Doesn’t Do (Because I Don’t Care)

vIsftpd is not here to impress RFC purists or earn a gold star from the IETF. It doesn’t want your approval. It wants your files.

Here are some things it does not do—and never will—because I’ve looked into the void of FTP server behavior, and I’ve chosen sanity.

It doesn’t support user accounts.
FTP daemons love user management. They live for it. PAM integration, shadow passwords, virtual users... I don’t care. I have one scanner. It doesn't have a name. It just barfs PDFs. We're not doing authentication roleplay.

It doesn’t support TLS.
This is a private network. No one is sniffing traffic unless they’re already inside, in which case I have bigger problems than invoice leaks. If you want TLS, use literally any other service that wasn’t built in the Bronze Age.

It doesn’t log in detail.
There’s a log. It tells you what happened. That’s it. No analytics, no dashboards, no creepy log spam about "potential malicious behavior." Just a quiet record of success and failure, like a responsible adult.

It doesn’t support upload quotas, fancy chrooted users, passive firewall negotiation, or whatever 45 flags vsftpd makes you set just to let someone say hello.
Why? Because I’ve done enough config debugging to last at least several lifetimes. And because none of that makes sense when you’re just trying to accept one goddamn file from a trusted machine on your own network.

If you need more features, you’re welcome to go back to one of the “real” FTP servers. Just don’t cry to me when they reject you because you had the audacity to use Root on your own system.


I built vIsftpd. I signed my name to it. Because I have opinions. And I have nothing to hide. The machine is mine. The network is mine. I will run what I want, how I want. That’s not a vulnerability. That’s ownership.