Self hosted mail server

I have had enough. It’s bad enough that social media has become the scourge of the Internet, but that doesn’t mean key services such as email should have to be stronghold(ed?) by Big Corp such as Google, Microsoft, and other massive vendors.

The Internet was built on a foundation of globally connected computers that chose to share information between eachother and all was well.

Now, pretty much _EVERYTHING_ on the web is behind some kind of walled garden and/or being harvested for user behaviour studies to increase revenue (through ads, mostly).

But I’d like to see if I can do something about this, in as far as my capabilities goes; it’s time to “take back” (I’ve actually never hosted my own email server before, so it’s more of a “move the responsibility of”) my emails.

This is a part guide, part resource, part tutorial on how I set my email up on a VPS service. You won’t be getting every single step as a command or how to edit your DNS records for your control panel on your registrar, but you should at least get a fairly detailed explanation of all the steps that are involved.

A word of forebearance

You will see me ramble and critisice from time to time. This isn’t a personal attack on anyone. It’s just that I have had to, on multiple occasions, go down a number of rabbit holes because documentation has been patchy, old and at times nonsensical. I know part of this frustration come from my own ineptness, so don’t take it too seriously. I am a huge fan of all the individuals that put their time into creating a set of tools such as docker-mailserver and make it next to a no-brainer to get it up and running. A big thank you to everyone involved.

Let’s get to the grind.

Tech stack

I have chosen to use the following techs

  • External VPS hosting – It is fairly cheap, and email shouldn’t require exorbitant amounts of resources, and you _have to_ be able to edit reverse DNS records
  • Debian 10 – No particular reason other than I like Debian
  • docker-mailserver – It has proven to be a one stop shop for an easy (well) get up and running component stack of different software that can deal with email

Look at your inventory before you move on

IP blacklisting delisting

Make sure your chosen server host isn’t on any kind of IP or email blacklist. This activity is a tough one with a big risk of being costly (as in $$$) since you

  • probably don’t know what IP you get (this post assumes 123.123.123.123)
  • don’t know if that IP is on any list yet
  • may not know of any tools can help you figure out what lists you are on

I don’t have an answer to all of this. You can use MX Toolbox’s blacklist lookup tool, but there are probably a lot more blacklisting going on that you will want to try and find so you have an ounce more chance of not getting you emails flagged as spam from the getgo.

I got to know my IP was on the BARRACUDA blacklist and I made an attempt at sending in a delisting request through their online form, and I seem to have been released from their clutches.

Microsoft/Outlook/Office are picky as all get out as well, so make additional efforts to get your IP delisted from there as well, even if you suspect you’re not on their list: https://sender.office.com/

rDNS (reverse DNS)

Get a host that supports rDNS (reverse DNS) and set a reverse value to something that you own, so that when a lookup happens (be it forward or reverse), they get the same hostnames and IP. E.g.;

$ host my.host // returns: "my.host has address 123.123.123.123"
$ dig +noall +answer -x 123.123.123.123 // returns: "123.123.123.123-in-addr.arpa [number] IN PTR my.host"

You could also use MX Toolbox reverse lookup tool to test this by supplying your mail host’s IP address and have it look this up for you.

Setting up docker-mailserver (and moar)

docker-mailserver

  1. Install docker and docker-compose on your host
  2. Get the docker-mailserver setup.sh script of your choice
    (honestly, the maintainers of docker-mailserver failed me here, because their documentation/guides are so bad at clearly explaining where you find different versions of this script, so you run into a big risk of using the wrong script version with the wrong docker-mailserver version, resulting in a bunch of issues.
    My take; Use a stable version of the script and docker-mailserver. Don’t attempt to run their “edge” version or whatever, since if you want to run this in any proper capacity, you want stable things.)
  3. Go to https://github.com/docker-mailserver/docker-mailserver/tags and take note of the release version name you want. For me, at this time, I’m going with v10.0.0
  4. Go to docker-mailservers Github main page and switch branches to the TAG you want. For me, that’s v10.0.0
  5. Locate the setup.sh file in the file tree and download it to somewhere on your mail server host.
    $ wget https://raw.githubusercontent.com/docker-mailserver/docker-mailserver/v10.0.0/setup.sh)
  6. $ chmod a+x ./setup.sh
  7. You also want a copy of the docker-compose.yml file
    $ wget https://raw.githubusercontent.com/docker-mailserver/docker-mailserver/v10.0.0/docker-compose.yml
  8. You also want a copy of the mailserver.env file
    $ wget https://raw.githubusercontent.com/docker-mailserver/docker-mailserver/v10.0.0/mailserver.env
  9. Now, here’s where things start to get tricky because you need to configure your docker-compose.yml and mailserver.env files to your liking, and that’s going to take some reading up on:
  10. $ docker-compose pull
  11. Test the runability of the setup.sh script (I have no idea why this script doesn’t have a CURRENT SCRIPT version that you can echo…..): $ ./setup.sh If this outputs a bunch of text with neat sections, you’re probably good to go.

