<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="4.2.0">Jekyll</generator><link href="/feed.xml" rel="self" type="application/atom+xml" /><link href="/" rel="alternate" type="text/html" /><updated>2021-08-19T02:25:39+00:00</updated><id>/feed.xml</id><title type="html">Strange Adventures In…</title><subtitle>This is the personal blog of Phil Skents. I talk about infosec, Jeeps, cats, electronics, gaming and pretty much anything else that creeps into my head. Enjoy, or don&apos;t, up to you.</subtitle><entry><title type="html">…Ansible: Creating Logical Volumes With Ansible</title><link href="/2021/06/17/creating-logical-volumes-with-ansible.html" rel="alternate" type="text/html" title="…Ansible: Creating Logical Volumes With Ansible" /><published>2021-06-17T22:07:13+00:00</published><updated>2021-06-17T22:07:13+00:00</updated><id>/2021/06/17/creating-logical-volumes-with-ansible</id><content type="html" xml:base="/2021/06/17/creating-logical-volumes-with-ansible.html">&lt;p&gt;Ansible is often overlooked for managing the more physical aspects of the devices it is used to configure, but it has some powerful tools for handling lower level duties, such as disks. Recently I was working on some old-fashioned VMWare virtual machines and discovered that a lot of the guidance for managing logical volumes in Ansible is dated so here are my modernized notes on taking a disk from device to volume. This is NOT a primer on LVM itself, an understanding of LVM is recommended before trying to implement these steps.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;Create a new logical volume group (&lt;a href=&quot;https://docs.ansible.com/ansible/latest/collections/community/general/lvg_module.html&quot;&gt;docs&lt;/a&gt;)&lt;/p&gt;

    &lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;- name: Create a volume group on top of /dev/sdb with physical extent size = 32MB
  community.general.lvg:
    vg: vg.storage
    pvs: /dev/sdb1
    pesize: 32
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Create a logical volume in your logical volume group (&lt;a href=&quot;https://docs.ansible.com/ansible/latest/collections/community/general/lvol_module.html#ansible-collections-community-general-lvol-module&quot;&gt;docs&lt;/a&gt;)&lt;/p&gt;

    &lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;- name: create logical volume
  community.general.lvol:
    vg: vg.storage
    lv: data
    size: 10g
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Create a filesystem on your new volume (&lt;a href=&quot;https://docs.ansible.com/ansible/latest/collections/community/general/filesystem_module.html#ansible-collections-community-general-filesystem-module&quot;&gt;docs&lt;/a&gt;)&lt;/p&gt;

    &lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;- name: Create a ext4 filesystem on the data volume
  community.general.filesystem:
    fstype: ext4
    dev: /dev/vg.storage/data
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Create a folder to mount our new volume to (&lt;a href=&quot;https://docs.ansible.com/ansible/latest/collections/ansible/builtin/file_module.html&quot;&gt;docs&lt;/a&gt;)&lt;/p&gt;

    &lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;- name: Create directory /data if does not exist
  ansible.builtin.file:
    path: /data
    state: directory
    mode: &apos;0755&apos;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Mount our new volume to /data (&lt;a href=&quot;https://docs.ansible.com/ansible/latest/collections/ansible/posix/mount_module.html&quot;&gt;docs&lt;/a&gt;)&lt;/p&gt;

    &lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;- name: mount the logical volume to /data
  ansible.posix.mount:
    path: /data
    src: /dev/vg.storage/data
    fstype: ext4
    state: mounted
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;These instructions were tested on Ubuntu 20.04 servers with Ansible 2.11 but should work on any Linux flavor that supports LVM.&lt;/p&gt;</content><author><name></name></author><category term="ansible" /><category term="logical volumes" /><category term="lvm" /><category term="automation" /><summary type="html">Ansible is often overlooked for managing the more physical aspects of the devices it is used to configure, but it has some powerful tools for handling lower level duties, such as disks. Recently I was working on some old-fashioned VMWare virtual machines and discovered that a lot of the guidance for managing logical volumes in Ansible is dated so here are my modernized notes on taking a disk from device to volume. This is NOT a primer on LVM itself, an understanding of LVM is recommended before trying to implement these steps.</summary></entry><entry><title type="html">…CLI: Configure Weechat for Libera.Chat with CertFP</title><link href="/2021/05/19/configure-weechat-for-liberachat-with-certfp.html" rel="alternate" type="text/html" title="…CLI: Configure Weechat for Libera.Chat with CertFP" /><published>2021-05-19T22:07:13+00:00</published><updated>2021-05-19T22:07:13+00:00</updated><id>/2021/05/19/configure-weechat-for-liberachat-with-certfp</id><content type="html" xml:base="/2021/05/19/configure-weechat-for-liberachat-with-certfp.html">&lt;p&gt;Freenode is dead, it’s weird to say it, but it is. I am not going to go into detail around the circumstances but the folk behind Freenode have moved on to a new IRC network, &lt;a href=&quot;https://libera.chat/&quot;&gt;Libera.Chat&lt;/a&gt;. For those of you looking to hook into this new community with a TUI I highly recommend &lt;a href=&quot;https://weechat.org/&quot;&gt;WeeChat&lt;/a&gt; for your CLI IRC needs and here is a quick how to on how to hook it up with CertFP for easy authentication.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;Install WeeChat, on MacOS this can be done with homebrew, for other operating systems follow the guides on WeeChat’s site&lt;/p&gt;

    &lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;brew install weechat&lt;/code&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Launch WeeChat ( &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;weechat&lt;/code&gt; ) and add the Libera.Chat server to your config&lt;/p&gt;

    &lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/server add liberachat irc.libera.chat/6697 -ssl&lt;/code&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;We can now connect to Libera.Chat for the first time&lt;/p&gt;

    &lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/connect liberachat&lt;/code&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Once connected it is time to claim our nickname (you will have connected with a default nickname that is likely not available). To do so we first need to switch to the nickname to see if it is free&lt;/p&gt;

    &lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/nick &amp;lt;YOUR_NICKNAME&amp;gt;&lt;/code&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;If it is free you will see your nickname change to the one you selected, if not try another. Once you have selected your nickname successfully we need to register it&lt;/p&gt;

    &lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/msg NickServ REGISTER &amp;lt;YOUR_PASSWORD&amp;gt; &amp;lt;YOUR_EMAIL@EXAMPLE.COM&amp;gt;&lt;/code&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Check your email and copy and paste in the command from that email to complete the registration of your nickname. At this point you have registered your nickname and can log into it with the password specified in step 5. For ease and security though we are going to switch to CertFP so we can use a cert for auth so for now disconnect from the server with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/disconnect&lt;/code&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;In a new terminal window create a new certificate with openssl&lt;/p&gt;

    &lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;openssl req -x509 -new -newkey rsa:4096 -sha256 -days 1096 -nodes -out libera.pem -keyout libera.pem&lt;/code&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Create the certificate directory for WeeChat&lt;/p&gt;

    &lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mkdir ~/.weechat/certs&lt;/code&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Copy your new certificate into our new directory&lt;/p&gt;

    &lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mv libera.pem ~/.weechat/certs&lt;/code&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Switching back to our WeeChat window we now need to configure WeeChat to use our certificate&lt;/p&gt;

    &lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;/set irc.server.libera.addresses irc.libera.chat/6697
/set irc.server.liberachat.ssl on
/set irc.server.liberachat.ssl_verify on
/set irc.server.liberachat.ssl_cert %h/certs/libera.pem
/set irc.server.liberachat.sasl_mechanism external
/set irc.server.liberachat.nicks &amp;lt;MY_NICKNAME&amp;gt;
/save
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Now we log into Libera.Chat using our password for (hopefully) the last time and register our certificate fingerprint&lt;/p&gt;

    &lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;/connect
/msg NickServ IDENTIFY &amp;lt;YOUR_NICKNAME&amp;gt; &amp;lt;YOUR_PASSWORD&amp;gt;
/msg NickServ CERT ADD
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Finally disconnect and reconnect to test your new, password free, login&lt;/p&gt;

    &lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;/disconnect
/connect
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
&lt;/ol&gt;</content><author><name></name></author><category term="freenode" /><category term="liberachat" /><category term="weechat" /><category term="irc" /><summary type="html">Freenode is dead, it’s weird to say it, but it is. I am not going to go into detail around the circumstances but the folk behind Freenode have moved on to a new IRC network, Libera.Chat. For those of you looking to hook into this new community with a TUI I highly recommend WeeChat for your CLI IRC needs and here is a quick how to on how to hook it up with CertFP for easy authentication.</summary></entry><entry><title type="html">…iOS: Loading Discord Web on iOS Safari</title><link href="/2021/04/13/load-discord-web-on-ios.html" rel="alternate" type="text/html" title="…iOS: Loading Discord Web on iOS Safari" /><published>2021-04-13T22:07:13+00:00</published><updated>2021-04-13T22:07:13+00:00</updated><id>/2021/04/13/load-discord-web-on-ios</id><content type="html" xml:base="/2021/04/13/load-discord-web-on-ios.html">&lt;p&gt;Discord have stopped iOS users from accessing NSFW servers using their app. They blame Apple, I call bull, but rather than play the blame game here is a quick and simple circumvention technique that you may find useful to bypass this unnecessary censorship.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Open up Safari on your iOS device&lt;/li&gt;
  &lt;li&gt;Go to the &lt;a href=&quot;https://discord.com/&quot;&gt;Discord homepage&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;By default this page will only allow you to download the app. Open up the page options and press “Request Desktop Site”&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;img src=&quot;/assets/IMG_1146.jpeg&quot; alt=&quot;Safari settings screenshot&quot; /&gt;&lt;/p&gt;

&lt;p&gt;A login button will now be displayed, enjoy Discord uncensored.&lt;/p&gt;</content><author><name></name></author><category term="discord" /><category term="ios" /><category term="censorship" /><summary type="html">Discord have stopped iOS users from accessing NSFW servers using their app. They blame Apple, I call bull, but rather than play the blame game here is a quick and simple circumvention technique that you may find useful to bypass this unnecessary censorship.</summary></entry><entry><title type="html">…CLI: Protonmail -&amp;gt; offlineimap -&amp;gt; notmuch -&amp;gt; Mutt</title><link href="/2021/03/15/protonmail-offlineimap-notmuch-mutt.html" rel="alternate" type="text/html" title="…CLI: Protonmail -&amp;gt; offlineimap -&amp;gt; notmuch -&amp;gt; Mutt" /><published>2021-03-15T19:54:13+00:00</published><updated>2021-03-15T19:54:13+00:00</updated><id>/2021/03/15/protonmail-offlineimap-notmuch-mutt</id><content type="html" xml:base="/2021/03/15/protonmail-offlineimap-notmuch-mutt.html">&lt;p&gt;Protonmail is a great service, after using it for over a year I cannot see myself returning to GMail or moving to another email service in the near future. Out of the box however it misses a few key features:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Offline backups&lt;/li&gt;
  &lt;li&gt;Desktop client compatibility&lt;/li&gt;
  &lt;li&gt;The ability to search the message body (by design I know, but still frustrating)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With a little tinkering these are all solvable problems, and using CLI tools (mostly).&lt;/p&gt;

&lt;h1 id=&quot;protonmail-bridge&quot;&gt;Protonmail Bridge&lt;/h1&gt;

&lt;p&gt;Out of the gate we need to be able to connect to Protonmail using standard protocols, like IMAP, which are not available by default. To achieve this we need a paid Protonmail account so we have access to Protonmail bridge. You shouldn’t need a whole lot of guidance to get this up and running, but the official documentation can be found &lt;a href=&quot;https://protonmail.com/bridge/install&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Once the bridge is up and running you will have IMAP and SMTP services running locally with the bridge translating those two protocols to Protonmail’s API.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Why not hydroxide&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/emersion/hydroxide&quot;&gt;Hydroxide&lt;/a&gt; is a third party alternative to the official bridge. I tried it out but it has issues, most notably the inability to move emails between folders, so I stuck to Bridge.&lt;/p&gt;

&lt;h1 id=&quot;offlineimap&quot;&gt;Offlineimap&lt;/h1&gt;

&lt;p&gt;&lt;a href=&quot;https://www.offlineimap.org/&quot;&gt;Offlineimap&lt;/a&gt; is going to be synchronizing our mailbox to a local directory, fulfilling our requirement for an offline backup as well as making our mail available to our local client. Install it using your package manager (brew for me) &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;brew install offlineimap&lt;/code&gt; and create a configuration file in your home directory called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.offlineimaprc&lt;/code&gt;, using this template:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;# ~/.offlineimaprc
[general]
accounts = main
pythonfile = ~/.offlineimap.py

[Account main]
localrepository = main-local
remoterepository = main-remote

# full refresh, in min
autorefresh = 0.2

# quick refreshs between each full refresh
quick = 10

# update notmuch index after sync
postsynchook = notmuch new

[Repository main-local]
type = Maildir
localfolders = ~/.mail

# delete remote mails that were deleted locally
sync_deletes = yes

[Repository main-remote]
type = IMAP
remoteport = 1143
remotehost = 127.0.0.1
remoteuser = $YOUR_EMAIL@protonmail.com
# remotepass = $SOME_PASS
remotepasseval = get_keychain_pass(account=&quot;$YOUR_EMAIL@protonmail.com&quot;, server=&quot;imaps://localhost&quot;)
keepalive = 60
holdconnectionopen = yes

# delete local mails that were deleted on the remote server
expunge = yes

# sync only these folders
folderfilter = lambda foldername: foldername in [&apos;INBOX&apos;, &apos;Archive&apos;, &apos;Sent&apos;, &apos;Trash&apos;]

# SSL
ssl = no
starttls = yes
sslcacertfile = ~/.protonbridge.pem
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Most of this file is pretty boring but there are some pieces to be aware of:&lt;/p&gt;

&lt;h2 id=&quot;credential-management&quot;&gt;Credential Management&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Skip this by uncommenting remotepass and entering the bridge password, but know that means you are storing a credential in plain text and that comes with all the risks you think it does and more. Don’t forget to comment out pythonfile and remotepasseval if you do this&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;My solution to this is MacOS focused, if you need a solution for another OS I would check out gpg. We do not want to store credentials in plain text, lets use the Keychain to store the password instead. Open up Keychain Access, select the “login” chain and select &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;File -&amp;gt; New Password Item&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Keychain Item Name = imaps://localhost
Account Name = $YOUR_EMAIL@protonmail.com
Password = $BRIDGE_PASSWORD
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We will use this entry in various ways in our configuration, but for offlineimap we need to craft a little python to get the password. Create &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.offlineimap.py&lt;/code&gt; in your home directory and copy in the following code&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;# ~/.offlineimap.py

import re, commands
def get_keychain_pass(account=None, server=None):
    params = {
        &apos;security&apos;: &apos;/usr/bin/security&apos;,
        &apos;command&apos;:  &apos;find-generic-password&apos;,
        &apos;account&apos;:  account,
        &apos;server&apos;:   server
    }

    command = &quot;%(security)s %(command)s -a %(account)s -s %(server)s -w&quot; % params
    outtext = commands.getoutput(command)
    return outtext
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;em&gt;This is a modified version of a python script found &lt;a href=&quot;https://blog.aedifice.org/2010/02/01/use-mac-os-xs-keychain-for-password-retrieval-in-offlineimap/&quot;&gt;here&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This python script is imported at &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pythonfile&lt;/code&gt; and the function is used by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;remotepasseval&lt;/code&gt; to get our password from the Keychain when it’s needed.&lt;/p&gt;

&lt;h2 id=&quot;certificates-and-tls&quot;&gt;Certificates and TLS&lt;/h2&gt;

&lt;p&gt;We need to provide a certificate file for this to work correctly due to Proton Bridge using a self signed cert. Once the bridge is running we can get the certificate by running &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;openssl s_client -starttls imap -connect 127.0.0.1:1143 -showcerts&lt;/code&gt;. Copy &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-----BEGIN CERTIFICATE-----&lt;/code&gt; through to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;----END CERTIFICATE-----&lt;/code&gt; and paste it into a new file in your home directory called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.protonbridge.pem&lt;/code&gt;.&lt;/p&gt;

&lt;h1 id=&quot;notmuch&quot;&gt;Notmuch&lt;/h1&gt;

&lt;p&gt;&lt;a href=&quot;https://notmuchmail.org/&quot;&gt;Notmuch&lt;/a&gt; is new to my setup so I do not have much to say about it at this time (ha). I will write more about it later but for now we will use a simple setup. Install with your package manager of choice, for example &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;brew install notmuch&lt;/code&gt; and run &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;notmuch setup&lt;/code&gt; to get a basic config going.&lt;/p&gt;

&lt;h1 id=&quot;mutt-or-neomutt&quot;&gt;Mutt (or Neomutt)&lt;/h1&gt;

&lt;p&gt;I use &lt;a href=&quot;https://neomutt.org/&quot;&gt;Neomutt&lt;/a&gt; instead of Mutt so all of the configurations assume Neomutt’s directory structure, they should be pretty similar though. Install Neomutt using your trusty package manager, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;brew install neomutt&lt;/code&gt; perhaps. Next we create a configuration file for Neomutt at &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~/.config/neomutt/neomuttrc&lt;/code&gt; and copy in the following:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;## Accounts
# Variables
set my_user = &quot;$YOUR_EMAIL@protonmail.com&quot;
set my_pass = `security find-generic-password -a YOUR_EMAIL@protonmail.com -s imaps://localhost -w`

# Protonmail

set realname = &quot;Firstname Lastname&quot;
set smtp_url = smtp://$my_user:$my_pass@127.0.0.1:1025
set ssl_force_tls
set ssl_starttls
set from = &quot;$YOUR_EMAIL@protonmail.com&quot;
set envelope_from
set use_from = &quot;yes&quot;

set mbox_type=Maildir
set folder=~/.mail/
set record=+Sent
set postponed=+Drafts
set trash=+Trash
set mail_check=2 # seconds

set virtual_spoolfile # use first defined virtual-mailbox as spool
virtual-mailboxes &quot;INBOX&quot; &quot;notmuch://?query=folder:INBOX&quot;
virtual-mailboxes &quot;Archive&quot; &quot;notmuch://?query=folder:Archive&quot;
virtual-mailboxes &quot;Sent&quot; &quot;notmuch://?query=folder:Sent&quot;
virtual-mailboxes &quot;Trash&quot; &quot;notmuch://?query=folder:Trash&quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;em&gt;This is a snippet from my neomuttrc that handles mail access and SMTP, I will publish my full configuration at some point, but this will get you started&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Things to note here are &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;set my_pass&lt;/code&gt; which is once again grabbing our password from the Keychain and the use of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;virtual-mailboxes&lt;/code&gt; to leverage notmuch, even if we are not doing much with it in this simple configuration.&lt;/p&gt;

&lt;h1 id=&quot;startup&quot;&gt;Startup&lt;/h1&gt;

&lt;p&gt;Now we have everything in place we can get it running. Make sure Proton Bridge is running then execute &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;offlineimap&lt;/code&gt; in a terminal to start the synchronization process. Once it is done offlineimap will call notmuch to index the emails thanks to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;postsynchook = notmuch new&lt;/code&gt; in its configuration file. After the initial sync is done (which may take a while) you can launch &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;neomutt&lt;/code&gt; and start working on your email!&lt;/p&gt;

&lt;p&gt;Assuming everything works you probably want Proton Bridge and offlineimap to run on startup, which I will leave up to you and your OS.&lt;/p&gt;</content><author><name></name></author><category term="cli" /><category term="offlineimap" /><category term="notmuch" /><category term="neomutt" /><summary type="html">Protonmail is a great service, after using it for over a year I cannot see myself returning to GMail or moving to another email service in the near future. Out of the box however it misses a few key features:</summary></entry><entry><title type="html">…Blogging: Going Static</title><link href="/2019/01/16/going-static.html" rel="alternate" type="text/html" title="…Blogging: Going Static" /><published>2019-01-16T18:54:13+00:00</published><updated>2019-01-16T18:54:13+00:00</updated><id>/2019/01/16/going-static</id><content type="html" xml:base="/2019/01/16/going-static.html">&lt;p&gt;For the past three years I have run this blog off of the Ghost CMS platform, and it has been good to me. I backed Ghost on Kickstarter way back in its infancy, I stuck with it through the good times and the bad, sadly however my time with the platform has come to an end. But why?&lt;/p&gt;

&lt;h1 id=&quot;ease&quot;&gt;Ease&lt;/h1&gt;

&lt;p&gt;No matter what CMS you pick they all have one thing in common, they need care and feeding, as do their components. When you commit to a CMS you take on a bunch of responsibilities, the CMS itself, the underpinning technologies, the database, all of these things need attention to keep them running smoothly.&lt;/p&gt;

&lt;p&gt;I also used a custom theme, which meant that every release I was having to tweak my code to keep it compatible with Ghost. Did I have to use a custom theme? Of course not, but I wanted to and that meant a lot of time hacking in fixes to account for new features I would never use anyway.&lt;/p&gt;

&lt;p&gt;By switching to a static site I was greatly reducing the number of dependencies I had to manage as well as reducing the amount of tinkering required to keep my site current.&lt;/p&gt;

&lt;h1 id=&quot;security&quot;&gt;Security&lt;/h1&gt;

&lt;p&gt;The vast majority of modern web site security issues can be boiled down to two main culprits. The first is that people dont keep things up to date, and in the world of the CMS we have a lot of moving parts that need to be patched, not least of which is the CMS itself. With my new static site all I have to do is keep the core OS up to date along with a single extra package, the web server.&lt;/p&gt;

&lt;p&gt;The second culprit is the trend towards interactivity. Back in The Good Old Days (tm) web sites were simple delivery mechanisms much like this one. Now it is percieved that we must accept user input in some way, be that a login, comments, or more complex web application functionality. Wherever we accept input however that input can be exploited by malicious actors for nefarious means. By returning to a static platform I have negated a whole slew of potential security issues in a single move.&lt;/p&gt;

&lt;h1 id=&quot;environmetal-concerns&quot;&gt;Environmetal concerns&lt;/h1&gt;

&lt;p&gt;For Ghost I operated a fairly minimal custom theme, this was designed to help the environment a little with each page load by forgoing the fancy bells and whistles of many sites and the CPU cycles needed to render them. Whilst this project will likely die with this move to static content you can read more about it &lt;a href=&quot;/skinnyspook&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The CMS and associated infrastructure was still absorbing more natural resources than strictly necessary however, and by waving it goodbye I can save even more CPU cycles than ever before.&lt;/p&gt;

&lt;h1 id=&quot;hello-jekyll&quot;&gt;Hello Jekyll&lt;/h1&gt;

&lt;p&gt;So this is goodbye Ghost, but hello Jekyll. I will likely do a later post on why I selected Jekyll over the large number of other trendy site generators out there, but for now welcome to our brave new world!&lt;/p&gt;</content><author><name></name></author><category term="blogging" /><summary type="html">For the past three years I have run this blog off of the Ghost CMS platform, and it has been good to me. I backed Ghost on Kickstarter way back in its infancy, I stuck with it through the good times and the bad, sadly however my time with the platform has come to an end. But why?</summary></entry><entry><title type="html">…40k: Picking up the hobby again</title><link href="/2018/07/14/40k-picking-up-the-hobby-again.html" rel="alternate" type="text/html" title="…40k: Picking up the hobby again" /><published>2018-07-14T03:37:54+00:00</published><updated>2018-07-14T03:37:54+00:00</updated><id>/2018/07/14/40k-picking-up-the-hobby-again</id><content type="html" xml:base="/2018/07/14/40k-picking-up-the-hobby-again.html">&lt;p&gt;The last time I played Warhammer 40000 I was 15 years old give or take. We played about once a month on a pool table in my friend’s basement with half painted armies, makeshift terrain and more house rules than i care to remember. Fast forward a few years and I have a friend who dearly wants to pick up the game again and thats enough of an excuse for me. The problem, i need an army ready in a months time.&lt;/p&gt;

&lt;h1 id=&quot;army-selection&quot;&gt;Army Selection&lt;/h1&gt;

&lt;p&gt;A hurried rule book purchase and speed read caught me up on the lore (which has seen some pleasant progression since I last played and holy crap Eye of Terror everywhere!) My first task was picking an army to build and paint in one month. Here are the guidelines i set for myself:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;This army is not forever, do not get too hung up on it&lt;/li&gt;
  &lt;li&gt;I need to acquire ~1000 points of it in one month&lt;/li&gt;
  &lt;li&gt;The army needs to be easy to paint in the alotted time&lt;/li&gt;
  &lt;li&gt;Xenos or heretic only, everyone plays Imperium, try something different&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&quot;the-candidates&quot;&gt;The Candidates&lt;/h1&gt;

&lt;h1 id=&quot;necrons&quot;&gt;Necrons&lt;/h1&gt;

&lt;p&gt;My gut reaction was to go Necron. They were practically non existent when I last played and it was fun seeing how they had grown into the lore, more importantly they checked all of my selection criteria. I did not love the idea though, not sure why. They stayed on the shortlist but I kept looking.&lt;/p&gt;

&lt;h1 id=&quot;dark-angels-fallen&quot;&gt;Dark Angels Fallen&lt;/h1&gt;

&lt;p&gt;I have always wanted to play an army of Fallen, I love the lore behind them and Dark Angels models are great. The catch, there was no way I was painting an army that ornate in time with my rusty modelling skills. This idea is on the back burner, but does not fit the criteria for now.&lt;/p&gt;

&lt;h1 id=&quot;craftworld-aeldari-eldar&quot;&gt;Craftworld Aeldari (Eldar)&lt;/h1&gt;

&lt;p&gt;Their name may have changed, and they may be one craftworld short compared to when I last played, but do they fit the criteria? At first I figured not, but then I remembered the fluff for Iyanden. Wraith models seemed to be easy to paint in bulk, and I had always wanted to give the Eldar a shot.&lt;/p&gt;

&lt;h1 id=&quot;next-steps&quot;&gt;Next Steps&lt;/h1&gt;

&lt;p&gt;After settling on an Iyanden war host I ordered the Codex and the Start Collecting box (which handily is loaded with Wraith stuff). Next stop, testing paint schemes.&lt;/p&gt;</content><author><name></name></author><category term="40k" /><summary type="html">The last time I played Warhammer 40000 I was 15 years old give or take. We played about once a month on a pool table in my friend’s basement with half painted armies, makeshift terrain and more house rules than i care to remember. Fast forward a few years and I have a friend who dearly wants to pick up the game again and thats enough of an excuse for me. The problem, i need an army ready in a months time.</summary></entry><entry><title type="html">…Azure: Replacing SSL Certificates on Application Gateways</title><link href="/2017/03/19/azure-replacing-ssl-certificates-on-application-gateways.html" rel="alternate" type="text/html" title="…Azure: Replacing SSL Certificates on Application Gateways" /><published>2017-03-19T00:52:30+00:00</published><updated>2017-03-19T00:52:30+00:00</updated><id>/2017/03/19/azure-replacing-ssl-certificates-on-application-gateways</id><content type="html" xml:base="/2017/03/19/azure-replacing-ssl-certificates-on-application-gateways.html">&lt;p&gt;There is a strange gap in the documentation for Azure Application Gateways around that famous Microsoft afterthought, SSL offload. Specifically, I am talking about what to do when an SSL certificate expires which if you are following best practices will be every year or two.&lt;/p&gt;

&lt;p&gt;The general advice is to perform a rip and replace of the listener, which is a downtime inducing event on not really practical in a busy production environment. Luckily we can remedy the issue with no outage with a few lines of PowerShell, but it would be nice if Microsoft would put this in the portal for all to use freely!&lt;/p&gt;

&lt;h1 id=&quot;the-script&quot;&gt;The Script&lt;/h1&gt;

&lt;p&gt;The Powershell to achieve the replacement is simple and looks like this:&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/philskents/2ad54e1dbe1e852df119683eca3155ba.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;First, we grab our Application Gateway and pop it into a variable. Next, we grab our certificate and do the same. One important note here is the Certificate Name MUST match the name of the certificate attached to your Application Gateway (you can find the name in the portal and in the resource explorer). Finally, we commit the change to our Application Gateway, a process that will take around 15 minutes so do not panic!&lt;/p&gt;

&lt;h1 id=&quot;disclaimer&quot;&gt;Disclaimer&lt;/h1&gt;

&lt;p&gt;Use this code at your own risk. It is provided without warranty, guarantee and if used incorrectly could hose all your backups and this would not be my fault!&lt;/p&gt;</content><author><name></name></author><category term="azure" /><summary type="html">There is a strange gap in the documentation for Azure Application Gateways around that famous Microsoft afterthought, SSL offload. Specifically, I am talking about what to do when an SSL certificate expires which if you are following best practices will be every year or two.</summary></entry><entry><title type="html">…Immigration: Adjustment of Status from L1-B (I-130 &amp;amp; I-485)</title><link href="/2017/01/12/immigration-adjustment-of-status-from-l1-b-i-130-i-485.html" rel="alternate" type="text/html" title="…Immigration: Adjustment of Status from L1-B (I-130 &amp;amp; I-485)" /><published>2017-01-12T03:42:37+00:00</published><updated>2017-01-12T03:42:37+00:00</updated><id>/2017/01/12/immigration-adjustment-of-status-from-l1-b-i-130-i-485</id><content type="html" xml:base="/2017/01/12/immigration-adjustment-of-status-from-l1-b-i-130-i-485.html">&lt;p&gt;This post is a brief PSA. For anyone adjusting from an L1-B visa to Green Card via meeting a wonderful American guy/girl (i.e. marriage) your package to USCIS should look a little like this:&lt;/p&gt;

&lt;h1 id=&quot;packet-cover&quot;&gt;Packet Cover&lt;/h1&gt;

&lt;ul&gt;
  &lt;li&gt;Cover letter for the entire packet (&lt;a href=&quot;https://docs.google.com/document/d/1NXATa-J3lzUikB0RnpelfaNsnIhspPWDCNSya3ODVGY/edit?usp=sharing&quot;&gt;example&lt;/a&gt;)&lt;/li&gt;
  &lt;li&gt;Completed G-1145 (e-notification registration)&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&quot;first-folder-i-130&quot;&gt;First Folder (I-130)&lt;/h1&gt;

&lt;ul&gt;
  &lt;li&gt;Cover letter for I-130 (&lt;a href=&quot;https://docs.google.com/document/d/15gKkCMbIbrL-0YTrTc9xZVBoQCf9EKVfWsaK6bawb40/edit?usp=sharing&quot;&gt;example&lt;/a&gt;)&lt;/li&gt;
  &lt;li&gt;Payment as per the list of fees found &lt;a href=&quot;https://www.uscis.gov/forms/our-fees&quot;&gt;here&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Completed form I-130 with attached evidence:
    &lt;ul&gt;
      &lt;li&gt;Copy of Petitioner’s U.S. birth certificate&lt;/li&gt;
      &lt;li&gt;Copy of Petitioner’s U.S. passport biographic page&lt;/li&gt;
      &lt;li&gt;Copy of the marriage certificate&lt;/li&gt;
      &lt;li&gt;Copy of any divorce certificates (if applicable)&lt;/li&gt;
      &lt;li&gt;One passport sized photo of the Petitioner (placed in a zip lock bag and attached to a blank sheet of paper)&lt;/li&gt;
      &lt;li&gt;One passport-sized photo of the Applicant (placed in a zip lock bag and attached to a blank sheet of paper)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;One completed G-325A filled out by the Petitioner&lt;/li&gt;
  &lt;li&gt;One completed G-325A filled out by the Applicant with attached evidence:
    &lt;ul&gt;
      &lt;li&gt;Copy of the Applicant’s foreign birth certificate&lt;/li&gt;
      &lt;li&gt;Copy of the Applicant’s visa page and associated passport stamps&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Evidence of a bonafide marriage which can include any of the items listed &lt;a href=&quot;http://www.immihelp.com/greencard/bona-fide-marriage-documentation.html&quot;&gt;here&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&quot;second-folder-i-485&quot;&gt;Second Folder (I-485)&lt;/h1&gt;

&lt;ul&gt;
  &lt;li&gt;Cover letter for I-485 (&lt;a href=&quot;https://docs.google.com/document/d/1ZVG1bSlLUr-AZOGLJWEr_uHeFLWSaV8c9x8eJT5-uhI/edit?usp=sharing&quot;&gt;example&lt;/a&gt;)&lt;/li&gt;
  &lt;li&gt;Payment as per the list of fees found &lt;a href=&quot;https://www.uscis.gov/forms/our-fees&quot;&gt;here&lt;/a&gt; (include payment for both I-485 and the biometric appointment in one check)&lt;/li&gt;
  &lt;li&gt;Form I-485, Application to Adjust Status with the following attached:
    &lt;ul&gt;
      &lt;li&gt;Copy of Applicant’s foreign birth certificate&lt;/li&gt;
      &lt;li&gt;Copy of Applicant’s foreign passport including L-1B visa and stamps (all pages)&lt;/li&gt;
      &lt;li&gt;Copy of Applicant’s latest I-94&lt;/li&gt;
      &lt;li&gt;Two passport-sized photos of the Applicant (placed in a zip lock bag and attached to a blank sheet of paper)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;I-693, Medical Examination of the Beneficiary completed by a civil surgeon, in a sealed (unopened) envelope&lt;/li&gt;
  &lt;li&gt;G-325A, Biographic Information filed by the Applicant&lt;/li&gt;
  &lt;li&gt;I-864, Affidavit of Support filed by Petitioner and the following supporting documents:
    &lt;ul&gt;
      &lt;li&gt;Copy of Petitioner’s US Passport as proof of citizenship&lt;/li&gt;
      &lt;li&gt;Copy of Petitioner’s last 3 years of tax returns&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;I-765, Application for Employment Authorization with the following attached:
    &lt;ul&gt;
      &lt;li&gt;Copy of Applicant’s Passport&lt;/li&gt;
      &lt;li&gt;Copy of Applicant’s existing Visa&lt;/li&gt;
      &lt;li&gt;Copy of Applicant’s foreign birth certificate&lt;/li&gt;
      &lt;li&gt;Copy of I-797C from previous work authorization&lt;/li&gt;
      &lt;li&gt;Two passport-sized photos of the applicant (placed in a zip lock bag and attached to a blank sheet of paper)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;I-131, Application for Travel Document (Advance Parole) with following attached:
    &lt;ul&gt;
      &lt;li&gt;Explanation for Form I-131 filing (&lt;a href=&quot;https://docs.google.com/document/d/1kK5pGKPAnFmhHnSCvcGcIfpV9zfOL2Bp2bAHkfOwthE/edit?usp=sharing&quot;&gt;example&lt;/a&gt;)&lt;/li&gt;
      &lt;li&gt;Two passport-sized photos of the applicant (placed in a zip lock bag and attached to a blank sheet of paper)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Take the two folders, put them in one envelope and ship them off to the Chicago lockbox. All this information is provided with zero warranty, YMMV!&lt;/p&gt;</content><author><name></name></author><category term="immigration" /><summary type="html">This post is a brief PSA. For anyone adjusting from an L1-B visa to Green Card via meeting a wonderful American guy/girl (i.e. marriage) your package to USCIS should look a little like this:</summary></entry><entry><title type="html">…Azure: Redirecting HTTP to HTTPS with Azure Application Gateways and SSL Offload</title><link href="/2016/08/23/appgatewayhttptohttps.html" rel="alternate" type="text/html" title="…Azure: Redirecting HTTP to HTTPS with Azure Application Gateways and SSL Offload" /><published>2016-08-23T18:41:18+00:00</published><updated>2016-08-23T18:41:18+00:00</updated><id>/2016/08/23/appgatewayhttptohttps</id><content type="html" xml:base="/2016/08/23/appgatewayhttptohttps.html">&lt;p&gt;OK, someone at Microsoft really dropped the ball with this one. HTTP to HTTPS redirection is one of those things that everyone needs to do, and in fact everyone should do (seriously, there is no excuse for unencrypted HTTP now, stop it).&lt;/p&gt;

&lt;p&gt;This is even stranger when you consider the fact that all the Application Gateway actually consists of is a specially configured IIS VM set. And to do this natively in IIS is really quite easy. Until Microsoft fix this little faux pas however there is a simple workaround using a small Ubuntu VM and a little reconfiguration of our Application Gateway.&lt;/p&gt;

&lt;h1 id=&quot;concept&quot;&gt;Concept&lt;/h1&gt;

&lt;p&gt;What we are trying to achieve is summarized in this diagram.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/azure_https_redirect.png&quot; alt=&quot;Application Gateway redirect diagram&quot; /&gt;&lt;/p&gt;

&lt;p&gt;We will be setting up two ports on our application gateway, one for plain traffic (port 80) and one for HTTPS traffic (port 443). When the gateway receives HTTP traffic it will forward it to an Ubuntu server running nginx where the request will be redirected to HTTPS. HTTPS traffic will be decrypted at the gateway and passed to our IIS box as normal.&lt;/p&gt;

&lt;h1 id=&quot;how-to&quot;&gt;How To&lt;/h1&gt;

&lt;p&gt;For the purposes of this guide I will assume you have already configured an Application Gateway with SSL offload and the backend IIS (or other web server) to match. I will focus on building the Ubuntu 16.04 VM and configuring nginx, as well as modifying the Application Gateway configuration.&lt;/p&gt;

&lt;h2 id=&quot;building-the-redirect-server&quot;&gt;Building the redirect server&lt;/h2&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;Provision a new Ubuntu VM from the Azure Portal. It does not have to be particularly large, remember it will exist solely to redirect traffic.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Once the machine is provisioned and you have logged in lets get everything up to date.&lt;/p&gt;

    &lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sudo apt-get update &amp;amp;&amp;amp; sudo apt-get upgrade&lt;/code&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Next we install nginx.&lt;/p&gt;

    &lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sudo apt-get install nginx&lt;/code&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;With nginx installed we can now start getting it configured. As we will be using this box for redirects only we can simply modify the default configuration.&lt;/p&gt;

    &lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sudo nano /etc/nginx/sties-available/defuault&lt;/code&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Delete the contents of this file and replace them with the following.&lt;/p&gt;

    &lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;server {
     listen 80 default_server;
     listen [::]:80 default_server;
     server_name _;
     return 301 https://$host$request_uri;
 }&lt;/code&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Restart nginx to apply the new configuration.&lt;/p&gt;

    &lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sudo service restart nginx&lt;/code&gt;&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;configuring-the-application-gateway&quot;&gt;Configuring the Application Gateway&lt;/h2&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;Log into the Azure Portal and find the Application Gateway that you wish to modify.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Under Settings select Backend Pools and add a new pool with your redirect server configured as the target IP.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Select listeners and create a new listener on port 80 for HTTP if you do not have one already.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Select Rules and create a new basic rule which takes your newly created listener and forwards it to your new backend pool.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;And thats it. I agree, this is a “hack” at best and Microsoft need to add a simple “Redirect HTTP to HTTPS” button somewhere in there. But if you need this capability now, this works!&lt;/p&gt;</content><author><name></name></author><category term="azure" /><summary type="html">OK, someone at Microsoft really dropped the ball with this one. HTTP to HTTPS redirection is one of those things that everyone needs to do, and in fact everyone should do (seriously, there is no excuse for unencrypted HTTP now, stop it).</summary></entry><entry><title type="html">…Powershell: Deleting old files from Azure Blob Storage</title><link href="/2016/08/17/deletingoldfilesfromazureblobstorage.html" rel="alternate" type="text/html" title="…Powershell: Deleting old files from Azure Blob Storage" /><published>2016-08-17T18:54:13+00:00</published><updated>2016-08-17T18:54:13+00:00</updated><id>/2016/08/17/deletingoldfilesfromazureblobstorage</id><content type="html" xml:base="/2016/08/17/deletingoldfilesfromazureblobstorage.html">&lt;p&gt;Backing up to Azure Blob Storage is great, especially if like me you use Ola Hallengren’s amazing (and free) jobs to backup MS SQL Server (and if you don’t, I recommend you do, find out more &lt;a href=&quot;https://ola.hallengren.com/&quot;&gt;here&lt;/a&gt;). What is not quite so awesome is cleaning up old files. Blobs do not behave like files, and certainly if you use Ola’s jobs setting the cleanup time when using a URL for the backup destination will cause the backup to fail. There is however hope, because we can do our cleanup using PowerShell!&lt;/p&gt;

&lt;h1 id=&quot;the-code&quot;&gt;The Code&lt;/h1&gt;

&lt;p&gt;The Gist below contains the code at time of writing. For the latest and greatest version keep an eye on the &lt;a href=&quot;https://github.com/philskents/pjspssnippets/blob/master/azure/Remove-OldAzureStorageBlob.ps1&quot;&gt;Github repo&lt;/a&gt;.&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/philskents/4e61ebe418a7861ed294044814d193d7.js&quot;&gt; &lt;/script&gt;

&lt;p&gt;Save this with a .ps1 extension and schedule it as you see fit.&lt;/p&gt;

&lt;h1 id=&quot;the-detail&quot;&gt;The Detail&lt;/h1&gt;

&lt;p&gt;We capture 7 arguments to make this script tick:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;storageAccountName&lt;/strong&gt; - The name (NOT the URL) of our Azure Storage Account&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;storageAccountKey&lt;/strong&gt; - The key for the Storage Account&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;containerName&lt;/strong&gt; - The name of the container we want to clean up&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;age&lt;/strong&gt; - The maximum age of the files we want to keep, anything older will be removed&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;errorSMTPServer&lt;/strong&gt; - The SMTP server to use to send an email if something goes wrong&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;errorSourceAddress&lt;/strong&gt; - The from email of any error messages&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;errorDestAddress&lt;/strong&gt; -  The to email of any error messages&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When working with Blob Storage we have to first build the storage context ($context in the above script) We do this by running New-AzureStorageContext and passing in the storage account name and storage account key we capture as parameters. Interestingly, this cmdlet does not verify this inforamtion, it just build a context object which we can then pass to other Azure storage cmdlets.&lt;/p&gt;

&lt;p&gt;The try/catch block then executes the Get-AzureBlobStorage cmdlet using our storage context from above and also adding the container to search. The results are filtered for anything older than the specified age and finally the filtered results passed to Remove-AzureStorageBlob for immediate destruction.&lt;/p&gt;

&lt;p&gt;Should anything go wrong the catch block grabs the error and sends it via email using the details provided.&lt;/p&gt;

&lt;h1 id=&quot;disclaimer&quot;&gt;Disclaimer&lt;/h1&gt;

&lt;p&gt;Use this code at your own risk. It is provided without warranty, guarantee and if used incorrectly could hose all your backups and this would not be my fault!&lt;/p&gt;</content><author><name></name></author><category term="powershell" /><summary type="html">Backing up to Azure Blob Storage is great, especially if like me you use Ola Hallengren’s amazing (and free) jobs to backup MS SQL Server (and if you don’t, I recommend you do, find out more here). What is not quite so awesome is cleaning up old files. Blobs do not behave like files, and certainly if you use Ola’s jobs setting the cleanup time when using a URL for the backup destination will cause the backup to fail. There is however hope, because we can do our cleanup using PowerShell!</summary></entry></feed>