Mounting Windows SMB Shares on Siemens IOT2000 for Node-RED

David Krause22 min read
Industrial NetworkingSiemensTutorial / How-to
Licensed PE Working through this on a live machine? A Maine-licensed engineer can take it from here — included with IMD hardware, by the hour for everything else. Book an engineer

Overview

The SIMATIC IOT2000 family (IOT2020 and IOT2040) is a Siemens edge gateway intended to sit between the OT network and a higher-level MES or engineering host. The IOT2020 uses an Intel Quark SE x86 CPU with 1 GB of RAM; the IOT2040 uses the Quark x1020 with the same RAM and adds a second Ethernet port, RS232/RS485, and battery-backed RTC. Both ship with a Yocto-based Linux image (Siemens Example Image V2.6.x or V3.x) that includes Node-RED 0.20 or newer, but not the CIFS client tools. Out of the box the IOT2000 cannot attach a Windows SMB share, and the built-in Node-RED file in and file out nodes operate exclusively on local filesystem paths.

This article documents the production-grade procedure for letting a Node-RED flow read and write files that physically live on a Windows host: prepare the SMB share, install or build cifs-utils on the IOT2000, perform a one-shot mount, drive the share from a Node-RED flow, and finally make the mount persistent across reboots. Each step gives the exact command, the expected output, the error codes that appear when the step fails, and the field-tested fix. The article ends with a troubleshooting matrix, security analysis, and an alternative-architectures table that covers FTP, SFTP, HTTP, MQTT, and Git-based distribution.

Use case context. A typical industrial application is the daily transfer of recipe files (CSV, JSON, XML) that an engineer maintains on a Windows workstation to a Node-RED flow that drives a SIMATIC S7-1200, S7-1500, or a PanelView Plus HMI. The mount approach below is the most direct implementation, but it inherits the operational risks of SMB. Read the Security Considerations section before exposing the share to a production control system.

Prerequisites and Components

Component Version / Specification Notes
SIMATIC IOT2020 Intel Quark SE x86, 1 GB DDR3, 8 MB flash, SD card boot Single Ethernet, USB 2.0, RS232/485
SIMATIC IOT2040 Intel Quark x1020, 1 GB DDR3, 8 MB flash, SD card boot Dual Ethernet, USB 2.0, RS232/485, RTC
Siemens Example Image V2.6.0 or V3.x (Yocto Morty / Kirkstone) Node-RED 0.20–3.x pre-installed
Node-RED version 0.20.x – 3.x Built-in file nodes; no extra palette required
cifs-utils 6.10 – 6.15 Provides mount.cifs, smbclient, cifs.upcall
Windows host Windows 10 1709+, Windows 11, Server 2016/2019/2022 SMB2 or SMB3 enabled, SMB1 disabled
Network TCP/IP, layer-2 reachable Port 445/TCP open between IOT2000 and the share host
Build toolchain (only for source build) gcc, make, autoconf, automake, libtool, pkg-config, gettext, libcap-ng-devel, libkrb5-devel, keyutils-devel, talloc-devel, popt-devel, attr-devel, samba-libs Provided by the IOT2000 development SDK or by opkg install on a development image
Access method SSH (port 22) or serial console Default user root on the Yocto image; password set on first boot

Before touching the Linux side, validate the network path. From the IOT2000 shell:

ping -c 3 192.168.10.99 nc -zv 192.168.10.99 445 getent hosts recipes-host

If nc -zv reports Connection refused or Connection timed out, the issue is the Windows firewall or the SMB service, not Linux. Resolve the network layer first.

SMB / CIFS Protocol Background

Server Message Block (SMB) is the file-sharing protocol implemented by Windows. Common Internet File System (CIFS) is the historical dialect and the name Linux adopted for its client implementation. Modern mount.cifs negotiates SMB2 or SMB3 when the server advertises them. The relevant version is selected with the vers= mount option. The valid values are 1.0, 2.0, 2.1, 3.0, and 3.1.1. SMB1 was deprecated by Microsoft in 2014 and removed from cifs-utils in version 6.11. A 2024-era IOT2000 image should never negotiate SMB1.

