# Agentic AI on the Plant Floor - Secure Deployment with OnLogic FR201 & ZeroClaw

![ZeroClaw on an FR201](../../../../assets/securely-deploying-agentic-ai-in-manufacturing-with-onlogic-fr201.jpg)

Most edge agent setups lean on Node.js runtimes, Python interpreters, or containerized stacks that pull in hundreds of megabytes of dependencies. That works fine on a beefy server, but on an industrial edge device sitting on a plant floor, all that bloat becomes a liability. More dependencies mean more attack surface, more things to patch, and more ways for something to break at 2 AM when nobody's around.

This guide takes a different approach. We'll deploy [ZeroClaw](https://github.com/zeroclaw-labs/zeroclaw) as a single static Rust binary on an [OnLogic FR201](https://www.onlogic.com/store/fr201/), managed by systemd, with no runtime dependencies. The result is a minimal, hardened, production-ready edge agent that boots up and runs without needing Node, Python, Docker, or anything else installed on the device.

## What Is the OnLogic FR201?

If you haven't come across it before, the OnLogic FR201 (also called the Factor 201) is essentially a Raspberry Pi that's been built for industrial environments. At its core is a Raspberry Pi Compute Module 4 (CM4) with a Broadcom BCM2711 quad-core Cortex-A72 ARM processor running at 1.5 GHz, paired with up to 8 GB of LPDDR4 memory. OnLogic designed their own carrier board and industrial chassis around the CM4, so what you get is the familiar Raspberry Pi ecosystem wrapped in hardware that can actually survive a factory floor.

Here's why it's a solid fit for edge deployments in manufacturing:

- **Fanless and sealed.** No moving parts means no dust buildup, no fan failures. OnLogic has thermal-validated the FR201 from 40°C to 60°C in a thermal chamber, so it can handle the heat near ovens, motors, or enclosed cabinets without breaking a sweat (literally).
- **Industrial I/O.** Dual Gigabit Ethernet (with optional Power over Ethernet), RS-232/422/485 serial via terminal block, USB 3.2, HDMI output, and a standard Raspberry Pi GPIO header. That serial port alone opens the door to talking directly to PLCs, sensors, and legacy equipment.
- **Compact form factor.** At roughly 102mm x 129mm x 38mm, it can be DIN-rail mounted or tucked into a control panel without taking up much space.
- **Auto power-on.** When power is applied, it boots automatically. No power button to press. This matters in industrial settings where devices need to come back online after a power cycle without human intervention.
- **M.2 storage expansion.** Beyond the CM4's onboard eMMC, there's an M.2 2280 SATA slot for adding a proper SSD, which is what we'll use for the OS and ZeroClaw.
- **Optional TPM 2.0.** For environments where hardware-rooted trust is a requirement.

It runs standard Raspberry Pi OS or Ubuntu, so all the ARM64 tooling you're already familiar with just works.

## Why This Setup Is More Secure

Before jumping into the steps, it's worth understanding why this approach is meaningfully more secure than typical agent deployments. This isn't security theater; each decision here removes a real category of risk.

**Single static binary, zero runtime dependencies.** ZeroClaw compiles down to one self-contained executable linked against musl libc. There's no Node.js runtime with its `node_modules` tree, no Python interpreter with pip packages, no JVM. Every dependency that isn't on the device is a dependency that can't be exploited. You don't need to worry about a supply-chain attack hiding in a transitive npm package because there are no npm packages.

**No package manager attack surface.** With no pip, npm, or cargo running on the device, there's no mechanism for a compromised process to pull down and execute arbitrary code from the internet. The only software that runs is what you explicitly put there.

**Dedicated service account with no login shell.** The `zeroclaw` user is created with `--shell /usr/sbin/nologin`, which means even if an attacker somehow compromised the service, they can't use that account to get an interactive shell on the device.

