ffmpeg-over-ip: remote GPU transcoding without passthrough or shared filesystems
Connect to remote ffmpeg servers
At a glance
- What is it?
- ffmpeg-over-ip lets a media server use a GPU that lives on another machine, because the client binary pretends to be ffmpeg, forwards the arguments to a server that runs a patched ffmpeg, and tunnels all file input and output back over one TCP connection so nothing is copied to the GPU host. It suits a container or virtual machine deployment that cannot get at the hardware, and it needs the server to be reachable and both sides to share a secret.
- Who is it for?
- Adopt ffmpeg-over-ip if your media server runs somewhere without a GPU and the hardware is available on another host, because it removes the need for device mounts, PCIe passthrough and a shared filesystem. Do not adopt it if you can already reach the GPU, since the round trip adds latency and a moving part, and the server still runs a patched ffmpeg.
- Can I use it commercially?
- Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
- Is it still maintained?
- Yes. The repository last received commits 4 days ago.
- What is it written in?
- Mainly Go, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The problem: a GPU on the wrong machine
The README opens by stating the goal, to use GPU-accelerated ffmpeg from anywhere, a Docker container, a VM, or a remote machine, without GPU passthrough or shared filesystems.
The problem section then describes the three ways people normally solve it, and every one of them is an infrastructure project rather than a configuration change.
Docker containers need the nvidia runtime, device mounts, and driver version alignment between the host and the container. Virtual machines need PCIe passthrough or SR-IOV, which is complex setup that locks the GPU to one VM. Remote machines need shared filesystems, NFS or SMB, with all the path mapping, mount maintenance and permission headaches that come with them.
The summary is the line that decides the design. You just want your media server to use the GPU for transcoding, and you should not need to restructure your infrastructure to make that happen.
That framing matters for the alternatives later, because every design decision in the project follows from wanting the change on the client side to be a single path change to a different binary.
The solution: a client that pretends to be ffmpeg
The solution is stated in two sentences. Run the ffmpeg-over-ip server on the host, or on any machine with a GPU. Point your app at the client binary instead of ffmpeg, and your app gets GPU-accelerated transcoding without needing direct GPU access.
The client pretends to be ffmpeg. It forwards the arguments to the server, which runs a patched ffmpeg that tunnels all file input and output back through the connection. And the consequence is the one that makes the whole thing work: files are never stored on the server.
That last point is the design's real insight. A remote transcoder normally has to fetch the media, keep it, write the result and clean up, which means a shared filesystem, a temporary copy of every file and a path mapping between the two machines. By tunnelling the file operations themselves, the server never needs to know where the media lives. It asks the client for the bytes as ffmpeg asks for them, and the client serves them from its own filesystem.
The diagram in the README makes the split concrete. The client side has the media server invoking ffmpeg, the client binary, and the local filesystem with the real files. The server side has a daemon listening on a port, the server binary, and the patched ffmpeg with its file input and output tunnelled back to the client. One TCP connection connects them.
The summary line is worth keeping: no GPU passthrough, no shared filesystem, no NFS, no SMB, just one TCP port.
How the work actually flows
The how it works section is four steps, and each of them answers a question you would otherwise have to guess.
First, your media server calls the client binary with normal ffmpeg arguments. Nothing about the call changes, which is the property that makes the deployment a configuration change rather than a code change.
Second, the client connects to the server and sends the command with HMAC authentication.
Third, the server launches its patched ffmpeg, which tunnels all file reads and writes back to the client. So when ffmpeg asks to open an input file, the request goes over the connection and the client opens it locally.
Fourth, stdout and stderr are forwarded in real time, and when ffmpeg exits, the client exits with the same code. That last part is the detail that makes the thing usable in practice, because a media server decides whether a transcode succeeded by the exit status, and a wrapper that returned its own status would break every job it ran.
The server is also concurrent. Multiple clients can connect to the same server simultaneously, and each session gets its own ffmpeg process, so one busy transcode does not queue behind another.
The releases include prebuilt ffmpeg and ffprobe binaries with broad hardware acceleration support, covering NVENC, QSV, VAAPI, AMF and VideoToolbox among others, built on the jellyfin-ffmpeg pipeline. And there is no need to install ffmpeg separately on either side, which removes a version mismatch problem that would otherwise be yours to manage.
Installing, and the configuration that lands afterwards
The quick start is one line on each side, and there are scripts for both Unix-like shells and PowerShell.
On the machine with the GPU, the server script.
curl -fsSL https://ffmpeg-over-ip.com/install-server.sh | shOn the media server machine, the client script.
curl -fsSL https://ffmpeg-over-ip.com/install-client.sh | sh
The PowerShell equivalents use the Invoke-RestMethod and Invoke-Expression pair, one for the server and one for the client.
What the scripts do is described in one sentence. Each script downloads the latest release, prompts for the host, the port and the auth secret, and writes a starter configuration file in the current directory. Re-runs are idempotent, so already installed binaries and existing configurations are left alone, which is a small property that matters when the script is a pipe to a shell and you will inevitably run it twice.
For a manual install or a detailed setup there is a quick start document, and the configuration reference covers the configuration file search paths, the server and client options, rewrites, logging and the address formats.
There is also a Docker document covering the Docker integration, a Unix socket setup and debugging tips, and a troubleshooting document for common issues. The template configuration files are in the repository as JSON with comments, one for the client and one for the server.
The security model, and the split licence
Two short sections, and both are the ones to read before you deploy.
The security section lists two properties. Authentication is HMAC-SHA256 with a shared secret, and every command is signed. And the deployment is a single port, because only the server listens on a port while the client makes outbound connections only.
The second point is a real design property rather than a convenience. A client that only dials out is easy to run behind a firewall, in a container with an egress policy, or on a network where inbound connections are refused. It also means the client does not need to be reachable, so a media server can sit on a private network and still use a GPU on the other side.
The licence is split, and the split follows the code. The fio layer and the ffmpeg patches, in the fio and patches directories, are GPL v3 because they are derived from ffmpeg. Everything else is MIT.
That arrangement is the correct one, because the parts derived from ffmpeg cannot be relicensed away from the GPL, and the Go code around them can be. A user distributing a build of the client or the server inherits the GPL terms for the patched components, and the rest is permissive.
The repository layout follows the same split, with the fio directory and the patches directory sitting alongside the Go code in cmd and internal, plus third_party, vendor, artifacts and a website directory, and a module file that requires a JSON with comments parser for the configuration templates.
Platforms, upgrades and the state of the project
The supported platforms table is complete across the board, with the client and the server plus ffmpeg both supported on Linux for x86_64 and arm64, macOS for arm64 and x86_64, and Windows for x86_64.
That symmetry is worth noting, because it means the client and the server can live on different operating systems, and because the arm64 rows mean the arrangement works on a small machine as well as a server.
The upgrade story has a document of its own. There is a section on upgrading from version 4 with a migration guide and a list of breaking changes, and the fact that a major version bump needed a guide says something about how much the internals changed.
The releases are steady, with 5.2.1 on 2026-06-14, 5.2.0 in May and 5.1.0 at the start of May, and the last push to the repository was on the same day as the 5.2.1 release.
The repository also carries a changelog, a contributing document with the build instructions, the test running and the project structure, a scripts directory, a tests directory and a documentation site directory, which is the shape of a project that is built and shipped as binaries for five platforms from one Go source tree.
The thing to weigh before adopting it is the trade. You gain GPU transcoding on a machine that cannot have the GPU, and you pay for it with an extra network hop in the middle of every transcode, a patched ffmpeg on the server, and a shared secret to manage. For a large media library transcoded over hours, that trade is usually worth it. For a single small file, it is not.
Editorial conclusion
Adopt ffmpeg-over-ip if your media server runs somewhere without a GPU and the hardware is available on another host, because it removes the need for device mounts, PCIe passthrough and a shared filesystem. Do not adopt it if you can already reach the GPU, since the round trip adds latency and a moving part, and the server still runs a patched ffmpeg. Before you deploy, read the security section, because the design depends on a shared HMAC secret and on the client making outbound connections only, and confirm the upgrade notes if you are moving from version 4.
Frequently asked questions
How does ffmpeg-over-ip give a media server access to a remote GPU?
The client binary pretends to be ffmpeg and forwards the arguments to a server that runs a patched ffmpeg, which tunnels all file reads and writes back to the client over a single TCP connection. Because the file operations are tunnelled, files are never stored on the server, so no shared filesystem is needed.
Does the media server need any code changes to use ffmpeg-over-ip?
The README says you point your app at the client binary instead of ffmpeg, and that the client pretends to be ffmpeg and forwards the arguments. The exit code of ffmpeg is preserved, so the client exits with the same code when the transcode finishes.
How is ffmpeg-over-ip secured?
Authentication is HMAC-SHA256 with a shared secret and every command is signed, and only the server listens on a port while the client makes outbound connections only, so a client behind a firewall or an egress policy can still reach a GPU on another machine.
What licence does ffmpeg-over-ip use?
It is a split licence. The fio layer and the ffmpeg patches, in the fio and patches directories, are GPL v3 because they are derived from ffmpeg, and everything else is MIT.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/steelbrain-ffmpeg-over-ip)Was this useful?