Here be dragons. Read this. It’s important. I have based a lot of this tutorial from https://docker-mailserver.github.io/docker-mailserver/edge/examples/tutorials/basic-installation/ but this specific step we are coming to, creating keys for DKIM, is missing a crucial step; you have to create a mail account on your mail server before generating the DKIM. Why? No idea yet. Why isn’t it mentioned in the doc? Beats me. But you should really really make it clear to the authors of this document that this is serious flaw to not have included. I spent a lot of time on google to figure this out…..

  1. Add an account to your mailserver $ ./setup.sh -i mailserver/docker-mailserver:10.0.0 email add info@ifthenel.se
    (For some reason the script doesn’t take into account any of the docker-compose.yml settings that specifically points out a designated version to interact with, so I’m including -i parameter. I can’t tell when omitting this would cause issues, so I include it for the setup parts, but not later)
  2. Set up DKIM with your docker-mailserver tag of choice: $ ./setup.sh -i mailserver/docker-mailserver:10.0.0 config dkim

DNS

This part is tricky, because DNS records are finicky, they need to be thoroughly tested and take HEAPS of time to update. You will spend quite some time with this if you don’t get it right on the first try. Get yourself a couple of days vacation for this part.

DKIM

  • TXT record
  • Hostname: mail._domainkey.my.domain
  • Value: Whatever is in the opendkim text file


Add the newly created DKIM details to your domain’s DNS records by first echoing them for easy copy and paste:
$ cat config/opendkim/keys/my.domain/mail.txt

This produces something you should add to your DNS records. Here’s the kicker; The strings are long and deliberately cut off because the maintainers don’t know if your DNS hoster supports strings that are longer than 255 characters in length. So, you will have either a good time entering these as you might know your DNS hoster’s limitations, or, more likely, a bad time and you have to figure out how to get these details stored properly. There’s some help though. MX Toolbox has a DKIM checker that you can utilise to verify you have your stuff set up right: https://mxtoolbox.com/dkim.aspx Good luck.

In the DNS editor, your hostname for this TXT record should be mail._domainkey.my.domain and the value should be the long ass string output from the cat command above.

After a long wait, check with the MX Toolbox DKIM Lookup

SPF

  • TXT record
  • Hostname: @
  • Value: v=spf1 mx ~all

This is simpler, because there are very few parameters. It’s still required for your emails to have a decent chance of not being marked as spam. There can be some benefit to adding refernces to other known SPF records, such as tthe ones used by Outlook, etc. One of those is “spf.protection.outlook.com”

Add a TXT record to your @ (hostname/zone/whatit’scalled) with the value: v=spf1 mx ~all

Tip: If you want to add Microsoft Outlook’s SPF, you would change the value to v=spf1 include:spf.protection.outlook.com mx ~all

Subdomain

  • A record
  • Hostname: mail
  • Value: IP address of your mail server host

Also a simpler DNS record change. You want to have a subdomain that keeps tabs on the IP address of you mail server host.

  1. Add an A record to the subdomain mail with the value of your mail server host IP address

MX

  • MX record
  • Hostname: @ or mail.my.domain.
  • Value: mail.my.domain

This is used for telling every server on the internets that you have a mail server somewhere with a certain subdomain name

  1. Add an MX record to the @ (hostname/zone/whatit’scalled) with the value mail.my.host.

DMARC

  • TXT record
  • Hostname: _dmarc.my.domain
  • Value: v=DMARC1; p=quarantine; rua=mailto:postmaster@my.domain; ruf=mailto:postmaster@my.domain; fo=1; adkim=s; aspf=s; pct=100; rf=afrf; ri=86400; sp=quarantine

Complicateder piece of DNS record than the last two, because there are a bunch of parameters in the TXT records that you should read up on and understand. I’ll just give you what I use for now.

  1. Add a TXT record to the _dmarc hostname with the value: v=DMARC1; p=quarantine; rua=mailto:postmaster@my.domain; ruf=mailto:postmaster@my.domain; fo=1; adkim=s; aspf=s; pct=100; rf=afrf; ri=86400; sp=quarantine

Testing

Here’s the part where you need to verify and verify again that everthing is in working order. Mostly MX Toolbox to the rescue.

MX

What you are looking for in the results is something along the lines of

  • Pref: 0
  • Hostname: my.domain
  • IP address: 123.123.123.123

If there are more than one result in the table, you want to ensure your email server, the one with the IP of 123.123.123.123, is at the top, with a “Pref” (priority) value that is lower than any of the others.

SPF

What you are looking for in the results is something along the lines of 4 rows, detailing the parameters of the SPF record. For instance, if the SPF record in DNS was set to: “v=spf1 include:spf.protection.outlook.com mx ~all” you want a result such as:

