Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

GitHub

This documentation is part of the "Projects with Books" initiative at zenOSmosis.

The source code for this project is available on GitHub.

Protocol Translation

Relevant source files

Purpose and Scope

This document explains how sshfs-mac-docker performs protocol translation to bridge SSH and SMB protocols. The system translates between SSH-based remote filesystem access (via SSHFS) and SMB-based local network sharing (via Samba) using filesystem operations and symbolic links within the Docker container.

For information about the overall three-tier architecture, see Three-Tier Design. For networking details including port mappings, see Network Architecture. For filesystem layout details, see Filesystem Layout.


Protocol Translation Overview

The system performs protocol translation by layering three distinct technologies—SSH, FUSE/SSHFS, and SMB/Samba—and connecting them through filesystem primitives. The translation occurs entirely within the Docker container's userspace, avoiding any kernel modifications on the macOS host.

graph TB
    subgraph "Remote Source"
        RemoteSSH["Remote SSH Server\nuser@host:path"]
end
    
    subgraph "Container Protocol Bridge"
        SSHLayer["SSH Protocol Layer"]
FUSELayer["FUSE Filesystem Layer"]
FileSystem["Filesystem Integration"]
SMBLayer["SMB Protocol Layer"]
SSHLayer -->|FUSE operations| FUSELayer
 
       FUSELayer -->|mounts to /remote| FileSystem
 
       FileSystem -->|symlink to /samba-share/remote| SMBLayer
    end
    
    subgraph "macOS Consumer"
        FinderSMB["macOS Finder\nSMB Client"]
end
    
 
   RemoteSSH -->|SSH port 22| SSHLayer
 
   SMBLayer -->|SMB ports 139/445| FinderSMB

Protocol Translation Layers

Diagram: Protocol Translation Stack

The translation chain transforms SSH-based remote access into SMB-based network share access through intermediate filesystem representations.

Sources: README.md, Dockerfile, smb.conf


SSH to FUSE Translation

The first translation occurs when SSHFS converts SSH protocol operations into FUSE filesystem operations, mounting the remote filesystem at /remote within the container.

SSHFS Mount Process

The SSHFS mount command translates remote SSH access into local filesystem operations:

README.md49

This command is executed inside the container via docker exec -it docker-sshfs bash README.md41

SSHFS Mount Options Mapping

Diagram: SSHFS Mount Option Translation

Critical Mount Options

Mount OptionPurposeWithout It
allow_otherAllows users other than the mounting user to access the mountSamba service cannot access files mounted by sshuser
uid=1000Sets file ownership to UID 1000 (sshuser)Write operations fail; filesystem appears read-only
gid=1000Sets group ownership to GID 1000 (sshuser group)Write operations fail; filesystem appears read-only

The allow_other option requires the user_allow_other configuration in /etc/fuse.conf Dockerfile24:

user_allow_other

This configuration is added during container build to enable cross-user filesystem access between the SSHFS mount (owned by sshuser) and the Samba service (running as a different process).

Sources: README.md:49-53, Dockerfile:24


graph TB
    subgraph "SSHFS Mount"
        RemoteDir["/remote\nFUSE mount point\nCreated: Dockerfile:12"]
RemoteFiles["Remote files\nvia SSHFS"]
end
    
    subgraph "Samba Share Root"
        SambaDir["/samba-share\nSamba root directory\nCreated: Dockerfile:15\nPermissions: 777"]
SymLink["/samba-share/remote\nSymbolic link\nCreated: Dockerfile:30"]
end
    
 
   RemoteFiles --> RemoteDir
 
   RemoteDir -->|ln -s /remote /samba-share/remote| SymLink
 
   SymLink -->|part of| SambaDir

Filesystem Integration Layer

The integration between the SSHFS mount at /remote and the Samba share at /samba-share occurs through a symbolic link, created during container build.

Diagram: Symbolic Link Integration Point

The symbolic link is created during the Docker image build process Dockerfile30:

This creates /samba-share/remote as a symbolic link pointing to /remote. The symbolic link is permanent—created once during image build and persisting across container restarts.

Directory Creation Sequence

