SSH Reverse Tunnel on Mac OS X

Phone Home

original source

I want to always be able to securely connect to my Mac Book Pro anywhere in the world. The following guide will enable me to connect to the laptop if I leave it at home, leave it at work, or in the unfortunate event that someone steals it and the thief defeats File Vault full disk encryption. This phone home technique will work as long as the laptop can create an outgoing ssh connection. It will work behind NAT routers, but probably not behind strong corporate firewalls that only allow web proxy traffic out (something like corkscrew could help with this if you need it).

A lot of other people have written guides about how to do this and have done it wrong. For example, people play tricks to avoid executing arbitrary commands by forcing ssh to execute something like /usr/bin/false. If you don’t to execute, don’t execute anything. Don’t pretend not allocating a pty is secure, it’s not, just prevents the obvious shell logins. Furthermore, use the Mac OS X launchd correctly to create and maintain connections automatically, don’t fork the ssh client, rely on the launchd KeepAlive feature.

In addition to the obvious purpose of connecting to a remote laptop that moves around alot, I’ve used this technique to circumvent poorly configured firewalls and to bring ad-hoc servers in other countries online before jumping on a transpacific flight with only 30 minutes to implement a “vpn”.

Fun stuff.

Setup The Server

First step is to setup an authorized_keys file to allow logins for a private key, run the following on the client machine (Mac OS X laptop in my case). If Elliptic Curve DSA (ECSDA) is available and supported on both ends, it can be used by adding “-t ecdsa” to the ssh-keygen command. Example default dsa key generation:

client $ ssh-keygen -f ~/.ssh/servername-home-fwd
Generating public/private rsa key pair.
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /Users/user/.ssh/servername-home-fwd.
Your public key has been saved in /Users/user/.ssh/
The key fingerprint is:
3b:c7:7f:77:49:5d:5f:35:1d:82:ad:20:c8:7d:1e:d2 user@client
The key's randomart image is:
+--[ RSA 2048]----+
|    . o .   o. .o|
|     o + E . ...o|
|        = o .   o|
|         . .    o|
|        S       =|
|         o     .o|
|        o o   . .|
|         o .  ..o|
|            .. ..|

Now a private key has been generated, read the public key on the client and copy it:

client $ cat ~/.ssh/

On the server paste the private key on it’s own line in ~/.ssh/authorized_keys or use ssh-copy-id for easy installation if available. Prefix the public key with command="",no-pty to prevent any commands from being executed using this private key and to prevent wasting resources for a pty (not a security feature). Optionally add a comment to the end so you can keep track of the purpose of this installed public key. The result should look something like the following:

server $ cat ~/.ssh/authorized_keys
command="",no-pty ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDUWUrEMfnP65pGSwdLFP323K7AG8Ah5JC0ArC660z7V0i3wSBf1lXnN3coc/ndw7C7NQw+wLTNp7FjkxheyNiMhf65pZI41HR+JJleQsAwCCpFwftKutfknpvai6FRkfE173iXGAU5YFGmlHBo3oAiSn09ZOAXieZ0+Sr0ZEAF5gJLLG4E94JUdEtCXcLYPWu0YX//k+PVvaK1/IjJ6gJGbzT+KA5Gv4VZecL+UC7VvgtcO6UBVNHo4eQBPdhiT1Asg71e3io2y+AwGg0J2smBcuhmrf3ud/BFNgHFjF3a7ilF2Hh7AYV16rRJrOazH83IBzgiBysiakF3OSHQXozV client@server:phone-home

Now you’ve allowed any remote machine to login to the user machine on the server with the private key generated above (~/.ssh/servername-home-fwd). The login won’t be able to run any commands and won’t be able to allocate a pty (which probably is pointless after no command execution, better safe then sorry).

Additionally, if it’s possible to modify the sshd_config file on the server, it should be modified to send ssh alive packets (similar to TCP keep alive) packets to the client. Root access on the server is typically necessary for this. On an Ubuntu server this can be accomplished with:

server $ echo "ClientAliveInterval 60" | sudo tee -a /etc/ssh/sshd_config
server $ sudo restart ssh
ssh start/running, process 6446