vspf1The SPF record version
+includespf.protection.outlook.comPassThe specified domain is searched for an ‘allow’.
+mxPassMatch if IP is one of the MX hosts for given domain name.
~allSoftFailAlways matches. It goes at the end of your record.

DKIM

  • https://mxtoolbox.com/dkim.aspx
  • Format: my.domain:mail

What you are looking for in the results is something along the lines of 4 rows, detailing the parameters of the DKIM record. For instance, if the DKIM (mail._domainkey) was set to: “v=DKIM1; h=sha256; k=rsa; p=jasdfjidjelajdvlkjg” you want a result such as:

vDKIM1VersionIdentifies the record retrieved as a DKIM record. It must be the first tag in the record.
hsha256Hash AlgorithmsA colon-separated list of hash algorithms that might be used.
krsa (Length: 4096 bits)Key TypeKey Type The type of the key used by tag (p).
pjasdfjidjelajdvlkjgPublic KeyThe syntax and semantics of this tag value before being encoded in base64 are defined by the (k) tag.

DMARC

  • https://mxtoolbox.com/dmarc.aspx
  • Format: my.domain

What you are looking for in the results is something along the lines of 10 rows, detailing the parameters of the DMARC record. For instance, if the DMARC (my.domain) was set to: “” you want a result such as:

vDMARC1VersionIdentifies the record retrieved as a DMARC record. It must be the first tag in the list.
p quarantine Policy Policy to apply to email that fails the DMARC test. Valid values can be ‘none’, ‘quarantine’, or ‘reject’.
pquarantinePolicyPolicy to apply to email that fails the DMARC test. Valid values can be ‘none’, ‘quarantine’, or ‘reject’.
ruamailto:postmaster@my.domainReceiversresses to which aggregate feedback is to be sent. Comma separated plain-text list of DMARC URIs.
rufmailto:postmaster@my.domainForensic ReceiversAddresses to which message-specific failure information is to be reported. Comma separated plain-text list of DMARC URIs.
fo1Forensic ReportingProvides requested options for generation of failure reports. Valid values are any combination of characters ’01ds’ seperated by ‘:’.
adkimsAlignment Mode DKIMIndicates whether strict or relaxed DKIM Identifier Alignment mode is required by the Domain Owner. Valid values can be ‘r’ (relaxed) or ‘s’ (strict mode).
adpfsAlignment Mode SPFIndicates whether strict or relaxed SPF Identifier Alignment mode is required by the Domain Owner. Valid values can be ‘r’ (relaxed) or ‘s’ (strict mode).
pct100PercentagePercentage of messages from the Domain Owner’s mail stream to which the DMARC policy is to be applied. Valid value is an integer between 0 to 100.
rfafrfForensic FormatFormat to be used for message-specific failure reports. Valid values are ‘afrf’ and ‘iodef’.
ri86400Reporting IntervalIndicates a request to Receivers to generate aggregate reports separated by no more than the requested number of seconds. Valid value is a 32-bit unsigned integer.
spquarantineSub-domain PolicyRequested Mail Receiver policy for all subdomains. Valid values can be ‘none’, ‘quarantine’, or ‘reject’.

There’s also a test results table, where you want all the checkmarks to turn up green.

TLS Cert using letsencrypt

My weapon of choice is and will probably for a long time be certbot/letsencrypt. I chose to use the officially provided script in “certonly” mode. It is fully possible to acquire a certificate without involing anything else. I had a small bump in the road where I included a domain that had an A record for my HTTP services and that failed the whole process because the HTTP service wouldn’t supply the info needed for certbot to complete. The gist of the command, though, is:

$ sudo certbot certonly --standalone  -d mail.my.domain1 -d mail.my.domain2 [more parameters]

and follow the instructions. Make sure to supply the mail domain, e.g. mail.my.domain and not only the root domain, as it can make things end up like it did for me in the beginning, where I don’t have a webserver that can properly reply on the ports/URL:s that certbot expects.

Now, edit the docker-compose.yml file to add a volume that points to the letsencrypt cert store path. For my setup this would result in a line under the volumes-section:

...
- /etc/letsencrypt:/etc/letsencrypt:ro
...

Don’t forget to restart your docker-mailserver, as a reload of details is required.

Catchall for everything but valid email accounts

This took some digging around. docker-mailserver isn’t really the authority here, but postfix, that’s included in docker-mailserver. I did find a couple of nice pointers in the docker-mailserver issue tracker that gave me the following understanding to get catchall to work as I expect; Catching all email to a single catchall-specific mail account, and deliver mail designated to valid accounts without ending up in both catchall and the valid account inbox:

  • Valid accounts need to have aliases to themselves
  • The domain, e.g. my.domain, need to have an alias pointing to the catchall account

So, for the sake of completeness, this is how would go about it:

  1. Create any valid email account(s) (these will require their own passwords)
  2. Create the catchall account (this will also require its own password)
  3. Create an alias to the catchall account with: ./setup.sh alias add @my.domain @catchall.my.domain
  4. Edit the newly created file config/postfix-virtual.cf and modify it to the following format:
