1# SSHFS File Systems {#sec-sshfs-file-systems} 2 3[SSHFS][sshfs] is a [FUSE][fuse] filesystem that allows easy access to directories on a remote machine using the SSH File Transfer Protocol (SFTP). 4It means that if you have SSH access to a machine, no additional setup is needed to mount a directory. 5 6[sshfs]: https://github.com/libfuse/sshfs 7[fuse]: https://en.wikipedia.org/wiki/Filesystem_in_Userspace 8 9## Interactive mounting {#sec-sshfs-interactive} 10 11In NixOS, SSHFS is packaged as `sshfs`. 12Once installed, mounting a directory interactively is simple as running: 13```ShellSession 14$ sshfs my-user@example.com:/my-dir /mnt/my-dir 15``` 16Like any other FUSE file system, the directory is unmounted using: 17```ShellSession 18$ fusermount -u /mnt/my-dir 19``` 20 21## Non-interactive mounting {#sec-sshfs-non-interactive} 22 23Mounting non-interactively requires some precautions because `sshfs` will run at boot and under a different user (root). 24For obvious reason, you can't input a password, so public key authentication using an unencrypted key is needed. 25To create a new key without a passphrase you can do: 26```ShellSession 27$ ssh-keygen -t ed25519 -P '' -f example-key 28Generating public/private ed25519 key pair. 29Your identification has been saved in example-key 30Your public key has been saved in example-key.pub 31The key fingerprint is: 32SHA256:yjxl3UbTn31fLWeyLYTAKYJPRmzknjQZoyG8gSNEoIE my-user@workstation 33``` 34To keep the key safe, change the ownership to `root:root` and make sure the permissions are `600`: 35OpenSSH normally refuses to use the key if it's not well-protected. 36 37The file system can be configured in NixOS via the usual [fileSystems](#opt-fileSystems) option. 38Here's a typical setup: 39```nix 40{ 41 fileSystems."/mnt/my-dir" = { 42 device = "my-user@example.com:/my-dir/"; 43 fsType = "sshfs"; 44 options = 45 [ # Filesystem options 46 "allow_other" # for non-root access 47 "_netdev" # this is a network fs 48 "x-systemd.automount" # mount on demand 49 50 # SSH options 51 "reconnect" # handle connection drops 52 "ServerAliveInterval=15" # keep connections alive 53 "IdentityFile=/var/secrets/example-key" 54 ]; 55 }; 56} 57``` 58More options from `ssh_config(5)` can be given as well, for example you can change the default SSH port or specify a jump proxy: 59```nix 60{ 61 options = 62 [ "ProxyJump=bastion@example.com" 63 "Port=22" 64 ]; 65} 66``` 67It's also possible to change the `ssh` command used by SSHFS to connect to the server. 68For example: 69```nix 70{ 71 options = 72 [ (builtins.replaceStrings [" "] ["\\040"] 73 "ssh_command=${pkgs.openssh}/bin/ssh -v -L 8080:localhost:80") 74 ]; 75 76} 77``` 78 79::: {.note} 80The escaping of spaces is needed because every option is written to the `/etc/fstab` file, which is a space-separated table. 81::: 82 83### Troubleshooting {#sec-sshfs-troubleshooting} 84 85If you're having a hard time figuring out why mounting is failing, you can add the option `"debug"`. 86This enables a verbose log in SSHFS that you can access via: 87```ShellSession 88$ journalctl -u $(systemd-escape -p /mnt/my-dir/).mount 89Jun 22 11:41:18 workstation mount[87790]: SSHFS version 3.7.1 90Jun 22 11:41:18 workstation mount[87793]: executing <ssh> <-x> <-a> <-oClearAllForwardings=yes> <-oServerAliveInterval=15> <-oIdentityFile=/var/secrets/wrong-key> <-2> <my-user@example.com> <-s> <sftp> 91Jun 22 11:41:19 workstation mount[87793]: my-user@example.com: Permission denied (publickey). 92Jun 22 11:41:19 workstation mount[87790]: read: Connection reset by peer 93Jun 22 11:41:19 workstation systemd[1]: mnt-my\x2ddir.mount: Mount process exited, code=exited, status=1/FAILURE 94Jun 22 11:41:19 workstation systemd[1]: mnt-my\x2ddir.mount: Failed with result 'exit-code'. 95Jun 22 11:41:19 workstation systemd[1]: Failed to mount /mnt/my-dir. 96Jun 22 11:41:19 workstation systemd[1]: mnt-my\x2ddir.mount: Consumed 54ms CPU time, received 2.3K IP traffic, sent 2.7K IP traffic. 97``` 98 99::: {.note} 100If the mount point contains special characters it needs to be escaped using `systemd-escape`. 101This is due to the way systemd converts paths into unit names. 102:::