3

macOS X Mojave 10.14.2, Kernel Darwin 18.2.0
Want to change 22 port listening for incoming SSH connections for any from 2222x further for security reasons.
Changing /etc/ssh/sshd_config make no sense..
This Methods describing before doesn't works too for me on Mojave
Any suggestions where is the port settings I can change?

/etc/ssh/sshd_config:

#       $OpenBSD: sshd_config,v 1.103 2018/04/09 20:41:22 tj Exp $

# This is the sshd server system-wide configuration file.  See
# sshd_config(5) for more information.
# This sshd was compiled with PATH=/usr/bin:/bin:/usr/sbin:/sbin
# SSH v2
Protocol 2
Port 2222
AddressFamily inet
#ListenAddress 0.0.0.0
#ListenAddress ::
#HostKey /etc/ssh/ssh_host_rsa_key
#HostKey /etc/ssh/ssh_host_ecdsa_key
HostKey /etc/ssh/ssh_host_ed25519_key

client's /etc/ssh/ssh_config:

 Host *
        Protocol 2
        Port 2222
        SendEnv LANG LC_*

port listening on sshd:

MBP:.ssh user$ > sudo lsof -iTCP -sTCP:LISTEN -n -P
    COMMAND     PID   USER   FD   TYPE             DEVICE SIZE/OFF NODE NAME
    launchd       1   root    8u  IPv6 0xad7e82fd153731a7      0t0  TCP *:445 (LISTEN)
    launchd       1   root   12u  IPv4 0xad7e82fd153798e7      0t0  TCP *:445 (LISTEN)
    launchd       1   root   14u  IPv6 0xad7e82fd22020067      0t0  TCP *:22 (LISTEN)
    launchd       1   root   20u  IPv4 0xad7e82fd2eeb3f67      0t0  TCP *:22 (LISTEN)
    launchd       1   root   24u  IPv6 0xad7e82fd153731a7      0t0  TCP *:445 (LISTEN)
    launchd       1   root   26u  IPv6 0xad7e82fd15373767      0t0  TCP *:548 (LISTEN)
    launchd       1   root   28u  IPv4 0xad7e82fd153798e7      0t0  TCP *:445 (LISTEN)
    launchd       1   root   29u  IPv6 0xad7e82fd22020067      0t0  TCP *:22 (LISTEN)
    launchd       1   root   33u  IPv4 0xad7e82fd15378f67      0t0  TCP *:548 (LISTEN)
    launchd       1   root   43u  IPv6 0xad7e82fd15373767      0t0  TCP *:548 (LISTEN)
    launchd       1   root   44u  IPv4 0xad7e82fd15378f67      0t0  TCP *:548 (LISTEN)
    launchd       1   root   47u  IPv4 0xad7e82fd2eeb3f67      0t0  TCP *:22 (LISTEN)
    kdc          87   root    5u  IPv6 0xad7e82fd15372be7      0t0  TCP *:88 (LISTEN)
    kdc          87   root    7u  IPv4 0xad7e82fd15377c67      0t0  TCP *:88 (LISTEN)
2

5 Answers 5

1

Say you want to change the default port 22 to port 22222

Open a terminal window

Edit the /etc/services file Enter: sudo vi /etc/services
You'll be prompted for you password and obtain an elevated security privilege to make changes.

Use the slash command to find the ssh service /ssh. There will be two entries, one for tcp and the other for udp

ssh 22/udp # SSH Remote Login Protocol
ssh 22/tcp # SSH Remote Login Protocol

Change the number 22 in both cases to 22222 or your desired port number.

Save the changes with :wEnter

You need to recycle the ssh daemon. Depending on your system setup, ssh may not be running. If it is not, the first command will fail; ignor it and move on to the second to start ssh.

Enter the following command to stop it:
sudo launchctl unload /System/Library/LaunchDaemons/ssh.plist

Now enter the following command to start SSH again:
sudo launchctl load -w /System/Library/LaunchDaemons/ssh.plist

Verify you can access the system by logging in with ssh using this command:
ssh localhost -p 22222

To put the system back, redo the above steps and change the ssh port back to 22.

3
  • Such simple is that. Definitely easy and successful result. Thank you Hogstrom But port in command: ssh -p 22222 localhost
    – Vitaly
    Jan 29, 2019 at 20:13
  • problem is if you want to ssh out, it will also use port 22222
    – sonjz
    Oct 5, 2021 at 3:54
  • To address the problem @sonjz points out, you can edit /etc/ssh/ssh_config to add " Port 22" so that outbound ssh still uses port 22. [edit: as pointed out in another answer...]
    – Neal Young
    Oct 28, 2021 at 18:04
2

To follow-up on Hogstrom's response you may want to additionally edit the /etc/ssh/ssh_config and uncomment the following :

Port 22

So when you attempt to ssh to a normal host (running port 22) that is chosen instead of the new ssh default that you set in /etc/services.

2

Listening on port 22 is handled by launchd, which is the equivalent of Unix's init, inetd and cron. Inetd can be configured to listen on a port and launch the appropriate command, rather than the command starting in daemon mode, same with launchd.

You'll notice that if you run a ps -ax | grep sshd none of them are listening on port 22. You'll also notice that if you run an lsof on the launchd process you'll see it listening on port 22.

launchd is configured via a bunch of .plist files in /Library/LaunchDaemons and /System/Library/LaunchDaemons The system directory being installed with the OS, and the non system is added after installation.