Mount option Effect Recommended value
vers= Forces SMB protocol version 3.0 or 3.1.1
sec= Authentication and signing mode ntlmssp for Windows passwords; krb5 for Active Directory
username=, password= Inline credentials (insecure) Avoid in production; use credentials= file
credentials= Path to a file with username, password, optionally domain /etc/samba/iotcred with mode 0600
uid=, gid= Owner UID/GID of mounted files uid=1000,gid=1000 for the Node-RED user
iocharset= Filename character set utf8
file_mode=, dir_mode= Permission bits on files / directories 0644 / 0755
noserverino Disable server-side inode generation Recommended for Windows shares; improves compatibility
_netdev Defer mount until the network is up Required in fstab entries
cache= Cache mode: none, strict, loose, singleclient loose for typical office-to-edge traffic
soft / hard Behavior on I/O timeout soft for industrial networks; hard can hang processes when the share disappears
timeo= I/O timeout in centiseconds (default 1000 = 10 s) timeo=3000 (30 s) for slow links
retrans= Number of retries before giving up retrans=2 with soft
x-systemd.automount Mount on first access instead of at boot Recommended on systemd-equipped images

Step 1: Configure the Windows SMB Share

  1. Create a folder on the Windows host that will hold the recipes, for example D:\Recipes.
  2. Right-click the folder, choose Properties → Sharing → Advanced Sharing, tick Share this folder, and set a share name such as Recipes. The resulting UNC path is \\HOSTNAME\Recipes or \\192.168.10.99\Recipes.
  3. Click Permissions, add the Windows account that the IOT2000 will use, and grant at minimum Read. For write access from Node-RED, grant Change or Full Control.
  4. Open Control Panel → Programs and Features → Turn Windows features on or off and confirm that SMB 1.0/CIFS File Sharing Support is disabled. Enable SMB Direct if your network adapter supports RDMA.
  5. Open the Windows Defender Firewall with Advanced Security console and confirm that the inbound rule File and Printer Sharing (SMB-In) is enabled on the active profile (Domain, Private, or Public).
  6. Test from a second Windows machine: \\192.168.10.99\Recipes should open, prompt for credentials, and list the folder contents.
  7. From a Windows PowerShell prompt, validate the share with Get-SmbShare -Name Recipes. The output should report the share path, the description, and the scope.

Microsoft's official procedure for sharing a folder over a network is documented at File sharing over a network in Windows.

SMB1 on Windows 10 and 11. Windows 10 1709 (Fall Creators Update) and all subsequent releases disable the SMB1 server by default. The mount.cifs client on cifs-utils 6.11 or later also removed SMB1 support. If you observe mount error(13): Permission denied with no other apparent cause, the share is most likely advertised only as SMB1. Enable SMB2/SMB3 on the Windows host rather than re-enabling SMB1.

Step 2: Install cifs-utils on the IOT2000

The stock Siemens IOT2000 image does not ship cifs-utils. Two options exist.

Option A: Use a custom image that bundles cifs-utils

Some Siemens Application Examples deliver example images that bundle cifs-utils along with smbclient and several other utilities. If your project allows, use such an image; it is the lowest-risk path. Verify the package is present with:

which mount.cifs smbclient cifs.upcall mount.cifs --version 2>&1 | head -1

Option B: Build cifs-utils from source on the device

When the production image is frozen, build the package in place. The build needs the development headers. On a Yocto-based IOT2000 image with the package feed enabled:

opkg update opkg install gcc make autoconf automake libtool pkg-config gettext \ libcap-ng-dev libkrb5-dev keyutils-dev talloc-dev popt-dev attr-dev

Download the cifs-utils release archive and transfer it to the IOT2000 (for example with WinSCP, scp, or the SD card). Connect to the device over SSH or via the serial console:

cd /tmp tar -xzf cifs-utils-<version>.tar.gz cd cifs-utils-<version> autoreconf -i ./configure --prefix=/usr --sysconfdir=/etc make -j$(nproc) make install

