GitHub: @ShobanChiddarth/openssh-server
You need to send a file to another machine on your network. It should be a solved problem. It is not.
Every method people actually reach for is either insecure, annoying to set up, or leaves something running on your machine long after you needed it. This post is about the one approach that gets all three things right - and it takes about two minutes to set up.
What You're Probably Doing (And Why It's Bad)
Let's go through the common options honestly.
Python HTTP server
python3 -m http.server 8080
Everyone knows this one. It works, and that's roughly where the positives end. Traffic is completely unencrypted. Anyone on the same network can see every byte in transit. There's no authentication - anyone who can reach the port can download anything you're serving.
Netcat
# sender
nc -l 9999 < file.txt
# receiver
nc 192.168.1.x 9999 > file.txt
Same problem. Cleartext, no auth, one shot if you're lucky. It's basically a raw pipe over TCP dressed up as a tool.
Installing openssh-server on your machine
This one at least solves the encryption problem. But now you've installed a permanent service on your host OS. sshd is running all the time, listening on port 22, attached to your actual system - its users, its filesystem, its everything. You wanted to share one folder for five minutes. You now have a permanently expanded attack surface.
And if you give the other person SSH credentials? They have a shell into your real machine. Full access. That's a lot of trust for a quick file transfer.
Samba / NFS
Heavy to configure, plenty of surface area, and definitely not something you spin up for a quick transfer and tear down cleanly.
The Actual Problem
The core issue with all of these is that they either skip encryption entirely, or they go too far in the other direction and give the other party more access than a file transfer requires.
What you actually want is:
- Encrypted transfer
- Auth (so not just anyone on the LAN can connect)
- Access scoped to exactly one directory, nothing else
- Zero footprint when you're done
The Solution: OpenSSH Inside a Docker Container
Here's the idea: run an SSH server inside a Docker container. Mount only the specific directory you want to share into that container. The other party connects over SSH, lands in that directory, and that's all they can see - not your home folder, not your system files, not anything else on your machine. When the transfer is done, you stop the container and it's completely gone.
The host OS never has sshd installed. No permanent service. No lingering open port. The container is the entire blast radius.
I built and published this as a ready-to-use Docker image with two variants: one based on Alpine Linux (smaller, recommended) and one based on Ubuntu Noble. The image handles user creation, password setup, and public key injection entirely through environment variables.
How It Works
When the container starts, the entrypoint script does the following:
- Reads
SSH_USER,SSH_PASSWORD, andSSH_PUBLIC_KEYfrom environment variables - Creates a low-privilege user inside the container with those credentials
- Writes the public key to that user's
~/.ssh/authorized_keys - Starts
sshdin the foreground
The user's home directory inside the container is whatever you bind-mount from your host. They can read and write files there. That's the full extent of what they can touch.
Step-by-Step: Running It
Prerequisites: Docker installed and running. That's it.
1. Pull the image
docker pull shobanchiddarth/openssh-server:alpine-1.0.0
Or if you prefer the Ubuntu variant:
docker pull shobanchiddarth/openssh-server:ubuntu-noble-1.0.0
2. Create the directory you want to share
mkdir -p /tmp/myshare
Put whatever files you want to transfer in here, or leave it empty for the other party to upload into.
3. Set up your environment variables
Grab the sample.env from the repo and copy it:
cp sample.env .env
Edit .env:
SSH_USER=USERNAME
SSH_PASSWORD=PASSWORD
SSH_PUBLIC_KEY=ssh-ed25519 AAAA... you@yourmachine
SSH_PUBLIC_KEY is optional in practice - if the other party doesn't have a key pair, they'll just use the password. But public key is always preferable.
4. Run the container
docker run -d \
--name myshare \
-p 0.0.0.0:2222:22 \
--env-file .env \
-v /tmp/myshare:/home/USERNAME \
shobanchiddarth/openssh-server:alpine-1.0.0
The -v flag is the key part. /tmp/myshare is the folder on your machine. /home/USERNAME is where the SSH user lands inside the container. Those two are linked - anything written to one appears in the other. The username in the path should match SSH_USER in your .env.
Your LAN IP is whatever ip a (Linux) or ipconfig (Windows) shows for your network interface - typically something like 192.168.1.x.
5. Transfer files from the other machine
# Upload a file
scp -P 2222 /path/to/file.txt USERNAME@192.168.1.x:~/
# Download a file
scp -P 2222 USERNAME@192.168.1.x:~/file.txt ./
# Interactive session
sftp -P 2222 USERNAME@192.168.1.x
This works from Linux, macOS, and Windows (via PowerShell with OpenSSH, WSL, or Git Bash - all ship with scp and sftp).
6. Tear it down
docker stop myshare
docker rm myshare
Port closed. No service running. Nothing left behind.
Windows Host Note
If you're running Docker Desktop on Windows, the volume mount path uses Windows-style paths:
docker run -d `
--name myshare `
-p 0.0.0.0:2222:22 `
--env-file .env `
-v C:\Users\YourName\myshare:/home/USERNAME `
shobanchiddarth/openssh-server:alpine-1.0.0
Everything else - the scp/sftp commands from the client side - is identical.
Security Properties at a Glance
| Property | Behavior |
|---|---|
| Encryption | SSH - all traffic encrypted in transit |
| Authentication | Password + public key |
| Host filesystem | Completely inaccessible from inside the container |
| Shell access | Scoped to the container only |
| Host SSH daemon | Never installed |
| Persistence after use | Zero - stop the container, it's gone |
One thing worth being explicit about: bind the port to 0.0.0.0 only on trusted networks. That makes the container reachable on all your local interfaces. If you want to lock it down to a specific interface, replace 0.0.0.0 with that interface's IP (e.g., 192.168.1.5:2222:22). Either way, don't forward port 2222 through your router - this is a LAN tool.
Why This Is Better
The Python HTTP server is convenient. This is only marginally less convenient - one docker run command instead of one python3 command - and in exchange you get encryption, authentication, proper access scoping, and a completely clean teardown.
If you have Docker, there's no good reason to reach for the HTTP server anymore.
The repo has both Alpine and Ubuntu variants, a sample.env template, and full usage documentation. Pull it, try it, and stop sharing files over cleartext.
The known_hosts problem
Let's say you want your friend to share a file to you. So you ask him his public ssh key and spin up a container with port and volume mapped. And then he tries to ssh into your container. Then he gets hit with this
ssh test@192.168.1.2
The authenticity of host '192.168.1.2 (192.168.1.2)' can't be established.
ED25519 key fingerprint is SHA256:9d8pzTNQ1vLi2laKIqHnzOG+QdgNv8bDQVz67sNJi1E.
This key is not known by any other names.
Are you sure you want to continue connecting (yes/no/[fingerprint])?
This is the unknown host warning, it is what ssh usually does to make sure you are accessing the machine you think you are accessing by showing the host key of the machine. So since your friend knows he is accessing your machine and trusts is, he types yes and then the host key gets added to ~/.ssh/known_hosts file. He then finishes the file sharing work and then closes the connection so you stop the container and delete it. Some time later if he wants to do another file sharing work, you spin up another container and if you are in the same LAN with the same private IP, ssh client on his machine sees your host with a different ssh host key when he is trying to access it. So it prints a message like this
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@ WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!
Someone could be eavesdropping on you right now (man-in-the-middle attack)!
It is also possible that a host key has just been changed.
The fingerprint for the ED25519 key sent by the remote host is
SHA256:s9QoffY4cHer0u66A9s57WzN3/ufOfCBGTq/v9fhr5w.
Please contact your system administrator.
Add correct host key in /home/mint/.ssh/known_hosts to get rid of this message.
Offending ECDSA key in /home/mint/.ssh/known_hosts:3
remove with:
ssh-keygen -f '/home/mint/.ssh/known_hosts' -R '[192.168.56.1]:2222'
Host key for [192.168.56.1]:2222 has changed and you have requested strict checking.
Host key verification failed.
But this can be ignored since it is true that the host key has changed and he has to remove the old known hosts entry with
ssh-keygen -f '/home/mint/.ssh/known_hosts' -R '[192.168.56.1]:2222'
as said in that message. If it is unsure whether or not SOMEONE is doing SOMETHING NASTY you should send your host key to your friend and ask him to compare. You can do it by
docker exec -it myshare /bin/sh # or /bin/bash if ubuntu
cd /etc/ssh
ls *host*.pub # to see the host public key names
ssh-keygen -lf ssh_host_ecdsa_key.pub
ssh-keygen -lf ssh_host_ed25519_key.pub
ssh-keygen -lf ssh_host_rsa_key.pub
Now send the output of the last 3 commands to him and tell him to enter the fingerprint of the algorithm (ecdsa or ed25519 or rsa) he is seeing in his screen and if it matches the host will be added to known_hosts (with the current host public key, so he will have to remove it later by following the above instructions) and the connection will happen.
Top comments (0)