The above modification will ping the client every 60 seconds the connection is idle as defined the ClientAliveInterval which is disabled by default. If ClientAliveCountMax (defaults to 3) number of pings go unanswered, the server will drop the connection. This is critical to detecting the remote client has disappeared and freeing up the port defined below for a reconnect from the client when it comes back online. It isn’t strictly necessary as the server will drop the connection after a while on its own, but significantly speeds up reconnects.

Test the Server Setup from the Client

Verify that the server is correctly setup by running the ssh command manually. This is important for two reasons:

  1. The first time the ssh client connects to the server, it by default needs the user to manually accept the host’s ssh key. This will never succeed in the automated launchd task described below and must be done ahead of time.
  2. Verify nothing is broken.

To test the configuration, run the following:

client $ ssh -i ~/.ssh/servername-home-fwd -NT -R 12345:localhost:22 remoteuser@servername

The result should be that the command blocks and appears to hang. At the same time, verify that port 12345 is now listening on the server. If port 22 on the client is in fact the ssh server this can be quickly tested by reading some data over the connection such as the SSH server’s version using netcat:

server $ netcat localhost 12345

After testing is complete, use CTRL-c to break both the ssh and netcat command. If something didn’t work, double check the steps above for errors before proceeding.

Setup The Client on OS X

Apple uses launchd to launch system services. The purpose of launchd is very similar to Ubuntu’s upststart and Freedesktop’s systemd in that it’s goal is to start services and manage them.

In a nuthsell the primary features needed for this phone home script are:

  1. Run at start-up without user intervention
  2. Run as another user
  3. Restart a process when it dies

First, we need to setup a plist file for OS X, create the following file and modify it as necessary for items such as the user and host name, place the following @ /Library/LaunchDaemons/

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "">
<plist version="1.0">
	  <string>-o ServerAliveInterval=60</string>
	  <string>-o ExitOnForwardFailure=yes</string>
	  <string>-R 12345:localhost:22</string>

This will switch to Username user on the Mac OS X client and then attempt to run the ssh command described by ProgramArguments. SSH command description:

  • -N – Don’t run a remote command. Attempting to run a remote command will fail due to the restrictions imposed by the authorized_keys file.
  • -T – Disable pty allocation. There is no need for this when only port-forwarding is desired.
  • -C – Request compression. This is optional, typically my processors out pace my network speed, especially when on 4G/LTE networks. This is optional.
  • -o ServerAliveInterval=60 – The client will attempt to send pings to the server ever 60 seconds. After 3 failed pings (Default ServerAliveCountMax is 3), the client will drop the connection and ssh with return.
  • -o ExitOnForwardFailure=yes – If port forwarding fails to get setup due to something like another process (or old ssh process) being bound to the hardcoded port, fail and return.
  • -i /Users/<username>/.ssh/servername-home-fwd – Use the specified ssh private key (generated above) for this connection. This must be the the private key for the public key in the authorized_keys file on the server.
  • -R 12345:localhost:22 – Remotely forward the localhost port 22 (sshd) to the server’s port 12345. This allows the server to connect to the client’s ssh port.
  • remoteuser@servername – Connect to ssh servername with user remoteuser.

When the ssh tunnel dies due to a change in network connection or fails to setup the initial port forwarding as requested, the launchd manager will restart it in 10 seconds due to the KeepAlivekey. The default restart time is 10 seconds and should work just fine for this task.

The RunAtLoad does as the name suggests and runs this launchd task at load and boot time.

If all goes according to plan, the launchd plist can be loaded and it will connect to the server:

sudo launchctl load /Library/LaunchDaemons/

Launchd will start up ssh as directed by the plist and connect to the remote server. The netcat command described above can be run on the remote server to verify it’s working. If it’s not working, check the logs on the client and server under /var/log for hints as to what went wrong. After modifying the plist file, be sure to unload it and then reload it by changing “load” to “unload” in the command described above followed again by “load.”