account1@my.domain account1@my.domain
account2@my.domain account2@my.domain
...
@my.domain catchall@my.domain

The order is crucial. You want the catchall to be at the bottom of this file at all times.

Multiple domains, one server

This ties into the TLS Cert section, insofar that the command to generate valid certificates is:

$ sudo certbot certonly --standalone  -d mail.my.domain1 -d mail.my.domain2 [more parameters]

and you will need to secure that you have your docker-compose.yml file set up to take into account the certificates:

...
- /etc/letsencrypt:/etc/letsencrypt:ro
...

and you need to have restarted docker-mailserver to have it react to those changes.

And, you also need to have updated the mailserver.env file to tell docker-mailserver that you’ll be using letsencrypt.

Other than that, there’s a few more things needed for your second domain. It is in general much the same as your primary domain, except for a few specific details that need to be unique to your second domain. Here’s the complete list as to not miss out on anything

  • MX DNS record
  • SPF DNS record
  • DKIM DNS record
  • DMARC DNS record
  • An email account tied to the second domain

Ok, that’s a lot of stuff again! But here’s the kicker; a few of them you can use as they mostly are from your primary domain, and others are super easy to set up.

The ones you can copy and easily modify from your primary domain are

  • MX record – You will use the same IP address for this as the primary one
  • SPF record – You use the same TXT value as the primary one
  • DMARC record – You use the same TXT value as the primary one, but I also modified the postmaster email address to align with the second domain

And this is the part where you need to do a little more work

DKIM

This is very much like generating DKIM from the setup steps in this page;

  1. Create an email account, e.g. postmaster@second.domain
  2. Generate the DKIM DNS record details by running $ ./setup.sh config dkim which will generate new keyfiles for your new domain (remember that the setup.sh-script use the domain names of already created accounts to determine what domains to generate DKIM DNS records for)
  3. Copy and paste the value from $ cat config/opendkim/keys/second.domain/mail.txt and create a new DNS record as explained in the DKIM-section in the setup steps on this page.

WordPress to Fe-di…verse…?

This is another post in the series about WordPress discoverability for the people wanting to not put all their eggs in one basket by handing over all their content creations to walled gardens such as Google+, Facebook, Twitter, etc.

The problem about discoverability is one of the toughest challenges to overcome; with walled gardens, everyone has an account that can follow and be followed.
On a blog, you can get followers but you’re going to have to look into other data points than followers, because there aren’t clear cut numbers to look at. Instead of follower count you’d most likely have a look at visitors and page count as part of your website analytics package.

But, if one of the core problems to solve is discoverability, then what can you do to increase it?

Well, it depends. There are a multitude of paid services that can help you boost your messages to different networks, but what if you don’t want to spend d money on shady businesses and want to have more control of your communication? A connection to the “Fediverse” is one potential path to take.

The Fediverse is a collection/ensemble of different servers used for e.g. social networking, micro/macroblogging, file hosting and the likes. These servers communicate with other servers using a standardised protocol, making them compatible with eachother. A couple notable places being part of the Fediverse are Diaspora, Hubxilla and Mastodon.

Now, things aren’t super clear cut on what level these services coincidence. On the Wikipedia page linked above you’ll see in more detail what network has what integration available.

What you as a WordPress owner can do is to attempt to reach out within these servers on the Fediverse, e.g. by installing a plugin (or developing a solution of your own, but expect it to take significant effort) and having that do the heavy lifting.

I have tested two different plugins

I’ve been on the fence which one to use longer term, because both of them are considered to be beta in their current state. I’ve opted for Pterotype for now, as the developer is super responsive on Mastodon, and seem very ambitious about wanting this plugin to get a much needed rework.

It’s fairly straightforward to set Pterotype up, but be aware that to test this fully, you also need a Mastodon profile;

  1. Install the plugin using your method of choice
  2. Find the Pterotype settings in the administration panel and click it
  3. Make modifications to your liking
  4. If you haven’t already, create a Mastodon profile. mastodon.social is a popular place.
  5. On Mastodon, search for (include @-signs, but replace the [text] with your website): @blog@[yourwebsiteaddress]
  6. You should see a profile pop up that you can now follow on Mastodon
  7. All done, you’re now discoverable on (a part of) the Fediverse

This isn’t without limits, though.

The general idea is that your blog should have a two way communication with the Fediverse. E.g; you make a post from WordPress and it shows up on the Fediverse. Or you get a comment on the Fediverse on a post that you made in WordPress, you should be able to manage the comment like a regular comment on your post.

The first part is in place, however with the caveat that someone needs to follow it for the posts to automatically show up. What I did was to use my Mastodon profile, searched for my blog as described above, and the followed it. That way, it’s hooked up and “publishing” through your account.

The other part, about having bi-directional communication, is unfortunately not working right now. You, for the time being, have a one directional path into the Fediverse, but you’re not getting the comments sent back to WordPress. I’ll keep an eye on the progress of the plugin to see if there’s any news later on.

Leaving Google+ – a multi part story about “the how to what”…?

Being a long time, albeit sporadic, user of Google+, it’s with some resentment sadness surprise rage sense of meh I’m now trying to find a new place in the Wide World of Memes.

I’m going to ramble a bit about the problem space, where I’m at, and what I’ve been faced with in terms of starting up a blog, that not only I read. The part you’re about to read, is a generic “Where I’m at right now”, and even though I’m going through a process of leaving Google+ by force, finding a new space, this may very well apply to other scenarios.

I started out typing this as the only and single post for all of my thoughts and ideas, and experiences, but realised that it would probably wouldn’t ever be published, because I fear that it could be an ever ongoing subject/topic.

Technology choice

Given that I’m not keen on either Facebook, or Twitter, and I’m not really interested in letting someone else own my content any more, I believe the only fair option I have, is to run my very own website.

Now, running your own website isn’t super hard but it’s not super easy. Especially if a lot of the things you want to accomplish are to type some stuff on a computer and publish it to the world. And, as an added bonus, have and know that you have readers/lurkers that read it.

The reason this is easier, is that WordPress exists. WordPress is easy enough to at least type text in, add an image or two, and hey presto, instant words on the Memernet!

The reason it’s harder, is that if you want to make sure you own your content, to the extent that you can always bring it with you no matter what (as long as you’re not breaking the law that is), is that you basically need to install, set up and maintain your own web server and WordPress installation, by yourself.

Now, very often it’s enough to be semi-owning your stuff; a lot of web hotels offer built in WordPress installations and backup options for you, and unless you really want to know what it’s like to manage all the details that go into this, you’re probably just as well off with a hotel provided WordPress installation.

Discoverability

Ok, so you, as did I, decided to go the WordPress route at least. You’re still keen on running your own show, defining your own space and place in the vast web of content creators!

You probably don’t have much of an issue with the actual content creation; you got thoughts, ideas, creativity and energy to “just do it”. A few strokes of the keys, an image and whamo; blog post!

But, there’s something missing. Something that makes this all seem worthwhile. (No, not coffee. You got that right beside you, or behind your screen. You probably just forgot in all the excitement.)

But you’re missing that electricity to your eco friendly engine; visitors! And boy are those visitors hard to come by! I mean, you know they’re there, and in the millions at that, but they’re awfully shy. Or busy. Probably very busy. With Facebook. And Twitter. And Tumblr. And Google+. And MySpace.
So what do you do? How to make these people interested in your writing antics and photographic memess? Well, that’s discoverability in a nutshell; making sure you do whatever you can to make yourself discoverable.

Approaches

There are some caveats here, because some of you may think that it’s easy, and do any or all of these things:

  • Email everyone you know and don’t know about your site
  • Contact anyone and everyone on Facebook about your site
  • Buy dubious services that “make sure you’ll get more likes and subscriptions to your blog, as well as spreading the word” for just a few cents

The reason the above things are not really something you should do is because they label you and your site as being spam. Not only will they be annoyed and aggravated, they’ll make sure to do whatever is possible to block you in future communication.

So, what else is there? Well, here’s where tech can be off assistance, but don’t look at this as a silver bullet; it won’t automatically help you get 5 million readers to get you a fast retirement check. It may help you. And it will cost you something in return; time. You will spend time “groking the technical mumbo jumbo” of different technologies, plugins, services, etc. You will spend time choosing what you want to use in terms of being discoverable. You will spend time analysing and learning how a tool works, to have it work the way you get the most benefit from it.

I’ll be covering different technologies, and it’ll process at at least the following topics:

  • RSS
  • Twitter
  • Facebook
  • “The Fediverse” (Mastodon, Friendica, a metric ton of other platforms)
  • SEO (Search Engine Optimisation)

So, I’ll stop it here for now, and hop on to the individual topics in future posts, alright?

WP permissions

Installing WordPress and keeping some sanity for the inevitable

  • Upgrade
  • Plugin modification
  • Theme modification

needs this link and excerpts:

https://stackoverflow.com/questions/18352682/correct-file-permissions-for-wordpress

Excerpt one:

When you setup WP you (the webserver) may need write access to the files. So the access rights may need to be loose.

chown www-data:www-data  -R * # Let Apache be owner
find . -type d -exec chmod 755 {} \;  # Change directory permissions rwxr-xr-x
find . -type f -exec chmod 644 {} \;  # Change file permissions rw-r--r--

After the setup you should tighten the access rights, according to Hardening WordPress all files except for wp-content should be writable by your user account only. wp-content must be writable by www-data too.

chown <username>:<username>  -R * # Let your useraccount be owner
chown www-data:www-data wp-content # Let apache be owner of wp-content