Expected output ends with lines such as libtool: install: /usr/bin/install -c mount.cifs /usr/sbin/mount.cifs. Verify the install with:

which mount.cifs ls -l /usr/sbin/mount.cifs /usr/sbin/umount.cifs mount.cifs -V
setuid bit. The mount.cifs and umount.cifs binaries must carry the setuid bit for non-root users (including the Node-RED service user) to mount and unmount shares. If ls -l shows -rwxr-xr-x, run:
chmod u+s /usr/sbin/mount.cifs /usr/sbin/umount.cifs chown root:root /usr/sbin/mount.cifs /usr/sbin/umount.cifs

Without the setuid bit, the Node-RED exec node will fail with Operation not permitted even when the credentials file is in place.

Step 3: Mount the Share from the Linux Shell

Create the mount point and a credentials file so passwords do not appear in shell history, process listings, or the systemd journal.

mkdir -p /mnt/recipes
cat > /etc/samba/iotcred <<'EOF'
username=iotuser
password=YourSecurePassword
domain=WORKGROUP
EOF
chmod 0600 /etc/samba/iotcred
chown root:root /etc/samba/iotcred

Perform a manual mount to validate the configuration end to end:

mount -t cifs //192.168.10.99/Recipes /mnt/recipes \ -o credentials=/etc/samba/iotcred,vers=3.0,sec=ntlmssp,\ uid=1000,gid=1000,iocharset=utf8,noserverino,soft,timeo=3000

A successful mount returns to the prompt with no output. Verify the mount is in place:

mount | grep cifs ls -l /mnt/recipes stat /mnt/recipes

The mount command should print a line similar to:

//192.168.10.99/Recipes on /mnt/recipes type cifs (rw,relatime,vers=3.0,sec=ntlmssp,uid=1000,gid=1000,...)

If the line is missing, the mount failed. Run dmesg | tail -20 to read the kernel log, which contains the underlying CIFS error message. The table in Step 5 covers the most common failure modes.

To unmount during testing:

umount /mnt/recipes

If the share is a guest share (no password), replace the credentials file with the inline options guest,uid=1000,gid=1000 and remove sec=ntlmssp. If the share lives on a Windows host in an Active Directory domain, use sec=ntlmssp with domain=YOURDOMAIN in the credentials file, or migrate to sec=krb5 with a valid /etc/krb5.keytab for full Kerberos authentication.

Step 4: Build the Node-RED Flow

Once the share is mounted locally, Node-RED's built-in file in and file out nodes read and write the recipes without any custom node or extra palette.

4.1 Read a recipe on a trigger

  1. Drag an inject node onto the canvas, set Payload to a timestamp string, and set Repeat to a 5-minute interval (interval with 300 seconds, or a cron expression).
  2. Drag a file in node, set Filename to /mnt/recipes/current.csv, and leave Format as utf-8 string.
  3. Drag a debug node.
  4. Wire inject → file in → debug.
  5. Click Deploy. Each inject tick produces a debug message containing the current recipe CSV.

4.2 Write a recipe from an HTTP upload

  1. Add an http in node configured as POST /upload with File upload enabled.
  2. Add a function node that sanitises the filename and moves the buffer to the payload:
  3. Add a file out node, leave its Filename property empty so it reads from msg.filename, and set the action to overwrite file.
  4. Add an http response node with status 200.
  5. Wire http in → function → file out → http response.

4.3 Sample function node

// Build a safe filename
var name = (msg.payload && msg.payload.name) || "recipe.csv";
// Strip path components to avoid directory traversal
name = name.replace(/^.*[\\\/]/, "");
// Replace unsafe characters
name = name.replace(/[^A-Za-z0-9._-]/g, "_");
// Refuse empty or hidden names
if (!name || name.charAt(0) === ".") {
    node.warn("Rejected filename: " + name);
    msg.payload = "invalid filename";
    msg.statusCode = 400;
    return [null, msg];
}
msg.filename = "/mnt/recipes/" + name;
if (msg.payload && msg.payload.buffer) {
    msg.payload = msg.payload.buffer;
}
return msg;
Filename injection. Any code that lets a remote client choose a filename is a security risk. The sanitisation step above prevents .. path traversal and strips shell metacharacters. For production, write to a staging directory (/var/staging/) and have a separate Node-RED flow move the file into /mnt/recipes/ only after validation. Keep the staging directory outside the cifs mount to avoid leaving partial files visible to the Windows host.

