<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>MacOS on David Hamann</title><link>https://davidhamann.de/tags/macos/</link><description>Recent content in MacOS on David Hamann</description><generator>Hugo</generator><language>en</language><copyright>&amp;copy; David Hamann</copyright><lastBuildDate>Sun, 11 Oct 2020 00:00:00 +0000</lastBuildDate><atom:link href="https://davidhamann.de/tags/macos/feed.xml" rel="self" type="application/rss+xml"/><item><title>Connecting to a host service from within a container using Docker for Mac</title><link>https://davidhamann.de/2020/10/11/connect-to-docker-host-macos/</link><pubDate>Sun, 11 Oct 2020 00:00:00 +0000</pubDate><guid>https://davidhamann.de/2020/10/11/connect-to-docker-host-macos/</guid><description>&lt;h3 id="tldr"&gt;TL;DR&lt;/h3&gt;
&lt;p&gt;Use &lt;code&gt;host.docker.internal&lt;/code&gt;.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;When you are running Docker on Linux and want to access services on the host from within a container, you can make use of the &lt;code&gt;docker0&lt;/code&gt; bridge interface (&lt;code&gt;ip a s docker0&lt;/code&gt;). This does not work when running Docker for Mac as the interface is inside a separate virtual machine (which you can confirm by getting a shell in that vm: &lt;code&gt;screen ~/Library/Containers/com.docker.docker/Data/vms/0/tty&lt;/code&gt;) and thus not visible on the local host.&lt;/p&gt;
&lt;p&gt;To workaround this, a reliable way to get to the macOS host is to use the &lt;code&gt;host.docker.internal&lt;/code&gt; DNS name which will always resolve to an IP where the host is reachable.&lt;/p&gt;
&lt;h3 id="example"&gt;Example&lt;/h3&gt;
&lt;p&gt;Let&amp;rsquo;s say you want to run some script in the container that connects to a specific HTTP target and want to observe the requests through a proxy running on your macOS machine (e.g. Burp). Then you would do:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;# Run some container
docker run -it alpine:latest /bin/sh

# ... install the dependencies for your script ...
# then run the script and target your local (!) intercept proxy
python3 exploit.py http://host.docker.internal:8081/whatever

# now observe the request in the proxy application running on the host
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;img alt="Capturing the request" loading="lazy" src="https://davidhamann.de/images/docker-mac-host-proxy.png"&gt;&lt;/p&gt;</description></item><item><title>UnicodeError when running Python script via macOS LaunchAgent</title><link>https://davidhamann.de/2018/12/07/python-unicodeerror-launchagent-locale/</link><pubDate>Fri, 07 Dec 2018 00:00:00 +0000</pubDate><guid>https://davidhamann.de/2018/12/07/python-unicodeerror-launchagent-locale/</guid><description>&lt;p&gt;If you are getting UnicodeErrors when reading/manipulating files using a Python script launched by a LaunchAgent or crontab, the problem might lie in the &amp;ldquo;current locale encoding&amp;rdquo;.&lt;/p&gt;
&lt;h3 id="sample-script"&gt;Sample script&lt;/h3&gt;
&lt;p&gt;Let&amp;rsquo;s assume you have the following code in a script set up to be launched by a LaunchAgent (also see &lt;a href="https://davidhamann.de/2018/03/13/setting-up-a-launchagent-macos-cron"&gt;my article on LaunchAgents&lt;/a&gt;):&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nb"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;some_path_to_file&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;read&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Let&amp;rsquo;s also assume that &lt;code&gt;some_path_to_file&lt;/code&gt; points to a &lt;code&gt;txt&lt;/code&gt; file containing some emojis (hey, why not? 😎) or some other unicode characters.&lt;/p&gt;
&lt;p&gt;Running a file with the above code snippet in your terminal session will probably not cause any issues, because – most likely – everything is set up to use utf-8 as the default encoding: &lt;code&gt;python3 my_snippet.py&lt;/code&gt;. Cool!&lt;/p&gt;
&lt;p&gt;However, when the script is launched by a LaunchAgent, you may get an error.&lt;/p&gt;
&lt;h3 id="unicodeerror-cant-decode-byte"&gt;UnicodeError: can&amp;rsquo;t decode byte&lt;/h3&gt;
&lt;p&gt;The error could look something like this:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;Traceback (most recent call last):
 [...]