Maybe you want to change the contents in wp-content later on. In this case you could

  • temporarily change to the user to www-data with su,
  • give wp-content group write access 775 and join the group www-data or
  • give your user the access rights to the folder using ACLs.

Whatever you do, make sure the files have rw permissions for www-data.


Excerpt two:

Giving the full access to all wp files to www-data user (which is in this case the web server user) can be dangerous. So rather do NOT do this:

chown www-data:www-data -R *

It can be useful however in the moment when you’re installing or upgrading WordPress and its plug-ins. But when you finished it’s no longer a good idea to keep wp files owned by the web server.

It basically allows the web server to put or overwrite any file in your website. This means that there is a possibility to take over your site if someone manage to use the web server (or a security hole in some .php script) to put some files in your website.

To protect your site against such an attack you should to the following:

All files should be owned by your user account, and should be writable by you. Any file that needs write access from WordPress should be writable by the web server, if your hosting set up requires it, that may mean those files need to be group-owned by the user account used by the web server process.

/

The root WordPress directory: all files should be writable only by your user account, except .htaccess if you want WordPress to automatically generate rewrite rules for you.

/wp-admin/

The WordPress administration area: all files should be writable only by your user account.

/wp-includes/

The bulk of WordPress application logic: all files should be writable only by your user account.

/wp-content/

User-supplied content: intended to be writable by your user account and the web server process.

Within /wp-content/ you will find:

/wp-content/themes/

Theme files. If you want to use the built-in theme editor, all files need to be writable by the web server process. If you do not want to use the built-in theme editor, all files can be writable only by your user account.

/wp-content/plugins/

Plugin files: all files should be writable only by your user account.

Other directories that may be present with /wp-content/ should be documented by whichever plugin or theme requires them. Permissions may vary.

Source and additional information: http://codex.wordpress.org/Hardening_WordPress

Port forwarding over SSH to an Android Thing(s)

I was a bit frustrated on this one, because even if the commands are fairly easy, the results are hard to debug when they show up.

I wanted to be able to connect to my Android Things RPi3 device over SSH. This is pretty much simple port forwarding shenanigans but I got stuck for it for about an hour.

My computer setup looks somewhat like this

 ____________
|            |
| Computer 1 |
| (client)   |
|____________|
      |
      | Interwebs
      |
 _____________
|             |
| Computer 2  |
| (server)    |
| port: 2222  |
|_____________|
      B
      B Wifi
      B
 ____________
|            |
| RPi 3      |
| (Android)  |
| port: 5555 |
|____________|

The command to make this work is

ssh -L 2223:[ip of RPi3]:5555 [user name to server]@[host name/ip of server] -p 2222

What this does is create a local port, 2223, on Computer 1 that connects to the ip of the RPi3 on port 5555, through the server using port 2222.

After this command is executed you will have to use your password to log in on your server, and it will end up at a console prompt. Open a new terminal window on Computer 1 and execute the following

adb connect localhost:2223

This will tell adb on Computer 1 to attempt a connection to itself, localhost, on port 2223, which is the one we created in the step above. This will automatically trigger that connection attempt to pass through the SSH tunnel and talk to the RPi3.

You should see your device being connected on Computer 1 through

adb devices

…and you should be good to go with monitoring, developing, or whatever you fancy, through adb.

Thanks to Otyg over at #sis on IRC

I’ve Framed! my hosts

And it feels great!

For a couple of days I’ve been poking around with a small tool to ease the burdens of keeping track of different web development environments.

The problem

Nowadays a lot of developers have a number of different environments set up to improve the way they work. It’s often safe to tinker around and break things in a development environment, a little less so in a stage environment and absolutely potential high risk disaster to do anything at all in live/production!

In order to try and fix this, I, in the early days, went the way of directly editing files server side on the different hosts. This had an added benefit of making it clear to anyone that visited that host, that it was a special type of environment. But, there was a downside. And that was that it was visible to everyone and not just to me, when surfing around on the different hosts. Plus, editing files like this is a nightmare to keep track of when deploying.

The solution: a multi browser extension

So, I thought that it would be nice to have these visual cues available on the client side, in the browsers, instead. I started looking around in the different browser addon stores and sure, I found one or two tools, but they were all either low on features or tied to only one browser.
To fix this, I started developing an extension for Chrome that could take of this. Said and done, I’ve now created an extension, Framed!, that works on three browsers so far; Chrome, Firefox and Opera. Soon, there will be Microsoft Edge and Safari versions but they are super quirky to work with, so don’t expect it to be available for a little while.

What it does

Anyways, what the extension does is allowing you to paint a frame around your choice of host(s), customisable to what color, thickness, placement (top, right, bottom, left), opacity and Z-index. As an added bonus, you can import/export your frames by copying and pasting a human readable and editable JSON format between the browsers you use.

I hope you find this tool useful, and I’ll spend some more time working on it to make it even more useful and polished.

How to get it

Here are the links to the extension on all browsers:

Taking back your control after Windows reinstall

