# autofs

# autofs Setup and Configuration Guide

`autofs` mounts filesystems on-demand when accessed and unmounts them after a configurable idle timeout. This makes it significantly more robust than static `/etc/fstab` mounts for network shares — a missing or offline host won't hang your boot, and stale mounts are cleaned up automatically.

---

## 1. Install

```bash
sudo apt update && sudo apt install autofs sshfs -y
```

For NFS shares also install:

```bash
sudo apt install nfs-common -y
```

---

## 2. How autofs Works

autofs has two config layers:

| File | Purpose |
|---|---|
| `/etc/auto.master` | Master map — defines mount point directories and which map file handles them |
| `/etc/auto.<name>` | Detail map — defines individual mounts under that directory |

When you access `/mnt/remote/myshare`, autofs intercepts it, reads the map, and mounts the share on the fly. After the timeout with no activity, it unmounts automatically.

---

## 3. Master Map — `/etc/auto.master`

Each line in `auto.master` follows this format:

```
<base_mount_dir>  <map_file>  [options]
```

Example:

```
/mnt/remote  /etc/auto.sshfs  --timeout=60,--ghost
/mnt/nfs     /etc/auto.nfs    --timeout=120,--ghost
```

**Key options:**

| Option | Effect |
|---|---|
| `--timeout=N` | Unmount after N seconds of inactivity |
| `--ghost` | Creates empty placeholder directories so the mount point is visible even when unmounted. Without this, `ls /mnt/remote` shows nothing until a mount is active |
| `--verbose` | Useful during setup/debugging |

### Important: auto.master entry placement

The default `/etc/auto.master` contains a `+auto.master` line which is a legacy NIS include directive. Your custom entries must go **above** this line, otherwise they may be ignored on some systems. The `+auto.master` line is safe to remove entirely on a standalone home server with no NIS infrastructure.

Clean minimal auto.master:

```
+dir:/etc/auto.master.d

/mnt/remote  /etc/auto.sshfs  --timeout=60,--ghost
```

The `+dir:/etc/auto.master.d` line is worth keeping — it allows dropping extra `.autofs` map files into that directory without editing auto.master directly.

---

## 4. Detail Map Files

### SSHFS (SSH/SFTP) — Modern Syntax

> **Important:** Many guides online show legacy syntax using `fstype=fuse` and `:sshfs#user@host` format. This does **not** work on modern Linux kernels. Always use `fstype=fuse.sshfs` with plain `user@host:/path` syntax.

Create `/etc/auto.sshfs`:

```
<mount_name>  -fstype=fuse.sshfs,rw,allow_other,IdentityFile=/home/conor/.ssh/id_ed25519,uid=1000,gid=1000,StrictHostKeyChecking=no,ServerAliveInterval=15,ServerAliveCountMax=3  conor@100.x.x.x:/home/conor
```

**Breakdown:**

| Part | Meaning |
|---|---|
| `<mount_name>` | The subdirectory created under the base — e.g. `farmdesktop` becomes `/mnt/remote/farmdesktop` |
| `-fstype=fuse.sshfs` | Correct modern fstype for SSHFS mounts |
| `rw` | Read/write |
| `allow_other` | Allows users other than root to access the mount |
| `IdentityFile=` | Path to SSH private key — **must use key auth, not password** |
| `uid=1000,gid=1000` | Map remote files to your local user. Check yours with `id conor` |
| `StrictHostKeyChecking=no` | Required because autofs runs as root which has an empty known_hosts — without this the mount hangs waiting for an interactive host key confirmation that never comes |
| `ServerAliveInterval=15` | Send keepalive every 15s to prevent silent disconnects |
| `ServerAliveCountMax=3` | Drop connection after 3 missed keepalives |

Full working example:

```
farm-server  -fstype=fuse.sshfs,rw,allow_other,IdentityFile=/home/conor/.ssh/cbcore-key,uid=1000,gid=1000,StrictHostKeyChecking=no,ServerAliveInterval=15,ServerAliveCountMax=3  conor@100.64.0.12:/home/conor
```