4.4 Listing the share contents

The built-in file in node does not list directories. Use the exec node to call ls -1 /mnt/recipes and parse the result in a function node:

var lines = (msg.payload || "").split("\n");
var files = [];
for (var i = 0; i < lines.length; i++) {
    var n = lines[i].trim();
    if (n.length > 0) files.push(n);
}
msg.payload = files;
return msg;

Feed the resulting array to a dropdown UI node so the operator can pick a recipe from a list rendered by the Dashboard. For real-time updates, place the exec node inside a flow that fires when a file-system change occurs; on Linux this is best done with inotifywait in a polling loop, since cifs shares do not deliver native inotify events.

4.5 Detecting changes written by the Windows host

The cifs client uses the kernel's directory entry cache, which by default holds entries for 30 seconds. Add the cache=loose option to the mount if the operator changes recipes interactively on the Windows side and the IOT2000 must see the change within a few seconds. For sub-second freshness, run an exec node every second that does ls -1 /mnt/recipes and compares the output to the previous tick.

Step 5: Persist the Mount Across Reboots

A mount performed with mount -t cifs does not survive a reboot. The two field-proven approaches are fstab and a systemd unit with retry logic.

5.1 /etc/fstab entry

Add a single line to /etc/fstab:

//192.168.10.99/Recipes /mnt/recipes cifs credentials=/etc/samba/iotcred,vers=3.0,sec=ntlmssp,uid=1000,gid=1000,iocharset=utf8,noserverino,soft,timeo=3000,_netdev,x-systemd.automount 0 0

The _netdev option tells systemd to wait for the network before attempting the mount. On systemd-equipped IOT2000 images (V3.x and newer), the x-systemd.automount option mounts the share on first access, which eliminates boot-time race conditions when the Windows host takes longer to come up than the IOT2000.

Test the fstab entry without rebooting:

systemctl daemon-reload mount -fav 2>&1 | grep recipes mount -a

The dry run reports what would be mounted; the actual mount happens on mount -a or on the next reboot.

5.2 Autostart script (rc.local / systemd unit)

For older images without full fstab support, or when the share is not always reachable, a small autostart script with retry logic is more robust. Create /opt/scripts/mount-recipes.sh:

#!/bin/sh
# mount-recipes.sh - retry mount of Windows share on boot
LOG=/var/log/mount-recipes.log
SHARE="//192.168.10.99/Recipes"
MNT="/mnt/recipes"
OPT="credentials=/etc/samba/iotcred,vers=3.0,sec=ntlmssp,uid=1000,gid=1000,soft,timeo=3000"

echo "=== mount-recipes start $(date) ===" >> "$LOG"
if mount | grep -q "${MNT} type cifs"; then
    echo "already mounted" >> "$LOG"
    exit 0
fi
for attempt in 1 2 3 4 5 6 7 8 9 10; do
    if mount -t cifs "$SHARE" "$MNT" -o "$OPT" >> "$LOG" 2>&1; then
        echo "mounted on attempt $attempt" >> "$LOG"
        exit 0
    fi
    echo "attempt $attempt failed, sleeping 10s" >> "$LOG"
    sleep 10
done
echo "FAILED after 10 attempts at $(date)" >> "$LOG"
exit 1

Make it executable and wire it into systemd:

chmod +x /opt/scripts/mount-recipes.sh mkdir -p /opt/scripts
cat > /etc/systemd/system/mount-recipes.service <<'EOF'
[Unit]
Description=Mount Windows Recipes share
After=network-online.target
Wants=network-online.target
StartLimitIntervalSec=300
StartLimitBurst=5

[Service]
Type=oneshot
ExecStart=/opt/scripts/mount-recipes.sh
RemainAfterExit=yes
Restart=on-failure
RestartSec=30

