All apps · 0 apps
FFmpeg-SSH-Worker
Docker app from heroeswearkapes Community Apps' Repository
Overview
Readme
View on GitHubFFmpeg SSH Worker
A lightweight, CPU-based FFmpeg rendering worker with SSH key authentication, designed for automation workflows.
FFmpeg SSH Worker was originally created as the rendering node for an n8n workflow that automatically assembled YouTube Shorts. n8n would connect to the worker over SSH, execute FFmpeg commands, and use the shared /work directory for source media, intermediate files, and completed renders.
Although originally built for n8n, the worker is not tied to it. Any automation platform, script, application, or remote system capable of executing commands over SSH can use the container as an isolated FFmpeg processing node.
No GPU is required. Media processing and encoding are performed using the host CPU.
Features
- FFmpeg 8
- CPU-based media processing and encoding
- OpenSSH server
- SSH public-key authentication
- Password authentication disabled
- Root SSH login disabled
- Persistent SSH host keys
- Persistent configuration through
/config - Shared rendering workspace through
/work libx264H.264 encodinglibx265H.265/HEVC encoding- Common FFmpeg audio and video codecs
- Fontconfig and DejaVu fonts for text and subtitle workflows
- Python 3
curljqgawknanotini- Docker healthcheck
- Docker Compose support
- Backward compatibility with the legacy
authorized_keysmount - Multi-architecture support
linux/amd64linux/arm64
Docker Image
The Docker image is published as:
heroeswearkapes/ffmpeg-ssh-worker
Pull the latest image:
docker pull heroeswearkapes/ffmpeg-ssh-worker:latest
How It Works
The container runs an OpenSSH server with FFmpeg and supporting utilities installed.
An automation system connects to the worker over SSH and executes FFmpeg commands remotely.
A typical workflow looks like:
Automation Platform
|
| SSH
v
FFmpeg SSH Worker
|
|-- /work/input
|-- FFmpeg processing
|-- /work/intermediate
`-- /work/output
The /work directory can be mounted to persistent storage or a shared media location on the Docker host.
This allows the automation platform to coordinate jobs while the worker performs the CPU-intensive media processing.
Requirements
You will need:
- Docker or Docker Compose
- A CPU capable of running the desired FFmpeg workload
- An SSH key pair for authentication
- Storage accessible to the container for media processing
A GPU is not required.
Quick Start
Clone the repository:
git clone https://github.com/heroeswearkapes/ffmpeg-ssh-worker.git
cd ffmpeg-ssh-worker
Create the runtime configuration:
cp .env.example .env
Create the configuration and work directories:
mkdir -p config work
Add your SSH public key:
cp ~/.ssh/id_ed25519.pub config/authorized_keys
If your public key has a different name, replace the source path accordingly.
Start the worker:
docker compose up -d
Check the container:
docker compose ps
View startup logs:
docker compose logs -f
Connect over SSH:
ssh -p 2222 worker@YOUR-SERVER-IP
The default SSH username is:
worker
Docker Compose
The included docker-compose.yaml uses:
services:
ffmpeg-ssh-worker:
image: heroeswearkapes/ffmpeg-ssh-worker:latest
container_name: ffmpeg-ssh-worker
environment:
TZ: ${TZ:-America/New_York}
ports:
- "${SSH_PORT:-2222}:22"
volumes:
- ${CONFIG_PATH:-./config}:/config
- ${WORK_PATH:-./work}:/work
restart: unless-stopped
Configuration
The public .env.example contains the runtime options used by Docker Compose.
SSH Port
SSH_PORT=2222
This is the host port used to connect to the worker.
The SSH server inside the container listens on port:
22
For example:
ssh -p 2222 worker@192.168.1.100
You can change the host port without changing the internal SSH configuration.
For example:
SSH_PORT=2223
would be accessed using:
ssh -p 2223 worker@YOUR-SERVER-IP
Configuration Path
CONFIG_PATH=./config
The configuration directory is mounted inside the container at:
/config
This directory stores:
authorized_keys- Persistent ED25519 SSH host key
- Persistent RSA SSH host key
Keeping /config persistent prevents the SSH server identity from changing when the container is recreated or updated.
Work Path
WORK_PATH=./work
The work directory is mounted inside the container at:
/work
This is the primary workspace for:
- Source media
- Audio
- Images
- Intermediate files
- Rendered video
- Completed output
The worker user must have permission to write to the mounted directory.
Timezone
TZ=America/New_York
Set this to the desired IANA timezone.
Examples:
America/New_York
America/Chicago
America/Denver
America/Los_Angeles
Etc/UTC
SSH Authentication
FFmpeg SSH Worker uses SSH public-key authentication.
Password authentication is disabled.
Root SSH login is disabled.
The default SSH user is:
worker
Generate an SSH Key
If you do not already have an SSH key pair:
ssh-keygen -t ed25519
The public key is normally created at:
~/.ssh/id_ed25519.pub
The private key is normally:
~/.ssh/id_ed25519
Never place the private key inside the container configuration directory.
Only the public key belongs in authorized_keys.
Preferred authorized_keys Configuration
The preferred location is:
/config/authorized_keys
With the included Docker Compose configuration, this corresponds to:
./config/authorized_keys
For example:
mkdir -p config
cp ~/.ssh/id_ed25519.pub \
config/authorized_keys
Then start or restart the container:
docker compose up -d
At startup, the worker copies the public keys into the SSH user's configuration and applies the required permissions.
Multiple SSH Public Keys
The standard OpenSSH authorized_keys format is supported.
Multiple public keys may be placed in the same file, one per line:
ssh-ed25519 AAAA... automation-system-1
ssh-ed25519 AAAA... automation-system-2
ssh-ed25519 AAAA... administrator
This allows multiple automation systems or administrators to access the same worker.
Persistent SSH Host Identity
SSH servers identify themselves using host keys.
FFmpeg SSH Worker stores its generated host keys under:
/config
The container generates persistent ED25519 and RSA host keys when they do not already exist.
As long as /config remains persistent, recreating or upgrading the container will retain the same SSH server identity.
This avoids SSH warnings such as:
WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!
that would otherwise occur if a new SSH host key were generated every time the container was recreated.
Legacy authorized_keys Compatibility
Older versions of FFmpeg SSH Worker expected authorized_keys to be mounted directly at:
/home/worker/.ssh/authorized_keys
This configuration remains supported for backward compatibility.
For example:
-v /path/to/authorized_keys:/home/worker/.ssh/authorized_keys:ro
New installations should use:
/config/authorized_keys
instead.
Docker CLI
Preferred Configuration
Create the required directories:
mkdir -p config work
Add your SSH public key:
cp ~/.ssh/id_ed25519.pub config/authorized_keys
Start the container:
docker run -d \
--name ffmpeg-ssh-worker \
-p 2222:22 \
-e TZ="America/New_York" \
-v "$(pwd)/config:/config" \
-v "$(pwd)/work:/work" \
--restart unless-stopped \
heroeswearkapes/ffmpeg-ssh-worker:latest
Then connect:
ssh -p 2222 worker@YOUR-SERVER-IP
Legacy Configuration
The original authorized-keys mount remains supported:
docker run -d \
--name ffmpeg-ssh-worker \
-p 2222:22 \
-v /path/to/authorized_keys:/home/worker/.ssh/authorized_keys:ro \
-v /path/to/work:/work \
--restart unless-stopped \
heroeswearkapes/ffmpeg-ssh-worker:latest
FFmpeg Usage
Once connected over SSH, FFmpeg can be used normally.
Check the installed version:
ffmpeg -version
List available encoders:
ffmpeg -encoders
List available decoders:
ffmpeg -decoders
List available filters:
ffmpeg -filters
CPU Rendering
FFmpeg SSH Worker is intentionally designed around CPU-based rendering.
No NVIDIA, Intel, or AMD GPU passthrough is required.
For H.264 CPU encoding:
ffmpeg \
-i /work/input.mp4 \
-c:v libx264 \
-preset medium \
-crf 23 \
-c:a aac \
/work/output.mp4
For H.265/HEVC CPU encoding:
ffmpeg \
-i /work/input.mp4 \
-c:v libx265 \
-preset medium \
-crf 28 \
-c:a aac \
/work/output.mp4
Encoding speed depends heavily on:
- CPU performance
- Resolution
- Frame rate
- Encoder
- Preset
- Filters
- Number of simultaneous jobs
Tested CPU Render
During development, the worker was validated by remotely executing an FFmpeg render over SSH using:
ffmpeg -y \
-f lavfi \
-i testsrc=size=1280x720:rate=30 \
-t 3 \
-c:v libx264 \
-preset veryfast \
-pix_fmt yuv420p \
/work/test-render.mp4
The resulting media was verified with ffprobe as:
codec_name=h264
width=1280
height=720
r_frame_rate=30/1
duration=3.000000
Using with n8n
FFmpeg SSH Worker was originally created specifically for an n8n-based YouTube Shorts automation workflow.
Instead of installing FFmpeg and media-processing dependencies directly into the n8n container, n8n used its SSH capabilities to send rendering commands to a dedicated worker.
Conceptually:
n8n
|
| SSH
v
FFmpeg SSH Worker
|
|-- receives/accesses source assets
|-- combines video and images
|-- processes audio
|-- applies FFmpeg filters
|-- renders the completed Short
`-- writes completed media to /work
This separates workflow orchestration from CPU-intensive media rendering.
n8n SSH Connection
A typical n8n SSH credential would use:
Host: YOUR-WORKER-IP
Port: 2222
Username: worker
Authentication: Private Key
The corresponding public key must exist in:
/config/authorized_keys
on the FFmpeg SSH Worker.
The private key remains with n8n.
Example n8n Command
An n8n SSH node could execute a command such as:
ffmpeg -y \
-i /work/source.mp4 \
-i /work/music.mp3 \
-c:v libx264 \
-preset medium \
-c:a aac \
-shortest \
/work/final-short.mp4
The exact FFmpeg command depends on the automation workflow.
Other Automation Platforms
The worker is not specific to n8n.
Any platform capable of SSH command execution can use it.
Possible uses include:
- Automated video rendering
- Social media video assembly
- YouTube Shorts generation
- Video transcoding
- Audio conversion
- Audio/video muxing
- Image-to-video workflows
- Subtitle processing
- Text overlays
- Thumbnail extraction
- Frame extraction
- Batch media processing
- CI/CD media jobs
- Custom shell automation
Included Utilities
In addition to FFmpeg and OpenSSH, the image includes several utilities useful for automation workflows:
bash
curl
jq
python3
gawk
nano
fontconfig
fonts-dejavu-core
tini
The exact versions depend on the current Ubuntu 26.04 packages included when the image is built.
Fonts and Text Rendering
The image includes:
fontconfig
fonts-dejavu-core
These provide a basic font environment for FFmpeg workflows involving text, subtitles, and other font-dependent filters.
Available fonts can be inspected with:
fc-list
Healthcheck
The container includes a Docker healthcheck that verifies the SSH service is listening on port 22.
Check container health with:
docker ps
or:
docker inspect \
--format='{{json .State.Health}}' \
ffmpeg-ssh-worker
A healthy container indicates that the SSH server is listening.
The healthcheck does not validate authentication credentials or execute an FFmpeg render.
Persistent Data
Two paths are intended to be persistent.
/config
Stores SSH-related configuration:
/config/authorized_keys
/config/ssh_host_ed25519_key
/config/ssh_host_ed25519_key.pub
/config/ssh_host_rsa_key
/config/ssh_host_rsa_key.pub
/work
Stores media used by automation jobs:
/work
The contents and directory structure under /work are entirely up to the workflow using the worker.
Permissions
The default worker account uses:
UID: 1000
GID: 1000
Username: worker
The /work mount must be writable by the worker account if FFmpeg is expected to create output there.
You can test this from inside the container:
docker exec ffmpeg-ssh-worker \
test -w /work \
&& echo "Writable" \
|| echo "Not writable"
The container does not recursively change ownership of /work at startup. This is intentional to avoid unexpectedly changing ownership across large host media shares.
Multi-Architecture Support
The Docker image supports:
linux/amd64
linux/arm64
This allows FFmpeg SSH Worker to run on standard x86-64 Docker hosts as well as ARM64 systems.
The ARM64 image uses the native Ubuntu ARM64 FFmpeg and OpenSSH packages.
Security
The SSH server is configured with:
- Root login disabled
- Password authentication disabled
- Public-key authentication enabled
- SSH access restricted to the
workeraccount
The container should still be treated like any other SSH-accessible system.
Recommended practices:
- Use strong ED25519 SSH keys.
- Never place private SSH keys in
/config. - Do not expose the SSH port directly to the public Internet unless you understand and accept the security implications.
- Restrict network access using firewall rules, VLANs, VPNs, or overlay networks where appropriate.
- Remove unused public keys from
authorized_keys. - Keep the container image updated.
The project's .dockerignore prevents common private-key filenames, authorized_keys, .env, secrets/, and work/ from being accidentally copied into the Docker build context.
Updating
Docker Compose
Pull the latest image:
docker compose pull
Recreate the container:
docker compose up -d
Persistent /config and /work data will remain intact.
Docker CLI
Pull:
docker pull heroeswearkapes/ffmpeg-ssh-worker:latest
Then recreate the container using the same port, /config, and /work mappings.
Because SSH host keys are stored under /config, the SSH server identity will remain consistent after recreation.
Troubleshooting
SSH connection refused
Verify the container is running:
docker ps
Check the logs:
docker logs ffmpeg-ssh-worker
Verify the configured host port:
docker port ffmpeg-ssh-worker
The default Docker Compose host port is:
2222
Permission denied (publickey)
The SSH server does not support password authentication.
Verify that:
/config/authorized_keys
exists and contains the public key corresponding to the private key being used by your SSH client.
Inspect the file:
cat config/authorized_keys
Check the container logs:
docker logs ffmpeg-ssh-worker
A correctly detected configuration should contain:
[INFO] Found /config/authorized_keys
[INFO] SSH authorized keys installed.
Container starts but warns that no authorized_keys file exists
The container can start without an SSH public key, but SSH login will not be possible.
Create:
config/authorized_keys
and place your SSH public key inside it.
Then restart:
docker compose restart
SSH host identification changed
With the preferred configuration, SSH host keys are persisted under:
/config
Make sure /config is mapped to persistent storage.
If /config is not persistent, recreating the container may generate a new SSH host identity.
/work is not writable
Check:
docker exec ffmpeg-ssh-worker \
test -w /work \
&& echo "Writable" \
|| echo "Not writable"
The default worker uses:
UID 1000
GID 1000
Adjust the host directory permissions as appropriate for your environment.
FFmpeg command not found
Verify:
docker exec ffmpeg-ssh-worker ffmpeg -version
FFmpeg is included directly in the image.
Check for libx264
Run:
docker exec ffmpeg-ssh-worker \
ffmpeg -hide_banner -encoders 2>/dev/null | grep libx264
You should see the libx264 encoder.
Check FFmpeg remotely over SSH
ssh -p 2222 worker@YOUR-SERVER-IP \
'ffmpeg -version | head -n 2'
Check container health
docker ps
For more detail:
docker inspect \
--format='{{json .State.Health}}' \
ffmpeg-ssh-worker
View logs
docker logs -f ffmpeg-ssh-worker
Startup logs include:
- SSH username
- UID/GID
- Configuration path
- Work path
- SSH authorized-key status
- SSH host-key status
- Workspace write status
- FFmpeg version
libx264availability- SSH configuration summary
- SSH server startup status
Render fails over SSH but works locally
Verify the SSH worker is using the same paths referenced by the FFmpeg command.
Remember that commands executed through SSH run inside the container.
For example, a host file located at:
./work/input.mp4
is available inside the container as:
/work/input.mp4
An FFmpeg command executed over SSH should therefore reference:
ffmpeg \
-i /work/input.mp4 \
-c:v libx264 \
/work/output.mp4
not the host-side path.
SSH connection closes during a long render
The SSH server is configured with:
ClientAliveInterval 120
ClientAliveCountMax 2
This helps detect disconnected clients while allowing long-running SSH sessions.
If the automation platform imposes its own command timeout, that timeout may need to be increased for long FFmpeg renders.
Render is slower than expected
FFmpeg SSH Worker intentionally uses CPU-based encoding.
Rendering performance depends heavily on:
- CPU model and available cores
- Resolution
- Frame rate
- Encoder
- Encoder preset
- Filters
- Source media
- Number of simultaneous jobs
For libx264, faster presets can significantly reduce render time at the expense of compression efficiency.
For example:
-preset veryfast
will normally encode faster than:
-preset medium
The worker does not currently configure GPU acceleration.
Find available FFmpeg encoders
Run:
docker exec ffmpeg-ssh-worker \
ffmpeg -hide_banner -encoders
Over SSH:
ssh -p 2222 worker@YOUR-SERVER-IP \
'ffmpeg -hide_banner -encoders'
Find available FFmpeg filters
Run:
docker exec ffmpeg-ssh-worker \
ffmpeg -hide_banner -filters
This can be useful when building automation workflows involving scaling, overlays, subtitles, text, audio processing, or other FFmpeg filters.
Verify fonts
List fonts available inside the container:
docker exec ffmpeg-ssh-worker fc-list
The image includes DejaVu fonts and Fontconfig for basic text-rendering workflows.
Container reports unhealthy
The Docker healthcheck verifies that the SSH service is listening on port 22.
Check the logs:
docker logs ffmpeg-ssh-worker
Then verify SSH is listening inside the container:
docker exec ffmpeg-ssh-worker \
nc -z 127.0.0.1 22 \
&& echo "SSH is listening" \
|| echo "SSH is not listening"
An unhealthy status does not test your SSH private key or execute an FFmpeg job. It only indicates whether the SSH service is reachable inside the container.
Versioning
Versioned releases are published alongside latest.
For example:
heroeswearkapes/ffmpeg-ssh-worker:latest
heroeswearkapes/ffmpeg-ssh-worker:v1.0
For most users:
latest
is recommended.
A versioned tag can be used when you want to pin the worker to a specific release.
Building from Source
Clone the repository:
git clone https://github.com/heroeswearkapes/ffmpeg-ssh-worker.git
cd ffmpeg-ssh-worker
Build a local image:
docker build \
-t ffmpeg-ssh-worker:local \
.
The default build creates:
Username: worker
UID: 1000
GID: 1000
These values can also be supplied as build arguments:
docker build \
--build-arg USERNAME=worker \
--build-arg UID=1000 \
--build-arg GID=1000 \
-t ffmpeg-ssh-worker:local \
.
The public image uses worker as the supported SSH username.
Multi-Architecture Images
Published Docker images support:
linux/amd64
linux/arm64
Both latest and versioned releases are published as multi-architecture images.
For example:
heroeswearkapes/ffmpeg-ssh-worker:latest
heroeswearkapes/ffmpeg-ssh-worker:v1.0
Docker will automatically pull the appropriate image for your host architecture.
Project History
FFmpeg SSH Worker started as a utility for an automated YouTube Shorts workflow built with n8n.
The workflow needed a dedicated system capable of performing CPU-intensive FFmpeg operations without adding FFmpeg, media-processing dependencies, and rendering workloads directly to the n8n container.
The solution was a small Docker worker that:
- Runs FFmpeg and supporting media utilities.
- Exposes SSH using public-key authentication.
- Provides a shared
/workdirectory. - Allows n8n to remotely execute rendering commands.
- Keeps workflow orchestration separate from media processing.
The same design can be useful for other automation systems, so the worker is maintained as a general-purpose SSH-accessible FFmpeg processing container while retaining its original n8n use case.
Source
Project source:
https://github.com/heroeswearkapes/ffmpeg-ssh-worker
Docker image:
heroeswearkapes/ffmpeg-ssh-worker
Security Notes
This container intentionally exposes an SSH server because remote command execution is its primary purpose.
Anyone possessing a private key corresponding to a public key in authorized_keys can execute commands as the worker user inside the container.
For that reason:
- Protect private SSH keys.
- Only add trusted public keys to
authorized_keys. - Do not publish private keys in Git repositories, Docker images, or automation exports.
- Avoid exposing the SSH port directly to the public Internet unless necessary.
- Prefer trusted LANs, VLANs, VPNs, or private overlay networks.
- Remove keys that are no longer required.
- Keep the image updated.
The worker is intentionally not privileged and does not require Docker socket access for normal operation.
Inspiration
FFmpeg SSH Worker was originally created to solve a rendering requirement in an n8n-based YouTube Shorts automation workflow.
It has since been generalized so the same SSH-accessible FFmpeg worker can be used by other automation platforms, scripts, and applications.
Disclaimer
This is an independent community project.
It is not affiliated with or endorsed by FFmpeg, n8n, Docker, Ubuntu, or any other third-party project referenced in the documentation.
License
This project is licensed under the MIT License.
See the LICENSE file for the full license text.
Install FFmpeg-SSH-Worker on Unraid in a few clicks.
Find FFmpeg-SSH-Worker in Community Apps on your Unraid server, review the template, and click Install. Unraid handles the Docker app or plugin setup from the published template.
Requirements
FFmpeg SSH Worker uses SSH public-key authentication.
The SSH username is:
worker
Password authentication and root SSH login are disabled.
After installation, place your SSH PUBLIC key in:
/mnt/user/appdata/ffmpeg-ssh-worker/authorized_keys
Only the public key should be placed in authorized_keys. Never place your SSH private key in the container configuration directory.
If you do not already have an SSH key pair, one can be generated from another system with:
ssh-keygen -t ed25519
After adding authorized_keys, restart the container.
With the default port configuration, connect using:
ssh -p 2222 worker@YOUR-UNRAID-IP
The /work directory is the shared FFmpeg workspace used for source media, intermediate files, and completed renders.
FFmpeg SSH Worker performs CPU-based media processing. No GPU is required.
Categories
Download Statistics
Related apps
Explore more like this
Explore allDetails
heroeswearkapes/ffmpeg-ssh-worker:latestRuntime arguments
- Network
bridge- Shell
bash- Privileged
- false
Template configuration
Host port used to connect to the FFmpeg worker over SSH. Example: ssh -p 2222 worker@YOUR-UNRAID-IP
- Target
- 22
- Default
- 2222
- Value
- 2222
Persistent SSH configuration. Place your public SSH key in authorized_keys within this directory. Persistent SSH host keys are also stored here.
- Target
- /config
- Default
- /mnt/user/appdata/ffmpeg-ssh-worker
- Value
- /mnt/user/appdata/ffmpeg-ssh-worker
Shared workspace for source media, intermediate files, and completed FFmpeg renders. The worker account must have write access to this location.
- Target
- /work
- Default
- /mnt/user/ffmpeg-work
- Value
- /mnt/user/ffmpeg-work
Timezone used inside the container. Use a valid IANA timezone such as America/New_York.
- Target
- TZ
- Default
- America/New_York
- Value
- America/New_York