Access via: `/mnt/remote/farm-server`

### Why legacy syntax fails

Old guides show:
```
farmdesktop  -fstype=fuse,rw,allow_other,...  :sshfs#conor@100.64.0.5:/home/conor
```

This tells autofs to call `mount -t fuse` with `sshfs#` as the device — an approach that relied on the generic FUSE kernel module handling the mount. Modern kernels expect `mount -t fuse.sshfs` with a plain remote path. Using the old syntax results in `signal 22 (SIGABRT)` and a failed mount with no useful error message.

---

### NFS

Create `/etc/auto.nfs`:

```
nas  -fstype=nfs4,rw,soft,intr  100.64.0.10:/exports/data
```

| Option | Meaning |
|---|---|
| `nfs4` | Use NFSv4 (preferred) |
| `soft` | Return error on timeout instead of hanging indefinitely |
| `intr` | Allow interrupting a hung NFS call with Ctrl+C |

---

### Samba / CIFS

Create `/etc/auto.smb`:

```
wiki  -fstype=cifs,rw,credentials=/home/conor/.smbcredentials,uid=1000,gid=1000,iocharset=utf8  ://100.64.0.10/wiki
```

`/home/conor/.smbcredentials`:

```
username=conor
password=yourpassword
```

```bash
chmod 600 /home/conor/.smbcredentials
```

---

## 5. FUSE Prerequisite for SSHFS

`allow_other` requires this line to be uncommented in `/etc/fuse.conf`:

```bash
sudo nano /etc/fuse.conf
```

Uncomment:

```
user_allow_other
```

Without this, SSHFS mounts via autofs (which runs as root) will be inaccessible to your user account.

---

## 6. SSH Key Setup

autofs runs as root, so two things must be true:

1. The key file must be readable by root
2. Root must have the remote host in its known_hosts — **or** `StrictHostKeyChecking=no` must be set

**Seed root's known_hosts before first use:**

```bash
sudo ssh -i /home/conor/.ssh/your-key conor@100.x.x.x echo "ok"
# Type "yes" when prompted to accept the host key
```

Alternatively, use `StrictHostKeyChecking=no` in the map file options (acceptable on a private Tailscale network).

**Option A** — use your existing user key (works if permissions allow root to read it):

```
IdentityFile=/home/conor/.ssh/id_ed25519
```

**Option B** — create a dedicated root-owned key for autofs:

```bash
sudo ssh-keygen -t ed25519 -f /root/.ssh/autofs_id_ed25519 -N ""
sudo ssh-copy-id -i /root/.ssh/autofs_id_ed25519.pub conor@100.x.x.x
```

Then use `IdentityFile=/root/.ssh/autofs_id_ed25519` in the map file. Cleaner — keeps autofs auth separate from your interactive SSH key.

---

## 7. Enable and Start autofs

```bash
sudo systemctl enable autofs --now
```

Reload after map file changes:

```bash
sudo systemctl reload autofs
```

Full restart required after auto.master changes:

```bash
sudo systemctl restart autofs
```

---

## 8. Testing

Trigger a mount by accessing the path directly:

```bash
ls /mnt/remote/farm-server
```

Check what's currently mounted:

```bash
mount | grep autofs
```

Verify autofs has loaded your maps correctly:

```bash
sudo automount --dumpmaps
```

Check status and logs:

```bash
sudo systemctl status autofs
sudo journalctl -u autofs -f
```

Force unmount manually:

```bash
sudo umount /mnt/remote/farm-server
```

---

## 9. Debugging a Failed Mount

If the mount silently fails, run autofs in foreground debug mode:

```bash
sudo systemctl stop autofs
sudo automount -f --verbose --debug 2>&1 | tee /tmp/autofs-debug.log &
sleep 2
ls /mnt/remote/farm-server
sleep 2
cat /tmp/autofs-debug.log
```

