ubuntu


A better open-source extension for Silhouette Cameo, Inkscape, and Ubuntu

This post demonstrates how to configure the open-source inkscape-silhouette extension on Ubuntu 18.04.

My previous method is documented here.

Even now this post is out of date, as Ubuntu 20.04 has almost certainly been released at the time of writing (though I am far too lazy to go check). It may also be out of date because I don’t see a lot of Silhoutte merchandise at the local craft store anymore. Is there a similar way to interface with the Cricut?

System and dependencies

Do the usual system prep before adding the software upon which Inkscape and the Silhouette extension depend:

1
2
sudo apt update
sudo apt upgrade

Ubuntu 18.04

Just as with a conventional printer, the Silhouette Cameo requires some drivers be installed before it can work with Ubuntu.

Open your System Settings:

Select Printers click Add:

Select your device and press Add:

You may see this:

Generic text-only driver automatically installed:

Inkscape

The Inkscape vector graphics tool has an extension that enables you to send your own SVG files to the Cameo.

Add the Inkscape repository and install:

1
2
3
sudo add-apt-repository ppa:inkscape.dev/stable
sudo apt update
sudo apt install inkscape

Run it from the command line to make sure it works:

1
inkscape

inkscape-silhouette extension

These steps are adapted from the inkscape-silhouette wiki.

This extension depends upon python-usb:

1
sudo apt install python-usb

Next, you’ll need to download a copy of the extension’s latest release. At the time of writing, you could obtain it from the command line like this:

1
2
3
cd ~
wget https://github.com/fablabnbg/inkscape-silhouette/releases/download/v1.22/inkscape-silhouette_1.22-1_all.deb
sudo dpkg -i inkscape-silhouette_1.22-1_all.deb

Try it out

Execute inkscape (from the command line, if you wish):

1
inkscape

Load the SVG file you want to cut and navigate to Extensions > Export > Send to Silhouette:

I leave the settings for you to play with. I only cut vinyl, so I go with the extension-provided defaults:

When ready, press Apply and watch your Silhouette Cameo spring to life.


Basic Android-React Native environment setup in Ubuntu 18.04

I am a test-driven developer who avoids fancy IDEs. I attempted to work through the details of a headless Android-React Native development environment, but quickly realized I was in over my head. This document outlines what may be the more typical workspace arrangement. It also demonstrates how I got everything working with Detox.

The following steps were executed on an Ubuntu 18.04 Desktop machine. What follows is heavily adapted from the Facebook and Detox.

Dependencies

Node

You need node 8.3 or newer. I’m using 10.15.3.

React Native CLI

1
npm install -g react-native-cli

Java JDK

This is the version recommended by Facebook. Installation instructions are adapted from those provided by DigitalOcean.

1
sudo apt install openjdk-8-jdk

Android Studio

You can download the IDE here. I simply installed via the Ubuntu Software manager.

On first execution, select Do not import settings and press _OK_. There are some Setup Wizard screens, which you can navigate. When given the opportunity, choose a Custom setup when prompted to select an installation type. Check the following boxes:

  • Android SDK
  • Android SDK Platform
  • Android Virtual Device

Click Next to install all of these components.

Configure SDK

A React Native app requires the Android 9 (Pie) SDK. Install it throught the SDK Manager in Android Studio. Expand the Pie selection by clicking the Show Package Details box. Make sure the follow options are checked:

  • Android SDK Platform 28
  • Intel x86 Atom_64 System Image _or_ Google APIs Intel x86 Atom System Image (I chose the first option)

Add the following lines to your $HOME/.bashrc config file:

1
2
3
4
5
export ANDROID_HOME=$HOME/Android/Sdk
export PATH=$PATH:$ANDROID_HOME/emulator
export PATH=$PATH:$ANDROID_HOME/tools
export PATH=$PATH:$ANDROID_HOME/tools/bin
export PATH=$PATH:$ANDROID_HOME/platform-tools

Load the config into the current shell:

1
source $HOME/.bashrc

Compile Watchman

1
2
3
4
5
6
7
8
sudo apt install libssl-dev autoconf automake libtool pkg-config python-dev
git clone https://github.com/facebook/watchman.git
cd watchman
git checkout v4.9.0 # the latest stable release
./autogen.sh
./configure
make
sudo make install

Install KVM

Adapted from here.

Check if your CPU supports hardware virtualization, by typing:

1
egrep -c '(vmx|svm)' /proc/cpuinfo

Install dependencies:

1
sudo apt-get install qemu-kvm libvirt-bin ubuntu-vm-builder bridge-utils

Add your user to some groups, replacing by your own username:

1
2
sudo adduser $USER kvm
sudo - $USER

Check if everything is ok:

1
sudo virsh -c qemu:///system list

React Native CLI

1
npm install -g react-native-cli

Create a React Native project

1
react-native init AwesomeProject

Use Android Studio to open ./AwesomeProject/android. Open AVD Manager to see a list of Android Virtual Devices (AVDs).

Click Create Virtual Device, pick a phone (I picked Nexus 5), press Next, and select the Pie API Level 28 image (I had to download it first).

I run the emulator apart from the Android Studio environment:

1
~/Android/Sdk/emulator/emulator -avd Nexus_5_API_28

Execute the AwesomeProject app:

1
2
cd AwesomeProject
react-native run-android

Add Detox to Android project

Here, I simply consolidated all the setup steps described over several pages of Detox docs.

1
2
npm install -g detox-cli
npm install --save-dev detox

