Containerized Netatalk

Netatalk comes with a Dockerfile and entry point script for running a
containerized AFP server and AppleTalk services.

Out of the box, exactly two users, and two shared volumes are supported
in this container. One of the shared volumes is a backup volume by
default. If you need a different setup, please use the manual
configuration option.

We use podman in these examples, but the Netatalk container should work
with any OCI compliant container runtime such as Docker or CRI-O.

Make sure you have a container runtime installed, then build the
netatalk container:

    podman build -f distrib/docker/netatalk.Dockerfile .

Alternatively, pull a pre-built container image from Docker Hub or GHCR.

How to Run

Once you have the netatalk image on your machine run it with your
preferred container runtime.

The easiest way to get started is to use the included compose.yml file.

    podman compose -f distrib/docker/compose.yml up

You just need to edit the file to set the AFP_USER and AFP_PASS
environment variables first.

Configuration

The easiest way to enable full functionality including Zeroconf service
discovery and AppleTalk is to use the host network driver.

For a hardened deployment, use the bridge network driver and expose port
548 for AFP. However, Zeroconf service discovery may not work and you
will have to manually specify the IP address in the client when
connecting to the file server.

It is recommended to set up a managed volume for persistent storage.
Without this, the shared volume be stored in volatile storage that is
lost upon container shutdown.

Below follows a sample podman run command for illustration. Substitute
AFP_USER and AFP_PASS with the appropriate user and password, and
ATALKD_INTERFACE with the network interface to use for AppleTalk.

We recommend named volumes for the shared volumes, but you can also use
bind mounts to host machine directories if you prefer, as long as the
permissions are set correctly for the AFP_USER and AFP_GROUP and
AFP_UID, and AFP_GID if set to match the user and group ids on the host
machine.

You also need to set the timezone with TZ to the IANA time zone ID for
your location, in order to get the correct time synchronized with the
Timelord time server.

    podman run --rm \
      --network host \
      --cap-add=NET_ADMIN \
      --volume "afpshare:/mnt/afpshare" \
      --volume "afpbackup:/mnt/afpbackup" \
      --volume "/var/run/dbus:/var/run/dbus" \
      --env AFP_USER= \
      --env AFP_PASS= \
      --env AFP_GROUP=afpusers \
      --env ATALKD_INTERFACE=eth0 \
      --env TZ=Europe/Stockholm \
      --name netatalk netatalk:latest

Constraints

The most straight forward way to enable Zeroconf service discovery as
well as the AppleTalk transport layer, is to use the host network driver
and NET_ADMIN capabilities.

Additionally, we rely on the host's D-Bus for Zeroconf, achieved with a
bind mount such as /var/run/dbus:/var/run/dbus. The left hand side of
the bind mount is the host machine, and the right hand side is the
container. The host machine path may have to be changed to match the
location of D-Bus on the host machine.

On certain host OSes, notably Ubuntu: if the Apparmor security policy
restricts D-Bus messages, enable the unconfined security option.

Example for the docker compose yaml configuration file:

        security_opt:
          - apparmor=unconfined

See the Docker AppArmor security profiles documentation for further
details.

The container is hard coded to output afpd (the Netatalk file server
daemon) logs to the container's stdout, with default log level info.
Logs from the AppleTalk daemons are sent to the syslog.

File search on mounted volumes in the Finder is supported with the cnid
Spotlight backend. The cnid backend supports filename search only, no
file content or metadata index searching. This is recommend over
localsearch/xapian (full content indexing) in production environments
for technical and privacy reasons.

MySQL CNID Backend

The MySQL CNID backend is an alternative to the default Berkeley DB CNID
backend which offers better scalability.

Here follows a compose example to run a container network with MariaDB
as the database for the MySQL CNID backend, plus a web interface to
administer the database for good measure.