**Systemd hardening directives.** The service unit we'll configure includes `NoNewPrivileges`, `PrivateTmp`, `ProtectSystem=strict`, `ProtectHome`, `RestrictNamespaces`, and more. These aren't just nice-to-haves. `ProtectSystem=strict` makes the entire root filesystem read-only from the service's perspective. `NoNewPrivileges` prevents privilege escalation through setuid binaries. Together, they create a tight sandbox around the process.

**Minimal OS footprint.** Raspberry Pi OS Lite is a headless Debian-based image with no desktop environment, no browser, no GUI libraries. Less installed software means fewer things that need patching and fewer potential vulnerabilities.

**SSH key authentication with password login disabled.** We configure SSH to only accept public key authentication and explicitly disable password login. This eliminates the entire class of brute-force and credential-stuffing attacks. Even if someone discovers the device's IP, there's no password to guess.

**File permissions on secrets.** The API key configuration file is locked down to `chmod 600`, readable only by the service account. No other user on the system can read it.

Compared to running a Docker container with a Node.js agent (which means you need Docker, containerd, the Node runtime, npm packages, and all their transitive dependencies), this approach has a dramatically smaller attack surface. In an OT environment where these devices sit on or near production networks, that matters.

## Prerequisites

Before you begin, make sure you have the following:

- An OnLogic FR201 device w/ SSD
- A power supply for the FR201, or PoE capability if your FR201 and switch support it
- An [SSK M.2 NVME SATA SSD adapter](https://a.co/d/0hPsHpAj) (so you can image the SSD from your workstation)
- A Cat5/6 Ethernet cable
- A monitor and keyboard for initial setup
- A small Phillips screwdriver for opening the FR201 case

## Installing Raspberry Pi OS Lite

When you order an FR201 from OnLogic, you can have them pre-install various Linux distributions. For ZeroClaw, we want **Raspberry Pi OS Lite (64-bit)**, the headless variant based on Debian. You can select this during ordering, or you can image the SSD yourself.

To image it yourself:

1. Download the [Raspberry Pi Imager](https://www.raspberrypi.com/software/) and install it on your workstation.
2. Power down the FR201, open the case, and remove the M.2 SSD. Connect it to your workstation using the SSK adapter.
3. Open the Raspberry Pi Imager and select **Raspberry Pi OS (other)** from the OS list, then choose **Raspberry Pi OS Lite (64-bit)**.
4. Set the hostname to `zero` (or whatever you prefer for your naming convention).
5. If your FR201 has Wi-Fi and you want to configure it now, enter your Wi-Fi credentials in the imager settings. Otherwise, skip this and use Ethernet.
6. Set the username to `claw` and choose a strong password. You'll need these credentials for initial login.
7. Under the **Services** tab in the OS customization settings, check **Enable SSH** and select **Use password authentication**. We'll switch to key-based authentication and disable password login after the first boot, but we need password auth enabled initially so we can get in and set things up.
8. Select the SSD as the target storage device.
9. Click **Write** to format the SSD and install the OS.
10. Once the write completes, the imager will eject the drive by default. Unplug the adapter and reconnect it so the drive remounts.
11. The FR201 requires specific firmware configuration files. Download and extract the appropriate set onto the boot partition of the SSD:
   - [Bullseye/Ubuntu 64-bit firmware](https://static.onlogic.com/resources/firmware/utilities/FR200_UBUNTU-64/FR200_UBUNTU-64.zip)
      - [Bookworm 64-bit firmware](https://static.onlogic.com/resources/firmware/utilities/FR200_UBUNTU-64/BookWorm_64bit.zip)
12. Safely eject the SSD, reinstall it in the FR201, and close the case.
## Initial Boot and Configuration

Connect the FR201 to a monitor, Ethernet cable, keyboard, and power supply. Because the FR201 has auto power-on, it will boot as soon as power is applied.

Log in with the `claw` user and the password you set during imaging, then update the system:

```bash
sudo apt update
sudo apt upgrade -y
```

### Locale and Keyboard

By default, Raspberry Pi OS ships with the locale set to Great Britain. If you're in the US (or anywhere else), you'll want to fix this now so you don't get surprised by weird character encoding issues later:

```bash
# Disable all locales except en_US.UTF-8
sudo sed -i 's/^\([^#].*\)/# \1/' /etc/locale.gen
sudo sed -i 's/^# en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/' /etc/locale.gen

# Generate the new locale
sudo locale-gen en_US.UTF-8

# Set the system locale
echo "LANG=en_US.UTF-8" | sudo tee /etc/default/locale
```

Set the keyboard layout to US:

```bash
sudo sed -i 's/^XKBLAYOUT=.*/XKBLAYOUT="us"/' /etc/default/keyboard
sudo setupcon
```

### Timezone

Set the timezone. For manufacturing systems that span multiple plants, UTC is often the safest bet since it avoids daylight saving time headaches and makes log correlation across sites straightforward:

```bash
sudo timedatectl set-timezone UTC
```

If you'd rather use a local timezone:

```bash
sudo timedatectl set-timezone US/Mountain
```

## SSH and Remote Access

Once the FR201 is on the network, you'll want to manage it headless over SSH. Grab the IP address from the FR201's console:

```bash
hostname -I
```

For the initial connection, use the password you set during imaging:

```bash
ssh claw@<IP_ADDRESS>
```

### Setting Up SSH Key Authentication

Password authentication works for the initial setup, but you don't want to leave it enabled on a device that's going to sit on a plant network. SSH keys are both more secure and more convenient. No passwords to remember, no brute-force risk.

On your workstation, generate an SSH key pair if you don't already have one:

```bash
ssh-keygen -t ed25519 -C "your_email@example.com"
```

When prompted for a file location, the default (`~/.ssh/id_ed25519`) is fine. You can optionally set a passphrase for an extra layer of protection on the key itself.

Copy your public key to the FR201:

```bash
ssh-copy-id claw@<IP_ADDRESS>
```

Enter your password one last time. After this, verify that key-based login works by opening a new SSH session:

```bash
ssh claw@<IP_ADDRESS>
```

You should get in without being prompted for a password. If that works, it's time to disable password authentication entirely.

### Disabling Password Authentication

SSH into the FR201 and edit the SSH daemon configuration:

```bash
sudo nano /etc/ssh/sshd_config
```

Find and update (or add) the following lines:

```
PasswordAuthentication no
ChallengeResponseAuthentication no
UsePAM no
```

Save the file and restart the SSH service:

```bash
sudo systemctl restart sshd
```

From this point on, only someone with the matching private key can SSH into the device. If you try to connect from a machine that doesn't have your key, the connection will be refused. This is exactly what we want for a device sitting on a production network.

### Install rsync

We'll use rsync to deploy the binary later, so install it now along with curl:

```bash
sudo apt install -y curl rsync
```

### Setting Up Tailscale for Remote Access

If these devices are going to be deployed across multiple plants (and you're not always on the same network), [Tailscale](https://tailscale.com/download/) is the easiest way to maintain secure remote access. It creates a WireGuard-based mesh VPN, so you can SSH into your FR201 from anywhere without exposing ports to the public internet.

```bash
curl -fsSL https://tailscale.com/install.sh | sh
```

Bring it up and authenticate:

```bash
sudo tailscale up
```

This will print a URL. Open it in your browser, log in to your Tailscale account, and authorize the device. Once it's connected, you can reach the FR201 by its Tailscale IP from any device on your tailnet.

## Cross-Compiling ZeroClaw

ZeroClaw is written in Rust, and we're going to cross-compile it on your workstation (Mac or Windows) to produce a static ARM64 binary that runs on the FR201 with no shared library dependencies.

### Install Rust

On macOS, install Homebrew first if you don't have it:

```bash
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
```

Then install Rust (works on both macOS and Windows):

```bash
# macOS
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
```

```bash
# Windows
winget install --id=Rustlang.Rustup -e
```

Restart your terminal and verify:

```bash
rustc --version
cargo --version
```

### Add the ARM64 musl Target

The `musl` target produces a fully static binary, no glibc dependency on the target device:

```bash
rustup target add aarch64-unknown-linux-musl
```

Verify it's installed:

```bash
rustup target list --installed
# You should see aarch64-unknown-linux-musl in the list
```

### Install the musl Cross-Compilation Toolchain

```bash
# macOS
brew install filosottile/musl-cross/musl-cross

# Windows
winget install --id=Filosottile.MuslCross -e
```

Verify:

```bash
which aarch64-linux-musl-gcc
```

### Clone and Configure the Project

```bash
git clone https://github.com/zeroclaw-labs/zeroclaw.git
cd zeroclaw
```

Tell Cargo to use the musl linker for the ARM64 target by editing `.cargo/config.toml`:

```toml
[target.aarch64-unknown-linux-musl]
linker = "aarch64-linux-musl-gcc"
```

### Build the Binary

```bash
cargo clean
cargo build --release --target aarch64-unknown-linux-musl
```

This will produce the static binary at `target/aarch64-unknown-linux-musl/release/zeroclaw`.

Verify it exists and check the architecture:

```bash
ls target/aarch64-unknown-linux-musl/release/zeroclaw
file target/aarch64-unknown-linux-musl/release/zeroclaw
# Should output: ELF 64-bit LSB executable, ARM aarch64
```

## Deploying to the FR201

Copy the binary to the FR201 using rsync (use the Tailscale IP if you set it up, otherwise use the local IP):

```bash
rsync -avz target/aarch64-unknown-linux-musl/release/zeroclaw claw@<IP_ADDRESS>:/home/claw/
```

SSH into the FR201, make the binary executable, and verify it runs:

```bash
ssh claw@<IP_ADDRESS>
chmod +x zeroclaw
./zeroclaw --version
```

## Setting Up Service Identity and Isolation

We don't want ZeroClaw running as `claw` or (worse) as root. Instead, we'll create a dedicated system user with no login shell and no home directory access. This is standard practice for daemon processes, and it means the ZeroClaw process only has access to exactly what we grant it.

Create the service user:

```bash
sudo useradd --system \
  --home /var/lib/zeroclaw \
  --create-home \
  --shell /usr/sbin/nologin \
  zeroclaw
```

Move the binary to a dedicated directory under `/opt` and set up a symlink:

```bash
sudo mkdir -p /opt/zeroclaw
sudo mv zeroclaw /opt/zeroclaw/
sudo chown -R zeroclaw:zeroclaw /opt/zeroclaw
sudo chmod 755 /opt/zeroclaw/zeroclaw
sudo ln -sf /opt/zeroclaw/zeroclaw /usr/local/bin/zeroclaw
```

Verify it works under the service account:

```bash
sudo -u zeroclaw /usr/local/bin/zeroclaw --version
```

## Configuring the Systemd Service

Now we'll create a systemd unit file that starts ZeroClaw on boot, restarts it on failure, and applies a set of security hardening directives that lock down what the process can do.

Create the service file:

```bash
sudo nano /etc/systemd/system/zeroclaw.service
```

Add the following:

```ini
[Unit]
Description=ZeroClaw Service
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
User=zeroclaw
Group=zeroclaw
ExecStartPre=/usr/bin/test -x /usr/local/bin/zeroclaw
ExecStart=/usr/local/bin/zeroclaw daemon
WorkingDirectory=/var/lib/zeroclaw
Restart=on-failure
RestartSec=5
StandardOutput=journal
StandardError=journal

# Hardening
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ProtectHome=true
ReadWritePaths=/var/lib/zeroclaw
RestrictNamespaces=true
RestrictRealtime=true
LockPersonality=true

[Install]
WantedBy=multi-user.target
```

Here's what each hardening directive does:

- **NoNewPrivileges** prevents the process (or any child process) from gaining elevated privileges through setuid/setgid binaries.
- **PrivateTmp** gives the service its own isolated `/tmp` and `/var/tmp`, so it can't read or write temp files from other services.
- **ProtectSystem=strict** makes the entire root filesystem read-only from the service's point of view. Only paths listed in `ReadWritePaths` are writable.
- **ProtectHome** blocks access to `/home`, `/root`, and `/run/user`, so the service can't snoop on user directories.
- **RestrictNamespaces** prevents the service from creating new Linux namespaces, blocking a common container-escape technique.
- **RestrictRealtime** prevents the service from acquiring real-time scheduling priority, which could be used to starve other processes.
- **LockPersonality** prevents changing the execution personality (e.g., switching to 32-bit mode), closing off another obscure attack vector.

Enable and start the service:

```bash
sudo systemctl daemon-reload
sudo systemctl enable zeroclaw
sudo systemctl start zeroclaw
```

Check that it's running:

```bash
systemctl is-active zeroclaw
journalctl -u zeroclaw -n 50 --no-pager
```

Reboot the FR201 to confirm the service starts automatically on boot:

```bash
sudo reboot
```

After it comes back up, verify again:

```bash
systemctl is-active zeroclaw
journalctl -u zeroclaw -n 50 --no-pager
```

## Configuring the ZeroClaw Agent

The last step is telling ZeroClaw which model to use. Edit the configuration file:

```bash
sudo -u zeroclaw nano /var/lib/zeroclaw/.zeroclaw/config.toml
```

Add your configuration:

```toml
api_key = "<YOUR-ANTHROPIC-API-KEY>"
default_provider = "anthropic"
default_model = "claude-haiku-4-5-20251001"
```

Lock down the permissions so only the zeroclaw user can read it:

```bash
sudo chmod 600 /var/lib/zeroclaw/.zeroclaw/config.toml
```

Test it by switching to the zeroclaw user context and running a quick prompt:

```bash
sudo -u zeroclaw -s
zeroclaw agent -m "What is the meaning of life?"
```

If you get a response back, you're good. The agent is running, the API key works, and ZeroClaw is fully operational on your FR201.

## Use Cases in Manufacturing

Now that you have a hardened, self-contained edge agent running on industrial hardware, here are some practical ways this could be put to work on a plant floor:

**Equipment health monitoring and predictive alerts.** Connect the FR201's serial port to a PLC or sensor gateway and have ZeroClaw watch for anomalies in temperature, vibration, or pressure readings. Instead of setting static thresholds that generate noise, the agent can analyze patterns over time and generate natural-language alerts when something actually looks off. Think "Pasteurizer 3 discharge temperature has been trending 2°F above baseline for the last 4 hours" rather than "TEMP HIGH."

**Production data collection and summarization.** In many plants, operators still log batch data on paper or in disconnected spreadsheets. An FR201 running ZeroClaw can pull data from OPC-UA servers, MQTT brokers, or even serial-connected scales and meters, then compile shift summaries, yield reports, or quality check logs automatically.

**Real-time SPC (Statistical Process Control).** Feed process measurements into ZeroClaw and let it flag when a process is drifting out of control limits. The agent can contextualize the data, correlate it with upstream variables, and suggest root causes rather than just throwing a red light on a dashboard.

**Maintenance work order generation.** When a fault code fires or a sensor trips, ZeroClaw can draft a structured maintenance work order with the equipment ID, fault description, suggested remediation steps, and relevant history, then push it to your CMMS via API. This saves the maintenance tech from having to manually create the ticket and gather context.

**Line changeover assistance.** For plants that run multiple products on the same line, ZeroClaw can provide operators with step-by-step changeover instructions based on the current and next product, pulling from SOPs stored locally on the device. It can also log changeover times and flag if steps are being skipped.

**Regulatory and compliance logging.** In food, pharma, or any regulated manufacturing environment, having an immutable, timestamped log of process conditions is important. The FR201's local storage combined with ZeroClaw's logging capabilities can provide a lightweight audit trail that doesn't depend on cloud connectivity.

The beauty of this setup is that each FR201 is self-contained. If the network goes down, the device keeps running. If you need to deploy to a new plant, you image an SSD, copy the binary, and you're up in under an hour. No Docker registries, no package managers, no dependency hell. Just one binary, one config file, and systemd keeping it alive.