Cannot change ssh port on High Sierra
Solution 1:
Has Apple locked this file [
/System/Library/LaunchDaemons/ssh.plist
] down definitively?
Yes, they have, you need to disable SIP (System Integrity Protection), but note that editing ssh.plist
is not the only option to change the SSH server port, there are other ways to achieve the same result.
There are (at least) 4 ways to change the port sshd
listens on:
-
Modifying
/System/Library/LaunchDaemons/ssh.plist
:Pros: cleanest way to configure
sshd
,sshd
started with System Preferences>Sharing>Remote Login listens on new port.Cons: convoluted setup (requires two restarts and disabling/re-enabling SIP).
Use case: definitive change of
sshd
port.
-
Creating a new plist
/Library/LaunchDaemons/ssh2.plist
:Pros: dual operation of
sshd
listening on standard and new port.Cons: CLI-only method to start
sshd
on the new port.Use case:
sshd
must listen on both the standard port and the additional port.
-
Modifying "ssh" entries in
/etc/services
:Pros: simplest method, no need to deal with SIP,
sshd
started with System Preferences>Sharing>Remote Login listens on new port.Cons: side effect:
ssh
defaults to new port when connecting to remote server (there's a workaround for that).Use case: temporary port change or testing
sshd
running on a different port.
-
Redirecting port 22 to new port with packet filter:
Pros: no need to deal with SIP,
sshd
started with System Preferences>Sharing>Remote Login seems to listen on new port.Cons: somewhat non-transparent (
sshd
configuration is untouched butsshd
listens on another/additional port) and confusing (firewall status in System Preferences not reliable), tiny side effect (remote client thinks it is connecting to port 22 (through env variablesSSH_CLIENT
andSSH_CONNECTION
)).Use case: definitive or temporary change of the
sshd
port,sshd
must listen on both the standard port and the additional port.
Let's take a closer look at them. (When choosing the new port, make sure it is not used by another service by running sudo lsof -i -n -P | grep <your port>
.)
1. Modifying /System/Library/LaunchDaemons/ssh.plist
This is the method you tried, let me describe it here for completion:
- Restart your Mac and hold down ⌘R immediately after your Mac begins to restart to enter macOS Recovery.
- Select Utilities>Terminal from the menu bar.
- Type
csrutil disable
to disable SIP. - Select Apple menu>Restart.
-
Log in, edit
/System/Library/LaunchDaemons/ssh.plist
and modify the Listeners section. For example, to change the port to2222
: Restart your Mac and hold down ⌘R immediately after your Mac begins to restart to enter macOS Recovery.
- Select Utilities>Terminal from the menu bar.
- Type
csrutil enable
to enable SIP and restart.
SSH server will now listen on the new port and you can start sshd
as usual through System Preferences>Sharing>Remote Login.
2. Creating a new plist /System/Library/LaunchDaemons/ssh2.plist
This method is nicely described in this answer, which basically says:
- Copy
/System/Library/LaunchDaemons/ssh.plist
to/Library/LaunchDaemons/ssh2.plist
to create a newsshd
startup script. -
Modify the label in
/Library/LaunchDaemons/ssh2.plist
to differenciate the new startup script from the built-in one, for example by appending a number "2":<key>Label</key> <string>com.openssh.sshd2</string>
-
Modify the port in the Listeners section as in the previous method. For example, to change the port to 2222:
<key>Sockets</key> <dict> <key>Listeners</key> <dict> <key>SockServiceName</key> <string>2222</string> <key>Bonjour</key> <array> <string>ssh</string> <string>sftp-ssh</string> </array> </dict> </dict>
-
Start
sshd
on the new port:sudo launchctl load -w /Library/LaunchDaemons/ssh2.plist
(To stop it, run
sudo launchctl unload /Library/LaunchDaemons/ssh2.plist
)
The SSH server will now listen on the new port. You can still use System Preferences>Sharing>Remote Login to start another instance of the SSH server that listens on the standard port (22/tcp). launchd
will listen on both ports:
$ sudo lsof -i -P -n
launchd 1 root 42u IPv6 0x9df385961b132cdf 0t0 TCP *:2222 (LISTEN)
launchd 1 root 44u IPv4 0x9df385961c81db1f 0t0 TCP *:2222 (LISTEN)
launchd 1 root 45u IPv6 0x9df385961b132cdf 0t0 TCP *:2222 (LISTEN)
launchd 1 root 47u IPv4 0x9df385961c81db1f 0t0 TCP *:2222 (LISTEN)
launchd 1 root 48u IPv6 0x9df385961b133e1f 0t0 TCP *:22 (LISTEN)
launchd 1 root 49u IPv4 0x9df385961b22d51f 0t0 TCP *:22 (LISTEN)
launchd 1 root 50u IPv6 0x9df385961b133e1f 0t0 TCP *:22 (LISTEN)
launchd 1 root 51u IPv4 0x9df385961b22d51f 0t0 TCP *:22 (LISTEN)
3. Modifying "ssh" entries in /etc/services
To change the sshd
port with this method, proceed as follows:
-
Edit
/etc/services
, look for these entries:ssh 22/udp # SSH Remote Login Protocol ssh 22/tcp # SSH Remote Login Protocol
and replace port 22 with a port of your choosing.
You can enable SSH with System Preferences>Sharing>Remote Login and sshd
will listen on the new port.
Why does this work? If you take a look at the Listeners section of the /System/Library/LaunchDaemons/ssh.plist
file, you will see that sshd
is configured to listen on the port assigned to the service named ssh in /etc/services
:
<key>Sockets</key>
<dict>
<key>Listeners</key>
<dict>
<key>SockServiceName</key>
<string>ssh</string>
(...)
</dict>
This is undoubtedly the simplest method, but it has a drawback: the SSH client will expect remote SSH servers to listen on the new port (instead of port 22) (thanks to jcaron for the hint). That is, ssh
reads /etc/services
to find out which the default SSH port is.
Fortunately there is an easy solution for this: uncomment Port 22
in /etc/ssh/ssh_config
(see man ssh_config
for more information).
4. Redirecting port 22 to new port with packet filter
The method uses the macOS packet filter (PF) to redirect all requests received at port 22 to the new sshd
port (thanks to Andrew Morton for the idea):
-
Create a new anchor file
/etc/pf.anchors/sshd
with contents (replace2222
with a port of your choosing):rdr pass inet proto tcp from any to any port = 2222 -> 127.0.0.1 port 22 # If you want `sshd` to listen on port 22 too, comment out the line below block drop in quick proto tcp from any to any port = 22
-
Add the "sshd" anchor rules by editing
/etc/pf.conf
(the order is relevant!):scrub-anchor "com.apple/*" nat-anchor "com.apple/*" rdr-anchor "com.apple/*" # Load sshd redirect rule rdr-anchor "sshd" dummynet-anchor "com.apple/*" anchor "com.apple/*" # Load other sshd rules anchor "sshd" load anchor "com.apple" from "/etc/pf.anchors/com.apple" # Tell PF where to find the sshd anchor load anchor "sshd" from "/etc/pf.anchors/sshd"
-
Enable and reload the packet filter:
sudo pfctl -F all -ef /etc/pf.conf
(To disable it, run
sudo pfctl -d
.)
Note that:
- the macOS firewall (System Preferences>Security & Privacy>Firewall) is under the hood the packet filter, so that when you disable the packet filter on the command line, you are also disabling the firewall, even if the Preferences Panel doesn't reflect the change.
-
SSH clients will think they are connecting to port 22 through the
SSH_CLIENT
andSSH_CONNECTION
env variables.
Editing sshd_config
doesn't work
Users running sshd
on other operating systems may be tempted to edit the SSH daemon configuration file, /etc/ssh/sshd_config
. In macOS, however, editing the Port
directive in /etc/ssh/sshd_config
won't achieve the desired result.