<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xsl" href="../assets/xml/rss.xsl" media="all"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>David Beath (Posts about IT)</title><link>https://davidbeath.com/</link><description></description><atom:link href="https://davidbeath.com/categories/it.xml" rel="self" type="application/rss+xml"></atom:link><language>en</language><lastBuildDate>Mon, 21 Feb 2022 17:09:58 GMT</lastBuildDate><generator>Nikola (getnikola.com)</generator><docs>http://blogs.law.harvard.edu/tech/rss</docs><item><title>Feedsearch API Updates</title><link>https://davidbeath.com/posts/2019-feedsearch-api-updates/</link><dc:creator>David Beath</dc:creator><description>&lt;p&gt;Over the past year I've been slowly working on improvements to the &lt;a href="https://feedsearch.dev"&gt;Feedsearch API&lt;/a&gt; that I published in late 2017, and wrote about in my &lt;a href="https://davidbeath.com/posts/feedsearch-api.html"&gt;previous post&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The biggest difference is that the old Feedsearch library has now been replaced with the new &lt;a href="https://github.com/DBeath/feedsearch-crawler"&gt;Feedsearch Crawler&lt;/a&gt; library, which is available for use in other projects as a &lt;a href="https://pypi.org/project/feedsearch-crawler/"&gt;PyPI package&lt;/a&gt;. The crawler is now able to make HTTP requests asyncronously, drastically speeding up the number of URLs that can be checked for feeds in the same amount of time, which in turn increases the feed detection rate in cases where the feed URL is not properly advertised.&lt;/p&gt;
&lt;!-- TEASER_END --&gt;