[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemctl enable mount-recipes.service
systemctl start mount-recipes.service

Verify the service is active and the share is mounted:

systemctl status mount-recipes.service journalctl -u mount-recipes.service --no-pager | tail -20 mount | grep recipes

5.3 Re-issuing the mount from Node-RED

For a more dynamic pattern, drive the mount from a Node-RED exec node. The mount command requires root, so Node-RED must run as root, or the binary must be setuid. Running all of Node-RED as root is a poor security practice. The recommended approach is a small setuid wrapper that only accepts a known share and mount point.

cat > /usr/local/bin/mount-recipes <<'EOF'
#!/bin/sh
# mount-recipes - fixed share and mount point, setuid root
exec /usr/sbin/mount.cifs //192.168.10.99/Recipes /mnt/recipes \
  -o credentials=/etc/samba/iotcred,vers=3.0,uid=1000,gid=1000,soft,timeo=3000
EOF
chmod 4755 /usr/local/bin/mount-recipes
chown root:root /usr/local/bin/mount-recipes

The Node-RED exec node then invokes /usr/local/bin/mount-recipes with no arguments. If you need the password supplied dynamically, pass it on stdin rather than on the command line. The exec node can be configured to send the password string to the spawned process's stdin, where mount.cifs will read it during the password prompt phase.

Verification and Acceptance Test

  1. Share reachability. From the IOT2000, run nc -zv 192.168.10.99 445 and confirm the port is open.
  2. Mount present. Run mount | grep recipes. The output must include a cifs line with the expected options.
  3. Read path. Deploy a file in node reading /mnt/recipes/current.csv and observe the debug payload. The payload must match the file on the Windows host.
  4. Write path. Trigger a file out node writing a known string. From a second Windows machine, run Get-ChildItem \\192.168.10.99\Recipes in PowerShell. The file size and timestamp must update.
  5. Persistence. Run reboot on the IOT2000. Wait 60 seconds, log in over SSH, and repeat steps 2–4 without manual mounting. The systemd unit or fstab must have remounted the share.
  6. Error handling. Power off the Windows host (or block port 445 with a firewall rule). Within 30 seconds, the mount-recipes service should report retries in the journal. The Node-RED file in node should report an error in its status badge and the debug tab.
  7. Recovery. Restore the Windows host. Within 30 seconds, the next retry or the next access to /mnt/recipes should re-establish the mount.

Performance Tuning

The cifs client exposes several tunables that affect throughput and freshness on a plant network.

Parameter Default Tuning recommendation Effect
cache= loose none for live data; loose for recipes that change rarely Tightens or relaxes the attribute and directory-entry cache
rsize=, wsize= 131072 (128 KiB) on SMB2/3 Default; reduce to 32768 on lossy wireless links Maximum read/write block size per request
actimeo= 10000 (10 s) on SMB2/3 Reduce to 1–2 seconds for live data Attribute cache timeout in seconds
echo_interval= 60 s Lower to 30 s on flaky links How often the client sends an SMB echo to keep the session alive
max_credits= 320 on SMB3 Lower to 128 on memory-constrained IOT2020 Maximum number of in-flight requests; lower value reduces memory pressure
Number of Node-RED file in triggers n/a Avoid sub-second polling; batch reads Reduces SMB traffic and CPU load on the IOT2000

For multi-megabyte recipe files, the bottleneck is almost always the kernel's copy-from-user path, not the wire. A 1 MB read on a 100 Mbit link completes in well under a second; a 50 MB file can take 5–10 seconds and block the Node-RED event loop. Use streaming writes via the exec node and dd for files larger than a few megabytes.

Troubleshooting Matrix

Symptom Likely cause Resolution
mount error(2): No such file or directory Wrong UNC path or share not published Validate the share from another Windows host; check for typos in the path
mount error(13): Permission denied Wrong credentials, no share permission, or SMB1 fallback Re-test credentials, grant share permission, force vers=3.0
mount error(22): Invalid argument Unsupported sec= or vers= value Try sec=ntlmssp, vers=3.0; check cifs-utils version
mount error(112): Host is down Port 445 blocked, host offline, or wrong IP nc -zv HOST 445 from the IOT2000; check firewall on Windows
Password for user@//host/share: prompt in exec cifs-utils falling back to interactive auth Provide credentials= file or pipe password via stdin to mount.cifs
Mount present, but Node-RED file in reports ENOENT Wrong path, permission bit, or SELinux/AppArmor ls -l /mnt/recipes/<file> as the Node-RED user; check file_mode
Mount present, but files are empty or stale Kernel attribute cache or cache= option Add cache=loose or actimeo=1 for better freshness
Mount disappears after reboot No persistence configured Add fstab entry or systemd unit per Step 5
Windows 10 cannot see the share from itself SMB1 disabled and client requesting SMB1 Enable SMB2 on the client via Windows features; use the host's IP rather than hostname
cifs-utils not found when running mount -t cifs Package not installed or not in image Build cifs-utils per Step 2 or switch to a custom image
High CPU on the IOT2000 while idle cifs kernel module retry loop after host went down Add soft and timeo=3000 options; do not use hard on industrial networks
Mount succeeds but every read returns Permission denied uid=/gid= mismatch with Node-RED user Check Node-RED's running uid with ps -o user,pid,cmd -C node-red; set matching uid=/gid=
Reboot leaves share in a half-mounted state fstab entry without _netdev Add _netdev and x-systemd.automount; or use the systemd unit in Step 5.2
Filename appears as garbled characters on Linux Windows codepage mismatch Add iocharset=utf8 to the mount options
Mount succeeds but file modifications are not visible to the Windows host Local kernel cache holding the dirty page Add cache=none or call sync from the application
PowerShell shows the share but Linux shows it as read-only Windows shared NTFS permissions differ from share permissions Align NTFS permissions with share permissions; the more restrictive of the two applies

Security Considerations

Sharing files between a production control system and a Windows workstation is a deliberate act and must be evaluated against the IEC 62443 zone and conduit model. Treat the Windows host as a higher-trust zone, the IOT2000 as a cell-site controller, and the SMB session as a conduit that crosses the boundary.

  • Credentials storage. The credentials file at /etc/samba/iotcred must be mode 0600, owned by root. Never embed credentials in Node-RED flow JSON files; export flows to an offline editor and check the JSON for accidental leakage before commit.
  • Transport encryption. SMB3 with sec=ntlmssp signs but does not encrypt traffic. For sensitive data, require sec=ntlmssp over an isolated VLAN, or migrate the recipes to SFTP/HTTPS with mutual TLS.
  • Protocol version. Pin vers=3.1.1 when the Windows host supports SMB3.1.1 encryption. Add seal or sign in the sec= option on cifs-utils ≥ 6.13 to enforce signing.
  • Account scope. Create a dedicated Windows user iotuser with the narrowest possible share rights and an unguessable password. Disable interactive logon for the account in Active Directory Users and Computers.
  • Network segmentation. Place the IOT2000 and the recipe host in the same engineering VLAN. Do not route SMB across the process control network.
  • Audit. Enable Windows security auditing for logon and file access on the share. Forward events to the central SIEM. On the IOT2000, log all mount and umount invocations to /var/log/messages with auditd rules.
  • File integrity. If the recipes drive safety-relevant control logic, compute a SHA-256 hash of the file on the Windows side and verify it on the IOT2000 in the Node-RED flow before consuming the data.

For a high-level primer on configuring SMB sharing on Windows, review Microsoft's File sharing over a network in Windows guide before exposing the share to the IOT2000.

Alternative Architectures

CIFS is convenient but not always the right tool. Consider the alternatives below when the recipe set grows, when the Windows host must be replaced by a version control system, or when the IOT2000 needs to be portable across plants.

Option Pros Cons Recommended when
Node-RED file in/out + cifs mount (this article) Zero custom code, built-in nodes, no protocol work in the flow Inherits SMB weaknesses, single-host coupling, no version control Small to mid-size recipe set, single Windows host, no compliance constraint
FTP / SFTP client in Node-RED Encrypted transport, mature tooling, audit logs on the server Adds an FTP server to the Windows host or replaces it with a NAS Recipes traverse plant boundaries, audit required
HTTP / REST with bearer token Firewall-friendly, scales to many devices, easy to monitor Requires a small HTTP service on the Windows host or a middleware box Many IOT2000 units consume the same recipe set
MQTT publish / subscribe Real-time push, no polling, fits the Node-RED model Requires a broker and a publisher on the Windows side Recipes change often and the HMI should react in <1 s
Git pull via Node-RED exec Versioned recipes, branch per product, signed commits Adds a developer workflow; Windows-side tooling Recipes are released as part of the product
OPC UA method call from a Windows service Native to the SIMATIC ecosystem, signed and encrypted Requires a Windows-side OPC UA server and Node-RED OPC UA client The same data is also consumed by TIA Portal or WinCC

The IOT2000 has enough CPU and RAM to run a small HTTP or MQTT client natively, so any of the alternatives can be implemented without the cifs-utils dependency. For pure local file access on the IOT2000 itself, leave the recipes on the SD card and let a service on the Windows host push changes through HTTP or SFTP.

Operational Notes

A few additional points observed in the field.

  • The cifs module is built into the standard IOT2000 kernel, so modprobe cifs is rarely required. If lsmod | grep cifs returns nothing, the kernel on your image does not include cifs support and you must rebuild the kernel or switch to a custom image.
  • The IOT2020 has 1 GB of RAM. A long-running cifs session that reads large files can fragment the page cache and starve Node-RED. Set vm.swappiness=10 in /etc/sysctl.d/ to favour dropping cache over swapping.
  • DNS resolution on the IOT2000 is sometimes slow when the engineering VLAN does not advertise a DNS server. Use the IP address in the UNC path or add the Windows host to /etc/hosts to avoid mount hangs during boot.
  • When the IOT2000 is in a DMZ and the Windows host is inside the OT network, an SMB session is typically allowed only inbound. The mount direction (IOT2000 → Windows) is supported by the IOT2000's default firewall, so no extra rule is needed.
  • The mount survives a Windows reboot on the share host if soft and timeo=3000 are set. The next access after the Windows host returns re-establishes the session automatically.

FAQ

Do I need a custom Node-RED node to read a Windows share?

No. Mount the share with cifs-utils and reference the local mount point in the built-in file in and file out nodes. The mount is a Linux concept; Node-RED only sees a normal directory path such as /mnt/recipes.

Where do I put the username and password?

Store them in a credentials file at /etc/samba/iotcred with mode 0600 and pass credentials=/etc/samba/iotcred as a mount option. Do not embed credentials in the Node-RED flow JSON, the systemd unit, or the command line, where they would appear in process listings and logs.

Why does the mount fail with Permission denied on a fresh Windows 10 install?

Windows 10 1709 and newer disable SMB1 by default, and modern cifs-utils no longer fall back to SMB1. Add vers=3.0 (or 3.1.1) to the mount options, and verify that SMB2/SMB3 is enabled on the Windows host under Windows features.

How do I make the mount survive an IOT2000 reboot?

Either add a line to /etc/fstab with the _netdev and x-systemd.automount options, or create a systemd oneshot service that calls mount -t cifs after network-online.target and enables retry on failure. Both approaches are detailed in Step 5.

Can I trigger the mount directly from a Node-RED flow?

Yes, by using the exec node to call a small setuid wrapper script that mounts only a fixed share and mount point. Avoid passing the password on the command line; pipe it on stdin or use a credentials file with mode 0600.

What is the recommended SMB protocol version in 2024?

SMB3.1.1 (vers=3.1.1) is the current default on Windows 11 and Server 2022. It supports AES-128 encryption when paired with sec=ntlmssp on a cifs-utils build that supports signing. SMB2.1 (vers=2.1) remains a safe fallback for older Windows hosts.

How do I list the files in the share from a Node-RED flow?

Use the exec node to run ls -1 /mnt/recipes and parse the stdout string in a function node with payload.split("\n"). Feed the resulting array to a dropdown UI node for operator selection.

Back to blog