61

I want to change which port sshd uses on a Mac server. For example, let's say from port 22 to port 32.

Editing /etc/sshd_config does not seem to work. Does anyone know how to change it? I'd prefer a method that's compatible with all OSX versions (or as many as possible, at least).

HopelessN00b
  • 53,385
  • 32
  • 133
  • 208
Alexander Artemenko
  • 1,323
  • 3
  • 13
  • 13
  • Also note that `/usr/libexec/sshd-keygen-wrapper` (shown in the plists below) can start a different SSH than specified in the plist itself. If you cat it, it always starts `/usr/sbin/sshd`. –  Aug 22 '15 at 00:22
  • Launching sshd with custom port via custom launchctl plist stopped working for me (ssh connections errored out) when I upgraded to Monterey (Oct 2021).. Editing /etc/services and launching sshd by enabling standard "sharing -> remote login" preference did work (but see caveats at https://superuser.com/q/1398824/199692). – Neal Young Oct 28 '21 at 18:21

4 Answers4

67

Every previous answer is working (as google suggest too), but they are dirty and inelegant.

The right way to change the listening port for a launchd handled service on Mac OS X is to make the changes the dedicated keys available in ssh.plist

So the solution is as simple as to use the port number instead of the service name.

An excerpt from my edited /System/Library/LaunchDaemons/ssh.plist:

    <key>Sockets</key>
    <dict>
            <key>Listeners</key>
            <dict>
                    <key>SockServiceName</key>
                    <string>22022</string>
                    <key>SockFamily</key>
                    <string>IPv4</string>
                    <key>Bonjour</key>
                    <array>
                            <string>22022</string>
                    </array>
            </dict>
    </dict>

Note:

To be able to edit this file on El Capitan, Sierra and probably future versions as well, you need to disable SIP (System Integrity Protection). See How do I disable System Integrity Protection (SIP).

For Catalina, even after disabling SIP, the volumes are unwritable. Use sudo mount -uw / in order to enable writing to /System. Do the change then restore SIP and reboot.


The above edit will also force sshd to listen only over IPV4.

After making any changes to ssh.plist, the file must be reloaded as follows:

sudo launchctl unload /System/Library/LaunchDaemons/ssh.plist
sudo launchctl load /System/Library/LaunchDaemons/ssh.plist

Note that using launchctl stop ... and launchctl start ... will NOT reload this file.

The man page with more information can be found by typing man launchd.plist or using this link.

drAlberT
  • 10,871
  • 7
  • 38
  • 52
  • This is indeed elegant. Where does this launchd.plist get edited or saved to? – Dan Rosenstark Apr 03 '11 at 13:54
  • 3
    @Yar launchd.plist is the name of the manual. The change is in the ssh.plist file in /System/Library/LaunchDaemons – Martijn Pieters Apr 20 '11 at 19:55
  • 1
    I note that you need to either restart the machine, or restart the ssh service with launchctl. – Danny Staple Dec 29 '11 at 08:31
  • It is also worth reading the other answers on this page to find out how to add multiple SSH ports and/or add named service ports (eg: `secret-ssh`), which combined with this answer seems like the "most elegant" way to add a port, and additionally should keep IPV6 working. – cwd May 11 '14 at 13:18
  • 5
    Grr... every upgrade of OS X (Yosemite in this case) discards this change, requiring me to remember what I did the last time to fix it, and where I found this info. Thanks for the fix! – Michael Nov 12 '14 at 02:08
  • Same here @Michael - good thing I upvoted – Mike Causer Nov 16 '14 at 14:15
  • I've adapted this answer to listen only on a specific IP address (by specifying SockNodeName), which is great—but I find that I must manually unload/reload the plist after every reboot in order for the ssh service to become available (at any address). My *guess* is that the specified SockNode is not available when the plist is read during boot, which results in it being discarded; when manually loaded post-boot, the SockNode is available and it works as desired. Any suggestions for a fix? – eggyal Nov 20 '14 at 15:01
  • +1 Works great for me on Yosemite. – Cyclonecode Dec 12 '14 at 02:55
  • Would you have any idea how to do this for two ports? So it accepts connections on both port 22 and 22022 for example? – Hassan Feb 26 '15 at 09:35
  • 2
    @Hassan you have to start two ssh instances .. i.e. add another Listener with different SockServiceName name and value – drAlberT Feb 26 '15 at 17:49
  • 5
    Notice that on the El Capitan version (and probably in future versions as well) you need to disable SIP (System Integrity Protection) before you can edit the file, see: http://apple.stackexchange.com/a/208481 – jcfrei Oct 06 '15 at 14:25
  • What is the purpose of the Bonjour key? –  Jan 02 '16 at 19:26
  • @jww to announce the service with the correct updated port – drAlberT Mar 08 '16 at 11:05
  • 1
    @jcfrei Thanks, I have incorporated your comment into the answer. – Carl Nov 11 '16 at 16:16
  • This isn't elegant, it's convoluted and reminds me of how much of a shiny piece of overpriced trash Mac OS X is. This solution requires one to have special knowledge of how Mac OS X internals work and apparently isn't preserved across upgrades. Some user experience that is. Elegant would be allowing you to just change the normal sshd config file and have it work the way it's supposed to. People like to make fun of Linux users for how much time is wasted trying to get something working. Well I've already wasted an hour trying to just change the sshd port on Mac OS X and it's still not working. – deltaray Feb 09 '19 at 14:36
  • 1
    For Catalina, even after disabling csrutil, the volumes are unwritable. Use the following in order to write to /Systems/: "sudo mount -uw /" – Manish Oct 08 '20 at 10:36
  • 1
    @Manish Thanks, I have incorporated your comment in the answer too. – drAlberT Oct 08 '20 at 17:53
18

If you want sshd to listen on an additional port, you can add multiple entries to the Sockets dictionary.

Example:

<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>Listeners2</key>
        <dict>
                <key>SockServiceName</key>
                <string>22022</string>
        </dict>
</dict>
raimue
  • 355
  • 2
  • 4
6

From what I read (and experienced) so far, there are three main methods which can be used:

  1. change the setting in the ssh.plist file;
  2. change the setting in the /etc/services file;
  3. change the setting in the /etc/sshd.conf file.

Another way to do it, which I personally by far prefer to all and each of these methods, because it avoids messing around with Mac OS X system files is using socat to redirect port 22 to whichever port you want.

  1. Download socat: http://www.dest-unreach.org/socat/download/socat-1.7.3.2.tar.gz
  2. Move the tar.gz file to your /usr/local/ directory (sudo mv ./socat-1.7.3.2.tar.gz /usr/local/bin/socat-1.7.3.2.tar.gz)
  3. Go to your /usr/local/bin directory (cd /usr/local/bin)
  4. Uncompress: sudo tar -xvzf socat-1.7.3.2.tar.gz
  5. Move to the uncompressed file directory: cd ./socat-1.7.3.2
  6. Run the usual configure, make and make install to install socat (sudo ./configure && sudo make && sudo make install)
  7. Redirect port 22 (default ssh) to any port you want (in the following ex., 2222) using the correct option by sending a socat call (sudo socat TCP-LISTEN:2222,reuseaddr,fork TCP:localhost:22)

You're done and your mac os x system files are left unchanged. In addition, this method works not only on Snow Leopard, but on all versions of Mac OS X and also on any machine on which socat may run.

The last thing you need to do if you use a router/firewall is to include the correct redirect commands in your router/firewall.

Also, it avoids getting stuck into the debate whether the ssh.plist method, the services method or the whatever method is better, more elegant or worse than the other.

You may also easily prepare a script that runs at start up to rebuild the socat redirection each you restart your machine. Place this in /Library/LaunchDaemons/com.serverfault.sshdredirect.plist:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>com.serverfault.sshdredirect</string>
    <key>KeepAlive</key>
    <dict>
        <key>NetworkState</key>
        <true/>
    </dict>
    <key>RunAtLoad</key>
    <true/>
    <key>ProgramArguments</key>
    <array>
        <string>/usr/local/bin/socat</string>
        <string>TCP-LISTEN:2222,reuseaddr,fork</string>
        <string>TCP:localhost:22</string>
    </array>
</dict>
</plist>

Use sudo launchctl load -w /Library/LaunchDaemons/com.serverfault.sshdredirect.plist to load it. It'll automatically load on future reboots.

In addition, you can also improve security by (i) setting your firewall to block any connections to your port 22 from any other interface than the loopback (127.0.0.1) and (ii) make a similar change in your sshd.conf file to have ssh listen on the loopback only.

Enjoy.

Cedric
  • 1
  • 1
  • 2
  • 3
    Editing the `/etc/services` file is a bad idea - it will affect things like SSH key login to your github or bitbucket accounts, which will seek to connect to the new port and fail. – ccpizza May 31 '14 at 00:23
  • 1
    You should build in a scratch directory. Then use `sudo` to install. You should not build with elevated privileges. –  Aug 22 '15 at 22:37
  • This also works on El Capitan where SIP makes changing /System/Library/LaunchDaemons/ssh.plist difficult. But, on El Capitan the "NetworkState" key is deprecated; I suggest `KeepAlive`. – Robert Tupelo-Schneck Oct 20 '15 at 13:25
  • with latest osx sierra, the working version is: https://gist.github.com/shanmuha/d97e9f1abdaf1c9b804f748f332a3ffd – Shanmu Mar 13 '17 at 17:42
1

I couldn't see this documented anywhere properly in a man page, but if you want to do nothing more than add an extra listener, you can use an array of listeners and have an extra dict. This doesn't require editing /etc/services if you use the port directly (but remember to open up the port on your firewall!)

    <key>Listeners</key>
    <array>
    <dict>
        <key>Bonjour</key>
        <array>
            <string>ssh</string>
            <string>sftp-ssh</string>
        </array>
        <key>SockServiceName</key>
        <string>ssh</string>
    </dict>
    <dict>
        <key>SockServiceName</key>
        <string>22222</string>
    </dict>
    </array>