Set AFP_CNID_SQL_PASS and MARIADB_ROOT_PASSWORD to the same password.

    services:
      netatalk:
        image: netatalk:latest
        networks:
          - afp_network
        ports:
          - "548:548"
        volumes:
          - afpshare:/mnt/afpshare
          - afpbackup:/mnt/afpbackup
          - /var/run/dbus:/var/run/dbus
        environment:
          - AFP_USER=atalk1
          - AFP_USER2=atalk2
          - AFP_PASS=
          - AFP_PASS2=
          - AFP_GROUP=afpusers
          - AFP_CNID_BACKEND=mysql
          - AFP_CNID_SQL_HOST=cnid_db
          - AFP_CNID_SQL_PASS=
        depends_on:
          - cnid_db

      cnid_db:
        image: mariadb:latest
        restart: always
        networks:
          - afp_network
        volumes:
          - cnid_db_data:/var/lib/mysql
        environment:
          - MARIADB_ROOT_PASSWORD=

      adminer:
        image: adminer:latest
        restart: always
        networks:
          - afp_network
        ports:
          - 8081:8080

    volumes:
      afpshare:
        name: afpshare
      afpbackup:
        name: afpbackup
      cnid_db_data:
        name: cnid_db_data

    networks:
      afp_network:
        driver: bridge

Webmin Module

Netatalk's Webmin module is distributed as a separate container image.
The module allows you to administer the Netatalk configuration via a web
interface. Here follows an example compose configuration to run the
module in a container.

Note that since the netatalk daemons run in a separate container, we
cannot control the services directly. Instead, activate polling of
changes to the afp.conf configuration file. Set AFP_CONFIG_POLLING to
the number of seconds to wait between polling attempts.

    services:
      netatalk:
        image: netatalk:latest
        networks:
          - afp_network
        ports:
          - "548:548"
        volumes:
          - afpshare:/mnt/afpshare
          - afpbackup:/mnt/afpbackup
          - afpconf:/etc/netatalk
          - /var/run/dbus:/var/run/dbus
        environment:
          - AFP_USER=atalk1
          - AFP_USER2=atalk2
          - AFP_PASS=
          - AFP_PASS2=
          - AFP_GROUP=afpusers
          - AFP_CONFIG_POLLING=5
          - MANUAL_CONFIG=1

      webmin:
        image: netatalk_webmin_module:latest
        networks:
          - afp_network
        ports:
          - "10000:10000"
        volumes:
          - afpconf:/etc/netatalk
          - /var/run/docker.sock:/var/run/docker.sock
        environment:
          - WEBMIN_USER=admin
          - WEBMIN_PASS=
        depends_on:
          - netatalk

    volumes:
      afpshare:
        name: afpshare
      afpbackup:
        name: afpbackup
      afpconf:
        name: afpconf

    networks:
      afp_network:
        driver: bridge

Printing

The CUPS administrative web app is running on port 631 in the container,
which is exposed to the host machine by default when using the host
network driver. This is used to configure CUPS compatible printers for
printing from an old Mac or Apple IIGS.

You may have to restart papd (or the entire container) after adding a
CUPS printer for it to be picked up as an AppleTalk printer.

Environment Variables

Mandatory Settings

These are required to set the credentials used to authenticate with the
file server.

  Variable    Description
  ----------- -------------------------------------------------------------------------------------------
  AFP_USER    Primary user of the shared volumes
  AFP_PASS    Password to authenticate with the primary user (8 chars or less when using INSECURE_AUTH)
  AFP_GROUP   Group that owns the shared volume dirs

Mandatory for AppleTalk

  Variable           Description
  ------------------ --------------------------------------------
  ATALKD_INTERFACE   The network interface to use for AppleTalk

Optional Settings

Value Type