The directories and symbolic link are created in this order during build:

  1. /remote directory created Dockerfile12
  2. /samba-share directory created Dockerfile15
  3. /samba-share permissions set to 777 Dockerfile21
  4. Symbolic link /samba-share/remote → /remote created Dockerfile30

The 777 permissions on /samba-share Dockerfile21 ensure that:

  • The Samba service can access the directory
  • Files created through SMB inherit permissive access
  • The symbolic link remains accessible to all processes

Sources: Dockerfile:12, Dockerfile:15, Dockerfile:21, Dockerfile:30


graph TB
    subgraph "Filesystem Layer"
        SambaShare["/samba-share\nServed directory"]
SymLink["/samba-share/remote\n→ /remote"]
RemoteMount["/remote\nSSHFS mount"]
end
    
    subgraph "Samba Configuration"
        ShareDef["[SSHFS Share]\nsmb.conf:10-19"]
PathConf["path = /samba-share\nsmb.conf:11"]
GuestConf["guest ok = yes\nsmb.conf:13"]
ForceUser["force user = sshuser\nsmb.conf:19"]
WritableConf["writable = yes\nsmb.conf:12"]
end
    
    subgraph "SMB Protocol"
        SMBPorts["Ports 139/445\nDockerfile:27"]
SMBClient["macOS SMB Client"]
end
    
 
   ShareDef --> PathConf
 
   ShareDef --> GuestConf
 
   ShareDef --> ForceUser
 
   ShareDef --> WritableConf
    
 
   PathConf --> SambaShare
 
   SambaShare --> SymLink
 
   SymLink -.->|follows link| RemoteMount
    
 
   ForceUser -.->|all operations as| sshuser["sshuser\nUID 1000"]
sshuser -.->|matches| RemoteMount
    
 
   ShareDef --> SMBPorts
 
   SMBPorts --> SMBClient

FUSE to SMB Translation

The final translation occurs when Samba serves the /samba-share directory (which contains the symbolic link to the SSHFS mount) over the SMB protocol.

Samba Configuration for Protocol Bridge

Diagram: Samba Configuration for Protocol Translation

The Samba share is defined in smb.conf smb.conf:10-19:

[SSHFS Share]
path = /samba-share
writable = yes
guest ok = yes
guest only = yes
read only = no
browseable = yes
create mask = 0777
directory mask = 0777
force user = sshuser

Critical Configuration Elements

ConfigurationPurposeImpact on Protocol Translation
path = /samba-shareSets root directory for SMB shareExposes directory containing symbolic link to SSHFS mount
force user = sshuserForces all file operations to run as sshuserMatches UID/GID from SSHFS mount options, enabling write access
guest ok = yesAllows guest authenticationSimplifies macOS client connection, avoiding credential management
writable = yesEnables write operationsAllows bidirectional protocol translation (read and write)

The force user = sshuser smb.conf19 is critical because:

  • SSHFS mounts files with uid=1000,gid=1000 (matching sshuser) README.md49
  • Samba operations run as sshuser, matching the file ownership
  • This alignment enables write access through the protocol bridge

Sources: smb.conf:10-19, README.md:49


sequenceDiagram
    participant Finder as "macOS Finder"
    participant SMB as "Samba Service\n(smbd)"
    participant FS as "Filesystem Layer\n(/samba-share)"
    participant Link as "Symbolic Link\n(/samba-share/remote)"
    participant Mount as "FUSE Mount\n(/remote)"
    participant SSHFS as "SSHFS Process"
    participant Remote as "Remote SSH Server"
    
    Finder->>SMB: SMB read request
    SMB->>FS: Access /samba-share/remote/file.txt\n(as sshuser)
    FS->>Link: Follow symbolic link
    Link->>Mount: Resolve to /remote/file.txt
    Mount->>SSHFS: FUSE read operation
    SSHFS->>Remote: SSH file read
    Remote-->>SSHFS: File contents
    SSHFS-->>Mount: FUSE response
    Mount-->>Link: File data
    Link-->>FS: File data
    FS-->>SMB: File data (as sshuser)
    SMB-->>Finder: SMB response

Bidirectional Data Flow

The protocol translation supports both read and write operations, with data flowing through the complete translation stack in both directions.

Read Operation Flow

Diagram: Read Operation Protocol Translation Flow

Write Operation Flow

Diagram: Write Operation Protocol Translation Flow

Write Access Requirements

Write operations succeed because of aligned user identity across the translation layers:

  1. SSHFS Mount: Files owned by uid=1000,gid=1000 README.md49
  2. Samba Configuration: force user = sshuser smb.conf19
  3. User Account: sshuser has UID 1000, GID 1000 Dockerfile9

Without this alignment, write operations fail. The uid=1000,gid=1000 mount options are noted as required for write access README.md53:

uid=1000,gid=1000 is needed for write-access (otherwise, it will be read-only if omitted)

Sources: README.md:49-53, smb.conf:19, Dockerfile:9


Protocol Translation Component Mapping

The following table maps high-level protocol translation concepts to specific code entities and configuration files:

Translation StageInput ProtocolOutput InterfaceCode EntityConfiguration
Remote to SSHFile I/OSSH protocoluser@host:path (mount target)SSH credentials
SSH to FUSESSH protocolFilesystem operationssshfs command README.md49-o allow_other,uid=1000,gid=1000
FUSE to FilesystemFUSE operationsVFS operations/remote mount point Dockerfile12user_allow_other Dockerfile24
Filesystem IntegrationVFS operationsVFS operations/samba-share/remote symlink Dockerfile30chmod 777 /samba-share Dockerfile21
Filesystem to SMBVFS operationsSMB protocolsmbd process Dockerfile33smb.conf smb.conf:1-19
SMB to NetworkSMB protocolTCP/IPPorts 139/445 Dockerfile27-p 127.0.0.1:139:139 -p 127.0.0.1:445:445 README.md31

Sources: README.md:31, README.md:49, Dockerfile:12, Dockerfile:21, Dockerfile:24, Dockerfile:27, Dockerfile:30, Dockerfile:33, smb.conf:1-19


graph TB
    subgraph "FUSE Configuration"
        FuseConf["user_allow_other\n/etc/fuse.conf\nDockerfile:24"]
end
    
    subgraph "SSHFS Mount Options"
        AllowOther["allow_other\nREADME.md:49"]
UIDMap["uid=1000\nREADME.md:49"]
GIDMap["gid=1000\nREADME.md:49"]
end
    
    subgraph "User Account"
        SSHUser["sshuser\nUID 1000, GID 1000\nDockerfile:9"]
end
    
    subgraph "Samba Configuration"
        ForceUser["force user = sshuser\nsmb.conf:19"]
GuestOK["guest ok = yes\nsmb.conf:13"]
Writable["writable = yes\nsmb.conf:12"]
end
    
    subgraph "Filesystem"
        SharePerms["chmod 777 /samba-share\nDockerfile:21"]
SymLink["ln -s /remote /samba-share/remote\nDockerfile:30"]
end
    
 
   FuseConf -->|enables| AllowOther
 
   AllowOther -->|allows cross-user access| ForceUser
    
 
   UIDMap -->|sets ownership| SSHUser
 
   GIDMap -->|sets ownership| SSHUser
 
   SSHUser -->|identity matches| ForceUser
    
 
   ForceUser -->|runs operations as| SharePerms
 
   SharePerms -->|writable by| SSHUser
    
 
   GuestOK -->|simplifies auth| ForceUser
 
   Writable -->|enables writes| ForceUser
    
 
   SymLink -->|integrates| SharePerms

Critical Configuration Dependencies

The protocol translation requires specific configuration elements that work together to enable cross-protocol access:

Configuration Dependency Graph

Diagram: Configuration Dependency Graph for Protocol Translation

All these configuration elements must be correctly set for the protocol translation to function:

  1. user_allow_other in fuse.conf enables the allow_other mount option
  2. allow_other mount option allows Samba to access SSHFS-mounted files
  3. uid=1000,gid=1000 mount options set file ownership to match sshuser
  4. force user = sshuser in Samba config aligns with SSHFS file ownership
  5. chmod 777 /samba-share ensures permissive access to the share directory
  6. Symbolic link connects the Samba share to the SSHFS mount point

If any single element is missing or misconfigured, the protocol translation fails—typically resulting in permission denied errors or read-only access.

Sources: Dockerfile:9, Dockerfile:21, Dockerfile:24, Dockerfile:30, README.md:49, smb.conf:12-13, smb.conf:19