{"id":4328,"date":"2022-06-26T15:02:57","date_gmt":"2022-06-26T13:02:57","guid":{"rendered":"https:\/\/oelna.de\/blog\/?p=4328"},"modified":"2022-06-26T15:58:57","modified_gmt":"2022-06-26T13:58:57","slug":"set-up-a-simpleish-http-2-webserver-on-macos","status":"publish","type":"post","link":"https:\/\/oelna.de\/blog\/4328","title":{"rendered":"Set up a simple(ish) HTTP\/2 webserver on  macOS"},"content":{"rendered":"\n<p>There have been moments where having HTTP\/2 on localhost would have been handy. Over the years I have tried a few things and recently I found a way I liked. I tend to dislike having to install too many things, but for this, it seems impossible to avoid. My instructions are based on macOS Catalina (10.15) (for <strong>Safari<\/strong>), but should work for previous versions and future versions as well.<\/p>\n\n\n\n<p>My steps were:<\/p>\n\n\n\n<p>From the Terminal app, generate a self-signed certificate to use for SSL. (maybe change to the directory you&#8217;d like to store the certs in first?, in my case &#8220;\/Users\/oelna\/.certificates&#8221;)<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>openssl req -x509 -nodes -newkey rsa:2048 -keyout key.pem -out cert.pem<\/code><\/pre>\n\n\n\n<p>This will create two .pem files (without setting a password for the key, which I found invaluable on a local machine, since I don&#8217;t want to enter a password every time I start the server.)<\/p>\n\n\n\n<p>During creation I chose to put in some reasonable values for country name, organization name and common name (&#8220;localhost.&#8221;).<\/p>\n\n\n\n<p>I tried to figure out a way to do this with the Python built-in HTTP server, but couldn&#8217;t, so I begrudgingly installed twisted for Python 3.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>pip3 install twisted<\/code><\/pre>\n\n\n\n<p>Depending on where you saved the .pem files generated earlier, you may have to adjust the paths for them in the following start command for twisted:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>twistd -n web --path=. -c \/Users\/oelna\/.certificates\/cert.pem -k \/Users\/oelna\/.certificates\/key.pem --https=4433<\/code><\/pre>\n\n\n\n<p>The parameters are pretty self-explanatory: -c is the certificate location, -k is the key file location, &#8211;https is the port the server will listen on, and &#8211;path is your website root (Most of the time I run the command from the directory the files are in, so I just put . there (=current directory)<\/p>\n\n\n\n<p>Twisted should start up and if it doesn&#8217;t fail, your site is ready for you at <strong>https:\/\/localhost:4433<\/strong><\/p>\n\n\n\n<p>Safari will complain, when you load the page, but you can click your way through.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large content_image retina\"><img decoding=\"async\" src=\"\/blog\/wp-photos\/2022-06-26\/safari-error.png\" alt=\"\"\/><\/figure>\n\n\n\n<p>Chrome is a completely different beast, though, and I have needed to make a few changes to how the certificates are created.<\/p>\n\n\n\n<p><strong>Chrome<\/strong><br>The instructions above worked well for me, but for Chrome I needed to go about it a little differently (sadly, more complicated). For this I used the <a href=\"https:\/\/stackoverflow.com\/a\/60516812\/3625228\" data-type=\"URL\" data-id=\"https:\/\/stackoverflow.com\/a\/60516812\/3625228\">instructions on Stackoverflow<\/a>.<\/p>\n\n\n\n<p>You need to become your own CA (&#8220;certificate authority&#8221;) and trust it on your machine. This fake CA will issue a certificate for localhost (which has to include something called <strong>subjectAltName<\/strong>). The resulting certificate for localhost also needs to be imported to Keychain and trusted for use with SSL. Let&#8217;s do it!<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># generate the CA key and cert\nopenssl genrsa -des3 -out myCA.key 2048\nopenssl req -x509 -new -nodes -key myCA.key -sha256 -days 825 -out myCA.pem<\/code><\/pre>\n\n\n\n<p>Prepare this <strong>localhost.ext<\/strong> file beforehand:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>authorityKeyIdentifier=keyid,issuer\nbasicConstraints=CA:FALSE\nextendedKeyUsage=serverAuth,clientAuth\nkeyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment\nsubjectAltName = @alt_names\n&#91;alt_names]\nDNS.1 = localhost\nIP.1 = 127.0.0.1<\/code><\/pre>\n\n\n\n<p>Next, generate a key and certificate signing request for localhost. (I think I read that when asked for the &#8220;common name&#8221; for the cert, you should put a period at the end, to make it a fully-qualified domain name (FQDN), like so: &#8220;localhost.&#8221;). It worked for me.<br>The &#8220;days&#8221; parameter can&#8217;t be larger than 825 on macOS, so that&#8217;s what I put.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>openssl genrsa -out localhost.key 2048\nopenssl req -new -key localhost.key -out localhost.csr\nopenssl x509 -req -in localhost.csr -CA myCA.pem -CAkey myCA.key -CAcreateserial -out localhost.crt -days 825 -sha256 -extfile localhost.ext<\/code><\/pre>\n\n\n\n<p>Import <strong>myCA.pem<\/strong> and <strong>localhost.crt<\/strong> into macOS <strong>Keychain Access.app<\/strong><br>&#8220;Get Info&#8221; on both of them and trust them with &#8220;Always Trust&#8221;.<\/p>\n\n\n\n<p> If ever you need a .pem file of the cert, just concat the .crt and .key like so:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>cat localhost.crt localhost.key &gt; localhost.pem<\/code><\/pre>\n\n\n\n<p>With these newly created and trusted certificates you can finally run Twisted again. Chrome will complain, but this time, you&#8217;ll be able to click through!<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>twistd -n web --path=. -c \/Users\/oelna\/.certificates\/localhost.crt -k \/Users\/oelna\/.certificates\/localhost.key --https=4433<\/code><\/pre>\n\n\n\n<figure class=\"wp-block-image size-large is-resized content_image retina\"><img loading=\"lazy\" decoding=\"async\" src=\"\/blog\/wp-photos\/2022-06-26\/chrome.png\" alt=\"\" width=\"723\" height=\"398\"\/><\/figure>\n","protected":false},"excerpt":{"rendered":"<p>There have been moments where having HTTP\/2 on localhost would have been handy. Over the years I have tried a few things and recently I found a way I liked. I tend to dislike having to install too many things, but for this, it seems impossible to avoid. My instructions are based on macOS Catalina [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"activitypub_content_warning":"","activitypub_content_visibility":"","activitypub_max_image_attachments":4,"activitypub_interaction_policy_quote":"anyone","activitypub_status":"","footnotes":""},"categories":[3,1],"tags":[],"class_list":["post-4328","post","type-post","status-publish","format-standard","hentry","category-english","category-general"],"_links":{"self":[{"href":"https:\/\/oelna.de\/blog\/wp-json\/wp\/v2\/posts\/4328","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/oelna.de\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/oelna.de\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/oelna.de\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/oelna.de\/blog\/wp-json\/wp\/v2\/comments?post=4328"}],"version-history":[{"count":6,"href":"https:\/\/oelna.de\/blog\/wp-json\/wp\/v2\/posts\/4328\/revisions"}],"predecessor-version":[{"id":4339,"href":"https:\/\/oelna.de\/blog\/wp-json\/wp\/v2\/posts\/4328\/revisions\/4339"}],"wp:attachment":[{"href":"https:\/\/oelna.de\/blog\/wp-json\/wp\/v2\/media?parent=4328"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/oelna.de\/blog\/wp-json\/wp\/v2\/categories?post=4328"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/oelna.de\/blog\/wp-json\/wp\/v2\/tags?post=4328"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}