Paste to package.json:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
"detox" : {
"configurations": {
"android.emu.debug": {
"binaryPath": "android/app/build/outputs/apk/debug/app-debug.apk",
"build": "cd android && ./gradlew assembleDebug assembleAndroidTest -DtestBuildType=debug && cd ..",
"type": "android.emulator",
"name": "Nexus_5_API_28"
},
"android.emu.release": {
"binaryPath": "android/app/build/outputs/apk/release/app-release.apk",
"build": "cd android && ./gradlew assembleRelease assembleAndroidTest -DtestBuildType=release && cd ..",
"type": "android.emulator",
"name": "Nexus_5_API_28"
}
}
}

Configure Gradle

In android/build.gradle you need to add this under allprojects > repositories. The default init will look much like this already. Note the two separate maven blocks:

1
2
3
4
5
6
7
8
9
10
11
12
13
allprojects {
repositories {
// ...
google()
maven {
// All of Detox' artifacts are provided via the npm module
url "$rootDir/../node_modules/detox/Detox-android"
}
maven {
url "$rootDir/../node_modules/react-native/android"
}
}
}

Set minSdkVersion in android/build.gradle:

1
2
3
4
5
buildscript {
ext {
// ...
minSdkVersion = 18
// ...

Add to dependencies in android/app/build.gradle:

1
2
3
4
5
dependencies {
// ...
androidTestImplementation('com.wix:detox:+') { transitive = true }
androidTestImplementation 'junit:junit:4.12'
}

Also in android/app/build.gradle, update defaultConfig:

1
2
3
4
5
6
7
8
9
android {
// ...

defaultConfig {
// ...
testBuildType System.getProperty('testBuildType', 'debug') // This will later be used to control the test apk build type
testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
}
}

Add Kotlin

In android/build.gradle, update `dependencies:

1
2
3
4
5
6
7
8
9
10
11
12
13
buildscript {
// ...

ext: {
// ...
kotlinVersion = '1.3.10' // Your app's version
}

dependencies: {
// ...
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion"
}
}

Create Android Test Class

Execute:

1
2
3
mkdir -p android/app/src/androidTest/java/com/awesomeproject/
wget https://raw.githubusercontent.com/wix/Detox/master/examples/demo-react-native/android/app/src/androidTest/java/com/example/DetoxTest.java
mv DetoxTest.java android/app/src/androidTest/java/com/awesomeproject/

At the top of the DetoxTest.java file, change com.example to com.awesomeproject.

Add testing frameworks

1
npm install mocha --save-dev

Create template example tests:

1
detox init -r mocha

Build app

1
detox build --configuration android.emu.debug

Run tests

Make sure the emulator is running:

1
~/Android/Sdk/emulator/emulator -avd Nexus_5_API_28

Start the react-native server:

1
react-native start

Run tests:

1
detox test -c android.emu.debug

Notes

Switch between projects I had difficulty with watchman. The instructions found here cleared the error:

1
2
watchman watch-del-all
watchman shutdown-server

Peace


A better open-source extension for Silhouette Cameo, Inkscape, and Ubuntu 16.04

See the new updated version for Ubuntu 18.04

I would have updated my previous attempt at configuring Inkscape to work with the Silhouette Cameo, but got so swept up in the excitement of cutting vinyl stickers, I forgot to do it until now. Unless something has changed since my last relevant post, InkCut doesn’t really work.

This post demonstrates how to configure the open-source inkscape-silhouette extension on Ubuntu 16.04.

System and dependencies

Do the usual system prep before adding the software upon which Inkscape and the Silhouette extension depend:

1
2
sudo apt update
sudo apt upgrade

Ubuntu 16.04

Just as with a conventional printer, the Silhouette Cameo requires some drivers be installed before it can work with Ubuntu.

Open your System Settings:

Open the Printers option:

Add a printer:

Hopefully you see your device in the list:

The drivers for generic printing devices will suffice in this situation:

Change your cutter’s name, if you like. I left these settings untouched:

Not sure what would happen if you attempted to print a test page. I cancelled:

If all is well, you should see the device you just added:

Inkscape

The Inkscape vector graphics tool has an extension that enables you to send your own SVG files to the Cameo.

Add the Inkscape repository and install:

1
2
3
sudo add-apt-repository ppa:inkscape.dev/stable
sudo apt update
sudo apt install inkscape

Run it from the command line to make sure it works:

1
inkscape

inkscape-silhouette extension

These steps are adapted from the inkscape-silhouette wiki.

This extension depends upon python-usb:

1
sudo apt install python-usb

Next, you’ll need to download a copy of the extension’s latest release. At the time of writing, you could obtain it from the command line like this:

1
2
3
cd ~
wget https://github.com/fablabnbg/inkscape-silhouette/releases/download/v1.19/inkscape-silhouette_1.19-1_all.deb
sudo dpkg -i inkscape-silhouette_1.19-1_all.deb

Try it out

Execute inkscape (from the command line, if you wish):

1
inkscape

Load the SVG file you want to cut and navigate to Extensions > Export > Send to Silhouette:

I leave the settings for you to play with. I only cut vinyl, so I go with the extension-provided defaults:

When ready, press Apply and watch your Silhouette Cameo spring to life.


A Home-Based Ubuntu 16.04 Production Server with Salvaged Equipment

Preface

As I’ve often griped before, my cloud service provider (cloudatcost.com) is not exactly reliable. I’m currently on Day 3 waiting for their tech support to address several downed servers. Three days isn’t even that bad considering I’ve waited up to two weeks in the past. In any case, though I wish them success, I’m sick of their nonsense and am starting to migrate my servers out of the cloud and into my house. As a cloud company that routinely loses its customers’ data, it’s prudent to prepare for their likely bankruptcy and closure.

I have an old smashed-up AMD Quad Core laptop I’m going to use as a server. The screen was totally broken, so as a laptop it’s kind of useless anyway. It’s a little lightweight on resources (only 4 GB of RAM), but this is much more than I’m used to. I used unetbootin to create an Ubuntu 16.04 bootable USB and installed the base system.

What follows are the common steps I take when setting up a production server. This bare minimum approach is a process I repeat frequently, so it’s worth documenting here. Once the OS is installed…

Change the root password

The install should put the created user into the sudo group. Change the root password with that user:

1
2
3
sudo su
passwd
exit

Update OS

An interesting thing happened during install… I couldn’t install additional software (i.e., open-ssh), so I skipped it. When it came time to install vim, I discovered I didn’t have access to any of the repositories. The answer here shed some light on the situation, but didn’t really resolve anything.

I ended up copying the example sources.list from the documentation to fix the problem:

1
sudo cp /usr/share/doc/apt/examples/sources.list /etc/apt/sources.list

I found out later that this contained all repositories for Ubuntu 14.04. So I ended up manually pasting this in /etc/apt/sources.list:

1
2
3
4
5
6
7
8
9
10
11
12
# deb cdrom:[Ubuntu 16.04 LTS _Xenial Xerus_ - Release amd64 (20160420.1)]/ xenial main restricted
deb http://archive.ubuntu.com/ubuntu xenial main restricted universe multiverse
deb-src http://archive.ubuntu.com/ubuntu xenial main restricted universe multiverse
deb http://archive.ubuntu.com/ubuntu xenial-updates main restricted universe multiverse
deb-src http://archive.ubuntu.com/ubuntu xenial-updates main restricted universe multiverse
deb http://archive.ubuntu.com/ubuntu xenial-backports main restricted universe multiverse
deb-src http://archive.ubuntu.com/ubuntu xenial-backports main restricted universe multiverse
deb http://archive.ubuntu.com/ubuntu xenial-security main restricted universe multiverse
deb-src http://archive.ubuntu.com/ubuntu xenial-security main restricted universe multiverse
# deb http://archive.ubuntu.com/ubuntu xenial-proposed main restricted universe multiverse
deb http://archive.canonical.com/ubuntu xenial partner
deb-src http://archive.canonical.com/ubuntu xenial partner

After that, update/upgrade worked (make sure it doesn’t actually work before messing around):

1
2
sudo apt update
sudo apt upgrade

Install open-ssh

The first thing I do is configure my machine for remote access. As above, I couldn’t install open-ssh during the OS installation, for some reason. After sources.list was sorted out, it all worked:

1
sudo apt-get install openssh-server

Check the official Ubuntu docs for configuration tips.

While I’m here, though, I need to set a static IP…

1
sudo vi /etc/network/interfaces

Paste this (or similar) under # The primary network interface, as per lewis4u.

1
2
3
4
5
auto enp0s25
iface enp0s25 inet static
address 192.168.0.150
netmask 255.255.255.0
gateway 192.168.0.1

Then flush, restart, and verify that the settings are correct:

1
2
3
sudo ip addr flush enp0s25
sudo systemctl restart networking.service
ip add

Start ssh

My ssh didn’t start running automatically after install. I did this to make ssh run on startup:

1
sudo systemctl enable ssh

And then I did this, which actually starts the service:

1
sudo service ssh start

Open a port on the router

This step, of course, depends entirely on the make and model of router behind which the server is operating. For me, I access the adminstrative control panel by logging in at 192.168.0.1 on my LAN.

I found the settings I needed to configure on my Belkin router under Firewall -> Virtual Servers. I want to serve up web apps (both HTTP and HTTPS) and allow SSH access. As such, I configured three access points by providing the following information for each:

  1. Description
  2. Inbound ports (i.e., 22, 80, and 443)
  3. TCP traffic type (no UDP)
  4. The private/static address I just set on my server
  5. Inbound private ports (22, 80, and 443 respectively)

Set up DNS

Again, this depends on where you registered your domain. I pointed a domain I have registered with GoDaddy to my modems’s IP address, which now receives requests and forwards them to my server.

Login via SSH

With my server, router, and DNS all properly configured, I don’t need to be physically sitting in front of my machine anymore. As such, I complete the following steps logged in remotely.

Set up app user

I like to have one user account control app deployment. Toward that end, I create an app user and add him to the sudo group:

1
2
sudo adduser app
sudo adduser app sudo

Install the essentials

git

Won’t get far without git:

1
sudo apt install git

vim

My favourite editor is vim, which is not installed by default.

1
sudo apt install vim

NERDTree

My favourite vim plugin:

1
2
3
4
mkdir -p ~/.vim/autoload ~/.vim/bundle
cd ~/.vim/autoload
wget https://raw.github.com/tpope/vim-pathogen/HEAD/autoload/pathogen.vim
vim ~/.vimrc

Add this to the .vimrc file:

1
2
3
4
call pathogen#infect()
map <C-n> :NERDTreeToggle<CR>
set softtabstop=2
set expandtab

Save and exit:

1
2
cd ~/.vim/bundle 
git clone https://github.com/scrooloose/nerdtree.git

Now, when running vim, hit ctrl-n to toggle the file tree view.

Docker

Current installation instructions can be found here. The distilled process is as follows:

1
2
sudo apt install apt-transport-https ca-certificates curl software-properties-common
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -

You can verify the key fingerprint:

1
sudo apt-key fingerprint 0EBFCD88

Which should return something like this:

1
2
3
4
pub   4096R/0EBFCD88 2017-02-22
Key fingerprint = 9DC8 5822 9FC7 DD38 854A E2D8 8D81 803C 0EBF CD88
uid Docker Release (CE deb) <docker@docker.com>
sub 4096R/F273FCD8 2017-02-22

Add repository and update:

1
2
sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
sudo apt update

Install:

1
sudo apt install docker-ce

Create a docker user group:

1
sudo groupadd docker

Add yourself to the group:

1
sudo usermod -aG docker $USER

Add the app user to the group as well:

1
sudo usermod -aG docker $USER

Logout, login, and test docker without sudo:

1
docker run hello-world

If everything works, you should see the usual Hello, World! message.

Configure docker to start on boot:

1
sudo systemctl enable docker

docker-compose

This downloads the current stable version. Cross reference it with that offered here.

1
2
3
su
curl -L https://github.com/docker/compose/releases/download/1.14.0/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose
chmod +x /usr/local/bin/docker-compose

Install command completion while still root:

1
2
curl -L https://raw.githubusercontent.com/docker/compose/master/contrib/completion/bash/docker-compose -o /etc/bash_completion.d/docker-compose
exit

Test:

1
docker-compose --version

node

These steps are distilled from here.

1
2
3
cd ~
curl -sL https://deb.nodesource.com/setup_6.x -o nodesource_setup.sh
sudo bash nodesource_setup.sh

Now install:

1
sudo apt-get install nodejs build-essential

Ruby

The steps followed conclude with installing rails. I only install ruby:

1
sudo apt-get install git-core curl zlib1g-dev build-essential libssl-dev libreadline-dev libyaml-dev libsqlite3-dev sqlite3 libxml2-dev libxslt1-dev libcurl4-openssl-dev python-software-properties libffi-dev nodejs

Using rbenv:

1
2
3
4
5
6
7
8
9
10
11
cd
git clone https://github.com/rbenv/rbenv.git ~/.rbenv
echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bashrc
echo 'eval "$(rbenv init -)"' >> ~/.bashrc
exec $SHELL

git clone https://github.com/rbenv/ruby-build.git ~/.rbenv/plugins/ruby-build
echo 'export PATH="$HOME/.rbenv/plugins/ruby-build/bin:$PATH"' >> ~/.bashrc
exec $SHELL

rbenv install 2.4.0

That last step can take a while…

1
2
rbenv global 2.4.0
ruby -v

Install Bundler:

1
gem install bundler

Done!

There it is… all my usual favourites on some busted up piece of junk laptop. I expect it to be exactly 1000% more reliable than cloudatcost.com.


Silhouette Cameo 3, Inkscape, InkCut, and Ubuntu

DEPRECATED!

This approach never really worked very well. Here are some better instructions.

Introduction

My wife and I had a hard time deciding between the Silhouette Cameo 3 and the Cricut Explore Air 2. We went with the Silhouette Machine because it seemed easier to get running on Ubuntu 16.04, though neither machines are particularly open source friendly. We had to dust off our old MacBook Air to upgrade the cutter’s firmware.

System and dependencies

I did the usual system prep before adding the software upon which Inkscape and InkCut depend:

1
2
sudo apt-get update
sudo apt-get upgrade

You don’t realize you need these packages until you try using InkCut for the first time and it crashes:

1
2
sudo apt-get install python-pip python-gtk2-dev python-cups
pip install pyserial

Inkscape

I have no long-term interest in using the hokey design software that comes with the Cameo machine, preferring to use the open source Inkscape vector graphics tool instead.

Added the Inkscape repository and install:

1
2
3
sudo add-apt-repository ppa:inkscape.dev/stable
sudo apt-get update
sudo apt-get install inkscape

Make sure you run Inkscape at least once before installing InkCut:

1
inkscape

This’ll create the .config folder into which the InkCut file will be moved (below).

InkCut

There are a few ways to send vector data straight from Inkscape to the Silhouette Cameo machine. I chose InkCut because it seems like the most popular and viable. This is also why I chose the Cameo over the Cricut machine… InkCut doesn’t work with Cricut.

1
2
3
cd ~
wget https://downloads.sourceforge.net/project/inkcut/InkCut-1.0.tar.gz
tar -xzvf InkCut-1.0.tar.gz -C .config/inkscape/extensions/

This InkCut tutorial was very helpful, but it still took a bit of trial and error to figure out how to get the software to talk to the Silhouette Cameo…

Ubuntu 16.04

Having never really owned a conventional printer, it hadn’t occurred to me that I would need to install any drivers. Turns out that’s how I got it working.

Open your System Settings:

Open the Printers option:

Add a printer:

Hopefully you see your device in the list:

The drivers for generic printing devices will suffice in this situation:

Change your cutter’s name, if you like. I left these settings untouched:

Not sure what would happen if you attempted to print a test page. I cancelled:

If all is well, you should see the device you just added:

Send Vector to Silhouette Cameo

Now that Inkscape and InkCut are installed and the OS and the Silhouette Cameo are friends, it’s time to configure InkCut to send data to the cutter.

The following is a simple project I whipped up for demo purposes. I want to use the Silhouette pen (instead of the cutter) to draw this curve.

In order for this to work with InkCut, you need to select all the curves you want to plot. I simply hit Ctrl-A to select everything (also Edit > Select All):

Select InkCut from the Inkscape menu as shown

The InkCut General tab gives you some options to configure in order to accommodate your cutting/drawing medium. It also allows you the opportunity to preview your vector. Click the Properties button:

The settings with which I was successful are shown below:

I show the Serial settings here just for reference. I have not been able to get this working successfully without installing the printer in Ubuntu first. Make sure the machine is turned on and Test Connection. The Silhouette machine should activate and perform a few short moves.

I copied these settings from the InkCut tutorial linked above:

Finally, send your vector to the plotter/cutter:

Conclusion

It was quite a thrill to finally get the Silhouette Cameo working with Ubuntu, though there are still some kinks to work out. I noticed that the curve I plotted had lines drawn when the pen should have been lifted off the paper. My preliminary research indicates that this is a problem in translation between the HPGL and GPGL protocols. More to come…


iRedMail setup and GoDaddy DNS records

I had it in mind to Dockerize email services on an Ubuntu server. I quickly realized email is a gongshow and opted for the fastest, easiest solution. This turned out to be iRedMail, which still proved a bit tricky when it came time to set up my GoDaddy DNS records.

Here’s what I did…

The system

  • Ubuntu 14.04 server
  • 1 vCPU
  • 2 GB (as recommended here)
  • 20 GB of storage

I buy my VMs from cloudatcost.com. They’re reasonably reliable and reasonably priced.

A (Host) records

Once your machine (wherever it be) is online, set the DNS A (Host) records right away. My DNS stuff is all managed at GoDaddy.

Then create another _A_ record and point it to the mail subdomain:

Prepare the environment

CloudAtCost sets creates a root user and sets the password. I ssh in and change it right away:

1
2
ssh root@rockyvalley.ca
passwd

There may be a compelling reason to create a non-root user, but since the iRedMail will be installed entirely as root, I’m going to skip that step until advised to do otherwise.

Set the domain name

First,

1
vim /etc/hostname

Change whatever’s inside to:

1
mail

and save. Then,

1
vim /etc/hosts

Change it to look like this:

1
2
3
4
5
6
127.0.0.1   mail.rockyvalley.ca mail localhost localhost.localdomain

# The following lines are desirable for IPv6 capable hosts
::1 localhost ip6-localhost ip6-loopback
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters

Change your domain name wherever appropriate (my example domain is rockyvalley.ca.

Reboot the machine.

Log back in:

1
ssh root@rockyvalley.ca

Execute

1
hostname -f

If you see something similar to

1
mail.rockyvalley.ca

then your server has been named appropriately.

Install iRedMail

Download the latest package.

1
2
3
4
cd /root
wget https://bitbucket.org/zhb/iredmail/downloads/iRedMail-0.9.2.tar.bz2
tar xjf iRedMail-0.9.2.tar.bz2
cd iRedMail-0.9.2

Execute the install script:

1
bash iRedMail.sh

This will install a bunch of stuff and then guide you through configuration. Press Enter to proceed past the intro screen.

Default mail storage path

Preferred web server

Choose preferred backend used to store mail accounts

Use the space bar to select the database (here, PostgreSQL).

Password for PostgreSQL administrator: postgres

Your first virtual domain

Password for the administrator of your domain

Optional components

Proceed with installation

I answered yes when asked:

1
2
< Question > Would you like to use firewall rules provided by iRedMail?
< Question > File: /etc/default/iptables, with SSHD port: 22. [Y|n]y

I answered _no_ when asked:

1
< Question > Restart firewall now (with SSHD port 22)? [y|N]n

I figured it unwise to restart because I’m logged in to my server via ssh.

Upon sucessful completion, the installer will spit out some valuable information:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
********************************************************************
* URLs of installed web applications:
*
* - Webmail:
* o Roundcube webmail: httpS://mail.rockyvalley.ca/mail/
*
* - Web admin panel (iRedAdmin): httpS://mail.rockyvalley.ca/iredadmin/
*
* You can login to above links with same credential:
*
* o Username: postmaster@rockyvalley.ca
* o Password: somesecretpassword
*
*
********************************************************************
* Congratulations, mail server setup completed successfully. Please
* read below file for more information:
*
* - /root/iRedMail-0.9.2/iRedMail.tips
*
* And it's sent to your mail account postmaster@rockyvalley.ca.
*
********************* WARNING **************************************
*
* Rebooting your system is required to enable mail services.
*
********************************************************************

Reboot now.

Set up DNS records

MX

The A records have already been set up. Create an MX record (I’m using GoDaddy, so I deleted the existing records before proceeding):

SPF

This gets set as a TXT record at GoDaddy:

DKIM

Log back into your server:

1
ssh root@rockyvalley.ca

Execute the following to determine your DKIM keys:

1
amavisd-new showkeys

This will return something like this:

1
2
3
4
5
6
7
8
9
10
; key#1, domain rockyvalley.ca, /var/lib/dkim/rockyvalley.ca.pem
dkim._domainkey.rockyvalley.ca. 3600 TXT (
"v=DKIM1; p="
"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApTNgVVL2+vIIcq9xioc5"
"B/ydJxaQRZ1eBKkO7mhz2ir5k3DdWl+y65GYR8TbP3z3essbwOnPocqnwX81RoW1"
"VAhPYlHU57OLSXnk3qYcRDHpT/UU/dOGdFclpuAXazUg0l8QhTgadtxsIRDlckKg"
"Vr6II7knZUrhfm84uJ3w858OIrzy8KOSXXfc8npTn48iy4okJGbHvVxE05m6f9/g"
"ie63Z5XkIZeJu7Nj6O/IOVitZh3uiKoOlBHULKqpNtHtPrnZHHX51OLkiezUBvG+"
"slHGPK710iW5ITDy5qm/VaANigXBnPrdF3S3sZMFprwa9GhGSkrnnJ40eCJVFgCm"
"FQIDAQAB")

All the stuff between the brackets needs to be put onto one line, like this:

1
v=DKIM1; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApTNgVVL2+vIIcq9xioc5B/ydJxaQRZ1eBKkO7mhz2ir5k3DdWl+y65GYR8TbP3z3essbwOnPocqnwX81RoW1VAhPYlHU57OLSXnk3qYcRDHpT/UU/dOGdFclpuAXazUg0l8QhTgadtxsIRDlckKgVr6II7knZUrhfm84uJ3w858OIrzy8KOSXXfc8npTn48iy4okJGbHvVxE05m6f9/gie63Z5XkIZeJu7Nj6O/IOVitZh3uiKoOlBHULKqpNtHtPrnZHHX51OLkiezUBvG+slHGPK710iW5ITDy5qm/VaANigXBnPrdF3S3sZMFprwa9GhGSkrnnJ40eCJVFgCmFQIDAQAB

All this gets set as another TXT record:

This may take some time to propagate (a couple hours even). These commands will help confirm that everything is set up okay:

1
2
dig -t txt dkim._domainkey.rockyvalley.ca
nslookup -type=txt dkim._domainkey.rockyvalley.ca

You’ll see the DKIM TXT record you just set once everything has propagated.

Verify public key availability:

1
amavisd-new testkeys

You should see this, if successful:

1
TESTING#1: dkim._domainkey.rockyvalley.ca    => pass

SSL/TLS

At this point, assuming time allowed for propagation, you should be able to send and receive email from the postmaster account. However, the certificates iRedMail sets up for you are self-signed, which means you get an ugly warning whenever you try to access your webmail. To fix this, you’ll need to get certs from a trusted certificate authority. I like to use startssl.com because they’re free.

Once obtained, transfer the certificates to the mail server:

1
scp rockyvalley.ca.tar.gz root@rockyvalley.ca:~

Login,

1
ssh root@rockyvalley.ca

unzip, decrypt, and lockdown:

1
2
3
4
tar -zxvf rockyvalley.ca.tar.gz 
cd rockyvalley.ca
openssl rsa -in ssl.key -out iRedMail.key
chmod 400 iRedMail.key

Since I chose Nginx as my web server and StartSSL as my CA, I need to chain my ssl.crt with StartSSL’s intermediate certificate:

1
cat ssl.crt sub.class1.server.ca.pem > iRedMail.crt

The certificates are now ready to be put in place. The self-signed certificates are stored in:

  • /etc/ssl/certs/iRedMail.crt
  • /etc/ssl/private/iRedMail.key

The new certificates were already named appropriately during decryption and chaining, so now it is simply a matter of overwriting the existing self-signed certificates:

Copy the certs to the correct directories:

1
2
mv iRedMail.crt /etc/ssl/certs/
mv iRedMail.key /etc/ssl/private/

Reboot the machine.

I rebooted in lieu of restarting individual services. Once back online, test sending and receiving. Everything should be good to go.


Insall node and npm with no sudo

I’ve been using node and his good buddy npm for a couple of years now. Up until three days ago, I would happily prefix sudo whenever an npm package gave me an EACCESS error. I’ve always known this is bad practice, but had never encountered an issue. This all changed when I attempted something fairly mundane: Deploy a Hexo blog with Capistrano.

For better or worse, my Capistrano deployment runs npm install as part of its routine. I tried mucking around with sudo and visudo, but to no avail. The blog would simply not deploy because of the restrictive sudo npm install step. At some point it finally occurred to me that npm shouldn’t need sudo anyway, so I’d best fix the problem properly. Instead I did a quick hack on my production server:

The quick hack

Just kidding, this is actually legit, especially given that I’m the only one able to muck around in production. The following is adapted from here. Basically, it allows you to use the -g option without sudo, because all global npm packages get stored under your home directory:

1
2
3
mkdir ~/npm-global
npm config set prefix '~/npm-global'
vim ~/.profile

Append the following to the ~/.profile just opened (or created):

1
export PATH=~/npm-global/bin:$PATH

Now update your system variables:

1
source ~/.profile

Install something globally to make sure it works:

1
npm install -g jshint

A nicer way, arguably

This is more appropriate for a production environment with multiple users. It is adapted from here.

Create a new group:

1
sudo groupadd nodegrp

Add current user to the group (with logname)

1
sudo usermod -a -G nodegrp `logname`

Get access to group:

1
newgrp nodegrp

You can check to see that the user has been added by running:

1
groups

Change group ownership on all the critical components:

1
2
3
sudo chgrp -R nodegrp /usr/lib/node_modules/
sudo chgrp nodegrp /usr/bin/node
sudo chgrp nodegrp /usr/bin/npm

On existing installs

After fixing the issue, there’s a real good chance that root still owns some of the packages installed in the user’s home directory. That’s easy to fix:

1
sudo chown -R $(whoami):$(whoami) ~/.npm

git remote repository - quick setup

I like to keep my project backups offsite. This is one quick way to set up a repository on a server machine.

For this you need a remote server installed with Ubuntu 14.04 (or whatever).

First, login

1
ssh daniel@example.com

Update and install

1
2
sudo apt-get update
sudo apt-get install git

Create the git directory

1
2
cd /opt
sudo mkdir git

Create the project directory

1
2
sudo mkdir my-project.git
cd my-project.git

Initialize a bare repository

1
sudo git init --bare

Change ownership recursively

1
sudo chown -R daniel:daniel .

Logout. Back on your local machine, clone the bare repository

1
git clone daniel@example.com:/opt/git/my-project.git

Initialize a new project, whatever it may be. I use a lot of node, so I might do this:

1
2
cd my-project
npm init

Commit the changes

1
2
3
git add .
git commit -m "Hello, my-project"
git push origin master

At this point, you may be told to set your name and email

1
2
git config --global user.name "Daniel Bidulock"
git config --global user.email daniel@capitolhill.ca

Try pushing again

1
git push origin master

Bingo, bango, sugar in the gas tank!


Extend a partition in Ubuntu

I recently upgraded one of my CloudAtCost servers from Developer 1 to Developer 3 because I needed more disk space. The upgrade got off to a rocky start. It took a week for the work to actually get done and then I was informed that I needed to extend my partition. I had no idea how to do that, and if CloudAtCost’s tech support did, they weren’t sharing.

As it turns out, this is all pretty easy. This document simply condenses the instructions I found here for my own future reference.

0. Back up your work!

I like rsync. The following

1
rsync -azP daniel@example.com:/opt/git .

copies everything out of the hypothetical git repositories on my server to my local machine.

1. Take a look at the partition table

Login to your server.

1
ssh daniel@example.com

You’ll need to know where the new partition lives:

1
sudo fdisk -l /dev/sda

After the next step is complete, there will be a new device in the list (probably at /dev/sda6)

Also, make note of the file system’s current size:

1
df -hT

This will be helpful in verifying that the following steps actually worked.

2. Create a new logical partition

1
sudo cfdisk

From the interface provided:

  1. Select the unallocated space
  2. Select New
  3. Select Logical and allocate all the available space (shown by default)
  4. Select Type and enter _8E_
  5. Select Write, type yes, and hit Enter
  6. Quit cfdisk
  7. Reboot the server (sudo reboot)

3. Take another look at the partition table

Once rebooted and re-logged in, run

1
sudo fdisk -l /dev/sda

and verify that there is, in fact, a new device that wasn’t there before (again, probably mounted at /dev/sda6). If there isn’t, you’re out of luck, because this is all just magic to me.

4. Create a new physical volume

Assuming the new device lives at /dev/sda6

1
sudo pvcreate /dev/sda6

5. Extend the existing volume group

1
sudo vgdisplay

Make note of the name associated with VG Name. Mine was called ubuntu1204-vg even though I’m running Ubuntu 14.04.

1
sudo vgextend ubuntu1204-vg /dev/sda6

6. Extend the logical volume

1
sudo lvdisplay

Make note of the path associated with LV Name used for the root filesystem (mine was /dev/ubuntu1204-vg/root)

1
sudo lvextend -l 100%FREE /dev/ubuntu1204-vg/root

6. Extend the file system

1
sudo resize2fs /dev/ubuntu1204-vg/root

7. Verify

1
df -hT

should reveal a file system much bigger than what you say in Step 1.

The preceding steps were ripped off from these guys, who, in turn, ripped off their info from here.


Deploying the Rails Tutorial Sample App

I recently worked through Michael Hartl’s wonderful Ruby on Rails Tutorial as a refresher. The software implemented under his direction offers functionality that basically every modern website requires (e.g., user sign up, password retrieval, etc). That which follows documents the steps I took to deploy all the best parts of that tutorial in a production environment.

Get a server

Much of this post was ripped off from this article. They recommend Digital Ocean. I like cloudatcost.com for no other reason than because they’re cheap. For the purposes of this post, it doesn’t really matter as long as it’s installed with Ubuntu 14.04.

Add a user account

The templated Rails application is executed under this account:

1
2
3
sudo adduser deploy
sudo adduser deploy sudo
su deploy

Install Ruby

Some dependencies

1
2
sudo apt-get update
sudo apt-get install git-core curl zlib1g-dev build-essential libssl-dev libreadline-dev libyaml-dev libsqlite3-dev sqlite3 libxml2-dev libxslt1-dev libcurl4-openssl-dev python-software-properties libffi-dev

rbenv

1
2
3
4
5
cd
git clone git://github.com/sstephenson/rbenv.git .rbenv
echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bashrc
echo 'eval "$(rbenv init -)"' >> ~/.bashrc
exec $SHELL

ruby-build plugin

1
2
3
git clone git://github.com/sstephenson/ruby-build.git ~/.rbenv/plugins/ruby-build
echo 'export PATH="$HOME/.rbenv/plugins/ruby-build/bin:$PATH"' >> ~/.bashrc
exec $SHELL

rbenv-gem-rehash plugins

1
git clone https://github.com/sstephenson/rbenv-gem-rehash.git ~/.rbenv/plugins/rbenv-gem-rehash

Ruby

1
2
3
rbenv install 2.2.1
rbenv global 2.2.1
ruby -v

bundler

1
2
echo "gem: --no-ri --no-rdoc" > ~/.gemrc
gem install bundler

The echo command prevents documentation for each gem being installed locally.

Install NodeJS

Since it is my intention to deploy this system to a production environment, I need to use the Asset Pipeline to prep my content for distribution across the web. All that requires node.

1
2
3
sudo add-apt-repository ppa:chris-lea/node.js
sudo apt-get update
sudo apt-get install nodejs

Install Rails

1
2
gem install rails -v 4.2.0
rails -v

Nginx and Passenger

Install Phusion’s PGP key to verify packages

1
2
gpg --keyserver keyserver.ubuntu.com --recv-keys 561F9B9CAC40B2F7
gpg --armor --export 561F9B9CAC40B2F7 | sudo apt-key add -

Add HTTPS support to APT

1
sudo apt-get install apt-transport-https

Add the passenger repository

1
2
3
4
sudo sh -c "echo 'deb https://oss-binaries.phusionpassenger.com/apt/passenger trusty main' >> /etc/apt/sources.list.d/passenger.list"
sudo chown root: /etc/apt/sources.list.d/passenger.list
sudo chmod 600 /etc/apt/sources.list.d/passenger.list
sudo apt-get update

nginx and passenger

1
sudo apt-get install nginx-full nginx-extras passenger

Configure

1
sudo vim /etc/nginx/nginx.conf

Uncomment the rbenv Phusion Passenger stuff. There should be some helpful hints in the file itself:

1
2
3
4
5
6
7
8
9
10
11
##
# Phusion Passenger
##
# Uncomment it if you installed ruby-passenger or ruby-passenger-enterprise
##

passenger_root /usr/lib/ruby/vendor_ruby/phusion_passenger/locations.ini;

passenger_ruby /home/deploy/.rbenv/shims/ruby; # If you use rbenv
# passenger_ruby /home/deploy/.rvm/wrappers/ruby-2.1.2/ruby; # If use use rvm, be sure to change the version number
# passenger_ruby /usr/bin/ruby; # If you use ruby from source

Get an SSL certificate

These instructions will produce a self-signed certificate:

1
2
sudo mkdir /etc/nginx/ssl
sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /etc/nginx/ssl/nginx.key -out /etc/nginx/ssl/nginx.crt

Alternatively, validate with startssl.com for free. This document provides some excellent additional information.

Add nginx host

1
2
3
sudo touch /etc/nginx/sites-available/mydomain.conf
sudo ln -s /etc/nginx/sites-available/mydomain.conf /etc/nginx/sites-enabled/mydomain.conf
sudo vim /etc/nginx/sites-available/mydomain.conf

Write the following to the file:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
server {
listen 80 default_server;
listen [::]:80 default_server ipv6only=on;

listen 443 ssl;

server_name gofish.mobi;

# SSL
ssl_certificate /etc/nginx/ssl/nginx.crt;
ssl_certificate_key /etc/nginx/ssl/nginx.key;

# Error logs
access_log /var/log/nginx/gofish.access.log;
error_log /var/log/nginx/gofish.error.log;

# Passenger
passenger_enabled on;
rails_env production;
root /home/deploy/rails-tutorial-template/current/public;

# redirect server error pages to the static page /50x.html
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}

# Static assets
location ^~ /assets/ {
gzip_static on;
expires max;
add_header Cache-Control public;
}
}

Start, or restart nginx:

1
sudo service nginx restart

PostgreSQL

Install:

1
sudo apt-get install postgresql postgresql-contrib libpq-dev

Create the deploy postgres user:

1
2
3
sudo su - postgres
createuser -U postgres -d -e -E -I -P -r -s deploy
exit

You’ll need to set the database password in config/application.yml.

Configure the environment

Before deploying with capistrano, a few files have to be in place. As the deploy user:

1
2
cd
mkdir -p rails-tutorial-template/shared/config

Get a secret key

If you have a rails project nearby, you can just type in

1
rake secret

Or, you can generate one by running irb

1
irb

and executing the following instructions:

1
2
3
require 'securerandom'
SecureRandom.hex(64)
exit

Copy the string generated by the SecureRandom.hex(64) command.

application.yml

This template uses figaro to manage all the sensitive stuff that sometimes goes into environment variables. The config/application.yml file it looks for isn’t committed to the repository, so you have to create it yourself:

1
2
cd rails-tutorial-template/shared/config
vim application.yml

Copy, paste, modify, and save the following:

1
2
3
4
5
6
7
8
9
10
11
12
# General
app_name: "rails_tutorial_template"

# Email
default_from: "noreply@gofish.mobi"
gmail_username: "noreply@gofish.mobi"
gmail_password: "secretnoreplypassword"

# Production
secret_key_base: "PasteTheSecretKeyFromThePreviousStepHere"
host: "gofish.mobi"
provider_database_password: "databasepassword"

I set up an account in Gmail to handle signup verifications and password resets.

database.yml and secrets.yml

There’s no sensitive information contained in the database.yml or secrets.yml files, so these can be copied directly from github.

1
2
wget https://raw.githubusercontent.com/RaphaelDeLaGhetto/rails-tutorial-template/master/config/database.yml
wget https://raw.githubusercontent.com/RaphaelDeLaGhetto/rails-tutorial-template/master/config/secrets.yml

Clone the template

This is meant to be completed on the development machine (not the server). It is assumed that postgresql and all the other dependencies are already installed (if not, do so as above).

1
2
3
4
5
6
7
git clone https://github.com/RaphaelDeLaGhetto/rails-tutorial-template.git
cd rails-tutorial-template
bundle install
sudo npm install
rake db:setup
rake db:seed
vim config/application.yml

Then copy, paste, and save the following in the file:

1
default_from: 'noreply@example.com'

Tests should all pass

1
rake

capistrano deployment

I’m still working on making this easier. From the project’s directory on the development machine set the following in config/deploy/production.rb

1
2
# Replace 127.0.0.1 with your server's IP address!
server 'gofish.mobi', user: 'deploy', roles: %w{web app}

Then run

1
bundle exec cap production deploy --trace

The deployment should succeed, but the site will not be accessible until the database is set up. Log in to the production server as deploy:

1
2
3
ssh deploy@gofish.mobi
cd rails-tutorial-template/current
RAILS_ENV=production rake db:setup

Now, enable the deploy user to restart passenger without providing a sudo password:

1
sudo visudo

Add this to the end of the file and save:

1
deploy ALL=(root) NOPASSWD: /usr/bin/passenger-config

Back on the local machine, the deployment should now succeed:

1
bundle exec cap production deploy --trace

If everything worked out right, then the app should be accessible at the configured domain name (gofish.mobi in my case).