UnicodeDecodeError: &amp;#39;ascii&amp;#39; codec can&amp;#39;t decode byte 0xf0 in position 13: ordinal not in range(128)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Why is this happening?&lt;/p&gt;
&lt;h3 id="all-about-the-context-or-whats-my-locale"&gt;All about the context, or: what&amp;rsquo;s my locale?&lt;/h3&gt;
&lt;p&gt;Running the script in your terminal session and running it via a LaunchAgent might mean you/Python are reading different locale/encoding settings, as can be seen by the return value of &lt;code&gt;getpreferredencoding&lt;/code&gt; from the &lt;code&gt;locale&lt;/code&gt; module.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; locale.getpreferredencoding(False)
`UTF-8`
or
`US-ASCII`
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;From the &lt;a href="https://docs.python.org/3/library/locale.html"&gt;Python help&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Return the encoding used for text data, according to user preferences. User preferences are expressed differently on different systems, and might not be available programmatically on some systems, so this function only returns a guess.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Now, let&amp;rsquo;s look at what happens when we don&amp;rsquo;t explicitly specify the &lt;code&gt;encoding&lt;/code&gt; argument for the &lt;code&gt;open&lt;/code&gt; function:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;In text mode, if encoding is not specified the encoding used is platform dependent: locale.getpreferredencoding(False) is called to get the current locale encoding.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;If the current locale cannot be determined, it will fall back to C locale &lt;code&gt;US-ASCII&lt;/code&gt;. &lt;code&gt;local.getlocale()&lt;/code&gt; in this case will likely also just return &lt;code&gt;(None, None)&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id="the-solution-always-specify-the-encoding"&gt;The solution: always specify the encoding!&lt;/h3&gt;
&lt;p&gt;If you just want to make sure that you can read your Unicode file properly, be explicit about the encoding, i.e.:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nb"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;some_path_to_file&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;encoding&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;utf-8&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;read&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&amp;hellip; and the problem should go away.&lt;/p&gt;</description></item><item><title>Using launchd agents to schedule scripts on macOS</title><link>https://davidhamann.de/2018/03/13/setting-up-a-launchagent-macos-cron/</link><pubDate>Tue, 13 Mar 2018 00:00:00 +0000</pubDate><guid>https://davidhamann.de/2018/03/13/setting-up-a-launchagent-macos-cron/</guid><description>&lt;p&gt;Even though &lt;code&gt;launchd&lt;/code&gt; has been around for quite some time now, I was still using &lt;code&gt;crontab&lt;/code&gt; for scheduling some of my scripts until recently. Since &lt;code&gt;launchd&lt;/code&gt; LaunchAgents can do much more and don&amp;rsquo;t expect your computer to be running at all times, it&amp;rsquo;s time to start using them more 😎.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s see how we can easily set up a LaunchAgent to run a Python script for the current user in regular intervals:&lt;/p&gt;
&lt;h2 id="write-a-plist-for-your-agent"&gt;Write a plist for your agent&lt;/h2&gt;
&lt;p&gt;Unlike crontab jobs, LaunchAgents are written in (quite verbose) plist XML. We define a &lt;code&gt;Label&lt;/code&gt; according to the name of our agent and then go on describing how it should behave (which program to run, what arguments, when to run it, etc.).&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s is an example with the filename &lt;code&gt;de.davidhamann.my-program.plist&lt;/code&gt; which we will place in &lt;code&gt;~/Library/LaunchAgents&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-xml" data-lang="xml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;&amp;lt;?xml version=&amp;#34;1.0&amp;#34; encoding=&amp;#34;UTF-8&amp;#34;?&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;&amp;lt;!DOCTYPE plist PUBLIC &amp;#34;-//Apple//DTD PLIST 1.0//EN&amp;#34; &amp;#34;http://www.apple.com/DTDs/PropertyList-1.0.dtd&amp;#34;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;&amp;lt;plist&lt;/span&gt; &lt;span class="na"&gt;version=&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;1.0&amp;#34;&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;&amp;lt;dict&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;key&amp;gt;&lt;/span&gt;Label&lt;span class="nt"&gt;&amp;lt;/key&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;string&amp;gt;&lt;/span&gt;de.davidhamann.my-program&lt;span class="nt"&gt;&amp;lt;/string&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;key&amp;gt;&lt;/span&gt;ProgramArguments&lt;span class="nt"&gt;&amp;lt;/key&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;array&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;string&amp;gt;&lt;/span&gt;/usr/local/bin/python3&lt;span class="nt"&gt;&amp;lt;/string&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;string&amp;gt;&lt;/span&gt;/Users/user/path/to/my-program.py&lt;span class="nt"&gt;&amp;lt;/string&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;/array&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;key&amp;gt;&lt;/span&gt;StartInterval&lt;span class="nt"&gt;&amp;lt;/key&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;integer&amp;gt;&lt;/span&gt;30&lt;span class="nt"&gt;&amp;lt;/integer&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;&amp;lt;/dict&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;&amp;lt;/plist&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="label"&gt;Label&lt;/h3&gt;
&lt;p&gt;The first interesting element to look at is &lt;code&gt;&amp;lt;key&amp;gt;Label&amp;lt;/key&amp;gt;&lt;/code&gt;. It precedes a &lt;code&gt;string&lt;/code&gt; element which provides the unique name for our agent. This name is generally the same as our plist filename without the extension (both should follow &lt;a href="https://en.wikipedia.org/wiki/Reverse_domain_name_notation"&gt;reverse-domain&lt;/a&gt; style). The label is required and we need it to later start our agent.&lt;/p&gt;
&lt;h3 id="programarguments"&gt;ProgramArguments&lt;/h3&gt;
&lt;p&gt;Next, we define what program to run and what arguments to pass to it. In the example we will run Python3 from &lt;code&gt;/usr/local/bin&lt;/code&gt; and give it the path of our script to execute.&lt;/p&gt;
&lt;h3 id="startinterval"&gt;StartInterval&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;StartInterval&lt;/code&gt; defines in what interval we want the program to run and takes an integer expected to contain the number of seconds. In our case, we run my-program.py every 30 seconds.&lt;/p&gt;
&lt;h2 id="load-and-start-the-agent-"&gt;Load and start the agent 🚀&lt;/h2&gt;
&lt;p&gt;LaunchAgents can be loaded, started and unloaded with &lt;code&gt;launchctl&lt;/code&gt;. To do so, we need to supply the ID of our target user and the plist file we just created. You can get your user-id via &lt;code&gt;id -u&lt;/code&gt; or &lt;code&gt;id -u &amp;lt;the-username&amp;gt;&lt;/code&gt;, respectively.&lt;/p&gt;
&lt;p&gt;Assuming we are in &lt;code&gt;~/Library/LaunchAgents/&lt;/code&gt; we can now load our agent by executing the following command:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;launchctl bootstrap gui/&amp;lt;your-user-id&amp;gt; de.davidhamann.my-program.plist&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;And then kick-start it with (or just wait 😊):&lt;/p&gt;
&lt;p&gt;&lt;code&gt;launchctl kickstart -k gui/&amp;lt;your-user-id&amp;gt;/de.davidhamann.my-program&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Note that we use the &lt;code&gt;Label&lt;/code&gt; in this command, not the plist filename. The &lt;code&gt;-k&lt;/code&gt; options means that the service will first be killed, if running (see &lt;code&gt;man launchctl&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;Our agent should now be active and starting the program every 30 seconds.&lt;/p&gt;
&lt;div class="notice notice-info"&gt;
 Note: we are setting up an agent for a user in a gui session. You may want to specify other targets, e.g. &lt;code&gt;system&lt;/code&gt; for system-wide services. See &lt;code&gt;man launchctl&lt;/code&gt; for more.
&lt;/div&gt;

&lt;h2 id="unloading"&gt;Unloading&lt;/h2&gt;
&lt;p&gt;Unloading an agent is as easy as:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;launchctl bootout gui/&amp;lt;your-user-id&amp;gt; de.davidhamann.my-program.plist&lt;/code&gt;&lt;/p&gt;
&lt;div class="notice notice-info"&gt;
 In other tutorials you may see the use of &lt;code&gt;launchctl load&lt;/code&gt;, &lt;code&gt;launchctl start&lt;/code&gt; and &lt;code&gt;launchctl unload&lt;/code&gt;. While these commands still work, they are from a from a previous implementation of &lt;code&gt;launchd&lt;/code&gt; and are classified as &amp;ldquo;Legacy&amp;rdquo;.
&lt;/div&gt;

&lt;h2 id="troubleshooting"&gt;Troubleshooting&lt;/h2&gt;
&lt;p&gt;In case you&amp;rsquo;re having trouble with an agent, you can either look into &lt;code&gt;system.log&lt;/code&gt; or direct the output to a desired location by adding two keys for output and errors to the &lt;code&gt;&amp;lt;dict&amp;gt;&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-xml" data-lang="xml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;&amp;lt;key&amp;gt;&lt;/span&gt;StandardOutPath&lt;span class="nt"&gt;&amp;lt;/key&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;&amp;lt;string&amp;gt;&lt;/span&gt;/log/path/out.log&lt;span class="nt"&gt;&amp;lt;/string&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;&amp;lt;key&amp;gt;&lt;/span&gt;StandardErrorPath&lt;span class="nt"&gt;&amp;lt;/key&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;&amp;lt;string&amp;gt;&lt;/span&gt;/log/path/error.log&lt;span class="nt"&gt;&amp;lt;/string&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Make sure to &lt;code&gt;bootout&lt;/code&gt;, &lt;code&gt;bootstrap&lt;/code&gt;, &lt;code&gt;kickstart&lt;/code&gt; again after you make your change.&lt;/p&gt;
&lt;div class="notice notice-info"&gt;
 &lt;strong&gt;Note:&lt;/strong&gt; The &lt;code&gt;Debug&lt;/code&gt; key, though mentioned in the &lt;code&gt;launchd&lt;/code&gt; manual, is not supported anymore.
&lt;/div&gt;

&lt;h2 id="other-use-cases"&gt;Other use cases&lt;/h2&gt;
&lt;p&gt;Another common use case is &lt;code&gt;StartCalendarInterval&lt;/code&gt; for starting a program at a given time. A nice property of this is, that it will handle sleep times. So &lt;code&gt;launchd&lt;/code&gt; would start the job the next time your computer wakes up and won&amp;rsquo;t just skip it like cron (it does not do that for &lt;code&gt;StartInterval&lt;/code&gt;, though I didn&amp;rsquo;t find that to be a problem for my cases).&lt;/p&gt;
&lt;p&gt;Have a look at &lt;code&gt;man launchd.plist&lt;/code&gt; for many more options or visit &lt;a href="https://developer.apple.com/library/content/documentation/MacOSX/Conceptual/BPSystemStartup/Chapters/CreatingLaunchdJobs.html"&gt;developer.apple.com&lt;/a&gt; for a broader (but in parts outdated) overview.&lt;/p&gt;</description></item><item><title>VPN: Temporarily solve same subnet conflicts</title><link>https://davidhamann.de/2017/09/27/vpn-connect-to-server-same-subnet/</link><pubDate>Wed, 27 Sep 2017 00:00:00 +0000</pubDate><guid>https://davidhamann.de/2017/09/27/vpn-connect-to-server-same-subnet/</guid><description>&lt;p&gt;I recently had the problem of needing to establish a connection to a server behind a VPN that was in the same subnet as the network I was connecting from. Every call I wanted to make to the server on the remote network wouldn&amp;rsquo;t go through as it was looking for the server on the local network.&lt;/p&gt;
&lt;p&gt;To eventually reach the server, I temporarily added a route to the routing tables, telling the client it should transmit traffic to the destination ip through the interface of the VPN connection.&lt;/p&gt;
&lt;p&gt;If you ever come across a similar situation, here&amp;rsquo;s how to solve it.&lt;/p&gt;
&lt;p&gt;First, find out which interface your VPN is using:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;&amp;gt; ifconfig&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s assume it runs via &lt;code&gt;ppp0&lt;/code&gt;. Let&amp;rsquo;s further assume that the server you want to reach is at 192.168.1.10. Now, to tell your client about it, add the route via the &lt;code&gt;route&lt;/code&gt; command (this is on macOS, but should work more or less the same on a Linux system):&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt; sudo route add -host 192.168.1.10 -interface ppp0
add host 192.168.1.10: gateway ppp0
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Doing a quick &lt;code&gt;ping&lt;/code&gt;, you should see that your desired server is now reachable.&lt;/p&gt;
&lt;p&gt;Note that when you re-connect you may need to setup the route again as the setting is not persisting.&lt;/p&gt;</description></item><item><title>Running Flask on macOS with mod_wsgi/wsgi-express</title><link>https://davidhamann.de/2017/08/05/running-flask-with-wsgi-on-macos/</link><pubDate>Sat, 05 Aug 2017 00:00:00 +0000</pubDate><guid>https://davidhamann.de/2017/08/05/running-flask-with-wsgi-on-macos/</guid><description>&lt;p&gt;Flask is a (&lt;a href="http://flask.pocoo.org/docs/0.12/foreword/#what-does-micro-mean"&gt;micro&lt;/a&gt;) web development Framework for Python. It is fairly simple to get started. All you need to do is to &lt;code&gt;pip install Flask&lt;/code&gt; into your virtualenv, give the FLASK_APP environment variable your file and run &lt;code&gt;flask run&lt;/code&gt; (described in detail in &lt;a href="http://flask.pocoo.org/docs/0.12/installation/#installation"&gt;installation&lt;/a&gt; and &lt;a href="http://flask.pocoo.org/docs/0.12/quickstart/"&gt;quick start&lt;/a&gt;). This will launch the development server and you can instantly start hacking around.&lt;/p&gt;
&lt;p&gt;When you want to use your Apache webserver, however, you need to install and configure a WSGI module. When I first wanted to do this I tried to install mod_wsgi via brew (&lt;code&gt;brew install mod_wsgi&lt;/code&gt; from the homebrew/apache tap), but quickly ran into some (apparently common) issues with the XCode toolchain. Then I discovered that there is a much easier way of installing mod_wsgi as a Python package.&lt;/p&gt;
&lt;p&gt;On the &lt;a href="https://pypi.python.org/pypi/mod_wsgi"&gt;PyPI&lt;/a&gt; page it says&amp;hellip;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;[it] will compile not only the Apache module for mod_wsgi, but will also install a Python module and admin script for starting up a standalone instance of Apache directly from the command line with an auto generated configuration.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="lets-try-it-out"&gt;Let&amp;rsquo;s try it out&lt;/h3&gt;
&lt;p&gt;At this point I assume you have virtualenv and the XCode cli tools (&lt;code&gt;xcode-select --install&lt;/code&gt;) installed (and of course the standard Apache from macOS). Everything else we will do together in the following steps.&lt;/p&gt;
&lt;h3 id="setting-up-virtualenv"&gt;Setting up virtualenv&lt;/h3&gt;
&lt;p&gt;Let&amp;rsquo;s start by creating the directory for the application and setting up our virtual environment:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ mkdir my_app
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ &lt;span class="nb"&gt;cd&lt;/span&gt; my_app/
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ virtualenv venv
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;New python executable in /your/path/my_app/venv/bin/python2.7
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Also creating executable in /your/path/my_app/venv/bin/python
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Installing setuptools, pip, wheel...done.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now we activate our environment:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ &lt;span class="nb"&gt;source&lt;/span&gt; venv/bin/activate
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;(&lt;/span&gt;venv&lt;span class="o"&gt;)&lt;/span&gt; $ &lt;span class="c1"&gt;# &amp;lt;- new prompt&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="installing-mod_wsgi"&gt;Installing mod_wsgi&lt;/h3&gt;
&lt;p&gt;Installing mod_wsgi is now easily done via pip:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;(&lt;/span&gt;venv&lt;span class="o"&gt;)&lt;/span&gt; $ pip install mod_wsgi
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Let&amp;rsquo;s see if it worked by launching the server:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;(&lt;/span&gt;venv&lt;span class="o"&gt;)&lt;/span&gt; $ mod_wsgi-express start-server
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Server URL : http://localhost:8000/
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Server Root : /tmp/mod_wsgi-localhost:8000:501
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Server Conf : /tmp/mod_wsgi-localhost:8000:501/httpd.conf
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Error Log File : /tmp/mod_wsgi-localhost:8000:501/error_log &lt;span class="o"&gt;(&lt;/span&gt;warn&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Request Capacity : &lt;span class="m"&gt;5&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt; process * &lt;span class="m"&gt;5&lt;/span&gt; threads&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Request Timeout : &lt;span class="m"&gt;60&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;seconds&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Startup Timeout : &lt;span class="m"&gt;15&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;seconds&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Queue Backlog : &lt;span class="m"&gt;100&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;connections&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Queue Timeout : &lt;span class="m"&gt;45&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;seconds&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Server Capacity : &lt;span class="m"&gt;20&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;event/worker&lt;span class="o"&gt;)&lt;/span&gt;, &lt;span class="m"&gt;20&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;prefork&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Server Backlog : &lt;span class="m"&gt;500&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;connections&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Locale Setting : de_DE.UTF-8
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;By pointing your browser to http://localhost:8000/, you should be greeted by this page:&lt;/p&gt;
&lt;p&gt;&lt;img alt="mod_wsgi test page" loading="lazy" src="https://davidhamann.de/images/wsgi_whiskey.jpg"&gt;&lt;/p&gt;
&lt;p&gt;Looks good. Let&amp;rsquo;s stop the server with &lt;code&gt;ctrl-c&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id="installing-flask-and-creating-the-web-app"&gt;Installing Flask and creating the web app&lt;/h3&gt;
&lt;p&gt;If you already have your Flask app, you can skip the next few commands, but for the sake of completeness, let&amp;rsquo;s install Flask and create a small sample web app (make sure you are still in your virtualenv):&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;(&lt;/span&gt;venv&lt;span class="o"&gt;)&lt;/span&gt; $ pip install Flask
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Let&amp;rsquo;s create another directory to put the code of our web application in, and fire up an editor for creating the code file:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;(&lt;/span&gt;venv&lt;span class="o"&gt;)&lt;/span&gt; $ mkdir my_app 
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;(&lt;/span&gt;venv&lt;span class="o"&gt;)&lt;/span&gt; $ vim my_app/__init__.py &lt;span class="c1"&gt;# &amp;lt;- choose the cli editor you want or just create the file with a gui editor &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Paste this code (from the &lt;a href="http://flask.pocoo.org/docs/0.12/quickstart/"&gt;Quick Start tutorial&lt;/a&gt;) into your file:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;flask&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Flask&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Flask&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vm"&gt;__name__&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nd"&gt;@app.route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;/&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;hello_world&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Hello, World!&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="creating-the-wsgi-script"&gt;Creating the wsgi script&lt;/h3&gt;
&lt;p&gt;To let the server know about our application, let&amp;rsquo;s create the wsgi script which we will later point to when starting the server.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;(&lt;/span&gt;venv&lt;span class="o"&gt;)&lt;/span&gt; $ &lt;span class="nb"&gt;pwd&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;/your/path/my_app &lt;span class="c1"&gt;# &amp;lt;- we are here&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;(&lt;/span&gt;venv&lt;span class="o"&gt;)&lt;/span&gt; $ vim my_app.wsgi &lt;span class="c1"&gt;# &amp;lt;- choose the cli editor you want or just create the file with a gui editor &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Paste this code into the new file:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;my_app&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;application&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="notice notice-info"&gt;
 &lt;strong&gt;UPDATE:&lt;/strong&gt; I initially set &lt;code&gt;sys.path.insert(0,&amp;quot;/your/path/my_app/&amp;quot;)&lt;/code&gt; in the snippet above. This is not needed, as the directory you run &lt;code&gt;mod_wsgi-express setup-server&lt;/code&gt; or &lt;code&gt;mod_wsgi-express start-server&lt;/code&gt; in is added to sys.path automatically. See &lt;a href="https://twitter.com/GrahamDumpleton/status/893961936915673088"&gt;these&lt;/a&gt; &lt;a href="https://twitter.com/GrahamDumpleton/status/893962278634004480"&gt;three&lt;/a&gt; &lt;a href="https://twitter.com/GrahamDumpleton/status/893962380345982976"&gt;tweets&lt;/a&gt;.
&lt;/div&gt;

&lt;h3 id="launching-the-server-with-the-wsgi-script"&gt;Launching the server with the wsgi script&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;(&lt;/span&gt;venv&lt;span class="o"&gt;)&lt;/span&gt; $ mod_wsgi-express start-server my_app.wsgi
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;By going to http://localhost:8000/ you should now see the &amp;ldquo;Hello, World!&amp;rdquo; from our Flask app.&lt;/p&gt;
&lt;p&gt;Doesn&amp;rsquo;t work for you? Didn&amp;rsquo;t work for me at first either as I had a typo in the code 🙂. Check out the error logs and you will see a hint of what might be wrong: &lt;code&gt;/tmp/mod_wsgi-localhost:8000:501/error_log&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id="running-the-server-in-the-background"&gt;Running the server in the background&lt;/h3&gt;
&lt;p&gt;If you want to continue with your shell session, but leave the server running, you can use &lt;code&gt;nohup&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;(&lt;/span&gt;venv&lt;span class="o"&gt;)&lt;/span&gt; $ nohup mod_wsgi-express start-server my_app.wsgi &lt;span class="p"&gt;&amp;amp;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This will leave the server running, while you can continue working in the session (output will go to the file nohup.out). To bring it back to the foreground, use &lt;code&gt;fg&lt;/code&gt;.&lt;/p&gt;
&lt;div class="notice notice-info"&gt;
 &lt;p&gt;&lt;strong&gt;UPDATE:&lt;/strong&gt; &lt;a href="http://blog.dscpl.com.au"&gt;Graham Dumpleton&lt;/a&gt; reached out to me and noted that the better way of running it in the background is by generating scripts via &lt;code&gt;setup-server&lt;/code&gt; and then use apachectl to start/stop. So you might want to execute the following (as root) instead of using &lt;code&gt;nohup&lt;/code&gt;:&lt;/p&gt;
&lt;p&gt;(feel free to change the port)&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mod_wsgi-express setup-server my_app.wsgi --port&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;8000&lt;/span&gt; --user _www --group _www --server-root&lt;span class="o"&gt;=&lt;/span&gt;/etc/mod_wsgi-express-8000
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And then control the server state via:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;/etc/mod_wsgi-express-8000/apachectl start
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;/etc/mod_wsgi-express-8000/apachectl stop
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h3 id="watching-for-changes"&gt;Watching for changes&lt;/h3&gt;
&lt;p&gt;When you develop your app and don&amp;rsquo;t want to reboot the server for each change, there is a convenient way of starting the server with the &lt;code&gt;--reload-on-changes&lt;/code&gt; option. Now you can change your files and have the changes immediately served.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;(&lt;/span&gt;venv&lt;span class="o"&gt;)&lt;/span&gt; $ mod_wsgi-express start-server --reload-on-changes my_app.wsgi
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="more-info"&gt;More info&lt;/h3&gt;
&lt;p&gt;You can find more info about mod_wsgi (e.g. running it on a privileged port as root) on the PyPI page: &lt;a href="https://pypi.python.org/pypi/mod_wsgi"&gt;mod_wsgi&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The command documentation is available here:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;(&lt;/span&gt;venv&lt;span class="o"&gt;)&lt;/span&gt; $ mod_wsgi-express start-server --help
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description></item><item><title>Sharing a VPN connection with another device on macOS Sierra/El Capitan</title><link>https://davidhamann.de/2017/04/19/sharing-vpn-on-macos/</link><pubDate>Wed, 19 Apr 2017 00:00:00 +0000</pubDate><guid>https://davidhamann.de/2017/04/19/sharing-vpn-on-macos/</guid><description>&lt;p&gt;There are multiple reasons why you would want to share a VPN connection from your Mac with another device. Maybe you have to install a proprietary VPN client which does not run on your main computer or you just don&amp;rsquo;t want to run/install it there. Maybe your main computer doesn&amp;rsquo;t &amp;ldquo;comply&amp;rdquo; (i.e. you would need to install additional AV software – who wants that?). Or you simply need it for streaming video to some TV box.&lt;/p&gt;
&lt;p&gt;I recently had the problem with a proprietary VPN client which I didn&amp;rsquo;t want to install on my main machine. I solved it by using another Mac running macOS 10.11 and am going to describe the process here and list the resources that were helpful.&lt;/p&gt;
&lt;div class="notice notice-info"&gt;
 If you are looking for a hardware VPN router or want to share a natively supported VPN connection (L2TP, IPSec) via &amp;ldquo;Internet Sharing&amp;rdquo;, you can stop reading here. I won&amp;rsquo;t cover this topic.
&lt;/div&gt;

&lt;p&gt;I quickly found the article &lt;a href="http://rodrigo.sharpcube.com/2010/06/20/using-and-sharing-a-vpn-connection-on-your-mac/"&gt;&amp;ldquo;Using (and sharing) a VPN connection on your Mac&amp;rdquo;&lt;/a&gt;, which looked like a great solution. It suggested the following little shell script:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;#!/bin/sh
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;natd -interface tun0
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ipfw -f flush
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ipfw add divert natd ip from any to any via tun0
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ipfw add pass all from any to any
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sysctl -w net.inet.ip.forwarding&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Unfortunately, there&amp;rsquo;s neither &lt;code&gt;ipfw&lt;/code&gt; nor &lt;code&gt;natd&lt;/code&gt; on El Capitan or Sierra, since they were deprecated with Yosemite. So, the &amp;ldquo;new&amp;rdquo; thing to look into was &lt;code&gt;pf&lt;/code&gt; (packet filter).&lt;/p&gt;
&lt;p&gt;After reading the man page of &lt;code&gt;pfctl&lt;/code&gt; and a bit more of googling, I found the solution. To load your own rules and share your VPN connection, you can use &lt;code&gt;pfctl -f&lt;/code&gt; and give it a list of nat entries defining the interfaces from and to. This article &lt;a href="https://roelant.net/2015/share-your-vpn-mac-el-capitan.html"&gt;&amp;ldquo;Share your VPN with Mac OS X El Capitan&amp;rdquo;&lt;/a&gt; from roelant.net helped a lot.&lt;/p&gt;
&lt;p&gt;My working natvpn.sh script now looked like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;#!/bin/sh
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sysctl -w net.inet.ip.forwarding&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sysctl -w net.inet.ip.fw.enable&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pfctl -f ./nat-rules -e
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="notice notice-info"&gt;
 You might need a &lt;code&gt;sudo pfctl -d&lt;/code&gt; before to disable the packet filter.
&lt;/div&gt;

&lt;p&gt;&amp;hellip;and the nat-rules file:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;nat on utun0 from en0:network to any -&amp;gt; (utun0)&lt;/code&gt;&lt;/p&gt;
&lt;div class="notice notice-info"&gt;
 You might need to change the interfaces utun0/en0 according to your preferences.
&lt;/div&gt;

&lt;p&gt;The next step was to go to my main machine and setup a new network service (&lt;code&gt;System Preferences -&amp;gt; Network&lt;/code&gt;). After clicking on the &amp;ldquo;+&amp;rdquo; button, I chose the adapter (in my case the Display Ethernet) and manual IPv4 configuration and entered my standard local networking details with the exception of the gateway address (might also be called &amp;ldquo;router address&amp;rdquo; on your machine). The gateway address is the IP of the mac on which the VPN client (incl. the script from above) was installed.&lt;/p&gt;
&lt;p&gt;After the service was created I just needed to change the order of the services to prioritze the newly created service (click on the action menu -&amp;gt; &lt;code&gt;Set Service Order&lt;/code&gt;) and then start the script (&lt;code&gt;./natvpn.sh&lt;/code&gt;). Et voilà, I could use the VPN connection established by the other Mac on my main machine Mac.&lt;/p&gt;
&lt;div class="notice notice-info"&gt;
 If you don&amp;rsquo;t like to set the service order every time you use the shared VPN, you might want to set up a new network location for your VPN work (&lt;code&gt;System Preferences -&amp;gt; Network -&amp;gt; Location -&amp;gt; Edit Locations … -&amp;gt; +&lt;/code&gt;)
&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Update: Troubleshooting&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;If sharing does not work after executing the steps above or stops working from one day to the other (yep, had that problem :-)), you should first check the nat-rules file. It is likely that either one of the interfaces is invalid or you might just have a typo in there. If it all looks OK but still doesn&amp;rsquo;t work, try to explicitly list the subnet, i.e. &lt;code&gt;nat on utun0 from 192.168.1.0/24 to any -&amp;gt; utun0&lt;/code&gt; and then start again.&lt;/p&gt;
&lt;p&gt;After running ./natvpn.sh you may also want to do a sanity check by listing the rules with &lt;code&gt;sudo pfctl -s all&lt;/code&gt;. You should see your entry under &lt;code&gt;TRANSLATION RULES&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Another thing to try is to flush all rules before attempting again: &lt;code&gt;pfctl -F all&lt;/code&gt;.&lt;/p&gt;</description></item></channel></rss>