We all do it. I mean, it’s not really a choice is it? It’s just something that has to be done more frequently than changing socks.

I’m of course talking about reinstalling Windows. Because, man, is this a totally non-hardened OS or what? You can go to one ad-powered website and get a whole slew of issues that will sit on you system partition for as long as you don’t do that reinstall. So you do it. You do the reinstall. And everything feels so much better; Things are snappier, all of a sudden you have your system drive storage space back, and still all the rest of the files on a separate drive since 2006, because you remember that time when you reinstalled and you naively put everything on one single huge drive… Everything got erased.

And now you’re trying to install Cygwin and get some projects going. Maybe try to clone a git project from your home controlled server. And then…. Permission denied, said Bill. Access Denied, said Bull. Oh yeah… Windows don’t know who the hell you are anymore. I mean, sure for the system drive it knows you are its benevolent master. But that separate drive. Ooooh, it’s more inpentetrable than Fort Knox.

Well, there are a thousand different vague answers ranging from so called MS Support and MVP’s to helpful forum users who tells you to install Norton to see if you have a virus, so you at same time can get a thousand new toolbars in IE installed.

There’s _one_ solution that’s worked. Only one. And it’s the command line. Because no OS creator in their right minds would make a command line that cannot rectify the errors all shitty 3rd party applications or window managers can make. Behold, the command:

icacls [The folder you want to get back control over] /reset /t /q

That’s it. Everything you need on one line. Don’t thank me, thank Reddit.

Just a small note on add_filter in WordPress

add_filters seem to have its use in a WordPress context. However, debugging them is shit. And there are not a whole lot of good examples around to explain how to work with them.

I was trying to figure out a way to modify the colour defaults for the quotes component in AESOP Story Engine, and that took me a couple of hours to figure out (I’m just not that used to mucking around with plugins, filters and hooks); mainly because there are absolutely zero actual examples on how you can override them defaults.

So, here it is

add_filter() – The bare minimum

add_filter([a filter associated to the component you want to affect], [a method name reference that you come up with]). E.g:

add_filter(‘aesop_quote_defaults’, ‘modify_defaults’)

modify_defaults() – A couple things

You actually get an incoming argument that contains stuff in it, that you can review with… let’s say… var_dump()?

modify_defaults($whatsThis) {

var_dump($whatsThis);

}

and stuff comes out that you can actually work with! Yeah, it’s going to print all over your wordpress page whenever this is being called, but it sure beats not knowing _anything_ about the contents!

So, what a total add_filter code snippet could look at in the context of changing the background colour for the quote module, that could go into a functions.php file in a child theme:

add_filter(aesop_quote_defaults‘, ‘modify_quote_defaults);

function modify_quote_defaults($defaults) {

        $defaults[background] =white‘;

        return $defaults;

}

So, now the background will by default be white, in terms of the quote module.

AESOP STORY MODE ENGINE; WAS THAT SO BLOODY HARD FOR YOU TO WRITE?!

I’m not (quite yet) a super savvy WordPress developer, and I shouldn’t have to resort to make a lot of Google searches (as an extra to reading your documentation), that proved to be several rabbit holes, and still I have to go through the core source code(!) to figure this out.

And not only that AESOP HORROR STORY ENGINE; It is your RESPONSIBILITY to document these things CLEARLY, but you seem to actually expect your userbase to go trawl your Github to find the fields that are applicable for these things. SHAME!

Anyways, apart from that, there’s a thing that I am a bit uncertain of how to do or handle appropriately;

  • How to modify the defaults used in the admin area of WordPress when adding each component?

Adding _your_ fonts to TinyMCE (WordPress)

This took me a while to figure out, mainly because I:

  • Went the quick and dirty route
  • Found a TON of tips on how to add Google Web and other web fonts, which I didn’t want because I
  • Wanted to load custom (TTF) fonts

I was about to use a WordPress plugin called Fonts, because it was minimal and had exactly what I needed:

  • The buttons to choose Font family and size
  • Enabled the possibility to add custom fonts

But, alas, there was a snag that I wasn’t particularly interested in pursuing. When reading the instructions on how to add custom fonts to the fonts list, you get linked to the WP SITES page where it, when coming to the actual solution part of the answer, states:

You have reached content available exclusively for members.

To enjoy unlimited access & support, register using this form, or login.

Clicking the register button and what do you know; registering sets you back $49.99 a month!

So instead I went the “Spend hours, days, even weeks” route (it took me longer than I suspected, I’ll give it that) and figured out something that seems to work!

Step 1 – Fonts

Now, I’m no expert in this field so I took the trusted “Throw it on the wall and see what sticks” approach and converted the fonts I needed to a number of other font formats, other than the one I had (otf). In the end, what I use is:

  • EOT
  • WOFF
  • TTF

The tools I used for this is FontForge and ttf2eot, both for Windows.

Step 2 – Development

You need:

  • 1 piece of Theme
  • 1 set of Plugins