If it is working, your Mac OS X will automagically open a reverse tunnel to the server described above. You can then login to the client Mac OS X machine by using ssh -p12345 user@localhost on the server. Note that the host will always be localhost due to port forwarding, and the user is the user on the Mac OS X client.

Doing Even More

I’m looking only to ssh back in to my laptop, but with a few modifications to the launchd plist, it’s possible to use this to setup ssh vpn tunnels using tun interfaces. Refer to the ssh man page for the the “-w” option. You’ll need to setup routes and what not to fully use it. Things get complicated quick and many times OpenVPN is a better solution.

Other uses? Let me know!

Создать новый файл в Finder (+ automator)

Было бы неплохо правой кнопкой мыши в Finder создать новый файл, как самизнаетегде.
Достичь этого можно с помощью создания Automator Service.

Создаем новый сервис:

How to Create New File in Finder action

Единствено, чтобы вызвать этот сервис, нужно кликнуть на фолдере, в котором мы создаем файл.

Thunderbolt storage для бедных (updated)

Если у вас новый Mac Pro, у которого очень мало по умолчанию внутреннего стораджа, а вам нужно вести монтаж в Final Cut Pro X (или любой другой, которая нравится) или играть в игрушки, и у вас нет дополнительных денег на что-нибудь типа Promise Pegasus2 M4/M6/M8, то вот более менее самое дешевое решение для расширения хранилища, существующее на данный момент.

Решение подойдет так же для пользователей iMac/Macbook Air/Pro.

Берем корзину HighPoint RocketStor 5212 Dual-Bay Thunderbolt Storage Dock стоимостью 10 075 ₷, thunderbolt кабель + желаемые HDD.
По цене/качеству выбрал SanDisk Extreme Pro 480 c 90000 IOPS и Seagate Constellation ES.3 7200 RPM 128MB cache (enterprise capacity) на 3TB (размер можно брать любой, какой больше нравится).

Получается такая штука (на картинке 2 стакана):

RocketStor thunderbolt


Скорость: SSD 530 MBps чтение/380 MBps запись, HDD 170/160 MBps.

Для особо страждующих, можно сконфигурировать  2 SSD в софтверный RAID 1, скорости получаются такие:

RAID 1 two SanDisk SSD Pro

Организация монтажного места:

  • система и весь софт стоят на внутреннем SSD
  • для скорости, исходники можно держать на SSD, а кэши класть на HDD. В этом случае скорость рендера будет максимальной, скорость экспорта – ограничение скорости чтения HDD при выгонке на SSD.
  • или можно наоборот: кэши на SSD, исходники на HDD. В этом случае скорость рендера будет ниже, зато скорость экспорта из FCPX будет максимальная, т.к. отрендеренные кадры уже лежат на SSD.

Если проект получается слишком большой, то вместо SSD можно использовать HDD, на одном держать кэши, на другом исходники.

Upd: пришла запоздалая мысль, что из этой конструкции можно просто Fusion Drive сделать же ш!

(примечание: FD2 у меня называется 2й стакан с дисками для fusion drive, вы можете называть диски как угодно)

# diskutil cs create FD2 disk2 disk3
Started CoreStorage operation
Unmounting disk2
Repartitioning disk2
Unmounting disk
Creating the partition map
Rediscovering disk2
Adding disk2s2 to Logical Volume Group
Unmounting disk3
Repartitioning disk3
Unmounting disk
Creating the partition map
Rediscovering disk3
Adding disk3s2 to Logical Volume Group
Creating Core Storage Logical Volume Group
Switching disk2s2 to Core Storage
Switching disk3s2 to Core Storage
Waiting for Logical Volume Group to appear
Discovered new Logical Volume Group "81647343-A688-42EF-931E-5280482C11C2"
Core Storage LVG UUID: 81647343-A688-42EF-931E-5280482C11C2
Finished CoreStorage operation

# diskutil cs createVolume 81647343-A688-42EF-931E-5280482C11C2 jhfs+ FD2 100%
The Core Storage Logical Volume Group UUID is 81647343-A688-42EF-931E-5280482C11C2
Started CoreStorage operation
Waiting for Logical Volume to appear
Formatting file system for Logical Volume
Initialized /dev/rdisk4 as a 3 TB case-insensitive HFS Plus volume with a 270336k journal
Mounting disk
Core Storage LV UUID: 63908B8B-2C26-4E68-A5B3-28250DC7A679
Core Storage disk: disk4
Finished CoreStorage operation