Then kill the debug instance and restart the service:

```bash
sudo pkill -9 -f automount
sudo rm -f /run/autofs.pid
sudo systemctl start autofs
```

If the mount command itself hangs, test it manually first:

```bash
# Test SSH connectivity as root
sudo ssh -i /path/to/key user@host echo "ok"

# Test sshfs as your normal user
mkdir /tmp/testmount
sshfs -o IdentityFile=/path/to/key user@host:/remote/path /tmp/testmount
ls /tmp/testmount
```

If sshfs works as your user but hangs as root, the issue is root's SSH environment (known_hosts, key permissions). Add `StrictHostKeyChecking=no` to the map options and ensure the key is readable by root.

---

## 10. Troubleshooting

| Symptom | Likely cause | Fix |
|---|---|---|
| `ls` on mount point returns "No such file or directory" | autofs not reading map, or entry placement in auto.master | Run `sudo automount --dumpmaps` to verify map is loaded; check entry is above `+auto.master` |
| Mount hangs on access | Root's known_hosts empty — SSH waiting for interactive host key confirmation | Add `StrictHostKeyChecking=no` to map options, or pre-seed with `sudo ssh user@host echo ok` |
| `signal 22` / SIGABRT in debug output | Legacy `fstype=fuse` + `sshfs#` syntax | Change to `fstype=fuse.sshfs` and plain `user@host:/path` |
| "Permission denied" accessing mounted path | `allow_other` not set or `user_allow_other` not in fuse.conf | Check `/etc/fuse.conf` |
| Mount works as root but not as user | `uid=` / `gid=` not set in map file | Add `uid=1000,gid=1000` (check with `id username`) |
| autofs fails to start after manual debug session | Stale PID file from debug automount process | `sudo pkill -9 -f automount && sudo rm -f /run/autofs.pid` |
| Changes to map file have no effect | autofs cached old config | `sudo systemctl reload autofs` |
| `ls /mnt/remote` shows nothing despite ghost mode | Ghost mode requires autofs to be fully running and map parsed | Run `sudo automount --dumpmaps` to confirm map loaded |

---

## 11. Full Example: Tailscale Homelab

`/etc/auto.master`:

```
+dir:/etc/auto.master.d

/mnt/remote  /etc/auto.sshfs  --timeout=60,--ghost
```

`/etc/auto.sshfs`:

```
farm-pi      -fstype=fuse.sshfs,rw,allow_other,IdentityFile=/root/.ssh/autofs_id_ed25519,uid=1000,gid=1000,StrictHostKeyChecking=no,ServerAliveInterval=15,ServerAliveCountMax=3  conor@100.64.0.2:/home/conor
farmdesktop  -fstype=fuse.sshfs,rw,allow_other,IdentityFile=/root/.ssh/autofs_id_ed25519,uid=1000,gid=1000,StrictHostKeyChecking=no,ServerAliveInterval=15,ServerAliveCountMax=3  conor@100.64.0.3:/home/conor
homeserver   -fstype=fuse.sshfs,rw,allow_other,IdentityFile=/root/.ssh/autofs_id_ed25519,uid=1000,gid=1000,StrictHostKeyChecking=no,ServerAliveInterval=15,ServerAliveCountMax=3  conor@100.64.0.4:/home/conor
```

Access:

```
/mnt/remote/farm-pi/
/mnt/remote/farmdesktop/
/mnt/remote/homeserver/
```

All mount on first access, unmount after 60 seconds idle. If a farm machine is offline, accessing its path returns an error immediately rather than hanging the system.

---

## Notes

- autofs mounts do **not** appear in `df` or `mount` output unless currently active — this is normal.
- `/etc/auto.master` changes require a full `systemctl restart autofs`; map file changes only need `systemctl reload autofs`.
- For Ansible management across your fleet, the map files and master config are straightforward to template — a single playbook can deploy consistent autofs config to all five machines.