Theme

If it’s one of your own themes or one that you made a child theme out of or you’re just messing in another one’s, doesn’t really matter. I will not go into any detail on how to make themes or edit the files for a specific theme, as that is abundantly well described pretty much everywhere on the InterWeb.

What really matters is what you put in the style.css (or corresponding style file) which is this:

/wp-content/plugins/add-fonts/fonts/my-font.css

Important to note here is that I reference a path to a plugin. If I can, I try to consolidate things. You could potentially place these wherever you’d like, but having a shared space is nice.

Now, this means that the wordpress pages will load the fonts (read on and you’ll see the contents of my-font.css as well) so they become available to the browser for viewing, should they not be available on the viewer’s computer already.

Onwards to the plugin!

Plugin

This is the gritty part to make TinyMCE actually show you the Font family dropdown box and load up the fonts you want. This took a b unch of hours to navigate, as I’m not used to mucking around in TinyMCE and the border between what WordPress can do and what TinyMCE expects is certainly not clear cut!

Anyways, what I ended up with is this folder structure

  • wp-content
    • plugins
      • add-fonts
        • add-fonts.php
        •  fonts
          • My-Font.eot
          • My-Font.woff
          • My-Font.ttf
          • my-font.css

I’m not claiming this to be the best structure, it’s just one that seem to work ok.

add-fonts.php

The meat of the plugin. This makes sure to

  • Add the Font family button to TinyMCE
  • Add the fonts you want to the Font family dropdown
  • Reflect your changes when you select a font

Quite simply, this is what it looks like:

/**
 * @package Add_Fonts
 * @version 1.0
 */
/*
Plugin Name: Add Fonts
Plugin URI:
Description: This simply adds "back" the Font Family button in TinyMCE and enables a custom (local) font
Author: Jonas Hellström (shellström)
Version: 1.0
Author URI: 
*/

/**
 * Adds the Font Family button
 */
add_filter( 'mce_buttons_3', 'my_mce_buttons_3' );
function my_mce_buttons_3( $buttons ) {
 $buttons[] = 'fontselect';
 return $buttons;
}

/**
 * Adds new font items to the Font Family dropdown
 */
add_filter( 'tiny_mce_before_init', 'wpex_mce_google_fonts_array' );
function wpex_mce_google_fonts_array( $initArray ) {
 // The format is [Font name in dropdown=Font name in font-family of CSS]
 $theme_advanced_fonts = 'My font=My font;';
 $initArray['font_formats'] = $theme_advanced_fonts;
 return $initArray;
}

/**
 * Loads the font-faces so the editor can reflect the selected font in the editor
 */
add_action( 'admin_init', 'wpex_mce_google_fonts_styles' );
function wpex_mce_google_fonts_styles() {
 $font1 = 'http://www.if-then-el.se/wp-content/plugins/add-fonts/fonts/my-font.css';
 add_editor_style( str_replace( ',', '%2C', $font1 ) );
}

/**
 * Imports the font-face styles for some reason
 */
add_action('admin_head-post.php', function() {
 ?>
 <style>
 @import url('https://www.if-then-el.se/wp-content/plugins/add-fonts/fonts/my-font.css');
 </style>
 <?php
});

It’s somewhat self explanatory. Except for the my-fonts.css reference in there. Well, how about we take a look at that as well, shall we?:

@font-face {
 font-family : 'My font';
 font-style  : normal;
 font-weight : normal;
 src         : url('https://www.if-then-el.se/wp-content/plugins/add-fonts/fonts/My-Font.eot');
 src         : url('https://www.if-then-el.se/wp-content/plugins/add-fonts/fonts/My-Font.eot?#iefix') format('embedded-opentype'),
 url('https://www.if-then-el.se/wp-content/plugins/add-fonts/fonts/My-Font.eot?#iefix.woff') format('woff'),
 url('https://www.if-then-el.se/wp-content/plugins/add-fonts/fonts/My-Font.eot?#iefix.ttf') format('truetype');
}

Well, as you can see these are mostly a ton of references to places where the font files are. The @import rule in the theme style.css at the beginning of this article uses these font definitions, so when you change something in this file, the theme will naturally just follow along.

Adding more fonts later on should be as simple as:

  • Generating the font files
  • Adding a new @font-face definition in my-font.css and making sure the paths are set correctly
  • Adding new $theme_advanced_fonts = ‘My font=My font;’; rows

References

I didn’t come up with this on my own, here’s a link to where I finally got stuff up and running for real:

  • http://stackoverflow.com/questions/24105575/how-to-add-new-font-to-tinymce-advanced

Final words

Since you’ve now created this as a plugin, you will also have to enable it in the Plugin tool of WordPress.

Compatibility? Well, I tested this out on WordPress 4.4.2 and I have absolutely _no_ idea whether it will work on older or newer versions. But the original StackOverflow answer was written in June of 2014, so it should be alright.