Server admin

Event rules.

An event rule does something when something happens: a file arrives, a package is received, a transfer fails, or a clock ticks. A rule can run a script, call a webhook, send a message, move or copy files, send files on, or write a checksum file.

Plans

Event rules are part of automation, which every Team, Business and Enterprise license includes. Automation is included. There is no separate workflow product or add-on to buy.

In Free mode a rule counts as the one free job. Event rules, hot folders and sync jobs share that one job. When a license ends or drops to Free mode, rules over the limit pause. They are not deleted. They start again when you load a license that includes automation.

Rules run after the virus scan, so a rule never touches a file that has not passed it.

Trigger, conditions, steps

Every rule has the same shape. A trigger says what starts it. Conditions narrow it down: all of them must be true. Steps run in order, and a later step can use the output of an earlier one.

Administrators can create any rule. Other users can create rules that have no command step, on folders they own.

Triggers

A rule starts on one of these events:

EventSent when
file.arrivedA file or folder is released from staging into a folder.
package.receivedA package is ready for its recipients.
receive_link.submittedAll files of one receive-link submission are released.
transfer.completedA transfer ends successfully.
transfer.failedA transfer ends with an error.
job.completedA hot folder or sync job run ends successfully.
job.failedA hot folder or sync job run fails.
scan.blockedThe virus scanner blocks a file.
schedule.tickThe rule's schedule fires.
manualAn administrator or the API starts the rule.
speedcheck.degradedA scheduled speed check finds a location more than 30% slower than its own average, or a limit below your license.

Each event is one JSON object with "event_version": 1. It carries an event ID, the type, the time, the server ID, the actor (a user, an outside email address, or the system) and paths. Paths are always relative to the storage root, never full paths on the server. Farwing keeps events for 30 days, so you can replay a run to debug a rule.

Wait until the file stops changing

The file.arrived trigger has a stable for setting, in seconds. The default is 30. A file starts the rule only after it has stopped changing for that long. It uses the same logic as hot folders, so a file that another program is still writing is not picked up half done. Raise the number if your source writes in bursts with long pauses.

Schedules

The schedule.tick trigger offers a schedule picker with three forms:

  • Every N minutes.
  • Daily at a time you choose.
  • Weekly, on the days and at the times you choose.

For anything else, type a cron line instead of using the picker.

Conditions

All conditions on a rule must be true for it to run.

ConditionMatches
PathA pattern, such as incoming/**/*.mov.
File typeThe extension of the file.
SizeAbove or below a value you set.
User or groupThe person who caused the event, or a group they belong to.
Sender email domainThe domain of the sender's address, such as example.com.
Form field valueThe answer to a custom field on a receive link.
Package recipientA recipient of the package.

Steps

StepWhat it does
Run a commandRuns a command or script on the server. Administrators only. See Run a command.
Call a webhookSends the event as a JSON POST to a URL. See Webhooks.
NotifySends an email, a Slack message or a Microsoft Teams message. Slack and Teams use their incoming-webhook URLs. The text comes from a template.
Move, copy or renameMoves, copies or renames the file. The destination comes from a template, for example projects/{{form.project}}/{{file.name}}.
Send to another Farwing serverSends the file to a second Farwing Server, the way a sync job does.
Send as a packageSends the files as a package to users or email addresses, with a message from a template.
Write a checksum fileWrites a SHA256SUMS file next to the files, or a .b3 file for BLAKE3.
DeleteDeletes the source file. The rule will not save until you tick the confirm switch.

Template values

Names, messages, destinations and URLs in a step are templates. A template can insert values and nothing else. These are all the values:

ValueIs replaced by
event.*Any field of the event.
{{file.path}}The file's path, relative to the storage root.
{{file.name}}The file's name with its extension.
{{file.stem}}The file's name without its extension.
{{file.ext}}The file's extension.
{{file.size}}The file's size.
{{actor.email}}The email address of the person or sender who caused the event.
{{actor.name}}Their name.
{{form.<field name>}}The answer to a custom field on a receive link.
{{link.name}}The name of the receive link.
{{package.subject}}The subject of the package.
{{date}}The date.
{{time}}The time.
{{steps.<step name>.output}}The output of an earlier step: the last 4 KB of a command's standard output, or a webhook's response body. A response that is JSON is parsed, so you can use its fields.