Set this environment variable to a specific value or string.

  Variable                        Description
  ------------------------------- -----------------------------------------------------------------------------------------------------------------------------------------
  User & Group Configuration      
  AFP_UID                         Specify user id of AFP_USER
  AFP_GID                         Specify group id of AFP_GROUP
  AFP_USER2                       Username for the secondary user
  AFP_PASS2                       Password for the secondary user
  Server Configuration            
  SERVER_NAME                     The name of the server (AFP and Zeroconf)
  SHARE_NAME                      The name of the primary shared volume
  SHARE_NAME2                     The name of the secondary shared (Time Machine) volume
  AFP_LOGLEVEL                    The verbosity of logs; default is "info"
  AFP_MIMIC_MODEL                 Use a custom macOS (OSX) AFP icon; examples: Tower, RackMount
  AFP_LEGACY_ICON                 Use a custom Classic Mac OS AFP icon; examples: daemon, sdcard
  AFP_LOGIN_MESSAGE               A message to display when a user logs in (Classic Mac OS only)
  ATALKD_OPTIONS                  A string with options to append to atalkd.conf
  Authentication Configuration    
  AFP_UAMS                        Space-separated list of UAM .so files to load, overriding the default list (uams_dhx2.so uams_srp.so) as well as the INSECURE_AUTH flag
  CNID Database Configuration     
  AFP_CNID_BACKEND                The backend to use for the CNID database: dbd, sqlite, or mysql
  AFP_CNID_SQL_HOST               The hostname or IP address of the CNID SQL server
  AFP_CNID_SQL_USER               The username to use when connecting to the CNID SQL server
  AFP_CNID_SQL_PASS               The password to use when connecting to the CNID SQL server
  AFP_CNID_SQL_DB                 The name of the designated database in the SQL server
  Directory Cache Configuration   
  AFP_DIRCACHESIZE                Directory cache size in entries (default: 65536)
  AFP_DIRCACHE_MODE               Cache algorithm: lru (default) or arc
  AFP_DIRCACHE_VALIDATION_FREQ    Validate cache every Nth access (default: 1, higher = better performance)
  AFP_DIRCACHE_RFORK_BUDGET       Total memory budget in KB for resource fork caching (default: 0 = disabled)
  AFP_DIRCACHE_RFORK_MAXSIZE      Max size in KB of a single cached resource fork entry (default: 1024)
  Charset Configuration           
  AFP_MAC_CHARSET                 Mac client charset (default: MAC_ROMAN); see afp.conf man page
  AFP_UNIX_CHARSET                Server filesystem charset (default: UTF8); see afp.conf man page
  AFP_VOL_CHARSET                 Volume charset (default: UTF8); see afp.conf man page
  Test Suite Configuration        
  TESTSUITE                       Run test suite on startup: spectest, lan, speed, login, readonly
  AFP_VERSION                     AFP protocol version for tests: 1-7 (default: 7 = AFP 3.4)
  AFP_HOST                        AFP server hostname/IP for tests (default: 127.0.0.1)
  AFP_PORT                        AFP server port for tests (default: 548)
  AFP_REMOTE                      Test remote AFP server (vs container-local)
  TEST_FLAGS                      Additional flags to pass to test binaries
  Other Configuration             
  TZ                              The timezone to use in the container
  AFP_CONFIG_POLLING              Poll afp.conf for changes every N seconds (for Webmin integration)
  AFP_CONVERT_APPLEDOUBLE         Convert AppleDouble files on the volume: yes or no (default)

Boolean Type

Set these environment variables to a non-zero value to enable, ex. "1"

  Variable                        Description
  ------------------------------- ---------------------------------------------------------------------------------------------------------------------------------
  Volume & Access Configuration   
  AFP_DROPBOX                     Enable dropbox mode; secondary user is guest with read only access to the second shared volume
  AFP_READONLY                    Mount volume as read-only
  DISABLE_TIMEMACHINE             The secondary shared volume is a regular volume, not a backup volume
  File System Configuration       
  AFP_EXTMAP                      Enable mapping of filename extension to Classic Mac OS type/creator
  AFP_ADOUBLE                     Use AppleDouble (ad) instead of system native EA for extended attributes
  Authentication Configuration    
  INSECURE_AUTH                   Enable the "RandNum", "ClearTxt", and "Guest" UAMs; the AFP password must be 8 chars or shorter; use AFP_UAMS for finer control
  Advanced Configuration          
  MANUAL_CONFIG                   Enable manual management of configurations; overrides most other options
  VERBOSE                         Enable verbose test output
  SERVER_LOGS                     Display afpd server logs after test completion
  IO_MONITORING                   Enable I/O monitoring for lantest (requires --privileged)
  DEBUG_ENTRY_SCRIPT              Enable bash debug mode (set -x) for entrypoint script