The configuration you're after is /System/Library/LaunchDaemons/ssh.plist

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
        <key>Disabled</key>
        <true/>
        <key>Label</key>
        <string>com.openssh.sshd</string>
        <key>Program</key>
        <string>/usr/libexec/sshd-keygen-wrapper</string>
        <key>ProgramArguments</key>
        <array>
                <string>/usr/sbin/sshd</string>
                <string>-i</string>
        </array>
        <key>Sockets</key>
        <dict>
                <key>Listeners</key>
                <dict>
                        <key>SockServiceName</key>
                        <string>ssh</string>
                        <key>Bonjour</key>
                        <array>
                                <string>ssh</string>
                                <string>sftp-ssh</string>
                        </array>
                </dict>
        </dict>
        <key>inetdCompatibility</key>
        <dict>
                <key>Wait</key>
                <false/>
                <key>Instances</key>
                <integer>42</integer>
        </dict>
        <key>StandardErrorPath</key>
        <string>/dev/null</string>
        <key>SHAuthorizationRight</key>
        <string>system.preferences</string>
        <key>POSIXSpawnType</key>
        <string>Interactive</string>
</dict>
</plist>

If you don't want it listening on port 22 anymore, you can just edit this file. Otherwise copy it, with a different name, to /Libary/LaunchDaemons and edit that copy. cp /System/Library/LaunchDaemons/ssh.plist /Library/LaunchDaemons/ssh-alt.plist

Edit the line just under the SockServiceName it is a string of the port number or port alias, hence why changing /etc/services works. You can either add the numeric port you want to the array in the plist or add the numeric port you want to /etc/services with your own identifier, like my-ssh-alt and change to that in the plist.

If you've copied to a new plist, Load the new plist;

sudo launchctl load -w /Library/LaunchDaemons/ssh-alt.plist

Else reload the ssh config, which I'll just copy from the other answer;

Enter the following command to stop it: sudo launchctl unload /System/Library/LaunchDaemons/ssh.plist

Now enter the following command to start SSH again: sudo launchctl load -w /System/Library/LaunchDaemons/ssh.plist

1
  • 1
    Launching sshd with a custom port via a custom launchctl plist stopped working for me when I upgraded to macOS Monterey (Oct 2021). Specifically, connections in to sshd on the port are now terminated with the error 'kex_exchange_identification: read: Connection reset by peer'. Editing /etc/services still seems to work as suggested in other answers.
    – Neal Young
    Oct 28, 2021 at 18:06
1

Script

Just threw together a small script based on what has been shared here in the forum (specifically silicontrip).

ssh_set_port() {
  # Ensure a port is specified
  if [ -z "$1" ]; then
    printf "No port specified...\n"
    return 1
  fi

  # Ensure original file exists
  if [ ! -f "/System/Library/LaunchDaemons/ssh.plistz" ]; then
    printf "SSH process definition not found in default location:\n%s\n" "/System/Library/LaunchDaemons/ssh.plist"
    return 1
  fi

  PORT="$1"
  FIND="<string>ssh<\/string>"
  REPLACE="<string>${PORT}<\/string>"

  # Unload existing service if a file already exists
  # (errors may occur if service is already unloaded - these can be ignored))
  if [ -f "/Library/LaunchDaemons/ssh.plist" ]; then
    sudo launchctl unload /Library/LaunchDaemons/ssh.plist > /dev/null 2>&1
  fi

  # Copy original SSH process definition and replace the port value
  sudo cp /System/Library/LaunchDaemons/ssh.plist /Library/LaunchDaemons/ssh.plist
  sudo sed -i '' "1,/${FIND}/s/${FIND}/${REPLACE}/" /Library/LaunchDaemons/ssh.plist

  # Load the service
  sudo launchctl load -w /Library/LaunchDaemons/ssh.plist

  printf "SSH port successfully updated to '%s'\nRun the following command to verify the port:\n\n  %s\n" "$1" "sudo lsof -iTCP -sTCP:LISTEN -n -P"
}

Usage

You can include the logic in a stand-alone script or include it in your shell profile (eg. ~/.zshrc, ~/.bashrc, etc..). I have included it in my shell profile. Example usage:

ssh_set_port 2200

Note

The launchctl subcommands load and unload are being deprecated, but still work in the latest version as of writing (good reference with link to documentation).

I plan to carry this around with the rest of my shell aliases.
Thank you all for the great answers 🙏

0

To add to silicontrip's answer, if you wanted both the original and new ports you can add an "Alternate Listeners" key (or any label apparently) in the Sockets section of ssh.plist:

...
 <key>Sockets</key>
 <dict>
     <key>Listeners</key>
     <dict>
          <key>SockServiceName</key>
          <string>ssh</string>
          <key>Bonjour</key>
          <array>
              <string>ssh</string>
              <string>sftp-ssh</string>
          </array>
     </dict>
     <key>Alternate Listeners</key>
     <dict>
         <key>SockServiceName</key>
         <string>(name of service)</string>
     </dict>
</dict>
...

Note that in Monterey the ProgramArguments section has changed since Big Sur (it used to call sshd directly). This resulted in a "kex_exchange_identification: read: Connection reset by peer" if you just copied an ssh.plist file from Big Sur to Monterey.

<key>ProgramArguments</key>
<array>
      <string>sshd-keygen-wrapper</string>
</array>

My problem with modifying /System/Library/LaunchDaemons/ssh.plist is that I don't want to break the apfs seal on the volume.

I created a copy of the ssh.plist in /Library/LaunchDaemons/ssh_alt.plist with a different Label and started it with

sudo launchctl load -w /Library/LaunchDaemons/ssh_alt.plist

and it seems to persist across boots so far.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.