一直是使用 samba 服务作为 NAS,移动硬盘插在 mac 上作为 TimeMachine 备份盘,但这样还是太笨拙了。

为了实现无线备份,一种方法是购买 Apple TimeCapsule,另一种则是利用 Linux 设备来搭建 Netatalk 服务器。正好又一台闲置的 Ubuntu 机器,于是就决定采用这种方式。

Netatalk 是一个开源的 AppleTalk 通信协议的实现,可以通过在 Linux 系统上搭建 Netatalk 服务来作为 macOS 设备的 AFP 服务器、AppleTalk 路由等等。结合 avahi 服务,可以达到 Apple 原生设备的效果。

本文基于 Ubuntu 18.04 环境搭建,其他环境配置类似。

硬盘挂载与配置

查看已连接的硬盘

1
2
3
4
5
$ fdisk -l   								# 查看系统连接的磁盘信息 
...
/dev/sdb3 649940992 976773119 326832128 155.9G Apple HFS/HFS+
# 显示需要挂载的 HFS + 分区在 /dev/sdb3

HFS + 分区关闭 journal

Mac 的 HFS + 分区一般都默认开启 journal 功能,因为 Linux 不支持读写 journaled HFS+,所以必须关闭这个功能。

可以把硬盘连接到 mac 操作

1
2
3
4
5
6
7
# 关闭 Journal
$ diskutil disableJournal disk0s2 # 假设 disk0s2 为需要挂载到 linux 上的磁盘分区
Journaling has been disabled on disk0s2

# 打开 Journal
$ diskutil enableJournal disk0s2
Journaling has been enabled on disk0s2

或者直接在 linux 上操作,通过下载 journalling_off.c 源码编译运行来关闭

1
2
3
4
5
6
7
$ cd /tmp
$ curl https://pastebin.com/raw/W8pfgHRe -o journalling_off.c
$ gcc journalling_off.c -o journalling_off
$ sudo ./journalling_off/dev/sdb3 # 根据 fdisk 的结果 /dev/sdb3 为对应 HFS + 分区
</code>sudo ./journalling_off/dev/sdb3
attributes = 0x80002100
journal has been disabled.

如果网速不好,源码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
//journalling_off.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <byteswap.h>



int main(int argc, char *argv [])
{
int fd = open (argv [1], O_RDWR);
if(fd < 0) {
perror ("open");
return -1;
}

unsigned char *buffer = (unsigned char *) mmap (NULL, 2048, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
if(buffer == (unsigned char*)0xffffffff) {
perror ("mmap");
return -1;
}

if((buffer [1024] != 'H') && (buffer [1025] != '+')) {
fprintf(stderr, "% s: HFS+ signature not found -- aborting.\n", argv [0]);
return -1;
}

unsigned long attributes = *(unsigned long *)(&buffer [1028]);
attributes = bswap_32 (attributes);
printf("attributes = 0x%8.8lx\n", attributes);

if(!(attributes & 0x00002000)) {
printf("kHFSVolumeJournaledBit not currently set in the volume attributes field.\n");
}

attributes &= 0xffffdfff;
attributes = bswap_32 (attributes);
*(unsigned long *)(&buffer [1028]) = attributes;

buffer [1032] = '1';
buffer [1033] = '0';
buffer [1034] = '.';
buffer [1035] = '0';

buffer [1036] = 0;
buffer [1037] = 0;
buffer [1038] = 0;
buffer [1039] = 0;

printf("journal has been disabled.\n");
return 0;
}

挂载

1
2
3
$ sudo mkdir /mnt/timemachine					# 创建挂载点 
$ sudo mount -t hfsplus -o force,rw /dev/sdb3 /mnt/timemachine
# 挂载点设置为 /mnt/timemachine

Netatalk 编译安装与配置

由于 apt 上的 Netatalk 的版本太老,所以选择编译安装。

编译

安装依赖库

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
$ sudo apt install -y \
build-essential \
libevent-dev \
libssl-dev \
libgcrypt-dev \
libkrb5-dev \
libpam0g-dev \
libwrap0-dev \
libdb-dev \
libtdb-dev \
avahi-daemon \
libavahi-client-dev \
libacl1-dev \
libldap2-dev \
libcrack2-dev \
libdbus-1-dev \
libdbus-glib-1-dev \
libglib2.0-dev

安装 checkinstall

1
$ sudo apt install --yes checkinstall

也可以通过 下载 deb 包 来安装

1
2
$ cd /tmp && curl http://archive.ubuntu.com/ubuntu/pool/universe/c/checkinstall/checkinstall_1.6.2-4ubuntu2_amd64.deb
$ sudo dpkg -i checkinstall_1.6.2-4ubuntu2_amd64.deb

设置环境变量

1
2
$ NETATALK_VERSION='3.1.11'
$ MAINTAINER='maywzh \<maywzh@gamil.com\>' # 这里换成 自己的名字和邮箱

下载 netatalk 源码

1
2
3
$ wget http://prdownloads.sourceforge.net/netatalk/netatalk-${NETATALK_VERSION}.tar.gz -P /tmp
tar -xzf /tmp/netatalk-${NETATALK_VERSION}.tar.gz -C /tmp
$ cd /tmp/netatalk-${NETATALK_VERSION}

编译

1
2
3
4
5
6
7
8
9
10
11
12
13
14
$ ./configure \
--with-init-style=debian-systemd \
--without-libevent \
--with-cracklib \
--enable-krbV-uam \
--with-pam-confdir=/etc/pam.d \
--with-dbus-daemon=/usr/bin/dbus-daemon \
--with-dbus-sysconf-dir=/etc/dbus-1/system.d
$ make
$ sudo checkinstall -D \
--pkgname='netatalk' \
--pkgversion="${NETATALK_VERSION}" \
--maintainer="${MAINTAINER}" \
$ make install

安装

安装依赖

1
2
3
4
5
6
7
8
9
10
11
$ sudo apt install -y \
avahi-daemon \
cracklib-runtime \
db-util \
db5.3-util \
libtdb1 \
libavahi-client3 \
libcrack2 \
libcups2 \
libpam-cracklib \
libdbus-glib-1-2

安装编译包

1
2
$ sudo dpkg -i netatalk_3.1.11-1_amd64.deb
$ sudo ldconfig

检查安装

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
$ netatalk -v
netatalk 3.1.11 - Netatalk AFP server service controller daemon

This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version. Please see the file COPYING for further information and details.

netatalk has been compiled with support for these features:

Zeroconf support: Avahi
Spotlight support: No

afpd: /usr/local/sbin/afpd
cnid_metad: /usr/local/sbin/cnid_metad
afp.conf: /usr/local/etc/afp.conf
netatalk lock file: /var/lock/netatalk

配置

配置文件

1
$ vim /usr/local/etc/afp.conf  

想深入了解配置请参考 官方文档

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
[Global]  
mimic model = AirPort #指定在 macOS 的 Finder 显示的图标
log level = default:warn
log file = /var/log/afpd.log
hosts allow = 192.168.50.0/24 #子网 允许访问的主机地址,根据需要自行修改
hostname = M-AFP # 主机名 随意设置
uam list = uams_dhx.so uams_dhx2.so #默认认证方式 用户名密码登录 参看官方文档

[Homes]
basedir regex = /home #用户的 Home 目录

[TimeMachine]
path = /mnt/TimeMachine #数据目录
time machine = yes #yes 才支持 TimeMachine
spotlight = no #关闭 spotlight 索引
vol size limit = 155000 #限制 TimeMachine 存储容量,单位为 MB

;[Files] # ; 注释
;path = /mnt/files #设置普通 afp 目录

权限设置

创建一个新用户,用于访问 AFP 服务

1
2
$ useradd afp    # 创建新用户 afp  
$ paaswd afp # 修改 afp 用户密码

Avahi 配置安装

Avahi 是一个开源项目,用于让 mac 在局域网自动发现 Linux AFP 服务器,具体可参看项目地址 https://github.com/lathiat/avahi。

安装

这个简单,直接 yum 就行

1
$ sudo apt install avahi -y  

配置

配置文件位置在 /etc/avahi/services/afpd.service

1
$ vim /etc/avahi/services/afpd.service

修改为以下内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?xml version="1.0" standalone='no'?>   
<!DOCTYPE service-group SYSTEM "avahi-service.dtd">
<service-group>
<name replace-wildcards="yes">DUKE-NAS-AFP</name>
<service>
<type>_afpovertcp._tcp</type>
<port>548</port>
</service>
<service>
<type>_device-info._tcp</type>
<port>0</port>
<txt-record>model=Xserve</txt-record>
</service>
</service-group>

服务启动

1
2
3
4
$ sudo systemctl start avahi-daemon  
$ sudo systemctl start netatalk
$ sudo systemctl enable avahi-daemon
$ sudo systemctl enable netatalk

查看 netatalk 和 avahi 端口是否启动监听,afp 监听 548 端口
请注意 Linux 防火墙问题,将对应端口放行

1
$ netstat -tulpn

至此, netatalk 部署完成。

参考

  1. Install Netatalk 3.1.11 on Ubuntu 18.04 Bionic
  2. Zero-configuration networking