TUNDRA Hosting

Simple hosting for static content with some extra nifty features. For your small demo site or your super complex API-driven single page application. It's the web front in your microservice architecture or just a convenient way to share some html with your friends.

To get started - drag this link to your bookmarks bar

Tundra
It's a little bit complicated to add bookmarklets in iOS. And the menu is not fit for mobile yet.

Features

(click on a feature to read more)

Static hosting

Push state url routing

If you are creating a single page application you probably want to have nice urls and use push state instead of the old hash navigation. Most modern web framework have routers that support this, other systems supports it with some confusing rewrite modules.

Tundra supports this by first check if a request is "direct" by locking for a dot "." in the last part of the request url. If the request is direct the asset is served or returns a 404 response if missing. Just lika a normal fileserver. If the request is missing a dot in the end it checks for the file and starts to serve that file. If the file is missing It looks for a parent folder and tries to serve that file.

Example:

  
  http://tundra-site.tndr.io/javascripts/all.js -> http://tundra-site.tndr.io/javascripts/all.js
  http://tundra-site.tndr.io/javascript/missing.js -> 404
  http://tundra-site.tndr.io/index.html -> http://tundra-site.tndr.io/index.html
  http://tundra-site.tndr.io/some/sub/folder -> http://tundra-site.tndr.io/index.html
  http://tundra-site.tndr.io/some/sub/folder/file.html -> 404
  http://tundra-site.tndr.io/angular.html/sub/folder/ -> http://tundra-site.tndr.io/angular.html
  

Deployment versioning

Every deploy gets its own version number as a unique sub domain. Which you can browse to and test before setting the version to the default version.

If you deploy to versioname: stage and projectname : example your deploy will be hosted at http://stage.example.tndr.io. You can then visit and test the page and if you are happy with the result you can set stage as the default version with set production in the menu. The site can then be accessed with the shorter http://example.tndr.io

The version name can include som special strings that are replace during deployment.

  
    DATE => 20150509, todays date
    TIME => 201632, time right now
    RANDOM => as2a3yt3, a 8 chars random string, useful for hard to guess urls.

    stage-DATETIME => stage-20150509201739
    semiprivate-RANDOMRANDOM => semiprivate-669wlhkmfpxpmm17
  

Rollbacks are easy. Just set a previous version as your default version.

Access restriction

In the configuration (se below) it possible to define a list of users with access. If you omit the visit array the site will be public for all to visit.

  
    "users" : {
      "visit" : [
        "user@example.com:pwd",
        "test:test"
       ],
      "admin" : [
        "admin@example.com:test"
      ]
    },
  

Or use a randomized version name to limit the access to only the users with correct url
  
    "versiontemplate" : "test-RANDOM",
    "options" : {
      "setasdefault" : false
    },
  

HTTPS and gzip

The certificate is self signed for now. To be able to use the bookmarklet on a https site first visit https://tndr.io and accept the certificate.

Custom domain names

To be able to use your own domain. Point your domain name to tndr.io in your DNS. The add a alias in your config.json.

  
    "config" : {
    [...]
      "alias" : {
        "example.com" : "example.tndr.io",
       }
    [...]
    }
  

It's also possible to point to a specific version of a project:

  
    "config" : {
    [...]
      "alias" : {
        "example.com" : "example.tndr.io",
        "stage.example.com" : "stage.example.tndr.io",
      }
    [...]
    }
  

API

Cross domain request proxy

If you ever tried to access data from a remote server on another doamin you have probably stumbled over No 'Access-Control-Allow-Origin' header is present, CORS and things like that.

To fetch a remote url without worrying about that, use the http proxy:

  
    http://[projectname].tndr.io/api/proxy/http://example.com
  

To be able to use the proxy a white list have to be defined in the config. It's also possible to add replacements in the config. Which is useful if you need a API key in your request but don't want to expose API keys in the client.

  
    http://[projectname].tndr.io/api/proxy/http://example.com/service/?API_KEY=EXAMPLE_KEY
  
  Make sure you don't use a key name that appear in the url, since it will be replaced.
  
    "config" : {
      [...]
      "proxy" : {
        "domains" : [
          "example.com"
        ],
        "replace" : {
          "EXAMPLE_KEY" : "thekey"
        }
      }
      [...]
    }
  

Emailing from client

Just add a request to the email endpoint.

In jquery it would look something like:

  
    $.post('http://tndr.io/api/email', {
      to : ['to@example.com'],
      from : 'to@example.com',
      subject : 'the subject of the message',
      text : 'the plain textversion',
      html : '<h1>and the html version</h1>'
    }, callback);
  

Its possible to define a white list of from or to addesses in the email section in the config to prevent the possiblity to use the server for email spaming. A subject property can be used to allow only one subject.

  
    "config" : {
      [...]
      "email" : {
        "to" : "email1@example.com,email1@example.com",
        "from" : "email@example.com"
      }
      [...]
    }
  

File upload

Upload files to the server to be shared between versions.

Simple form upload:

  
    <form action="http://tndr.io/api/release/upload" method="post" enctype="multipart/form-data">
      <input type="text" name="example">
      <input type="text" name="callback_url" value="http://example.tndr.io/upload_done#">
      <input type="file" name="files">
      <input type="submit">
    </form>
  
The callback_url specifies a url to redirect to after the upload, it might be useful if you put the upload within an iframe. The path to the uploaded files will be appended to the callback_url, so add a ? or # to be able to read it with javascript. If you add the base url to the server the redirect will go the image. If the callback is missing a json response is returned instead.