Run a command

Administrators only. Only an administrator can create or change a rule that has a command step. A command runs on your server, so Farwing does not let anyone else write one.
  • A command runs as the server's own non-root user, in a working folder made for that run.
  • It does not run through a shell. An administrator can turn on Run through shell for a step when it needs one.
  • The event, as JSON, arrives on the command's standard input.
  • The paths given to a command are full paths inside the storage root, which the command can read.
  • A step may run for 1 hour by default. An administrator can change the limit.
  • Secrets you use in a step, such as webhook tokens and Slack URLs, are stored encrypted. They are hidden in the portal after you save them, and shown as *** in logs and run records.

Environment variables

The main values of the event are also set as FARWING_* environment variables for the command. These two are always set:

VariableHolds
FARWING_FILE_PATHThe full path of the file, which the command can open.
FARWING_EVENT_TYPEThe event type, such as file.arrived.

Everything else about the event is in the JSON on standard input.

Scripts in Docker

In Docker, keep your scripts in a folder on the host and mount it at /scripts. Add one line to the volumes of your compose file:

    volumes:
      - /data:/data
      - /srv/files:/files
      - /srv/scripts:/scripts

A script that logs each arrival looks like this. Make it executable on the host, then use /scripts/log-arrival.sh as the command of the step.

#!/bin/sh
# /scripts/log-arrival.sh
# Appends one line to a log for every file a rule hands to it.
echo "$FARWING_EVENT_TYPE: $FARWING_FILE_PATH" >> /data/arrivals.log
chmod +x /srv/scripts/log-arrival.sh

The Farwing image is small on purpose and does not include tools such as ffmpeg. Adding tools to the image shows how to add one. To run a tool on another machine instead, use a webhook step to call a service there.

Webhooks

A webhook step sends a POST with a JSON body. The body holds the event, the rule, the run ID and the outputs of the steps that have run so far.

  • Any 2xx status counts as success.
  • The call times out after 30 seconds.
  • A failed call retries before the step fails. See Retries and failures.
  • Farwing blocks calls to the server's own private network addresses (10.*, 192.168.*, 127.*, link-local addresses and similar) unless an administrator allows them in settings. To call a service on your own network, ask an administrator to allow it.

Checking a webhook signature

Every webhook call carries a Farwing-Signature header. Its value is sha256= followed by the lowercase hex of an HMAC-SHA256 of the exact request body, keyed with the rule's secret. Check it before you trust the call, so you know it came from your server. Three rules apply:

  • Compute the HMAC over the raw bytes of the body, before any JSON parsing. Parsing and writing the JSON again can change the bytes.
  • Compare with a constant-time function, as the examples do. A plain == can leak how much of the signature matched.
  • Refuse the call with 401 when the signature is missing or wrong.

Python

This receiver uses only the standard library. Run it with python3 hook.py.

import hashlib
import hmac
from http.server import BaseHTTPRequestHandler, HTTPServer

SECRET = b"the-rule-secret"  # the secret of the rule that calls this URL


class Hook(BaseHTTPRequestHandler):
    def do_POST(self):
        body = self.rfile.read(int(self.headers.get("Content-Length", 0)))
        given = self.headers.get("Farwing-Signature", "")
        expected = "sha256=" + hmac.new(SECRET, body, hashlib.sha256).hexdigest()
        if not hmac.compare_digest(expected.encode(), given.encode()):
            self.send_response(401)  # not from this server: refuse
            self.end_headers()
            return
        # The signature matched, so the body is the exact bytes Farwing sent.
        print(body.decode())
        self.send_response(204)
        self.end_headers()


HTTPServer(("", 8080), Hook).serve_forever()

Node.js

This receiver uses only Node.js itself. Run it with node hook.js.