&lt;p&gt;The second new feature is that all discovered feeds are now saved to a database, along with the website and the URL paths where they were discovered. In this way we can now return a list of all feeds that have been discovered on a site, and remove the need to crawl a site or URL every time a feed search is requested.&lt;/p&gt;
&lt;p&gt;In addition to these, I've extended the results provided by the API to add few new fields:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;content_length: The length of the feed in bytes at the time it was last seen.&lt;/li&gt;
&lt;li&gt;is_podcast: Whether or not the feed contains valid &lt;a href="https://en.wikipedia.org/wiki/Podcast"&gt;podcast&lt;/a&gt; elements and enclosures.&lt;/li&gt;
&lt;li&gt;last_seen: The date that the feed was last crawled by Feedsearch.&lt;/li&gt;
&lt;li&gt;last_updated: The date that the feed was last updated by the publisher.&lt;/li&gt;
&lt;li&gt;velocity: A calculation of the mean number of entries per day in the feed, at the time that the feed was last crawled.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Feedsearch Crawler&lt;/h3&gt;
&lt;p&gt;The &lt;a href="https://github.com/DBeath/feedsearch-crawler"&gt;Feedsearch Crawler&lt;/a&gt; is built as a separate library from the API, so that it's available for others to use, fork, and extend as they see fit.&lt;/p&gt;
&lt;p&gt;I had been thinking for a few years now that what was really needed for feed detection was to use a proper &lt;a href="https://en.wikipedia.org/wiki/Web_crawler"&gt;Web crawler&lt;/a&gt;. As I kept upgrading the original &lt;a href="https://github.com/DBeath/feedsearch"&gt;Feedsearch library&lt;/a&gt; to improve detection rates and add features such as &lt;a href="https://en.wikipedia.org/wiki/Favicon"&gt;Favicon&lt;/a&gt; fetching, the time needed perform a search kept increasing, due to the synchronous design of the &lt;a href="https://docs.python-requests.org/en/latest/"&gt;Requests&lt;/a&gt; HTTP library. It was at the time that I started adding asynchronous HTTP requests to Feedsearch, and therefore requiring that I keep track of which URLs have been requested, that I realised I was just building a crappier Web crawler, without a proper architecture. So I built my own, because why not?&lt;/p&gt;
&lt;p&gt;The design and features of the base crawler itself are nothing special, but the FeedsearchSpider built on top of it is meant to be as discriminating as possible in what it crawls, while still finding as many feeds as possible. In order to do this the spider uses a number of regular expressions to filter page links that may lead to feeds, and then prioritises them for the crawl queue.&lt;/p&gt;
&lt;h3&gt;Feedsearch Gateway API&lt;/h3&gt;
&lt;p&gt;The API is built as the &lt;a href="https://github.com/DBeath/feedsearch-gateway"&gt;Feedsearch Gateway&lt;/a&gt; project, and is responsible for all the custom functionality that is not required in the generic crawler library, such as providing the actual API and dealing with saving results.&lt;/p&gt;
&lt;p&gt;When crawling websites, it's not particularly polite to use a lot of resources, and so I needed the ability to cache the results. Because I already had Feedsearch running on &lt;a href="https://aws.amazon.com/lambda/"&gt;AWS Lambda&lt;/a&gt;, I decided to use &lt;a href="https://aws.amazon.com/dynamodb/"&gt;DynamoDB&lt;/a&gt; for the database. Whenever a search is completed, the following information is saved to the database:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;All feeds found in the crawl and their metadata.&lt;/li&gt;
&lt;li&gt;The host URL of the site and the time it was crawled.&lt;/li&gt;
&lt;li&gt;The URL of the path that was crawled, the time it was crawled, and the URLs of the feeds that were found from that path.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;When a search is started, the API first queries the database for the feeds that were already found and the site information. If the search is for the host URL of the site (e.g. &lt;a href="https://example.com"&gt;https://example.com&lt;/a&gt;), then the site is only crawled again if it hasn't been crawled recently, and all feeds that have ever been found to belong to the site are returned.&lt;/p&gt;
&lt;p&gt;If the search contains a path (e.g. &lt;a href="https://example.com/path/testing/"&gt;https://example.com/path/testing/&lt;/a&gt;) then the database is checked to see if that path has already been crawled. If the path has been crawled recently, then the list of URLs found at that path are checked against the sites feeds, and the matching feeds are returned. When the path is searched, only feeds found from the crawl of that path are returned. This is done to increase the chance that only feeds relevant to that particular query are returned, especially if the site contains a lot of feeds.&lt;/p&gt;
&lt;p&gt;Finally, the &lt;a href="https://feedsearch.dev"&gt;Feedsearch site&lt;/a&gt; itself is run behind &lt;a href="https://workers.cloudflare.com/"&gt;Cloudflare Workers&lt;/a&gt;. Cloudflare doesn't cache HTML by default, but because the API homepage is designed to be as static as possible, it makes sense to cache it with the Workers cache API, so that we don't have to make a request to the Lambda function every time the page is requested. Instead, only requests to the API route are forwarded to the Lambda.&lt;/p&gt;</description><category>API</category><category>crawling</category><category>IT</category><category>RSS</category><category>Web</category><guid>https://davidbeath.com/posts/2019-feedsearch-api-updates/</guid><pubDate>Thu, 07 Nov 2019 16:50:14 GMT</pubDate></item><item><title>Feedsearch API</title><link>https://davidbeath.com/posts/feedsearch-api/</link><dc:creator>David Beath</dc:creator><description>&lt;p&gt;I've just published a new microsite and API called &lt;a href="https://feedsearch.dev"&gt;Feedsearch&lt;/a&gt;, which provides an easy way to search websites for &lt;a href="https://en.wikipedia.org/wiki/RSS"&gt;RSS&lt;/a&gt;, &lt;a href="https://en.wikipedia.org/wiki/Atom_(standard)"&gt;Atom&lt;/a&gt;, and &lt;a href="https://jsonfeed.org/"&gt;JSON&lt;/a&gt; feeds.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://feedsearch.dev"&gt;Feedsearch&lt;/a&gt; is primarily meant to be a thin public API wrapper around the &lt;a href="https://pypi.org/project/feedsearch/"&gt;Feedsearch Python package&lt;/a&gt;, which I wrote to support feed search capabilities in my side project &lt;a href="https://auctorial.com"&gt;Auctorial&lt;/a&gt;. I couldn't find a public library or service that both searched for feeds and returned feed and site metadata, so I wrote this one. In addition to the API, the site allows users to search for feeds using a standard webform.&lt;/p&gt;
&lt;!-- TEASER_END --&gt;

&lt;p&gt;The code and documentation for the Feedsearch package is hosted in the &lt;a href="https://github.com/DBeath/feedsearch"&gt;Feedsearch Github repository&lt;/a&gt;. The site and API code is &lt;a href="https://github.com/DBeath/feedsearch-gateway"&gt;also on Github&lt;/a&gt;. The API runs on the &lt;a href="https://github.com/pallets/flask"&gt;Flask&lt;/a&gt; framework, and is converted with the ridiculously easy to use &lt;a href="https://github.com/Miserlou/Zappa"&gt;Zappa&lt;/a&gt; library to run on &lt;a href="https://aws.amazon.com/lambda/"&gt;AWS Lambda&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Acknowledgements are due to &lt;a href="https://dfm.io/"&gt;Dan Foreman-Mackey&lt;/a&gt; for his &lt;a href="https://github.com/dfm/feedfinder2"&gt;Feedfinder2&lt;/a&gt; library, from which I stole and extended the original code for Feedsearch, and to &lt;a href="https://scripting.com/"&gt;Dave Winer&lt;/a&gt; for giving us RSS in the first place.&lt;/p&gt;
&lt;p&gt;I hope people keep using and writing code for RSS. I think it's important that RSS continues to thrive, both on a personal level (it's how I get most of my reading material), and on a professional level (it's used heavily in &lt;a href="https://auctorial.com"&gt;Auctorial&lt;/a&gt;). RSS is by far the best way we currently have to propagate news and articles around the web; Facebook, Twitter, and Reddit aren't suited for the kind of aggregation that RSS enables.&lt;/p&gt;</description><category>API</category><category>IT</category><category>RSS</category><category>Web</category><guid>https://davidbeath.com/posts/feedsearch-api/</guid><pubDate>Fri, 08 Dec 2017 10:03:53 GMT</pubDate></item><item><title>Nginx and ELB Proxy Protocol Forwarding</title><link>https://davidbeath.com/posts/elb-nginx-proxy-forwarding/</link><dc:creator>David Beath</dc:creator><description>&lt;p&gt;Recently I noticed that an application I'm hosting on &lt;a href="https://aws.amazon.com/elasticbeanstalk/"&gt;AWS Elastic Beanstalk&lt;/a&gt; wasn't logging the Client IP Address of my users. After a lot of digging I found the issue was to do with the configuration of the &lt;a href="https://www.nginx.com/resources/wiki/"&gt;Nginx&lt;/a&gt; servers running on the &lt;a href="https://aws.amazon.com/ec2/"&gt;EC2&lt;/a&gt; instances and in my application's &lt;a href="https://www.docker.com/"&gt;Docker&lt;/a&gt; container, and in the TCP passthrough configuration of the &lt;a href="https://aws.amazon.com/elasticloadbalancing/"&gt;Elastic Load Balancer&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;So here's a quick post about my particular setup and the configuration I used to fix this issue of Client IP Addresses not being forwarded.&lt;/p&gt;
&lt;!-- TEASER_END --&gt;

&lt;h3&gt;Elastic Beanstalk Setup&lt;/h3&gt;
&lt;p&gt;In a little more detail, my setup consists of an application hosted within a Docker container running on EC2 instances configured by Elastic Beanstalk, which sit behind an Elastic Load Balancer (ELB). Because of issues with Certificate support in ELB, I'm not using AWS's Certificate Manager or using the built-in SSL termination in ELB, but instead using TCP passthrough on the ELB, and using a custom Nginx configuration on each EC2 instance to terminate the SSL connection. The Docker container on each instance also has it's own Nginx configuration, which proxies the application server, in my case &lt;a href="https://uwsgi-docs.readthedocs.io/en/latest/"&gt;UWSGI&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The steps that a request takes to get to the application are:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;User makes an HTTPS request.&lt;/li&gt;
&lt;li&gt;ELB uses TCP passthrough to pass the encrypted request to an EC2 instance.&lt;/li&gt;
&lt;li&gt;Nginx in EC2 decrypts the HTTPS request and passes the HTTP to it's Docker container.&lt;/li&gt;
&lt;li&gt;The Nginx server on Docker proxies the request to UWSGI.&lt;/li&gt;
&lt;li&gt;The application hosted by UWSGI handles the request.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;In all, the parts that you need to configure to forward the Client IP Address are the TCP passthrough on ELB and each of the two Nginx servers.&lt;/p&gt;
&lt;h3&gt;Proxy Protocol&lt;/h3&gt;
&lt;p&gt;The first problem is that if you're using a TCP load balancer to pass through the request, the load balancer will not add an &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-For"&gt;&lt;em&gt;X-Forwarded-For&lt;/em&gt;&lt;/a&gt; header, and so the downstream Nginx server will only see the IP Address of the load balancer. The problem and part of the solution is &lt;a href="https://chrislea.com/2014/03/20/using-proxy-protocol-nginx/"&gt;described in better detail here&lt;/a&gt;. The linked solution is a little different from what I'm going to show below, because I'm proxying the request another hop down the line, but please read the link to better understand what's going on.&lt;/p&gt;
&lt;p&gt;The first step is to enable Proxy Protocol support on the Elastic Load Balancer. AWS has a &lt;a href="https://docs.aws.amazon.com/elasticloadbalancing/latest/classic/enable-proxy-protocol.html"&gt;good tutorial&lt;/a&gt; on how to do that.&lt;/p&gt;
&lt;p&gt;Once the ELB has Proxy Protocol support enabled, you can configure the Nginx server on the EC2 instances. The relevant parts of the configuration look something like this:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&lt;span class="k"&gt;log_format&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;elb_log&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="nv"&gt;$proxy_protocol_addr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$remote_user'&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="s"&gt;'[&lt;/span&gt;&lt;span class="nv"&gt;$time_local]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$request"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="nv"&gt;$status&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$body_bytes_sent&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="s"&gt;'"&lt;/span&gt;&lt;span class="nv"&gt;$http_referer"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$http_user_agent"'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="k"&gt;server&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kn"&gt;listen&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;443&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;ssl&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;http2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;proxy_protocol&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kn"&gt;server_name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;localhost&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kn"&gt;set_real_ip_from&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="mi"&gt;172&lt;/span&gt;&lt;span class="s"&gt;.31.0.0/20&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kn"&gt;real_ip_header&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;proxy_protocol&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kn"&gt;access_log&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;/var/log/nginx/elb-access.log&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;elb_log&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;# SSL Certificate settings go here.&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kn"&gt;location&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;/&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kn"&gt;proxy_pass&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="s"&gt;https://docker&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kn"&gt;proxy_http_version&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="s"&gt;.1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kn"&gt;proxy_set_header&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;Connection&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kn"&gt;proxy_set_header&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;Host&lt;/span&gt;&lt;span class="w"&gt;               &lt;/span&gt;&lt;span class="nv"&gt;$host&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kn"&gt;proxy_set_header&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;X-Real-IP&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="nv"&gt;$proxy_protocol_addr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kn"&gt;proxy_set_header&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;X-Forwarded-For&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;$proxy_protocol_addr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kn"&gt;proxy_set_header&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;X-Forwarded-Proto&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nv"&gt;$scheme&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;Here's what's happening in the above config:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The &lt;em&gt;listen&lt;/em&gt; directive now has &lt;em&gt;proxy_protocol&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;set_real_ip_from&lt;/em&gt; tells Nginx the real CIDR range of addresses that the ELB is using.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;real_ip_header&lt;/em&gt; tells us that we're using the &lt;em&gt;proxy_protocol&lt;/em&gt; value to access the client headers.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;X-Real-IP&lt;/em&gt; and &lt;em&gt;X-Forwarded-For&lt;/em&gt; use the &lt;em&gt;$proxy_protocal_addr&lt;/em&gt;, which is the client IP information taken from the proxy protocol.&lt;/li&gt;
&lt;li&gt;The &lt;em&gt;elb_log&lt;/em&gt; format is now using the &lt;em&gt;$proxy_protocal_addr&lt;/em&gt; for the client IP.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Also note that the &lt;em&gt;listen&lt;/em&gt; directive can support both &lt;em&gt;http2&lt;/em&gt; and &lt;em&gt;proxy_protocol&lt;/em&gt;, so if your version of Nginx supports &lt;a href="https://hpbn.co/http2/"&gt;HTTP/2&lt;/a&gt; then you can enable that just fine. However, the &lt;em&gt;proxy_http_version&lt;/em&gt; directive in this case is still &lt;em&gt;1.1&lt;/em&gt;, as it &lt;a href="https://mailman.nginx.org/pipermail/nginx/2015-December/049445.html"&gt;doesn't make sense&lt;/a&gt; to use HTTP/2 for proxy backends.&lt;/p&gt;
&lt;p&gt;If you deployed the above config, you should now see that Nginx server on the EC2 instance is now logging the correct client IP Address.&lt;/p&gt;
&lt;h3&gt;Multiple Nginx Proxies&lt;/h3&gt;
&lt;p&gt;Now that we have the Nginx server on the EC2 instance receiving the correct Client IP from the Load Balancer, we need to foward that IP on to the Nginx server in the Docker container.&lt;/p&gt;
&lt;p&gt;The &lt;em&gt;X-Forwarded-For&lt;/em&gt; and &lt;em&gt;X-Real-IP&lt;/em&gt; directives in the above config will properly forward the Client IP from the EC2 instance's Nginx server. However, Nginx appends each proxy's IP address to the &lt;em&gt;X-Forwarded-For&lt;/em&gt; header, as described in more detail &lt;a href="https://distinctplace.com/2014/04/23/story-behind-x-forwarded-for-and-x-real-ip-headers/"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The solution to this is in the last Nginx proxy configuration is to include the IP address ranges of all previous known proxies in the &lt;em&gt;set_real_ip_from&lt;/em&gt; directive. You can then set the &lt;em&gt;real_ip_header&lt;/em&gt; directive to &lt;em&gt;X-Forwarded-For&lt;/em&gt;. The final piece is to set &lt;em&gt;real_ip_recursive&lt;/em&gt; to &lt;em&gt;on&lt;/em&gt;, which will return the leftmost (original) IP instead of the rightmost (most recent) IP from the &lt;em&gt;X-Forwarded-For&lt;/em&gt; header.&lt;/p&gt;
&lt;p&gt;My Nginx configuration for the Docker container now looks like this:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&lt;span class="k"&gt;upstream&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;app&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kn"&gt;server&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;unix:///tmp/uwsgi.sock&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="k"&gt;server&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kn"&gt;listen&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;default_server&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kn"&gt;set_real_ip_from&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;172&lt;/span&gt;&lt;span class="s"&gt;.31.0.0/20&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;# IP of the ELB&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kn"&gt;set_real_ip_from&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;172&lt;/span&gt;&lt;span class="s"&gt;.17.0.0/20&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;# IP of the EC2 instance&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kn"&gt;real_ip_header&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="s"&gt;X-Forwarded-For&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kn"&gt;real_ip_recursive&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="no"&gt;on&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kn"&gt;location&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;/&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kn"&gt;uwsgi_pass&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;app&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kn"&gt;include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;uwsgi_params&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;You can see that I've included the IP ranges of both the ELB and the EC2 instance. With a config similar to this you should now see the Nginx instance in the Docker container log the correct Client IP, and pass that IP through to your application.&lt;/p&gt;</description><category>hosting</category><category>IT</category><category>Nginx</category><category>tutorial</category><category>Web</category><guid>https://davidbeath.com/posts/elb-nginx-proxy-forwarding/</guid><pubDate>Mon, 17 Apr 2017 10:35:06 GMT</pubDate></item><item><title>Testing HTTP Responses in Node.js</title><link>https://davidbeath.com/posts/testing-http-responses-in-nodejs/</link><dc:creator>David Beath</dc:creator><description>&lt;p&gt;It generally goes without saying these days that testing is an important part of the development process. However, testing is not always the easiest thing to master, and it can be difficult to know where to start, especially when it comes to learning a new language. &lt;a href="https://nodejs.org/"&gt;Node.js&lt;/a&gt; adds an extra twist on this difficulty, in that your code is running Asynchronously, and you will often be dealing with HTTP calls.&lt;/p&gt;
&lt;p&gt;Having just been through the process of learning Node.js and working on a simple application that deals with calling and receiving responses from an external API, the most painful thing I found was that there aren't many tutorials on how to test HTTP requests and responses that I find particularly clear. So, this tutorial aims to provide clear information on how to effectively test your requests and responses, with a little bit about testing emitted events.&lt;/p&gt;
&lt;!-- TEASER_END --&gt;

&lt;h3&gt;Setting up the Test Environment&lt;/h3&gt;
&lt;p&gt;For these tests we'll be using the &lt;a href="https://visionmedia.github.io/mocha/"&gt;Mocha&lt;/a&gt; testing framework along with the &lt;a href="https://chaijs.com/"&gt;Chai&lt;/a&gt; assertion library. We'll also use the popular &lt;a href="https://github.com/mikeal/request"&gt;Request&lt;/a&gt; library to send requests to our server.&lt;/p&gt;
&lt;p&gt;Create a new folder for you project and install Mocha, Chai, and Request to it by running:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&amp;gt; npm install mocha chai request
&lt;/pre&gt;
&lt;p&gt;By default, Mocha looks for tests in a folder called &lt;code&gt;/test&lt;/code&gt; within the project root, so create the folder with:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&amp;gt; mkdir &lt;span class="nb"&gt;test&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;In order to run our tests we'll set up a &lt;a href="https://en.wikipedia.org/wiki/Make_(software)#Makefiles"&gt;Makefile&lt;/a&gt; in the project root, the code of which looks like this:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&lt;span class="nv"&gt;REPORTER&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; spec

&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    @NODE_ENV&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;test&lt;/span&gt; ./node_modules/.bin/mocha &lt;span class="se"&gt;\&lt;/span&gt;
        --reporter &lt;span class="k"&gt;$(&lt;/span&gt;REPORTER&lt;span class="k"&gt;)&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
        --ui tdd

&lt;span class="nf"&gt;test-w&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    @NODE_ENV&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;test&lt;/span&gt; ./node_modules/.bin/mocha &lt;span class="se"&gt;\&lt;/span&gt;
        --reporter &lt;span class="k"&gt;$(&lt;/span&gt;REPORTER&lt;span class="k"&gt;)&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
        --growl &lt;span class="se"&gt;\&lt;/span&gt;
        --ui tdd &lt;span class="se"&gt;\&lt;/span&gt;
        --watch

&lt;span class="nf"&gt;.PHONY&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;test&lt;/span&gt; &lt;span class="n"&gt;test&lt;/span&gt;-&lt;span class="n"&gt;w&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;Be careful when you're creating the Makefile that you indent the lines with &lt;em&gt;Tab&lt;/em&gt; characters and not spaces.&lt;/p&gt;
&lt;p&gt;You can now run your tests once with:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&amp;gt; make &lt;span class="nb"&gt;test&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;You should see something like &lt;code&gt;0 passing (2ms)&lt;/code&gt;, which indicates that the test suite ran but didn't find any tests. If you see an error then the most likely options are probably that you've got spaces in your Makefile, or that Make can't find Mocha, in which case check that you have a &lt;code&gt;/node_modules&lt;/code&gt; directory in your project folder and that Mocha is installed to it.&lt;/p&gt;
&lt;p&gt;Alternatively, you can also run the tests continuously in the background with:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&amp;gt; make test-w
&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;make test&lt;/code&gt; command should also be added to the &lt;em&gt;scripts&lt;/em&gt; section of your &lt;code&gt;/package.json&lt;/code&gt; file, and Mocha, Chai, and Request to &lt;em&gt;devdependencies&lt;/em&gt;; like so:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;"scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;"test"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"make test"&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;"devDependencies"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;"mocha"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"*"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;"chai"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"*"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;"request"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"*"&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;h3&gt;Creating our Server&lt;/h3&gt;
&lt;p&gt;Next we'll create the server that we'll be testing (Yes, by most standards writing the code before the tests is backasswards, but this is for demo purposes). This server will listen for requests and respond according to the content of the request header. If the request has a &lt;a href="https://en.wikipedia.org/wiki/List_of_HTTP_header_fields"&gt;Content-Type&lt;/a&gt; header of 'text/plain' it will respond with an HTTP 200 "OK" code and emit an &lt;a href="https://nodejs.org/api/events.html"&gt;Event&lt;/a&gt; called &lt;em&gt;success&lt;/em&gt; containing the body of the request. For any other Content-Type header we will return an HTTP 400 "Bad Request" error.&lt;/p&gt;
&lt;p&gt;Create a &lt;code&gt;server.js&lt;/code&gt; file in a new &lt;code&gt;lib&lt;/code&gt; folder in your project directory, with the code below:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&lt;span class="c1"&gt;// ./lib/server.js&lt;/span&gt;

&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;http&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'http'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;server&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;createServer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'content-type'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="s1"&gt;'text/plain'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;''&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'data'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;chunk&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;body&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nx"&gt;chunk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'end'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;writeHead&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s1"&gt;'Content-Type'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'text/plain'&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
      &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;end&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'correct header'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;emit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'success'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;writeHead&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;400&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s1"&gt;'Content-Type'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'text/plain'&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;end&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'wrong header'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/pre&gt;
&lt;h3&gt;Setting up the Tests&lt;/h3&gt;
&lt;p&gt;Before we write our first test, we need to do a little more setup. The first thing we will need to do is to require Chai's &lt;em&gt;expect&lt;/em&gt; function in our test suite. So we'll create a file in our &lt;code&gt;/test&lt;/code&gt; folder called &lt;code&gt;tests.js&lt;/code&gt;:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&amp;gt; touch test/tests.js
&lt;/pre&gt;
&lt;p&gt;And with the first two lines we'll require the expect function from Chai:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;expect&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Chai'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;You may have noticed that our server doesn't start automatically, as it has no &lt;em&gt;listen&lt;/em&gt; call. The second line of our server code contains a &lt;a href="https://nodejs.org/api/modules.html"&gt;module export&lt;/a&gt; that allows our server to be imported into another file. We can then start the server before our tests run, and close it when they finish. To do this we need to import our server into &lt;code&gt;tests.js&lt;/code&gt;, and within the main 'describe' function in which we write our tests we'll include 'before' and 'after' functions.&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&lt;span class="c1"&gt;// ./test/tests.js&lt;/span&gt;

&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;server&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'../lib/server.js'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'server response'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;before&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;8000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nx"&gt;after&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;close&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/pre&gt;
&lt;h3&gt;Writing the Response Tests&lt;/h3&gt;
&lt;p&gt;We can now get round to actually writing our tests. We'll write three tests, in order to test each response from our server; the incorrect header response, the successful header response, and the data emitted on a successful response. First, we need to require the Request library at the beginning of &lt;code&gt;tests.js&lt;/code&gt;:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'request'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;Now we can include the test within our 'describe' function, immediately below the 'after' function:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&lt;span class="nx"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'should return 400'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;done&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'https://localhost:8000'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
    &lt;span class="nx"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;statusCode&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;equal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;400&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;equal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'wrong header'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;done&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;The &lt;em&gt;it&lt;/em&gt; statement, just like &lt;em&gt;describe&lt;/em&gt;, &lt;em&gt;before&lt;/em&gt;, and &lt;em&gt;after&lt;/em&gt;, follows the &lt;a href="https://en.wikipedia.org/wiki/Behavior-driven_development"&gt;BDD&lt;/a&gt; standard for writing tests. We begin by describing what the test should return, and then a function containing the tests. Because our code is Asynchronous, we need to invoke a callback (in this case called &lt;em&gt;done&lt;/em&gt;) so that Mocha knows to wait until the test is complete.&lt;/p&gt;
&lt;p&gt;The second line begins our request to the server. We're calling request with a &lt;em&gt;GET&lt;/em&gt; (though it could just as well be &lt;em&gt;POST&lt;/em&gt;) and passing in the address of our server; in this case localhost listening on port 8000. There is also a function with &lt;em&gt;error&lt;/em&gt;, &lt;em&gt;response&lt;/em&gt;, and &lt;em&gt;body&lt;/em&gt; callbacks. Within the function we're listening for a response, and this is where the test really happens.&lt;/p&gt;
&lt;p&gt;The Chai assertion library works by chaining together natural language assertions, making the tests fairly easy to read. In this case we're expecting the StatusCode of the response to equal &lt;em&gt;400&lt;/em&gt; and the body of the response to read &lt;em&gt;wrong header&lt;/em&gt;. The final part of the code is the &lt;em&gt;done()&lt;/em&gt; callback; without which the test will exit with a timeout error.&lt;/p&gt;
&lt;p&gt;Our second test will test the response if the request contains the &lt;em&gt;Content-Type: text/plain&lt;/em&gt; header.&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&lt;span class="nx"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'should return 200'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;done&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;options&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'https://localhost:8000'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="s1"&gt;'Content-Type'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'text/plain'&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;statusCode&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;equal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;200&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;equal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'correct header'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;done&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;This test is much like the first, expect we've added an options object containing the destination url and headers of our request. This is passed as the first parameter of the request, so that our request will be sent to &lt;a href="https://localhost:8000"&gt;https://localhost:8000&lt;/a&gt; with the correct &lt;em&gt;Content-Type&lt;/em&gt; header. By creating an options object like this it become very easy to use the Request library to create a request with any parameters we'd like.&lt;/p&gt;
&lt;p&gt;These two tests show the basic form for creating thorough HTTP Server tests. By adding more expect statements and adding different &lt;a href="https://chaijs.com/api/bdd/"&gt;parameters&lt;/a&gt; to the chain, you can easily test all the different parts of your responses.&lt;/p&gt;
&lt;h3&gt;Testing Emitters&lt;/h3&gt;
&lt;p&gt;Now that we can test our responses, I figure that the next step might be to test what our code is emitting internally. While not technically part of the scope of this article, if you're developing and testing HTTP Requests and Responses in Node.js, at some point your going to be using event emitters and listeners, and in fact you already have. In our server the code &lt;code&gt;req.on('data', function () {});&lt;/code&gt; is an event listener, listening for the &lt;em&gt;data&lt;/em&gt; event that is emitted when we receive data. Same with the &lt;code&gt;req.on('end')&lt;/code&gt; function.&lt;/p&gt;
&lt;p&gt;As you can see if you look back at our server code, once we receive the &lt;em&gt;end&lt;/em&gt; event, we send out our own &lt;em&gt;success&lt;/em&gt; event that contains the body of the received request. To test that we're successfully emitting, we'll add a body to our request, and we'll need to set a timeout in our test to make sure that the event is firing within a reasonable time.&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&lt;span class="nx"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'should emit request body'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;done&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;options&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'https://localhost:8000'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="s1"&gt;'Content-Type'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'text/plain'&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'successfully emitted request'&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;eventFired&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{});&lt;/span&gt;

  &lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'success'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;eventFired&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;equal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'successfully emitted request'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nx"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;eventFired&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;equal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;done&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mf"&gt;10&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;We have now attached a body to our request, that should be emitted back to us, and an &lt;em&gt;eventFired&lt;/em&gt; variable set to &lt;em&gt;false&lt;/em&gt;, that will be set to true when the event fires. The expect statements are no longer in the &lt;em&gt;request&lt;/em&gt; function, as we are not testing the HTTP response. The code &lt;code&gt;server.on('success', function (data) {})&lt;/code&gt; listens for the success event, and passes the data from that event into a function. Within the function we set &lt;em&gt;eventFired&lt;/em&gt; to true, and test to see that the emitted data is correct. The &lt;em&gt;setTimeout&lt;/em&gt; function is required in order to properly test that the event fired. If the event does not fire, then the test will fail gracefully rather than with a timeout error.&lt;/p&gt;
&lt;h3&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;We now have some basic tests that should reasonably cover the server code. This basic setup should work with most Node.js projects, and the general idea of this sort of testing is an essential skill in any programming language. If you'd like to have a look at or download and test the full code yourself then it can be found &lt;a href="https://github.com/DBeath/node-test-tutorial"&gt;here&lt;/a&gt;.&lt;/p&gt;</description><category>IT</category><category>servers</category><category>tutorial</category><category>Web</category><guid>https://davidbeath.com/posts/testing-http-responses-in-nodejs/</guid><pubDate>Mon, 03 Mar 2014 01:29:39 GMT</pubDate></item><item><title>Bittorrent Sync is not FOSS</title><link>https://davidbeath.com/posts/bittorrent-sync-is-not-foss/</link><dc:creator>David Beath</dc:creator><description>&lt;p&gt;&lt;a href="https://web.archive.org/web/20131211102756/https://www.bittorrent.com/sync"&gt;Bittorrent Sync&lt;/a&gt; has been getting a lot of press lately for being a really good file synchronisation solution. I was thinking about installing it on my systems today, to act as a secure, decentralised alternative to &lt;a href="https://www.dropbox.com"&gt;Dropbox&lt;/a&gt;. Then I had a sudden thought: "Wait, is Bittorrent Sync open source?".&lt;/p&gt;
&lt;p&gt;Turns out no, &lt;a href="https://web.archive.org/web/20130607013155/https://forum.bittorrent.com/topic/17782-bittorrent-sync-faq-unofficial/"&gt;it's not&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Well, crap.&lt;/p&gt;
&lt;!-- TEASER_END --&gt;

&lt;p&gt;It sounds like such a good system, and just because it's not &lt;a href="https://en.wikipedia.org/wiki/Free_and_open-source_software"&gt;FOSS&lt;/a&gt; doesn't mean it's not a really good piece of software, and as perfectly secure as it's possible to be these days. After all, Dropbox is closed and everyone (including me) trusts them to a certain extent (with non-critical stuff), though it doesn't exactly have the strongest reputation for security. The problem is that anyone who knows anything about computer security and cryptography also knows that a security solution that no-one else can inspect is a potentially insecure solution.&lt;/p&gt;
&lt;p&gt;While I would probably never do any more than glance at the source code if it was open, I would feel much safer in the knowledge that people much more clued up than me about security had most likely pored over the code looking for bugs and security holes. I trust &lt;a href="https://keepass.info/"&gt;KeePass&lt;/a&gt; with my passwords because anyone can check the code to make sure it's not transmitting all my passwords to the NSA, GCHQ, GCSB, any other alphabet soup agency, Google, Facebook, or the Russian Mafia (to list just a few possible nefarious organisations). Likewise for the other open source software I use, I trust that there's enough people looking at the code that someone would raise a stink if something was awry.&lt;/p&gt;
&lt;p&gt;Looking through the Bittorrent forums, this has all been debated to death. The BT Sync team have stated that they're considering the option of taking it open source. I hope they do. In the meantime, I figure I might as well go ahead and use it; the only files of mine that really require strong encryption is the aforementioned KeePass database, and that's already encrypted.&lt;/p&gt;
&lt;p&gt;However, if I do ever find myself in a position where my life and liberty depend on secure communications, I won't be using anything that isn't open source.&lt;/p&gt;</description><category>IT</category><category>Security</category><guid>https://davidbeath.com/posts/bittorrent-sync-is-not-foss/</guid><pubDate>Tue, 10 Dec 2013 08:26:33 GMT</pubDate></item><item><title>Configuring SSL in Nginx</title><link>https://davidbeath.com/posts/configuring-ssl-in-nginx/</link><dc:creator>David Beath</dc:creator><description>&lt;p&gt;This post aims to be a fairly thorough guide to getting &lt;a href="https://en.wikipedia.org/wiki/Secure_Sockets_Layer"&gt;SSL&lt;/a&gt; up and running on an &lt;a href="https://en.wikipedia.org/wiki/Nginx"&gt;Nginx&lt;/a&gt; server, largely for my own reference in future, but it may prove useful to anyone else who stumbles across it. I'm going to assume that you have a working installation of Nginx, or know how to get one going. If not, then bookmark this page and find a tutorial on how to get it going first, such as the section on Nginx in my post &lt;a href="https://davidbeath.com/posts/installing-tiny-tiny-rss-from-scratch.html"&gt;here&lt;/a&gt;, or the &lt;a href="https://nginx.org/en/docs/install.html"&gt;Installation&lt;/a&gt; and &lt;a href="https://nginx.org/en/docs/beginners_guide.html"&gt;Beginner's Guide&lt;/a&gt; pages on the official site.&lt;/p&gt;
&lt;!-- TEASER_END --&gt;

&lt;h3&gt;Get an SSL Certificate&lt;/h3&gt;
&lt;p&gt;The first step in setting up SSL on your server is to procure an &lt;a href="https://www.globalsign.eu/ssl-information-center/what-is-an-ssl-certificate.html"&gt;SSL Certificate&lt;/a&gt; from an approved &lt;a href="https://en.wikipedia.org/wiki/Certificate_authority"&gt;Certificate Authority&lt;/a&gt; (CA). The easiest way to do this is to purchase one from a certificate reseller such as &lt;a href="https://www.cheapssls.com/"&gt;CheapSSLs.com&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;For a single site with no subdomains, such as a blog, that doesn't require all the extra features of more expensive certificates, then a certificate such as &lt;a href="https://www.cheapssls.com/comodo-ssl-certificates/positivessl.html"&gt;Comodo Positive SSL&lt;/a&gt; will do fine.&lt;/p&gt;
&lt;p&gt;Once you've purchased the certificate, you'll need to create a Certificate Signing Request.&lt;/p&gt;
&lt;h4&gt;Creating a CSR&lt;/h4&gt;
&lt;p&gt;A Certificate Signing Request (CSR) is a file that contains the application information for your certificate, such as your location and the name of the domain you want to secure, as well as your &lt;a href="https://en.wikipedia.org/wiki/Public-key_cryptography"&gt;Public Key&lt;/a&gt;. For creating the CSR we'll be using &lt;a href="https://www.openssl.org/"&gt;OpenSSL&lt;/a&gt;, so if you don't have that on your server you can install it with the following command:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&amp;gt; sudo apt-get install openssl
&lt;/pre&gt;
&lt;p&gt;Before we start creating files, it's recommended that you have a proper location to store them in. On Linux systems this would be something like &lt;code&gt;/etc/ssl/localcerts/&lt;/code&gt;, so lets start there.&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&amp;gt; sudo mkdir /etc/ssl/localcerts
&amp;gt; sudo &lt;span class="nb"&gt;cd&lt;/span&gt; /etc/ssl/localcerts
&lt;/pre&gt;
&lt;p&gt;To generate the public and private keys that will be used for the CSR, use this command:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&amp;gt; sudo openssl req -nodes -newkey rsa:2048 -days &lt;span class="m"&gt;365&lt;/span&gt; -keyout myserver.key -out server.csr
&lt;/pre&gt;
&lt;p&gt;This will create two files; &lt;code&gt;myserver.key&lt;/code&gt;, the private key file, and &lt;code&gt;server.csr&lt;/code&gt;, the Certificate Signing Request. When you enter the above command, you should of course set the name of both files to one appropriate for the server you are securing.&lt;/p&gt;
&lt;p&gt;Generally your CA should require you to use &lt;a href="https://en.wikipedia.org/wiki/RSA_(algorithm)"&gt;RSA&lt;/a&gt; 2048, this is specified with the &lt;code&gt;-newkey rsa:2048&lt;/code&gt; portion of the command. If you purchased a certificate that is valid for more than a year, then the &lt;code&gt;-days 365&lt;/code&gt; portion should be set to the number of days your certificate is valid.&lt;/p&gt;
&lt;p&gt;Once you've entered the above command, you'll be asked to enter the details into your CSR. These details (with examples) are:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;Country Name &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt; letter code&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;AU&lt;span class="o"&gt;]&lt;/span&gt;: US
State or Province Name &lt;span class="o"&gt;(&lt;/span&gt;full name&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;Some-State&lt;span class="o"&gt;]&lt;/span&gt;: California
Locality Name &lt;span class="o"&gt;(&lt;/span&gt;eg, city&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;[]&lt;/span&gt;: Los Angeles
Organization Name &lt;span class="o"&gt;(&lt;/span&gt;eg, company&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;Internet Widgits Pty Ltd&lt;span class="o"&gt;]&lt;/span&gt;: ACME Ltd
Organizational Unit Name &lt;span class="o"&gt;(&lt;/span&gt;eg, section&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;[]&lt;/span&gt;: Widgets
Common Name &lt;span class="o"&gt;(&lt;/span&gt;eg, YOUR name&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;[]&lt;/span&gt;: widgets.acme.com
Email Address &lt;span class="o"&gt;[]&lt;/span&gt;:
&lt;/pre&gt;
&lt;p&gt;And two 'extra', comletely optional details:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;A challenge password &lt;span class="o"&gt;[]&lt;/span&gt;:
An optional company name &lt;span class="o"&gt;[]&lt;/span&gt;:
&lt;/pre&gt;
&lt;p&gt;If you enter a period '.' into one of the above fields then the field will be left blank.&lt;/p&gt;
&lt;p&gt;One thing that seems to get glossed over is that the &lt;strong&gt;Common Name&lt;/strong&gt; field is the &lt;a href="https://en.wikipedia.org/wiki/Fully_qualified_domain_name"&gt;fully qualified domain name&lt;/a&gt; (FQDN) of your site. So if you're wanting to secure &lt;code&gt;example.com&lt;/code&gt;, then that's what you put in the common name field. If you're securing a subdomain like &lt;code&gt;subdomain.example.com&lt;/code&gt;, then make sure you enter it like that. Unless you've bought a wildcard certificate, then your certificate will only cover a single domain or subdomain.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;WARNING&lt;/strong&gt;: Make very sure you've entered the Common Name correctly before you submit your CSR. (Yes, I have made this mistake. Don't do important things when you're tired.)&lt;/p&gt;
&lt;p&gt;Once you've created the CSR, go to the site you purchased your certificate from and activate it. You'll be asked to enter your CSR into an online form, so open your CSR file up in a text editor and paste the entire contents into the enrollment form, including the BEGIN and END lines.&lt;/p&gt;
&lt;h4&gt;Installing your Certificate&lt;/h4&gt;
&lt;p&gt;Once your CSR has been approved, you'll get an email containing your new certificate, and the Root certificates required. Copy these to the folder where you intend to store your certificates. For this example we'll use the SSL localcerts directory we created previously &lt;code&gt;/etc/ssl/localcerts/&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;You may want to combine the certificates together into one file. If so, then you can use the &lt;code&gt;cat&lt;/code&gt; command to concatenate the files in reverse order of authority. For example, if you've got a Comodo Positive SSL Certificate, then you should have three files; the certificate for your domain (eg. &lt;code&gt;example.com.crt&lt;/code&gt;), the intermediate certificate (eg. &lt;code&gt;PositiveSSLCA2.crt&lt;/code&gt;), and the root certificate (eg. &lt;code&gt;AddTrustExternalCARoot.crt&lt;/code&gt;). So to concatenate these files the command would be:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&amp;gt; sudo cat example.com.crt PositiveSSLCA2.crt AddTrustExternalCARoot.crt &amp;gt;&amp;gt; example.com.chained.crt
&lt;/pre&gt;
&lt;h3&gt;Configuring Nginx&lt;/h3&gt;
&lt;p&gt;You can now set about adding your certificate to your server configuration in Nginx. If you installed Nginx from a package, it should have SSL enabled already, otherwise if you're building from source you'll have to specifically enable it during configuration.&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&amp;gt; ./configure --with-http_ssl_module --with_http_spdy_module
&lt;/pre&gt;
&lt;p&gt;If you're using SSL then you may as well use &lt;a href="https://en.wikipedia.org/wiki/SPDY"&gt;SPDY&lt;/a&gt; to help speed up the connection.&lt;/p&gt;
&lt;p&gt;Now you can configure your Virtual Hosts for SSL. In the server block of your configuration, you need to set it to listen on port 443, specify the certificate and private key, and SSL protocols and cipher settings.&lt;/p&gt;
&lt;p&gt;This is an example of a basic Nginx Virtual Host file with SSL enabled:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&lt;span class="k"&gt;server&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kn"&gt;listen&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;443&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;ssl&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;spdy&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kn"&gt;server_name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;example.com&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kn"&gt;root&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;/srv/www/example.com&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kn"&gt;index&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;index.html&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kn"&gt;ssl_certificate&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;/etc/ssl/localcerts/example.com.chained.crt&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kn"&gt;ssl_certificate_key&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;/etc/ssl/localcerts/example.com.key&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;The listen directive specifies that the server should listen on the HTTPS port, 443, instead of the usual port 80, that SSL is on, and that it is using the SPDY protocol. The ssl_certificate directive points to the location of the chained certificate we created. The ssl_certificate_key directive points to the private key that was created when we created the certificate signing request.&lt;/p&gt;
&lt;p&gt;The above provides the minimum configuration required to enable SSL on Nginx. All you need to do is restart Nginx, and you should be able to visit your site using HTTPS.&lt;/p&gt;
&lt;h4&gt;SSL Security in Nginx&lt;/h4&gt;
&lt;p&gt;Of course, the above basic configuration only uses the most basic default security, so you'll probably want to do some additional configuration.&lt;/p&gt;
&lt;p&gt;The first thing you'll want to do is to set the SSL Ciphers your server will use. This &lt;a href="https://blog.cloudflare.com/staying-on-top-of-tls-attacks"&gt;post&lt;/a&gt; has a good explanation on the background of using ciphers. The exact list of ciphers you should use is dependent on how secure you want to be, and what performance considerations you have. The ciphers I use are:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&lt;span class="k"&gt;ssl_ciphers&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;ECDHE-RSA-AES256-SHA384:AES256-SHA256:RC4:HIGH:!MD5:!aNULL:!eNULL:!NULL:!DH:!EDH:!AESGCM&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;This gives me an 'A' rating on the &lt;a href="https://www.ssllabs.com/ssltest/index.html"&gt;SSL Server Test&lt;/a&gt;, while still providing decent performance.&lt;/p&gt;
&lt;p&gt;The rest of my SSL configuration is as follows:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&lt;span class="k"&gt;ssl_session_timeout&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5m&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="k"&gt;ssl_prefer_server_ciphers&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;on&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="k"&gt;ssl_session_cache&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;shared:SSL:10m&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="k"&gt;ssl_protocols&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;TLSv1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;TLSv1.1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;TLSv1.2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="k"&gt;ssl_ecdh_curve&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;secp521r1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;&lt;em&gt;ssl_session_timeout 5m;&lt;/em&gt; is the time it takes for the client's ssl session information to be removed from the cache. A longer time means that the ssl session won't have to be renegotiated as often, improving performance if there are a lot of connections. 5 minutes is the default time for many client browsers.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;ssl_prefer_server_ciphers on;&lt;/em&gt; means that the server will prefer to use ciphers specified in the &lt;code&gt;ssl_ciphers&lt;/code&gt; directive over the ciphers preferred by clients.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;ssl_session_cache shared:SSL:10m;&lt;/em&gt; lets Nginx use its own cache instead of the one provided by OpenSSL, thus allowing Nginx to separate SSL jobs between its own workers.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;ssl_protocols TLSv1 TLSv1.1 TLSv1.2;&lt;/em&gt; is the list of supported protocols, which in this case is only TLSv1 or greater. SSLv3 and below are not recommended due to security vulnerabilities, and most browsers support TLS now.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;ssl_ecdh_curve secp521r1;&lt;/em&gt; is the &lt;a href="https://en.wikipedia.org/wiki/Elliptic_curve_cryptography"&gt;Elliptic curve&lt;/a&gt; key used for the ECDHE cipher.&lt;/p&gt;
&lt;p&gt;If you want a much more in-depth look at securely configuring Nginx, then &lt;a href="https://calomel.org/nginx.html"&gt;calomel.org&lt;/a&gt; has an excellently thorough post detailing nearly everything you need to know.&lt;/p&gt;
&lt;h4&gt;Redirecting to HTTPS&lt;/h4&gt;
&lt;p&gt;If you want to redirect all your traffic to the SSL version of your site, then you'll need to specify another Virtual Host to accept HTTP traffic and redirect it to HTTPS.&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&lt;span class="k"&gt;server&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kn"&gt;listen&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kn"&gt;server_name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;example.com&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kn"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;301&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;https://example.com&lt;/span&gt;&lt;span class="nv"&gt;$request_uri&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;This server block listens on port 80, and then performs an &lt;a href="https://en.wikipedia.org/wiki/HTTP_301"&gt;HTTP 301&lt;/a&gt; redirect to the requested URI. As this is a permanent redirect of a full URL then &lt;code&gt;return&lt;/code&gt; rather than &lt;code&gt;rewrite&lt;/code&gt; is the correct Nginx directive to use.&lt;/p&gt;
&lt;h3&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;You should now have a secure implementation of SSL on your website. You may want to use tools such as &lt;a href="https://developers.google.com/speed/pagespeed/"&gt;pagespeed&lt;/a&gt; to test the speed of your site, as it may require a bit of tweaking to get the best balance between performance and security.&lt;/p&gt;</description><category>IT</category><category>Nginx</category><category>servers</category><category>tutorial</category><category>Web</category><guid>https://davidbeath.com/posts/configuring-ssl-in-nginx/</guid><pubDate>Sun, 17 Nov 2013 03:32:49 GMT</pubDate></item><item><title>Ubuntu Post-Install Guide</title><link>https://davidbeath.com/posts/ubuntu-post-install-guide/</link><dc:creator>David Beath</dc:creator><description>&lt;p&gt;Having reinstalled Ubuntu a few times on various machines, I figured it's about time that I recorded a few of the post installation steps I take, so that I don't have to keep looking them up. The instructions below are for Ubuntu 13.10, and can be done in any order.&lt;/p&gt;
&lt;!-- TEASER_END --&gt;

&lt;h3&gt;Install Bumblebee&lt;/h3&gt;
&lt;p&gt;Bumblebee is a package that prevents laptops that run Nvidia Optimus graphics from running the dedicated graphics card permanently. Installing this is the first thing I do, otherwise things get quite toasty. Further instructions &lt;a href="https://wiki.ubuntu.com/Bumblebee"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&amp;gt; sudo add-apt-repository ppa:bumblebee/stable
&amp;gt; sudo apt-get update
&amp;gt; sudo apt-get install bumblebee bumblebee-nvidia primus linux-headers-generic

&amp;gt; sudo shutdown -r now
&lt;/pre&gt;
&lt;h3&gt;Disable Apport&lt;/h3&gt;
&lt;p&gt;Apport is the error reporting service for Ubuntu. Most of the errors it pops up with are pretty minor, and Canonical knows about them by now anyway. You can either get rid of it entirely or just disable it. Instructions from &lt;a href="https://howtoubuntu.org/how-to-disable-apport-error-reporting-in-ubuntu#.UoVIoXiLe1E"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;To disable Apport:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&amp;gt; sudo service apport stop

&amp;gt; sudo nano /etc/default/apport
&lt;/pre&gt;
&lt;pre class="code literal-block"&gt;&lt;span class="na"&gt;enabled&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;0&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;To remove Apport entirely:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&amp;gt; sudo apt-get purge apport
&lt;/pre&gt;
&lt;h3&gt;Install Unity-Tweak-Tool&lt;/h3&gt;
&lt;p&gt;Unity Tweak Tool is always good for tweaking the Unity interface to your preferences. I think the default launcher is much too large, and I like to set the font-size smaller too.&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&amp;gt; sudo apt-get install unity-tweak-tool
&lt;/pre&gt;
&lt;h3&gt;Install Sublime Text 3&lt;/h3&gt;
&lt;p&gt;Sublime Text 3 seems to be everyone's favourite text editor these days, and it's what I use to write these blog posts. Instructions courtesy of &lt;a href="https://www.webupd8.org/2013/07/sublime-text-3-ubuntu-ppa-now-available.html"&gt;webupd8.org&lt;/a&gt;.&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&amp;gt; sudo add-apt-repository ppa:webupd8team/sublime-text-3
&amp;gt; sudo apt-get update
&amp;gt; sudo apt-get install sublime-text-installer
&lt;/pre&gt;
&lt;p&gt;To prevent annoying update notifications, once Sublime Text is open add the following code in: Preferences &amp;gt; Settings - User:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&lt;span class="na"&gt;"update_check": false&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;h3&gt;Install Numix GTK3 Theme&lt;/h3&gt;
&lt;p&gt;Numix is my favourite GTK3 Theme, and looks good in Unity. Check it out at their &lt;a href="https://numixproject.org/"&gt;website&lt;/a&gt;.&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&amp;gt; sudo add-apt-repository ppa:numix/ppa
&amp;gt; sudo apt-get update
&amp;gt; sudo apt-get install numix-gtk-theme
&lt;/pre&gt;
&lt;p&gt;Alternatively, for a few other themes as well if you're running 13.10:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&amp;gt; sudo apt-get install shimmer-themes
&lt;/pre&gt;
&lt;h3&gt;Remove Ubuntu One&lt;/h3&gt;
&lt;p&gt;Ubuntu One doesn't really seem to be under active development anymore, and there are better cloud solutions out there, so you might as well remove it. Instructions from &lt;a href="https://askubuntu.com/questions/353987/remove-ubuntu-one"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&amp;gt; killall ubuntuone-login ubuntuone-preferences ubuntuone-syncdaemon
&amp;gt; sudo rm -rf ~/.local/share/ubuntuone
&amp;gt; rm -rf ~/.cache/ubuntuone
&amp;gt; rm -rf ~/.config/ubuntuone
&amp;gt; mv ~/Ubuntu&lt;span class="se"&gt;\ &lt;/span&gt;One/ ~/UbuntuOne_old/

&amp;gt; sudo apt-get purge ubuntuone-client python-ubuntuone-*
&lt;/pre&gt;
&lt;h3&gt;Disable Login Drum Sounds&lt;/h3&gt;
&lt;p&gt;I hate login sounds, and a quick search shows a lot of other people do as well, yet Ubuntu no longer has any options to disable them. So if you can't stop it from playing the sound, just remove the file. These &lt;a href="https://www.linuxandlife.com/2012/05/how-to-turn-off-or-change-login-sound.html"&gt;instructions&lt;/a&gt; should work regardless of version.&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&amp;gt; &lt;span class="nb"&gt;cd&lt;/span&gt; /usr/share/sounds/ubuntu/stereo
&amp;gt; mv system-ready.ogg system-ready.ogg.old
&lt;/pre&gt;
&lt;h3&gt;Install VLC Player&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://www.videolan.org/vlc/index.html"&gt;VLC&lt;/a&gt; is the best video player, enough said.‎&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&amp;gt; sudo apt-get install vlc
&lt;/pre&gt;
&lt;h3&gt;Disable Amazon Shopping&lt;/h3&gt;
&lt;p&gt;A lot of people really dislike the direction the Canonical has taken by integrating online shopping searches into Unity Lens search, and I agree. There is a button to turn it off in the settings, but I'd just as soon &lt;a href="https://www.webupd8.org/2013/10/how-to-disable-amazon-shopping.html"&gt;remove it altogether&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Paste the following into your terminal:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&amp;gt; gsettings &lt;span class="nb"&gt;set&lt;/span&gt; com.canonical.Unity.Lenses disabled-scopes &lt;span class="s2"&gt;"['more_suggestions-amazon.scope', 'more_suggestions-u1ms.scope', 'more_suggestions-populartracks.scope', 'music-musicstore.scope', 'more_suggestions-ebay.scope', 'more_suggestions-ubuntushop.scope', 'more_suggestions-skimlinks.scope']"&lt;/span&gt;
&lt;/pre&gt;
&lt;h3&gt;Improve Battery Life&lt;/h3&gt;
&lt;p&gt;Some &lt;a href="https://www.webupd8.org/2013/10/8-things-to-do-after-installing-ubuntu.html"&gt;instructions&lt;/a&gt; for a tool that may help improve laptop battery life. Warning: May cause issues with external devices due to powering off USB ports.&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&amp;gt; sudo apt-add-repository ppa:linrunner/tlp
&amp;gt; sudo apt-get update
&amp;gt; sudo apt-get install tlp tlp-rdw
&amp;gt; sudo tlp start
&lt;/pre&gt;
&lt;h3&gt;Development Tools&lt;/h3&gt;
&lt;p&gt;So I don't forget, these are some of the packages that are useful to have to development purposes.&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&amp;gt; sudo apt-get install python-software-properties python python-pip g++ make python-dev git
&lt;/pre&gt;
&lt;p&gt;Instructions for installing nodejs.&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&amp;gt; sudo add-apt-repository ppa:chris-lea/node.js
&amp;gt; sudo apt-get update
&amp;gt; sudo apt-get install nodejs
&lt;/pre&gt;
&lt;h3&gt;KeePass&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://keepass.info/"&gt;KeePass&lt;/a&gt; is my preferred password manager. Keep the password file in Dropbox and you can access it anywhere. The install instructions for Ubuntu are &lt;a href="https://sourceforge.net/p/keepass/discussion/329220/thread/17d1bd26"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&amp;gt; sudo apt-add-repository ppa:jtaylor/keepass
&amp;gt; sudo apt-get update
&amp;gt; sudo apt-get install keepass2
&lt;/pre&gt;
&lt;h3&gt;Dropbox&lt;/h3&gt;
&lt;p&gt;You can find the download for Dropbox on their &lt;a href="https://www.dropbox.com/install?os=lnx"&gt;site&lt;/a&gt; as usual. In Ubuntu 13.10 you may come across an issue where the Dropbox icon isn't showing in the status bar. If so, just install the following package:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&amp;gt; sudo apt-get install libappindicator1
&lt;/pre&gt;</description><category>IT</category><category>tutorial</category><guid>https://davidbeath.com/posts/ubuntu-post-install-guide/</guid><pubDate>Fri, 15 Nov 2013 01:13:44 GMT</pubDate></item><item><title>Reading XBee RSSI with Arduino</title><link>https://davidbeath.com/posts/reading-xbee-rssi-with-arduino/</link><dc:creator>David Beath</dc:creator><description>&lt;p&gt;Last year I spent quite a lot of time trying to read the &lt;a href="https://en.wikipedia.org/wiki/Received_signal_strength_indication"&gt;Recieved Signal Strength Indicator&lt;/a&gt; from an XBee for a project I was working on. I had planned to blog about the process, but never got round to writing any more than two posts. However, I had a look at the nascent blog for the first time in a while, and it surprised me that it was getting a respectable number of views, especially for something that wasn't particularly informative and hadn't been updated in so long. Having a look at the analytics, I realised that like I been doing, there are still a lot of people trying to figure out how to read RSSI from an XBee to an Arduino. So here's a tutorial and some pointers for getting XBees set up for signal strength reading.&lt;/p&gt;
&lt;!-- TEASER_END --&gt;

&lt;p&gt;The first thing you're going to need is of course a couple of &lt;a href="https://en.wikipedia.org/wiki/XBee"&gt;XBee&lt;/a&gt; units. You'll also need an XBee usb connector like &lt;a href="https://www.sparkfun.com/products/8687"&gt;this&lt;/a&gt; to configure them from your computer. For this tutorial I'll explain how to read the signal strength with an &lt;a href="https://www.arduino.cc"&gt;Arduino&lt;/a&gt;, though you can just use a PC.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;PLEASE NOTE&lt;/strong&gt;: Unless you want to set up a &lt;a href="https://en.wikipedia.org/wiki/Wireless_mesh_network"&gt;Wireless mesh network&lt;/a&gt;, you should use the &lt;a href="https://www.digi.com/products/wireless-wired-embedded-solutions/zigbee-rf-modules/point-multipoint-rfmodules/xbee-series1-module"&gt;XBee 802.15.4&lt;/a&gt; modules, also known as the Series 1 modules. The Series 1 operates a standard point to point network. The Series 2 modules, the &lt;a href="https://www.digi.com/products/wireless-wired-embedded-solutions/zigbee-rf-modules/zigbee-mesh-module/xbee-zb-module"&gt;XBee ZB&lt;/a&gt;, use the ZigBee mesh protocol. Because of this, they do not include RSSI information in the packet, and anyway, the RSSI is only good for the last hop. Make sure you know your required use-case before ordering these modules. &lt;em&gt;You have been warned.&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;XBee Configuration&lt;/h3&gt;
&lt;p&gt;Before doing anything with your XBees, read this list of &lt;a href="https://www.faludi.com/projects/common-xbee-mistakes/"&gt;common XBee mistakes&lt;/a&gt;. It will save you a lot of time wondering why things aren't working as they should. I also recommend you read the official &lt;a href="https://www.google.com/search?q=xbee+getting+started+guide"&gt;Getting Started Guide&lt;/a&gt;, and consult the &lt;a href="https://www.google.com/search?q=xbee+product+manual"&gt;Product Manual&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In order to configure your XBees, by far the easiest way is to use &lt;a href="https://hub.digi.com/support/products/xctu/"&gt;X-CTU&lt;/a&gt;. Unfortunately this only runs on Windows, though it may be possible to get it working with WINE in Linux. For very basic instructions on how to use X-CTU, look &lt;a href="https://examples.digi.com/get-started/configuring-xbee-radios-with-x-ctu/"&gt;here&lt;/a&gt;. Alternatively, you check out the instructions &lt;a href="https://examples.digi.com/get-started/basic-xbee-802-15-4-chat/3/"&gt;here&lt;/a&gt; on how to configure them from a terminal.&lt;/p&gt;
&lt;p&gt;Getting the XBees talking to each other should be a fairly simple matter. You'll want the &lt;em&gt;PAN ID&lt;/em&gt; and &lt;em&gt;Channel&lt;/em&gt; settings to be the same on each XBee you're using, and of course the &lt;em&gt;MY&lt;/em&gt; address should be unique to each XBee. If you're using only two XBees to talk to each other, then set the &lt;em&gt;Destination address high&lt;/em&gt; to &lt;code&gt;0&lt;/code&gt; and the &lt;em&gt;Destination low&lt;/em&gt; address to the &lt;em&gt;MY&lt;/em&gt; address of the other XBee. Otherwise, if you're wanting to broadcast to all XBees listening on the same &lt;em&gt;Channel&lt;/em&gt; and &lt;em&gt;PAN ID&lt;/em&gt;, then set the &lt;em&gt;Destinaton high&lt;/em&gt; address to &lt;code&gt;0&lt;/code&gt;, and the &lt;em&gt;Destination low&lt;/em&gt; address to &lt;code&gt;FFFF&lt;/code&gt; to enable broadcast mode.&lt;/p&gt;
&lt;p&gt;The final setting is to change the &lt;em&gt;API Enable&lt;/em&gt; setting to "2", which will allow the Arduino to control the XBee using API commands.&lt;/p&gt;
&lt;h3&gt;Arduino Configuration&lt;/h3&gt;
&lt;p&gt;I'm going to assume that if you're reading this tutorial, then you already have a basic understanding of Arduino code, and how to use them. You'll need to download the &lt;a href="https://github.com/andrewrapp/xbee-arduino"&gt;xbee-arduino&lt;/a&gt; library and put it in your Arduino library folder.&lt;/p&gt;
&lt;p&gt;In your Arduino code include and intitialise the xbee-arduino library.&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;XBee.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;&lt;/span&gt;

&lt;span class="n"&gt;XBee&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;xbee&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;XBee&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;Then the start the serial connection to the XBee and computer in setup.&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;// XBee serial connection&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;xbee&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;begin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;9600&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;// Computer serial connection&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;Serial&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;begin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;9600&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;For the purposes of this tutorial, we're going to have one XBee send a packet, and the other read the packet and output the RSSI value. You can have the sending XBee just send from a terminal, and use only one Arduino for receiving, but I'm going to show the code for having both XBees attached to an Arduino. The code about applies to both sender and receiver.&lt;/p&gt;
&lt;h4&gt;Sending Packets&lt;/h4&gt;
&lt;p&gt;On your sending XBee/Arduino, before the setup, initialise the payload. You can of course change the payload anywhere within the loop. I'm going to set the payload to "Hi".&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&lt;span class="kt"&gt;uint8_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sc"&gt;'H'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sc"&gt;'i'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;Then specify the destination address that you're going to send to. This is the &lt;em&gt;Serial High&lt;/em&gt; and &lt;em&gt;Serial Low&lt;/em&gt; address of the recieving XBee. If you're broadcasting, then you can skip this step.&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&lt;span class="n"&gt;XBeeAddress64&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;addr64&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;XBeeAddress64&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mh"&gt;0x0013a200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x403e0f30&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;In this example, because we're not dealing with sending updated data, we can create the transmit request in setup. The &lt;em&gt;Tx16Request&lt;/em&gt; takes three parameters; the address it's being sent to, the payload, and the size of the payload. If you're broadcasting, then change the address parameter to &lt;code&gt;0xFFFF&lt;/code&gt;.&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&lt;span class="n"&gt;Tx16Request&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tx16&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Tx16Request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;addr64&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;Finally, in your loop, send the packet. I'm going to set it to send every 50 milliseconds.&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;loop&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;xbee&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tx16&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;delay&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;h4&gt;Receiving Packets and reading RSSI&lt;/h4&gt;
&lt;p&gt;On your receiver, before setup, you'll first need to initialise a Response object.&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;Rx16Response&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rx16&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Rx16Response&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;In the loop, your XBee will first wait for an incoming packet. The value within the brackets specifies how long it shoud continue waiting before continuing through the loop. For this example, because we're only doing the one thing, listening for and reading the signal strength of a packet, we can afford to wait a while.&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;xbee&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;readPacket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;Once a packet is received, in order to prevent errors we first check if the response is available, then check if it matches the response type we want. Only then do we actually read the packet.&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&lt;span class="c1"&gt;// Check if available&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;xbee&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getResponse&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;isAvailable&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;// Check if packet is correct type&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;xbee&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getResponse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getApiId&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;RX_16_RESPONSE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// Read the packet&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;xbee&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getResponse&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;getRx16Response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rx16&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;Now you can read the signal strength from the packet and send it to the computer. If you don't want to print out the previous RSSI value every time through the loop whenever a packet isn't received (which you shouldn't), then this code should go within your &lt;em&gt;if&lt;/em&gt; statements immediately after you've read the packet.&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&lt;span class="n"&gt;Serial&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rx16&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getRssi&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;And if you want to print out the payload:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rx16&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getDataLength&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;Serial&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rx16&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;HEX&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;h3&gt;Final Code&lt;/h3&gt;
&lt;p&gt;Your code for the sender should look something like this:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;XBee.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;&lt;/span&gt;

&lt;span class="n"&gt;XBee&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;xbee&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;XBee&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="kt"&gt;uint8_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sc"&gt;'H'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sc"&gt;'i'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="n"&gt;XBeeAddress64&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;addr64&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;XBeeAddress64&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mh"&gt;0x0013a200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x403e0f30&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="n"&gt;Tx16Request&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tx16&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Tx16Request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;addr64&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;xbee&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;begin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;9600&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;loop&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;xbee&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tx16&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;delay&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;And the code for the receiver something like this:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;XBee.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;&lt;/span&gt;

&lt;span class="n"&gt;XBee&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;xbee&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;XBee&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="n"&gt;Rx16Response&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rx16&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Rx16Response&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;xbee&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;begin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;9600&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;Serial&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;begin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;9600&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;loop&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;xbee&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;readPacket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;xbee&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getResponse&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;isAvailable&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;xbee&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getResponse&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;getApiId&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;RX_16_RESPONSE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="n"&gt;xbee&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getResponse&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;getRx16Response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rx16&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="n"&gt;Serial&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rx16&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getRssi&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;You should now have a couple of XBees that are talking to each other, and can read the signal strength of the packets. For a full example of working code, where a whole bunch of senders broadcast to multiple receivers, which then send the data to an aggregator, check out my &lt;a href="https://github.com/DBeath/rssi-aggregator"&gt;Github repository&lt;/a&gt;.&lt;/p&gt;</description><category>Arduino</category><category>IT</category><category>RSSI</category><category>tutorial</category><category>XBee</category><guid>https://davidbeath.com/posts/reading-xbee-rssi-with-arduino/</guid><pubDate>Fri, 11 Oct 2013 01:47:53 GMT</pubDate></item><item><title>Installing Tiny Tiny RSS from scratch</title><link>https://davidbeath.com/posts/installing-tiny-tiny-rss-from-scratch/</link><dc:creator>David Beath</dc:creator><description>&lt;p&gt;Considering that a couple of times now I've been a proponent of using an RSS reader, I figured it was time I wrote a tutorial on how to install &lt;a href="https://tt-rss.org/"&gt;Tiny Tiny RSS&lt;/a&gt;, using &lt;a href="https://nginx.org/"&gt;Nginx&lt;/a&gt; as the server and &lt;a href="https://www.postgresql.org/"&gt;PostgreSQL&lt;/a&gt; for the database. While as with any piece of software there are a number of tutorials and guides already out there, I've found that none of them provided a complete instruction set that didn't have me running into and searching for solutions to multiple errors. To that end, this tutorial aims to both provide as complete a set of fool-proof instructions as I can make, both for newbies to self-hosting, and simply as a reference for my future self should I need to do this again.&lt;/p&gt;
&lt;!-- TEASER_END --&gt;

&lt;p&gt;This set of instructions assumes that you're running a Debian based Linux distro. I've tested this setup on a clean Ubuntu Server 12.04 virtual machine, and the settings are roughly the same as I'm using on my Debian server. It's assumed that you either know how to set up a server already, or are capable of reading a tutorial to do so (If not, then why are you reading this? Go use &lt;a href="https://cloud.feedly.com/"&gt;Feedly&lt;/a&gt;). There are some very good tutorials at &lt;a href="https://www.digitalocean.com/community/"&gt;Digital Ocean&lt;/a&gt; and &lt;a href="https://library.linode.com/"&gt;Linode&lt;/a&gt;, and I'd recommend either of them for hosting purposes.&lt;/p&gt;
&lt;h3&gt;Installation&lt;/h3&gt;
&lt;p&gt;On to the install. While not strictly necessary, the first thing I recommend is to make sure that your server is using the correct time, so install ntp to keep the system clock updated.&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&amp;gt; sudo apt-get install ntp
&lt;/pre&gt;
&lt;p&gt;For most of the commands in this tutorial you'll need super user privileges, so you can either run them as root (not recommended) or use &lt;code&gt;sudo&lt;/code&gt; like I've used in this tutorial.
You'll also need to edit a bunch of files in a text editor. I've used &lt;code&gt;nano&lt;/code&gt; for this tutorial because it's easier to use and you can just copy the commands straight, but I usually use &lt;code&gt;vim&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;PHP&lt;/h3&gt;
&lt;p&gt;Unfortunately, despite the fact that &lt;a href="https://eev.ee/blog/2012/04/09/php-a-fractal-of-bad-design/"&gt;PHP sucks&lt;/a&gt; (seriously, read the article, even if you disagree it's an interesting read), Tiny Tiny RSS is built with PHP. However, just because a language sucks doesn't mean that programs written in it necessarily have to, and tt-rss is the best of the self-hosted RSS readers. Still, that means you're going to have to install PHP, and get it working nicely with Nginx.&lt;/p&gt;
&lt;p&gt;Install PHP 5 and the components necessary to get it playing nicely with everything else.&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&amp;gt; sudo apt-get install php5 php5-fpm php5-curl php5-pgsql php5-gd php5-mcrypt php5-cli
&lt;/pre&gt;
&lt;p&gt;There's one line in php.ini you'll need to change, which will prevent a possible &lt;a href="https://wiki.nginx.org/Pitfalls#Passing_Every_.7E_.5C.php.24_request_to_to_PHP"&gt;security issue&lt;/a&gt;.&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&amp;gt; sudo nano /etc/php5/fpm/php.ini
&lt;/pre&gt;
&lt;p&gt;Change this line:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&lt;span class="na"&gt;cgi.fix_pathinfo&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;1&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;To this:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&lt;span class="na"&gt;cgi.fix_pathinfo&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;0&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;The other change is to make PHP-FPM listen on a UNIX socket rather than a TCP socket.&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&amp;gt; sudo nano /etc/php5/fpm/pool.d/www.conf
&lt;/pre&gt;
&lt;p&gt;Change the line:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&lt;span class="na"&gt;listen&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;127.0.0.1:9000&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;To:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&lt;span class="na"&gt;listen&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;/var/run/php5-fpm.sock&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;Finally, restart PHP.&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&amp;gt; sudo /etc/init.d/php5-fpm restart
&lt;/pre&gt;
&lt;h3&gt;Nginx&lt;/h3&gt;
&lt;p&gt;Now that PHP is configured, you'll want to configure Nginx. There's a very good &lt;a href="https://blog.martinfjordvald.com/nginx-primer/"&gt;primer&lt;/a&gt; by Martin Fjordvald on the basics of Nginx configuration which you can read to get an understanding of what's going on. If you want to dig deeper for various other settings, the &lt;a href="https://nginx.org/en/docs/"&gt;documentation&lt;/a&gt; for Nginx is quite thorough.&lt;/p&gt;
&lt;p&gt;This tutorial is going to have you build Nginx from source, since the .deb packages are not always up to date. It's really not that much harder than setting it up from a package install anyway.&lt;/p&gt;
&lt;p&gt;First, install the packages required to compile the source.&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&amp;gt; sudo apt-get install gcc make libpcre3-dev openssl libssl-dev
&lt;/pre&gt;
&lt;p&gt;I also prefer to have Nginx use a dedicated system account with no login or password access for a bit of extra security.&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&amp;gt; sudo adduser --system --no-create-home --disabled-login --disabled-password --group nginx
&lt;/pre&gt;
&lt;p&gt;Then download and unpack the latest Nginx version.&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&amp;gt; wget https://nginx.org/download/nginx-1.5.6.tar.gz

&amp;gt; tar -xzvf nginx-1.5.6.tar.gz

&amp;gt; &lt;span class="nb"&gt;cd&lt;/span&gt; nginx-1.5.6
&lt;/pre&gt;
&lt;p&gt;The configure command sets the parameters for the build. This is where you can change the default install directory and the different modules that Nginx uses. Nginx doesn't allow you to change modules without rebuilding, so you'll need to select or deselect any modules here. The only module I'll add is the http_ssl module, which will allow you to add SSL to your site later if you wish. I also prefer to just use the default install directory, so I won't change that, but I'll set the user and group Nginx uses to the one I created earlier.&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&amp;gt; ./configure --user&lt;span class="o"&gt;=&lt;/span&gt;nginx --group&lt;span class="o"&gt;=&lt;/span&gt;nginx --with-http_ssl_module
&lt;/pre&gt;
&lt;p&gt;Now we can build and install Nginx.&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&amp;gt; make &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; sudo make install
&lt;/pre&gt;
&lt;h4&gt;Nginx Configuration&lt;/h4&gt;
&lt;p&gt;Change to the directory you installed Nginx to:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&amp;gt; &lt;span class="nb"&gt;cd&lt;/span&gt; /usr/local/nginx
&lt;/pre&gt;
&lt;p&gt;There are various methods people use for controlling the sites on their server. The .deb install uses a &lt;code&gt;sites-enabled&lt;/code&gt; and &lt;code&gt;sites-disabled&lt;/code&gt; style configuration, but since I don't have many sites on my server, I prefer to keep each site configuration file in the conf/ folder, and include each one manually in nginx.conf.&lt;/p&gt;
&lt;p&gt;So, for this tutorial, we'll create a ttrss.conf file.&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&amp;gt; sudo nano conf/ttrss.conf
&lt;/pre&gt;
&lt;p&gt;My ttrss.conf looks something like this (except I have SSL enabled):&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&lt;span class="c1"&gt;# Tiny Tiny RSS Configuration&lt;/span&gt;

&lt;span class="k"&gt;server&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kn"&gt;listen&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kn"&gt;server_name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;domainname&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;www.domainname&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kn"&gt;root&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;/var/www/ttrss&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kn"&gt;index&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;index.php&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kn"&gt;error_log&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;/var/log/nginx/ttrss.error.log&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kn"&gt;access_log&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;/var/log/nginx/ttrss.access.log&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kn"&gt;location&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;/&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kn"&gt;try_files&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$uri&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$uri/&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;/index.php&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kn"&gt;location&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;~&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sr"&gt;\.php$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kn"&gt;include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;fastcgi.conf&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;# don't use fastcgi_params&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kn"&gt;fastcgi_pass&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;unix:/var/run/php5-fpm.sock&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kn"&gt;fastcgi_index&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;index.php&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;A brief primer:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;listen&lt;/em&gt;: the port that the server listens for incoming connections on.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;server_name&lt;/em&gt;: the FQDN (fully qualified domain name) that the server uses for this connection. I set this to listen on both example.com and www.example.com.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;root&lt;/em&gt;: the root directory that the site's files are located at.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;index&lt;/em&gt;: the index file that the server directs traffic to. In this case you only need index.php, but can also include index.html or .htm, or any other file you want to use as a homepage.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;error_log&lt;/em&gt;: the location of the error log for this site.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;access_log&lt;/em&gt;: the location of the access log for this site.
The first location block accepts all incoming requests:&lt;/li&gt;
&lt;li&gt;&lt;em&gt;try_files&lt;/em&gt;: this just makes the URL search engine friendly. Not really necessary in this case, but it doesn't hurt.
The second location block catches all incoming php requests:&lt;/li&gt;
&lt;li&gt;&lt;em&gt;include fastcgi.conf&lt;/em&gt;: this file comes with Nginx and includes all the parameters for using fastcgi. It's almost the same as fastcgi_params, but you'll have issues using fastcgi_params in Ubuntu 12.04, unless you include the line &lt;code&gt;SCRIPT_FILENAME $document_root$fastcgi_script_name&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;fastcgi_pass&lt;/em&gt;: the socket that fastcgi passes requests through.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;fastcgi_index&lt;/em&gt;: the index file that fastcgi uses.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Next, you'll need to edit nginx.conf.&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&amp;gt; sudo nano conf/nginx.conf
&lt;/pre&gt;
&lt;p&gt;The only change that you really need to make to this file is to add the line &lt;code&gt;include ttrss.conf&lt;/code&gt; in the http block, but this is my recommended configuration below.&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&lt;span class="c1"&gt;# Nginx Configuration&lt;/span&gt;

&lt;span class="k"&gt;user&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;nginx&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;nginx&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="k"&gt;worker_processes&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;auto&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;# optimal value is number of cpu cores&lt;/span&gt;

&lt;span class="k"&gt;error_log&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;/var/log/nginx/error.log&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="s"&gt;events&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kn"&gt;worker_connections&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2048&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="k"&gt;http&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;# Virtual Host Configuration&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kn"&gt;include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;ttrss.conf&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;# Basic Settings&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kn"&gt;include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;mime.types&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kn"&gt;default_type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;application/octet-stream&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kn"&gt;sendfile&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;on&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kn"&gt;tcp_nopush&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;on&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kn"&gt;tcp_nodelay&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;off&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kn"&gt;client_header_timeout&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;20s&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kn"&gt;client_body_timeout&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;20s&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kn"&gt;send_timeout&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;20s&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;# Disable Nginx version number in error pages and Server header&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kn"&gt;server_tokens&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;off&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;# Silently block all undefined vhost access&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kn"&gt;server&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kn"&gt;server_name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;_&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kn"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;444&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;# Gzip Settings&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kn"&gt;gzip&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;on&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kn"&gt;gzip_disable&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"msie6"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kn"&gt;gzip_comp_level&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kn"&gt;gzip_min_length&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;256&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kn"&gt;gzip_vary&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;on&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kn"&gt;gzip_proxied&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;any&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kn"&gt;gzip_types&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;*&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;Finally, start Nginx.&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&amp;gt; sudo /usr/local/nginx/sbin/nginx
&lt;/pre&gt;
&lt;p&gt;If you need to make any changes to Nginx after it's been started, just open and change the config files. Then run this command to reload the Nginx with the new configuration.&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&amp;gt; sudo /usr/local/nginx/sbin/nginx -s reload
&lt;/pre&gt;
&lt;h3&gt;Postgres&lt;/h3&gt;
&lt;p&gt;Tiny Tiny RSS recommends using &lt;a href="https://www.postgresql.org/"&gt;PostgreSQL&lt;/a&gt; over MySQL for the database, as PostgreSQL is slightly faster. For a single user, it probably wouldn't make much difference, depending on how many feeds you have. The instructions for installing PostgreSQL are mostly taken from the Ubuntu community wiki &lt;a href="https://help.ubuntu.com/community/PostgreSQL"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Install PostgreSQL.&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&amp;gt; sudo apt-get install postgresql
&lt;/pre&gt;
&lt;p&gt;Log in to the postgres command line as user postgres.&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&amp;gt; sudo -u postgres psql postgres
&lt;/pre&gt;
&lt;p&gt;Change the password for the postgres user. Type in the command below, hit enter, then enter as password. Make sure to save all your passwords in a good password manager somewhere. I recommend &lt;a href="https://keepass.info/"&gt;KeePass&lt;/a&gt;.&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&amp;gt; &lt;span class="se"&gt;\p&lt;/span&gt;assword postgres
&lt;/pre&gt;
&lt;p&gt;While you're still in the postgres command line, create a database and database user for tt-rss. The password must be entered surrounded by single quotes.&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&lt;span class="nv"&gt;postgres&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="c1"&gt;# CREATE USER ttrss WITH PASSWORD 'password';&lt;/span&gt;

&lt;span class="nv"&gt;postgres&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="c1"&gt;# CREATE DATABASE ttrssdb;&lt;/span&gt;

&lt;span class="nv"&gt;postgres&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="c1"&gt;# GRANT ALL PRIVILEGES ON DATABASE ttrssdb to ttrss;&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;Exit the postgres command line.&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&lt;span class="nv"&gt;postgres&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="c1"&gt;# \q&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;From this point, you might be able to get tt-rss to access the database, but I wasn't until I edited a line in the postgresql config to allow access.&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&amp;gt; sudo nano /etc/postgresql/9.1/main/pg_hba.conf
&lt;/pre&gt;
&lt;p&gt;Add this line to allow tt-rss to use the database:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&lt;span class="na"&gt;local all ttrss md5&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;Now restart PostgreSQL.&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&amp;gt; sudo service postgresql restart
&lt;/pre&gt;
&lt;h3&gt;Tiny Tiny RSS&lt;/h3&gt;
&lt;p&gt;Finally, it's now time to install Tiny Tiny RSS itself. Yeah, I know it takes a while to get here. I assure you, it's worth it in the end, and you shouldn't have to worry about it much at all once you've got it properly set up. The installation instructions for tt-rss can be be found &lt;a href="https://tt-rss.org/redmine/projects/tt-rss/wiki/InstallationNotes"&gt;here&lt;/a&gt;, but once again they seem somewhat incomplete.&lt;/p&gt;
&lt;p&gt;First, make a directory for tt-rss to be served from. This should be the same as the directory you specified as root in your ttrss.conf file for Nginx.&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&amp;gt; sudo mkdir -p /var/www/ttrss
&lt;/pre&gt;
&lt;p&gt;You'll need to set the owner of the directory to the user that you're installing and running tt-rss as.&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&amp;gt; sudo chown -R user:group /var/www/
&lt;/pre&gt;
&lt;p&gt;Now change to the directory above.&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&amp;gt; &lt;span class="nb"&gt;cd&lt;/span&gt; /var/www
&lt;/pre&gt;
&lt;p&gt;Download and extract the latest version of Tiny Tiny RSS.&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&amp;gt; wget https://github.com/gothfox/Tiny-Tiny-RSS/archive/1.10.tar.gz

&amp;gt; tar -xzvf &lt;span class="m"&gt;1&lt;/span&gt;.10.tar.gz
&lt;/pre&gt;
&lt;p&gt;Rename the extracted directory so that it matches the root directory you specified earlier, then open the directory.&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&amp;gt; mv Tiny-Tiny-RSS-1.10/ ttrss

&amp;gt; &lt;span class="nb"&gt;cd&lt;/span&gt; /var/www/ttrss
&lt;/pre&gt;
&lt;p&gt;The following folders need to have their permissions changed to be writable by anyone with an account on the system, or tt-rss won't be able to save files there.&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&amp;gt; sudo chmod -R &lt;span class="m"&gt;777&lt;/span&gt; cache/images/ cache/js/ cache/export/ cache/upload/ feed-icons/ lock/
&lt;/pre&gt;
&lt;p&gt;Now you should be able to navigate in your browser to the site that you are hosting tt-rss from. This should be the same as the server_name you specified in ttrss.conf. If you installed tt-rss into a sub-folder of the domain, then the address will be &lt;code&gt;https://domainname/ttrss/&lt;/code&gt;. If you got the configuration correct, you should see the Tiny Tiny RSS install page.&lt;/p&gt;
&lt;p&gt;The installation page will have a few fields to enter. These will be the credentials for tt-rss to use the database, as well as the full URL that you'll access tt-rss from. Once you've entered the database details, click the 'Test Configuration' button. If there are errors, you'll get a message saying so, and it shouldn't be too hard to figure out what to do from there. If it's good to go, you'll see a text box with a lot of configuration lines. Copy that config data to your clipboard, and then into a config file on your server with:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&amp;gt; sudo nano /var/www/ttrss/config.php
&lt;/pre&gt;
&lt;p&gt;Save that file, and reload tt-rss in your browser. You should now be able to login with the default user &lt;code&gt;admin&lt;/code&gt; and password &lt;code&gt;password&lt;/code&gt;. Once you're logged in, change the admin settings in the preferences at top right.&lt;/p&gt;
&lt;p&gt;The final required step is to set up automatic updating of your feeds. You can skip this, but you'll have to manually click on each feed to check for updates if you don't. The &lt;a href="https://www.gnu.org/software/screen/"&gt;screen&lt;/a&gt; command will permanently run feed updates in the background, defaulting to once every 30 minutes.&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&amp;gt; screen -d -m php ./update_daemon2.php
&lt;/pre&gt;
&lt;h3&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;You should now have a working installation of Tiny Tiny RSS on your server, accessible from anywhere in the world. If you've used RSS Readers before, you can import your feeds from an OPML file, otherwise, find some good blogs and start adding feeds.&lt;/p&gt;</description><category>hosting</category><category>IT</category><category>Nginx</category><category>RSS</category><category>servers</category><category>tutorial</category><category>Web</category><guid>https://davidbeath.com/posts/installing-tiny-tiny-rss-from-scratch/</guid><pubDate>Wed, 02 Oct 2013 03:43:39 GMT</pubDate></item><item><title>Web Design: A good rant</title><link>https://davidbeath.com/posts/web-design-a-good-rant/</link><dc:creator>David Beath</dc:creator><description>&lt;p&gt;A &lt;a href="https://web.archive.org/web/20130924212147/https://unitscale.com/mb/bomb-in-the-garden/"&gt;really interesting talk&lt;/a&gt; by Matthew Butterick about the state of Web Design.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;It’s now or nev­er for the web. The web is a medi­um for cre­ators, in­clud­ing de­sign­ers. But af­ter 20 years, the web still has no cul­ture of de­sign ex­cel­lence. Why is that? Because de­sign ex­cel­lence is in­hib­it­ed by two struc­tur­al flaws in the web. First flaw: the web is good at mak­ing in­for­ma­tion free, but ter­ri­ble at mak­ing it ex­pen­sive. So the web has had to rely large­ly on an ad­ver­tis­ing econ­o­my, which is weak­en­ing un­der the strain. Second flaw: the process of adopt­ing and en­forc­ing web stan­dards, as led by the W3C, is hope­less­ly bro­ken. Evidence of both these flaws can be seen in a) the low de­sign qual­i­ty across the web, and b) the speed with which pub­lish­ers, de­vel­op­ers, and read­ers are mi­grat­ing away from the web, and to­ward app plat­forms and me­dia plat­forms. This ev­i­dence strong­ly sug­gests that the web is on its way to be­com­ing a sec­ond-class plat­form. To ad­dress these flaws, I pro­pose that the W3C be dis­band­ed, and that the lead­er­ship of the web be re­or­ga­nized around open-source soft­ware prin­ci­ples. I also en­cour­age de­sign­ers to ad­vo­cate for a bet­ter web, lest they find them­selves confined to a shrink­ing ter­ri­to­ry of possibilities.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I really sympathise with his views on this. The design of most major websites is crap. Unfortunately, he's correct in his assertion that this is largely to do with the fact that advertising drives most of the web. It's going to take a lot of work to find ways around this.&lt;/p&gt;
&lt;p&gt;As I'm currently working on plans for my new idea for a useful site, so this kind of thing is something that I'm doing a lot of thinking about lately. It's so easy to just copy the base format that most sites use without thinking about whether that design is the best for your current situation.&lt;/p&gt;</description><category>Design</category><category>IT</category><category>Web</category><guid>https://davidbeath.com/posts/web-design-a-good-rant/</guid><pubDate>Sun, 15 Sep 2013 10:00:48 GMT</pubDate></item><item><title>A Failure of Ideology</title><link>https://davidbeath.com/posts/a-failure-of-ideology/</link><dc:creator>David Beath</dc:creator><description>&lt;p&gt;There's an &lt;a href="https://www.nzherald.co.nz/business/chris-barton-is-the-cost-of-broadband-about-to-rise/M7BB73UKTEPRJTTIUUZXVQF73I/?c_id=5&amp;amp;objectid=11118623"&gt;article&lt;/a&gt; in the New Zealand Herald today, highlighting the ridiculousness of the current government's intervention in the broadband market. Feel free to skip the rest of this post if you wish, but I recommend you at least read the article. It does a good job of going over the issues from a technical, legal, and governmental angle, but there is one area it doesn't cover, which journalists mostly seem to shy away from, and that is the ideological angle.&lt;/p&gt;
&lt;!-- TEASER_END --&gt;

&lt;p&gt;For those who don't know, a quick backstory first. Currently in New Zealand our broadband internet services are sorely lacking compared to other &lt;a href="https://en.wikipedia.org/wiki/Organisation_for_Economic_Co-operation_and_Development"&gt;OECD&lt;/a&gt; countries, against which we always compare ourselves. The current government, led by the National party, has thus initiated a plan to roll out 100 Mbps Fibre Broadband to the majority of New Zealand by 2020. The vast majority of the tender for the work went to &lt;a href="https://www.chorus.co.nz/"&gt;Chorus&lt;/a&gt;, which was spun off from Telecom NZ as New Zealand's main infrastructure provider. Subsequently, as part of a long running effort to reduce the costs of broadband, the Commerce Commission decided that the prices Chorus charges for use of the copper network should more accurately reflect the cost of running the network. Now the government, represented by the Minister for Communications, Amy Adams, has decided that the wholesale price for copper should reflect the price for fibre, citing concerns that if the cost of copper is lowered, then consumers won't upgrade to fibre.&lt;/p&gt;
&lt;p&gt;The article I listed at the beginning of this post does a good job of demolishing the incredibly spurious reasoning going on behind the government's decision. However, what I find interesting is what this action says about the government's underlying ideology. The National party is generally described as a Center-Right party in political terms, with the main opposition party, Labour, being Center-Left. As you'd expect from a right-leaning party, National frequently espouses pro business and pro free market values. This then should cause National some serious ideological problems when it comes to actions such as the above.&lt;/p&gt;
&lt;h3&gt;The Pro Business angle&lt;/h3&gt;
&lt;p&gt;Lets start with the pro business angle. Commonly accepted doctrine states that monopolies are generally detrimental to smaller businesses, having the money and power to outcompete in price and features, or simply buy them out. In extreme cases, the larger companies can even lobby to get the law changed in their favour, or at least get a few nice kickbacks. This latter case seems to be the situation we are currently faced with.&lt;/p&gt;
&lt;p&gt;In bowing to Chorus's wishes in raising the price of copper, the government is effectively providing a subsidy to Chorus at the expense of the rest of us. There are a number of smaller ISP's who would like to compete on price, but Chorus having control of the vast majority of copper and fibre backbone in New Zealand means that they can't. Keeping the price of copper high also keeps costs higher for the many small businesses here that require an internet connection, and increases the cost for those business to expand. It should also be fairly uncontroversially accepted that higher prices also retard the development of internet based businesses in New Zealand.&lt;/p&gt;
&lt;p&gt;The government can therefore be said to be subsidising Chorus and their shareholders at the expense of the thousands more small business owners. That would seem to me to go against their stated values of supporting small business.&lt;/p&gt;
&lt;h3&gt;The Pro Free Market angle&lt;/h3&gt;
&lt;p&gt;Espousing free market values generally means that one believes that government regulation should be limited, or even removed entirely, in order to allow the market to more freely adjust to an optimum state without regulatory distortion. This is the staple of modern neo-liberal philosophy, yet this National government's actions seem to run opposite to this principle. If you believe that the free market should in most cases provide the best outcome, then why would you then make a policy that distorts prices in favour of a single monopolistic company?&lt;/p&gt;
&lt;p&gt;Now, many people would argue that the Commerce Commission's decision to lower the price of copper is also regulatory distortion, and they would be correct. The problem we have in New Zealand is that we're so small that there simply isn't room for the market to work effectively at the scale required for major infrastructure projects. Thus you see situations here where you're practically required to be a monopoly in order to afford to roll out infrastructure. In this case the Commerce Commission's job is to ensure that in the absense of price competition, the prices these monopolistic companies are allowed to charge closer reflect the market costs of building and running the infrastructure, and not the monopoly rents they could otherwise charge. Whether you agree with regulation or not, the actions of the Commerce Commission should allow the situation to more accurately reflect a free market.&lt;/p&gt;
&lt;p&gt;By explicity saying that the price of copper should be higher, for no other reason than that it will discourage consumers from moving to fibre, the government is effectively stating that they do not in fact believe in the free market. They don't believe that the advantages of fibre are enough to outweigh the costs in relation to copper. If they believe that the market thinks fibre isn't good enough to justify it's increased cost, then why is the government paying to roll it out in the first place? In fact, as explained in the above article, fibre uptake is proceeding as expected, and Chorus projects that it's worth the money, else they wouldn't have tendered for what is basically a long term loan.&lt;/p&gt;
&lt;p&gt;There are many more potential examples, and it would be possible to go much deeper into the various philosophies surrounding this issue, but I think I've given a decently broad overview of why this policy represents a failure on the part of the National party to stick to it's stated ideologies. Those on the left should have no trouble explaining why they think it's bad that the government is regulating in favour of a large corporation, while I've just outlined why I think those on the right should also be against this policy.&lt;/p&gt;</description><category>IT</category><category>Politics</category><guid>https://davidbeath.com/posts/a-failure-of-ideology/</guid><pubDate>Tue, 03 Sep 2013 03:48:17 GMT</pubDate></item><item><title>A New Blog</title><link>https://davidbeath.com/posts/a-new-blog/</link><dc:creator>David Beath</dc:creator><description>&lt;p&gt;So, I guess it's time I started to write a blog. I've always read that it's recommended in IT to write a blog, or maybe in any industry these days, in order to have some sort of recognisable professional presence. Or, at the very least, to keep your rants off Facebook.&lt;/p&gt;
&lt;p&gt;At any rate, there are plenty of things I could talk about, and I will. I tend mostly to have strong opinions on Politics, Information Technology, Economics, the Environment, and any intersection between the bunch, though not necessarily in that order. I think I'll start off properly with a politics post next.&lt;/p&gt;
&lt;!-- TEASER_END --&gt;

&lt;p&gt;Anyway, I figure I might as well write about the tools I used to set this blog up. Starting from the bottom of the stack, my server is a VPS hosted by &lt;a href="https://www.linode.com/"&gt;Linode&lt;/a&gt;. I like that I have full control over my machine, without having to worry about the hardware. Even the lowest tier plan gets me more than enough machine for my needs, and the documentation and tools they have are really good. Definitely recommended.&lt;/p&gt;
&lt;p&gt;The server OS is &lt;a href="https://debian.org"&gt;Debian&lt;/a&gt;, because for me it was either that or Ubuntu Server for the easy and familiar option. Fanboys can feel free to flame away at whatever choice is made, but I like something stable.&lt;/p&gt;
&lt;p&gt;For the HTTP server itself, I'm using &lt;a href="https://nginx.org"&gt;nginx&lt;/a&gt;. Apache is just to mainstream, and from everything I've read it doesn't scale as well. Not that scaling should be a problem for me for a long time, if ever, but you never know. I've found nginx to be just as easy, if not easier, to understand and configure compared to Apache anyway.&lt;/p&gt;
&lt;p&gt;Finally, I use &lt;a href="https://getnikola.com/"&gt;Nikola&lt;/a&gt; to generate this blog. Nikola is a static blog generator, so all the files on this site are just plain HTML, no CMS needed. The site design is basically just an unmodified &lt;a href="https://get.foundation/"&gt;Foundation&lt;/a&gt; theme, which for now looks good enough. Besides, if you're not using an RSS reader to read this blog (once you've first visited and decided to keep reading of course), then you damned well should be. Why on earth would you manually visit blogs to read?&lt;/p&gt;
&lt;p&gt;On the non-essential side of things, analytics on the blog are handled by &lt;a href="https://piwik.org"&gt;Piwik&lt;/a&gt;, so that I don't have to send all my data to Google Analytics. The thing I use this server for the most though, is &lt;a href="https://tt-rss.org"&gt;Tiny Tiny RSS&lt;/a&gt;. I find that using an RSS reader is essential for keeping up with the world. Like most everyone else, I used to use Google Reader, but of course anyone who hasn't been living under a rock this year knows the story of how they shut it down, and the gnashing and wailing of teeth that ensued. I contributed my part of that, on my tiny corner of Google Plus and Facebook.&lt;/p&gt;
&lt;p&gt;Just like many others, I decided that if I couldn't trust even Google with my stuff, then it might be better to go self-hosted. Tiny Tiny RSS was the self hosted solution with the most recommendations, and I've been pretty happy with it so far. It's nice to know that you've got a service that no-one is going to arbitrarily remove, just so long as you have a good backup policy in place.&lt;/p&gt;
&lt;p&gt;Someday soon, I might get round to routing my mail through my server as well, though I might like to have it on a different one. A single point of failure for everything I rely on makes me nervous.&lt;/p&gt;
&lt;p&gt;In conclusion, Welcome to my Blog, and don't be afraid to look into self hosting if you're at all technically inclined. It's the 21st century, and all the information you need is out there.&lt;/p&gt;</description><category>hosting</category><category>IT</category><category>RSS</category><category>servers</category><guid>https://davidbeath.com/posts/a-new-blog/</guid><pubDate>Fri, 23 Aug 2013 09:23:54 GMT</pubDate></item></channel></rss>