diff --git a/config/plugins/interactive_environments/jupyter/config/jupyter.ini.sample b/config/plugins/interactive_environments/jupyter/config/jupyter.ini.sample
new file mode 100644
index 00000000000..c89fe09a8bc
--- /dev/null
+++ b/config/plugins/interactive_environments/jupyter/config/jupyter.ini.sample
@@ -0,0 +1,43 @@
+[main]
+# Following options are ignored if using the Galaxy dynamic proxy but
+# are useful if mapping a range of ports for environment consumption.
+#password_auth = False
+#ssl = False
+
+[docker]
+# Command to launch docker container. For example `sudo docker` or `docker-lxc`.
+# If you need to use a command like `sg` you can do that here, just be sure to
+# wrap all of the docker portion in single quotes. E.g. `sg 'docker' 'docker {docker_args}'`
+#
+# It is recommended that you use command_inject if you need to inject
+# additional parameters. This command string is re-used for a `docker inspect`
+# command and will likely cause errors if it is extensively modified, past the
+# usual group/sudo changes.
+#command = docker {docker_args}
+
+# The docker image name that should be started.
+image = bgruening/docker-jupyter-notebook:16.01
+
+# Additional arguments that are passed to the `docker run` command.
+command_inject = --sig-proxy=true -e DEBUG=false -e DEFAULT_CONTAINER_RUNTIME=120
+
+# URL to access the Galaxy API with from the spawn Docker containter, if empty
+# this falls back to galaxy.ini's galaxy_infrastructure_url and finally to the
+# Docker host of the spawned container if that is also not set.
+#galaxy_url =
+
+# The Docker hostname. It can be useful to run the Docker daemon on a different
+# host than Galaxy.
+#docker_hostname = localhost
+
+# Try to set the tempdirectory to world execute - this can fix the issue
+# where 'sudo docker' is not able to mount the folder otherwise.
+# "finalize namespace chdir to /import permission denied"
+#wx_tempdir = False
+
+# Overwride the IE tempdirectory. This can be useful if you regular tempdir is
+# located on an NFS share, which does not work well as Docker volume. In this case
+# you can have a shared sshfs share which you can use as temporary directory to
+# share data between the IE and Galaxy.
+#docker_galaxy_temp_dir = None
+
diff --git a/config/plugins/interactive_environments/jupyter/config/jupyter.xml b/config/plugins/interactive_environments/jupyter/config/jupyter.xml
new file mode 100644
index 00000000000..e1c8bd0040c
--- /dev/null
+++ b/config/plugins/interactive_environments/jupyter/config/jupyter.xml
@@ -0,0 +1,16 @@
+
+
+
" + password + "
More details ...",
+ "Please login manually",
+ {'closeButton': true, 'timeOut': 100000, 'tapToDismiss': false}
+ );
+}
+
+function message_failed_connection(){
+ toastr.error(
+ "Could not connect to Jupyter Notebook. Please contact your administrator. More details ...",
+ "Security warning",
+ {'closeButton': true, 'timeOut': 20000, 'tapToDismiss': true}
+ );
+}
+
+function message_no_auth(){
+ // No longer a security issue, proxy validates Galaxy session token.
+ /*
+ toastr.warning(
+ "IPython Notebook was lunched without authentication. This is a security issue. More details ...",
+ "Security warning",
+ {'closeButton': true, 'timeOut': 20000, 'tapToDismiss': false}
+ );
+ */
+}
+
+
+/**
+ * Load an interactive environment (IE) from a remote URL
+ * @param {String} password: password used to authenticate to the remote resource
+ * @param {String} notebook_login_url: URL that should be POSTed to for login
+ * @param {String} notebook_access_url: the URL embeded in the page and loaded
+ *
+ */
+function load_notebook(password, notebook_login_url, notebook_access_url){
+ $( document ).ready(function() {
+ // Test notebook_login_url for accessibility, executing the login+load function whenever
+ // we've successfully connected to the IE.
+ test_ie_availability(notebook_login_url, function(){
+ _handle_notebook_loading(password, notebook_login_url, notebook_access_url);
+ });
+ });
+}
+
+
+function keep_alive(){
+ /**
+ * This is needed to keep the container alive. If the user leaves this site
+ * this function is not constantly pinging the container, the container will
+ * terminate itself.
+ */
+
+ var request_count = 0;
+ interval = setInterval(function(){
+ $.ajax({
+ url: notebook_access_url,
+ xhrFields: {
+ withCredentials: true
+ },
+ type: "GET",
+ timeout: 500,
+ success: function(){
+ console.log("Connected to IE, returning");
+ },
+ error: function(jqxhr, status, error){
+ request_count++;
+ console.log("Request " + request_count);
+ if(request_count > 30){
+ clearInterval(interval);
+ clear_main_area();
+ toastr.error(
+ "Could not connect to IE, contact your administrator",
+ "Error",
+ {'closeButton': true, 'timeOut': 20000, 'tapToDismiss': false}
+ );
+ }
+ }
+ });
+ }, 30000);
+}
+
+
+/**
+ * Must be implemented by IEs
+ */
+function _handle_notebook_loading(password, notebook_login_url, notebook_access_url){
+ if ( ie_password_auth ) {
+ // Make an AJAX POST
+ $.ajax({
+ type: "POST",
+ // to the Login URL
+ url: notebook_login_url,
+ // With our password
+ data: {
+ 'password': password
+ },
+ xhrFields: {
+ withCredentials: true
+ },
+ // If that is successful, load the notebook
+ success: function(){
+ append_notebook(notebook_access_url);
+ },
+ error: function(jqxhr, status, error){
+ if(ie_password_auth){
+ // Failure happens due to CORS
+ message_failed_auth(password);
+ append_notebook(notebook_access_url);
+ }else{
+ message_failed_connection();
+ // Do we want to try and load the notebook anyway? Just in case?
+ append_notebook(notebook_access_url);
+ }
+ }
+ });
+ }
+ else {
+ // Not using password auth, just embed it to avoid content-origin issues.
+ message_no_auth();
+ append_notebook(notebook_access_url);
+ }
+}
diff --git a/config/plugins/interactive_environments/jupyter/templates/jupyter.mako b/config/plugins/interactive_environments/jupyter/templates/jupyter.mako
new file mode 100644
index 00000000000..d76e2998e95
--- /dev/null
+++ b/config/plugins/interactive_environments/jupyter/templates/jupyter.mako
@@ -0,0 +1,70 @@
+<%namespace name="ie" file="ie.mako" />
+
+<%
+import os
+import shutil
+import hashlib
+
+# Sets ID and sets up a lot of other variables
+ie_request.load_deploy_config()
+ie_request.attr.docker_port = 8888
+ie_request.attr.import_volume = False
+
+if ie_request.attr.PASSWORD_AUTH:
+ m = hashlib.sha1()
+ m.update( ie_request.notebook_pw + ie_request.notebook_pw_salt )
+ PASSWORD = 'sha1:%s:%s' % (ie_request.notebook_pw_salt, m.hexdigest())
+else:
+ PASSWORD = "none"
+
+## Jupyter Notbook Specific
+if hda.datatype.__class__.__name__ == "Ipynb":
+ DATASET_HID = hda.hid
+else:
+ DATASET_HID = None
+
+# Add all environment variables collected from Galaxy's IE infrastructure
+ie_request.launch(env_override={
+ 'notebook_password': PASSWORD,
+ 'dataset_hid': DATASET_HID,
+})
+
+## General IE specific
+# Access URLs for the notebook from within galaxy.
+notebook_access_url = ie_request.url_template('${PROXY_URL}/ipython/notebooks/ipython_galaxy_notebook.ipynb')
+notebook_login_url = ie_request.url_template('${PROXY_URL}/ipython/login?next=${PROXY_PREFIX}%2Fipython%2Ftree')
+
+%>
+
+