В итоге у нас в системе появился диск под названием FD2 и разделом FD2 (на скрине раздел у меня называется 3.5TBFD2):

Fusion Drive из SSD и HDD

Скорость чтения/записи равна скорости чтения/записи самого быстрого диска в fusion drive, в нашем случае это SSD:

DiskSpeedTest fusion drive

Switch use of F-keys from command line in OS X

#OSX #commandline #macosx
Кто часто работает в командной строке и кому нужны клавиши F1-F12, но при этом периодически пользовать OSX в «домашних» целях – небольшой скриптик, который позволяет переключать поведение клавиатуры. Открываем AppleScript Editor, создаем новый скрипт, копируем туда код. Экспортируем как Application (run-only).

--Enable/Disable "Use all F1, F2, etc. keys as standard function keys" option in Keyboard & Mouse Preference pane and close System Preferences
tell application "System Events"
tell application "System Preferences"
reveal anchor "keyboardTab" of pane ""
end tell
click checkbox 1 of tab group 1 of window 1 of application process "System Preferences"
end tell
if application "System Preferences" is running then
tell application "System Preferences" to quit
end if

Hint: если у вас OS X 10.9 Mavericks, надо открыть настройки безопасности и разрешить доступ к Accessibility фичам:
Accessibility settings

Конвертируем ссылки на windows-шары в правоверные OS X ссылки

Ссылки на windows шары (share, ресурсы): \\\share

В OS X/Unix ссылки выглядят немного по другому: smb://

Запускаем Automator, создаем новый сервис:

Create automator windows share link converter

sed -e 's/\\/\//g' | sed -e 's/^/smb:/'

Сохраняем сервис под подходящим названием (например «convert windows share link») и пробуем: выделяем windows-ссылку  -> правой кнопкой мыши -> в списке сервисов выбираем наш сервис (convert windows share link). После этих действий в буфере обмена будет ссылка на windows-ресурс правоверный для мака: smb://

Как поменять hostname, computername и bonjour name в OS X

ComputerName is the so-called “user-friendly” name for the Mac, it’s what will show up on the Mac itself and what will be visible to others when connecting to it over a local network. This is also what’s visible under the Sharing preference panel.

scutil --set ComputerName "MacBook Willy"

HostName is the name assigned to the computer as visible from the command line, and it’s also used
by local and remote networks when connecting through SSH and Remote Login.

scutil --set HostName "centauri"

LocalHostName is the name identifier used by Bonjour and visible through file sharing services likeAirDrop

scutil --set LocalHostName "MacBookPro"


scutil --get HostName

Если вдруг Mac OS X не видит 802.11n и/или 5 ГГц WiFi сетьи-wifi-5-ГГц.35327/
Отключение 802.11d


Удаляем дубликаты из меню «Открыть с помощью» (Open with)

Периодически и макоси сносит крышу, в результате в меню «Открыть с помощью» появляется странное месиво из программ:

Избавляемся от этим командой:

/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/LaunchServices.framework/Versions/A/Support/lsregister -kill -r -domain local -domain user;killall Finder;echo "Open With has been rebuilt, Finder will relaunch"

или двумя:

lsregister -kill -r -domain local -domain user

killall Finder



OS X Tweaks

Большое количество скрытых твиков для OS X, прямо раздолье.
# включить полный доступ к кнопкам с клавиатуры (например с помощью Tab ходить по модальным окнам)
# Enable full keyboard access for all controls (e.g. enable Tab in modal dialogs
defaults write NSGlobalDomain AppleKeyboardUIMode -int 3
# включить субпиксельный рендер шрифтов на не-apple экранах
# Enable subpixel font rendering on non-Apple LCDs
defaults write NSGlobalDomain AppleFontSmoothing -int 2
# включить 2d док
# Enable the 2D Dock
defaults write no-glass -bool true