14

As subject: I cannot edit the file ssh.plist which is located in /System/Library/LaunchDaemons. I want to change the sshd port.

I tried to use 'information' in the finder and unlock it. This didn't work. I tried:

As root, I tried..

macos:LaunchDaemons root# pwd && chown $USER ssh.plist 
/System/Library/LaunchDaemons
chown: ssh.plist: Operation not permitted

I also tried to cp the file to my own Desktop, edit it in situ and cp it back.

macos:LaunchDaemons root# pwd && cp /Users/darren/Desktop/ssh.plist .
/System/Library/LaunchDaemons
cp: ./ssh.plist: Operation not permitted

I did this before - a while back. I think it was maybe the one before Sierra, but I don't recall the 'code name' of that release.

Has Apple locked this file down definitively?

1
  • Hi Darren, I was revising open questions and you may want to upvote/mark my answer as accepted, since, from your feedback, I understand it solved your issue. Marking a question as solved also helps others who have a similar issue, as it shows your question has the answer you were looking for.
    – jaume
    Jun 25, 2020 at 9:21

1 Answer 1

30

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.


Edit: macOS 11 Big Sur and later add strong cryptographic protections to system content, which seems to make the first proposed solution (modifying /System/Library/LaunchDaemons/ssh.plist) not feasible. Thank you to Jo Liss and Carl for their feedback in the comments below!


There are (at least) 4 ways to change the port sshd listens on:

  1. 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.

  1. 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.

  1. 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.

  1. 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 but sshd 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 variables SSH_CLIENT and SSH_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:

  1. Restart your Mac and hold down R immediately after your Mac begins to restart to enter macOS Recovery.
  2. Select Utilities>Terminal from the menu bar.
  3. Type csrutil disable to disable SIP.
  4. Select Apple menu>Restart.
  5. Log in, edit /System/Library/LaunchDaemons/ssh.plist and modify the Listeners section. For example, to change the port to 2222:

enter image description here

  1. Restart your Mac and hold down R immediately after your Mac begins to restart to enter macOS Recovery.
  2. Select Utilities>Terminal from the menu bar.
  3. 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:

  1. Copy /System/Library/LaunchDaemons/ssh.plist to /Library/LaunchDaemons/ssh2.plist to create a new sshd startup script.

  2. 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>
    
  3. 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>
    
  4. 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:

  1. 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):

  1. Create a new anchor file /etc/pf.anchors/sshd with contents (replace 2222 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
    
  2. 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"
    
  3. 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 and SSH_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.

22
  • 1
    Would it make more sense to use the firewall to translate the port number? Especially as /etc/services is meant to be the IANA-assigned port numbers: Non standard ssh port: should I edit /etc/services? Sep 1, 2018 at 19:16
  • 1
    @jaume, no, I actually mean ssh, the client. If it looks up the ssh service rather than use a hardcoded 22, then modifying /etc/services would also affect outgoing ssh connections (the default remote port the client would connect to). Not saying it’s actually the case (haven’t tried), just wondering.
    – jcaron
    Sep 2, 2018 at 11:52
  • 1
    @jcaron Now I understand what you mean, very good question, yes, I tested it and the SSH client reads the value of the "ssh" entry in /etc/services and tries to connect to port 2222 (or whatever port is defined in there). That is, /etc/services not only changes the behavior of sshd, but also of ssh. I didn't expect that, I will edit the answer and point that out (with a workaround).
    – jaume
    Sep 2, 2018 at 12:59
  • 1
    I'd recommend copying ssh.plist into /Library/LaunchDaemons, changing the filename, label, and port, and loading that as a separate service. See this page at codedmemes.com for details. Sep 3, 2018 at 13:45
  • 1
    Confirmed #1 works on Mojave
    – Elle Mundy
    Sep 29, 2018 at 23:33

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .