{"id":2265,"date":"2012-04-02T15:28:22","date_gmt":"2012-04-02T21:28:22","guid":{"rendered":"http:\/\/bililite.nfshost.com\/blog\/?p=2265"},"modified":"2012-04-02T15:28:22","modified_gmt":"2012-04-02T21:28:22","slug":"using-nfs-net-with-amazon-s3","status":"publish","type":"post","link":"https:\/\/bililite.com\/blog\/2012\/04\/02\/using-nfs-net-with-amazon-s3\/","title":{"rendered":"Using NFS.net with Amazon S3"},"content":{"rendered":"<p>Since I started using <a href=\"http:\/\/nearlyfreespeech.net\">nearlyfreespeech.net<\/a> 3 months ago, I've been very pleased. Getting them to set up <a href=\"https:\/\/members.nearlyfreespeech.net\/dwachss\/support\/faq?q=SSHKeys&keywords=ssh&form=1#SSHKeys\">access with a private key<\/a> was straightforward and the email support person was prompt, helpful and friendly. The only <a href=\"http:\/\/bililite.nfshost.com\/blog\/2012\/02\/03\/nearly-free-speech\/\" title=\"Nearly Free Speech\">downsides<\/a> are the safe mode restrictions, which I have been easily able to work around, and the expensive storage ($1\/MB\/month), which would add up quickly with all the <a href=\"\/webservices\/?page=icons\">icons<\/a> and <a href=\"\/webservices\/?page=fonts\">fonts<\/a> I'm serving with the <a href=\"\/webservices\/\">webservices<\/a>.<\/p>\r\n<p>So I put them onto <a href=\"http:\/\/aws.amazon.com\/s3\/\">Amazon's S3<\/a> at <a href=\"http:\/\/bililite.s3.amazonaws.com\">bililite.s3.amazonaws.com<\/a> with the intent of using that like a <a href=\"http:\/\/en.wikipedia.org\/wiki\/Content_delivery_network\">Content Delivery Network<\/a> (though it isn't really unless I pay for <a href=\"http:\/\/aws.amazon.com\/cloudfront\/\">CloudFront<\/a> as well)&mdash;static, large files should come tranparently from S3 while the dynamic site runs on NFS.net.<\/p>\r\n<p>I do this with a bit of <code>.htaccess<\/code> hackery. It's harder to create or modify files on S3, so files that are in active developement are on the webserver. I want to serve those files <em>if they exist<\/em>. Only if the desired files do not exist do I want to get them from S3. Unfortunately, NFS.net does not support <a href=\"http:\/\/httpd.apache.org\/docs\/2.0\/mod\/mod_proxy.html\"><code>mod_proxy<\/code><\/a>, so the redirecting is not transparent (and we can't do things that require <a href=\"https:\/\/developer.mozilla.org\/en\/Same_origin_policy_for_JavaScript\">same-origin security<\/a>). But for images and the like, this works:<\/p>\r\n<pre><\/code>SetEnvIf Request_URI . CDN=http:\/\/bililite.s3.amazonaws.com\r\nRewriteEngine On\r\nRewriteBase \/\r\nRewriteCond %{REQUEST_FILENAME} !-f\r\nRewriteCond %{REQUEST_URI} ^\/(images|inc|fonts)\/\r\nRewriteRule . %{ENV:CDN}%{REQUEST_URI}<\/code><\/pre>\r\n<p>Line 1 creates a variable named <code>CDN<\/code>. The directive <a href=\"http:\/\/httpd.apache.org\/docs\/2.3\/mod\/mod_env.html#setenv\"><code>SetEnv<\/code><\/a> would be more natural to use as <code>SetEnv CDN http:\/\/bililite.s3.amazonaws.com<\/code>, but URL rewriting is done <em>before<\/em> <code>SetEnv<\/code> runs. The newer <code>SetEnvIf<\/code> runs early enough for the variable to be used for rewriting, but it's conditional, so we use a dummy condition: <code>REQUEST_URI .<\/code>, which means \"If the requested URI matches any character\"<\/p>\r\n<p>Line 4 tests whether the requested file exists on the server. Only if it does not exist (<code>!-f<\/code>) is the next line tested, which is whether the file is in any of the CDN directories.<\/p> \r\n<p>If it is to be redirected, create the new URL by concatenating the <code>CDN<\/code> variable with the requested URI, which does not contain the protocol or hostname. Thus <code><a href=\"http:\/\/bililite.com\/images\/silk\/add.png\">http:\/\/bililite.com\/images\/silk\/add.png<\/a><\/code> has a <code>REQUEST_URI<\/code> of <code>\/images\/silk\/add.png<\/code> and the rewritten URL is <code>http:\/\/bililite.s3.amazonaws.com\/images\/silk\/add.png<\/code>.<\/p>\r\n<p>The advantage of setting a variable in the <code>.htaccess<\/code> (aside from having the \"magic constant\" at the top of the file\") is that this is passed to the PHP code as <code class=\"language-php>$_SERVER['CDN']<\/code> and can be used like <code class=\"language-php>imagecreatefrompng($_SERVER['CDN'].'\/images\/silk\/add.png')<\/code>. So the name of the S3 server is written in just one place, with no need to change multiple files if it changes.<\/p>","protected":false},"excerpt":{"rendered":"Since I started using nearlyfreespeech.net 3 months ago, I've been very pleased. Getting them to set up access with a private key was straightforward and the email support person was prompt, helpful and friendly. The only downsides are the safe mode restrictions, which I have been easily able to work around, and the expensive storage [&hellip;]","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[20],"tags":[],"_links":{"self":[{"href":"https:\/\/bililite.com\/blog\/wp-json\/wp\/v2\/posts\/2265"}],"collection":[{"href":"https:\/\/bililite.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/bililite.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/bililite.com\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/bililite.com\/blog\/wp-json\/wp\/v2\/comments?post=2265"}],"version-history":[{"count":11,"href":"https:\/\/bililite.com\/blog\/wp-json\/wp\/v2\/posts\/2265\/revisions"}],"predecessor-version":[{"id":2277,"href":"https:\/\/bililite.com\/blog\/wp-json\/wp\/v2\/posts\/2265\/revisions\/2277"}],"wp:attachment":[{"href":"https:\/\/bililite.com\/blog\/wp-json\/wp\/v2\/media?parent=2265"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/bililite.com\/blog\/wp-json\/wp\/v2\/categories?post=2265"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/bililite.com\/blog\/wp-json\/wp\/v2\/tags?post=2265"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}