const crypto = require("node:crypto");
const http = require("node:http");

const SECRET = "the-rule-secret"; // the secret of the rule that calls this URL

http
  .createServer((req, res) => {
    const chunks = [];
    req.on("data", (chunk) => chunks.push(chunk));
    req.on("end", () => {
      const body = Buffer.concat(chunks);
      const expected = Buffer.from(
        "sha256=" + crypto.createHmac("sha256", SECRET).update(body).digest("hex"),
      );
      const given = Buffer.from(String(req.headers["farwing-signature"] || ""));
      const ok = given.length === expected.length && crypto.timingSafeEqual(given, expected);
      if (!ok) {
        res.statusCode = 401; // not from this server: refuse
        return res.end();
      }
      // The signature matched, so the body is the exact bytes Farwing sent.
      console.log(body.toString("utf8"));
      res.statusCode = 204;
      res.end();
    });
  })
  .listen(8080);

Try it

With a receiver running, this signs a small body and sends it. A correct signature returns 204. Change one character of the body after signing and the receiver returns 401.

BODY='{"test":true}'
SIG=$(printf '%s' "$BODY" | openssl dgst -sha256 -hmac "the-rule-secret" -r | cut -d' ' -f1)
curl -i -X POST http://localhost:8080 -H "Farwing-Signature: sha256=$SIG" --data-binary "$BODY"

Retries and failures

  • Retries: each step can retry 0 to 5 times, waiting longer between tries. Webhooks default to 3 and commands to 0.
  • On failure: choose per step whether the run stops or goes on to the next step.
  • Failure email: Farwing emails the rule's owner when a run fails. This is on by default.
  • Limits: by default a rule runs at most 2 times at once, and the whole server runs at most 8. Extra runs wait in line.

Test before you trust it

  • Test with a sample event. Pick a real past event or a made-up one.
  • Dry run. Shows what each step would do, with the templates filled in, and does nothing.
  • Re-run. Runs any past run again.

Start with a dry run on a real event. Check the destinations and the messages, then switch the rule on.

Run history

Every run has a record. The run history page filters by rule, status and date, and keeps runs for 90 days. A record shows:

  • The event that started the run and whether the conditions passed.
  • For each step: its status, when it started and ended, the exit code or HTTP status, and its output. Output is the last 64 KB of standard output and standard error.

A run is queued, running, done, failed, skipped or interrupted. If the server stops during a run, Farwing marks the run interrupted when it starts again. It does not run it again unless the rule says to.

Audit and API

  • Admin → Audit records every rule change and every manual start.
  • The REST API creates, changes, deletes, enables and disables rules, starts a rule by hand, lists runs and returns one run. The API is part of every paid plan.

Ready-made rules

The New rule screen offers six rules to start from. Choose one, change the folder, address or URL to yours, run a dry run, then switch it on.

Convert new videos to small H.264 preview copies

When a video arrives, this rule runs ffmpeg to make a small H.264 preview copy, so people can watch it without downloading the original. It needs ffmpeg, which is not in the Farwing image. Add it first with Adding tools to the image. Because it contains a command step, only an administrator can create it.

Write a SHA-256 checksum file for each received package

When a package is received, this rule writes a SHA256SUMS file next to its files. Use it when your clients or your own archive need a checksum list to verify files later.

Copy everything from a receive link to an S3 folder

When a receive link submission is complete, this rule copies its files to a folder on an S3 storage root. Add the S3 storage in Admin → Storage first, then point the copy step at the folder you want.

Post to Slack when a package arrives

When a package is received, this rule posts a message to a Slack channel. Create an incoming-webhook URL in Slack, paste it into the notify step, and edit the message. Farwing stores the URL encrypted and hides it after you save.

Forward new files in a folder to another Farwing server

When a file arrives in the folder you choose, this rule sends it to a second Farwing Server. Set the folder in the path condition and the other server in the send step.

Email a daily list of received files

Once a day, this rule emails a list of the files your server received. Choose the time in the schedule and the address in the notify step. It needs email set up on the server.