Or do a more advanced javascript upload with FileReader and Blobs as the editor does.

Download sites

All releases that you have access to are downloadable. It's convinient if you want to test and modify a site on the web. Just navigate to it, deploy it to tundra and then download the site. Do the modifications and redeploy it.

Simple text editing

A simple editor are included in the menu. Just put an attribute to a block to make it editable. Works with images as well.

html editor:

  
    <section data-tundra-editor="small_section">
      </h1>Header text</h1>
      </p>Some texts</p>
    </section>
  

image upload:

  
    <img data-tundra-upload="the_image" src="logo.jpg"/>
  

Deployments

Bookmarklet deployments

Add the bookmarklet to your browser and click the bookmarklet to op en the menu on the page you want to deploy.

Image of the deployment menu

Deploy button

Add this code snipplet for a deploy button to your page. When you press the button the page is deployed to the server, super easy. The button will self destruct on the way to the server.

  
    
    <script type="text/javascript" src="http://tndr.io/api/assets/js/deploy.js"></script>
    <button data-tundra-deploy="[version].[project]">Deploy</button>
  

The data-tundra-deploy attribute defines the version and project name of te deploy. If a config file is present the attribute can be empty.

  
    <button data-tundra-deploy="[version].[project]" [...] > //uses the version and project separated by a dot
    <button data-tundra-deploy="[project]" [...] >           //uses the project name and DATETIME as default version template, unless defined in config.
    <button data-tundra-deploy [...] >                       //uses the configuration in the config file
  

Easy configuration

You can deploy to the server without any configurations. But to be able to use the email and proxy apis you need to place a config file in the web root of you application named tundra.json. You can download one from the bookmarklet menu.

Example:

  
/* Comments in JSON are stripped out before parsing. */
/* The config are shared between all versions in a project. */

{
  /* The name of the project */
  "projectname" : "tundra-site",

  /* Defined the format of versions, default is 'DATETIME' eg. 160209132802
  DATE, TIME and RANDOM are replaced during deploy to todays date, time or a random 8 char string.
  Can be combined with other strings eg. stage-RANDOM or DATE-TIME */
  "versiontemplate" : "DATETIME",

  "options" : {
    /* Sets the latest deploy as the default version. eg example.tndr.io are set to 160209132802.example.tndr.io,
    if that is tha latest deploy. */
    "setasdefault" : false,

    /* The depth for follow links in html files. */
    "recursionDepth" : 5,

    /* If false, shorthand for recursion_depth 0 */
    "followLinks" : true
  },

  /* Lists users that are allowed to visit and update the site.

  The format are username:password and the protection is basic auth */
  "users" : {
    /* Uncomment and update the list if you want to restrict access to only these users */
    /* "visit" : [
      "visitor@example.com"
    ], */

    /* All admin users are also allowed as visitors. At least one admin user are required */
    "admin" : [
      "test:test"
    ]
  },

  /* Config for email sending, mailing are restricted with whitelists to avoid spaming */
  "email" : {
    /* allowed to adresses. Used for "contact us" senarios. Remove to accept all */
    "to" : [
      "support@example.com"
     ],

    /* allowed from adresses. Used for mailinglist senarios. Remove to accept all */
    "from" : [
      "info@example.com"
     ]
  },

  /* Config for request proxing */
  "proxy" : {
    /* Allowed domains to proxy to. */
    "domains" : [
      "example.com"
    ],

    /* Strings in uris to be replaced, useful for API keys that can't be exposed in the client */
    "replace" : {
      "APIKEY" : "the_key"
    }
  }
}
  

It's also possible to add a `filelist.txt` with a list of all files to upload in the web root. The filelist.txt is a list of files with a filename on each row. The simpliest way to do it is to run

  
    find . -type f > filelist.txt
  

CLI and CI

If you don't like the magic of the bookmarklet its possible to create releases with curl instead. Here is an example using middleman and uploading a zip.

  
    #!/bin/bash

    middleman build
    cd build
    zip -r ../build.zip .
    cd ..
    read -s -p "Enter Password: " password

    curl --user user@example.com:$password \
    --form _zip=@"build.zip" \
    --form config="`<build/tundra.json`" \
    --form versionname="`git rev-parse --short HEAD`" \
    http://tndr.io/api/release/createFromZip?projectname=example


  

A similar approach can of course be used by Jenkins, Codeship or other CI tools.

Installation and deployment

Basic deployment

  1. 1. Add the tundra menu bookmarklet to your browser
  2. 2. Navigate to the page you want to deploy. On localhost, intranet, public internet or whatever
  3. 3. Press the bookmarklet
  4. 4. Choose a name and and if subpages should be deployed
  5. 5. Click deploy
  6. 6. Done! click on the link to visit the page

Add to bookmarks: Tundra

It's a little bit complicated to add bookmarklets in iOS. And the menu is not fit for mobile yet.

Configuration deployment

To avoid others to deploy to the same subdomain, the subdomain need to be reserved with a configuration file. The configuration also allows the project to use more features as emailing, proxy, user restriction.

  1. 1. Open the menu
  2. 2. In the menu, select download configuration
  3. 3. Chose your username (email) and a password
  4. 4. Click download and add the file to your public folder
  5. 5. Edit the file to configure the project
  6. 6. Deploy the project as in basic deployment above

Contact

If you have any bugs, improvements suggestions or questions. Don't hesitate to send a message with this tundra proxied google form.