FFmpeg-SSH-Worker

FFmpeg-SSH-Worker

Docker app from heroeswearkapes Community Apps' Repository

Overview

FFmpeg SSH Worker is a lightweight, CPU-based FFmpeg rendering worker with SSH public-key authentication, designed for automation workflows. Originally created as the rendering node for an n8n workflow that automatically assembled YouTube Shorts, the worker can be used by n8n or any other automation platform, script, or application capable of executing commands over SSH. Provides FFmpeg, OpenSSH, persistent SSH host keys, a shared /work directory, and common media-processing utilities. CPU rendering only. No GPU passthrough is required. Supports both amd64 and arm64 Docker hosts.

FFmpeg 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
  • libx264 H.264 encoding
  • libx265 H.265/HEVC encoding
  • Common FFmpeg audio and video codecs
  • Fontconfig and DejaVu fonts for text and subtitle workflows
  • Python 3
  • curl
  • jq
  • gawk
  • nano
  • tini
  • Docker healthcheck
  • Docker Compose support
  • Backward compatibility with the legacy authorized_keys mount
  • Multi-architecture support
    • linux/amd64
    • linux/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 worker account

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
  • libx264 availability
  • 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:

  1. Runs FFmpeg and supporting media utilities.
  2. Exposes SSH using public-key authentication.
  3. Provides a shared /work directory.
  4. Allows n8n to remotely execute rendering commands.
  5. 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.

Open the Apps tab on your Unraid server Search Community Apps for FFmpeg-SSH-Worker Review the template variables and paths Click Install

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.

Download Statistics

69
Total Downloads

Related apps

Details

Repository
heroeswearkapes/ffmpeg-ssh-worker:latest
Last Updated2026-08-25
First Seen2026-08-25

Runtime arguments

Network
bridge
Shell
bash
Privileged
false

Template configuration

SSH PortPorttcp

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
ConfigurationPathrw

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
Work DirectoryPathrw

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
TimezoneVariable

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