diff --git a/cobbler/cexceptions.py b/cobbler/cexceptions.py
index bb4b3e8..adabbee 100644
--- a/cobbler/cexceptions.py
+++ b/cobbler/cexceptions.py
@@ -35,6 +35,10 @@ class CobblerException(exceptions.Exception):
    def __str__(self):
        return repr(self.value)
 
+
 class CX(CobblerException):
    pass
 
+
+class FileNotFoundException(CobblerException):
+    pass
diff --git a/cobbler/item.py b/cobbler/item.py
index 562e265..b7ff047 100644
--- a/cobbler/item.py
+++ b/cobbler/item.py
@@ -77,7 +77,7 @@ class Item:
         return utils.from_datastruct_from_fields(self,seed_data,self.get_fields())
 
     def to_datastruct(self):
-        return utils.to_datastruct_from_fields(self,self.get_fields())
+        return utils.to_datastruct_from_fields(self, self.get_fields())
 
     def printable(self):
         return utils.printable_from_fields(self,self.get_fields())
diff --git a/cobbler/item_profile.py b/cobbler/item_profile.py
index 989dd92..e2b745d 100644
--- a/cobbler/item_profile.py
+++ b/cobbler/item_profile.py
@@ -59,7 +59,8 @@ FIELDS = [
   ["mgmt_classes",[],'<<inherit>>',"Management Classes",True,"For external configuration management",0,"list"],
   ["template_files",{},'<<inherit>>',"Template Files",True,"File mappings for built-in config management",0,"dict"],
   ["redhat_management_key","<<inherit>>","<<inherit>>","Red Hat Management Key",True,"Registration key for RHN, Spacewalk, or Satellite",0,"str"],
-  ["redhat_management_server","<<inherit>>","<<inherit>>","Red Hat Management Server",True,"Address of Spacewalk or Satellite Server",0,"str"]
+  ["redhat_management_server","<<inherit>>","<<inherit>>","Red Hat Management Server",True,"Address of Spacewalk or Satellite Server",0,"str"],
+  ["template_remote_kickstarts", "SETTINGS:template_remote_kickstarts", "SETTINGS:template_remote_kickstarts", "", False, "", 0, "bool"]
 ]
 
 class Profile(item.Item):
diff --git a/cobbler/item_system.py b/cobbler/item_system.py
index 1a3b99c..58bc734 100644
--- a/cobbler/item_system.py
+++ b/cobbler/item_system.py
@@ -76,6 +76,7 @@ FIELDS = [
   ["template_files",{},0,"Template Files",True,"File mappings for built-in configuration management",0,"dict"],
   ["redhat_management_key","<<inherit>>",0,"Red Hat Management Key",True,"Registration key for RHN, Satellite, or Spacewalk",0,"str"],
   ["redhat_management_server","<<inherit>>",0,"Red Hat Management Server",True,"Address of Satellite or Spacewalk Server",0,"str"],
+  ["template_remote_kickstarts", "SETTINGS:template_remote_kickstarts", "SETTINGS:template_remote_kickstarts", "", False, "", 0, "bool"]
 ]
 
 class System(item.Item):
diff --git a/cobbler/kickgen.py b/cobbler/kickgen.py
index bff034d..11091cd 100644
--- a/cobbler/kickgen.py
+++ b/cobbler/kickgen.py
@@ -60,42 +60,6 @@ class KickGen:
         self.repos       = config.repos()
         self.templar     = templar.Templar(config)
 
-    def generate_kickstart_for_profile(self,g):
-
-        g = self.api.find_profile(name=g)
-        if g is None:
-           return "# profile not found"
-
-        distro = g.get_conceptual_parent()
-        meta = utils.blender(self.api, False, g)
-        if distro is None:
-           raise CX(_("profile %(profile)s references missing distro %(distro)s") % { "profile" : g.name, "distro" : g.distro })
-        kickstart_path = utils.find_kickstart(meta["kickstart"])
-        if kickstart_path is not None and os.path.exists(kickstart_path):
-            # the input is an *actual* file, hence we have to copy it
-            try:
-                meta = utils.blender(self.api, False, g)
-                ksmeta = meta["ks_meta"]
-                del meta["ks_meta"]
-                meta.update(ksmeta) # make available at top level
-                meta["yum_repo_stanza"] = self.generate_repo_stanza(g,True)
-                meta["yum_config_stanza"] = self.generate_config_stanza(g,True)
-                meta["kickstart_done"]  = self.generate_kickstart_signal(0, g, None)
-                meta["kickstart_start"] = self.generate_kickstart_signal(1, g, None)
-                meta["kernel_options"] = utils.hash_to_string(meta["kernel_options"])
-                kfile = open(kickstart_path)
-                data = self.templar.render(kfile, meta, None, g)
-                kfile.close()
-                return data
-            except:
-                utils.log_exc(self.api.logger)
-                raise
-
-        elif kickstart_path is not None and not os.path.exists(kickstart_path):
-            if kickstart_path.find("http://") == -1 and kickstart_path.find("ftp://") == -1 and kickstart_path.find("nfs:") == -1:
-                return "# Error, cannot find %s" % kickstart_path
-        return "# kickstart is sourced externally, or is missing, and cannot be displayed here: %s" % meta["kickstart"]
-
     def generate_kickstart_signal(self, is_pre=0, profile=None, system=None):
         """
         Do things that we do at the start/end of kickstarts...
@@ -216,45 +180,68 @@ class KickGen:
 
         return "wget \"%s\" --output-document=/etc/yum.repos.d/cobbler-config.repo\n" % (url)
 
-    def generate_kickstart_for_system(self,s):
+    def generate_kickstart_for_system(self, sys_name):
 
-
-        s = self.api.find_system(name=s)
+        s = self.api.find_system(name=sys_name)
         if s is None:
             return "# system not found"
 
-        profile = s.get_conceptual_parent()
-        if profile is None:
+        p = s.get_conceptual_parent()
+        if p is None:
             raise CX(_("system %(system)s references missing profile %(profile)s") % { "system" : s.name, "profile" : s.profile })
-        distro = profile.get_conceptual_parent()
+
+        distro = p.get_conceptual_parent()
         if distro is None: 
             # this is an image parented system, no kickstart available
             return "# image based systems do not have kickstarts"
-        meta = utils.blender(self.api, False, s)
+
+        return self.generate_kickstart(profile=p, system=s) 
+
+    def generate_kickstart(self, profile=None, system=None):
+
+        obj = system
+        if system is None:
+            obj = profile
+
+        meta = utils.blender(self.api, False, obj)
         kickstart_path = utils.find_kickstart(meta["kickstart"])
-        if kickstart_path and os.path.exists(kickstart_path):
-            try:
-                ksmeta = meta["ks_meta"]
-                del meta["ks_meta"]
-                meta.update(ksmeta) # make available at top level
-                meta["yum_repo_stanza"] = self.generate_repo_stanza(s, False)
-                meta["yum_config_stanza"] = self.generate_config_stanza(s, False)
-                meta["kickstart_done"]  = self.generate_kickstart_signal(0, profile, s)
-                meta["kickstart_start"] = self.generate_kickstart_signal(1, profile, s)
-                meta["kernel_options"] = utils.hash_to_string(meta["kernel_options"])
-                # meta["config_template_files"] = self.generate_template_files_stanza(g, False)
-                kfile = open(kickstart_path)
-                data = self.templar.render(kfile, meta, None, s)
-                kfile.close()
-                return data
-            except:
-                traceback.print_exc()
-                raise CX(_("Error templating file"))
-        elif kickstart_path is not None and not os.path.exists(kickstart_path):
-            if kickstart_path.find("http://") == -1 and kickstart_path.find("ftp://") == -1 and kickstart_path.find("nfs:") == -1:
-                return "# Error, cannot find %s" % kickstart_path
-        return "# kickstart is sourced externally: %s" % meta["kickstart"]
 
+        if not kickstart_path:
+            return "# kickstart is missing or invalid: %s" % meta["kickstart"]
+
+        ksmeta = meta["ks_meta"]
+        del meta["ks_meta"]
+        meta.update(ksmeta) # make available at top level
+        meta["yum_repo_stanza"] = self.generate_repo_stanza(obj, (system is None))
+        meta["yum_config_stanza"] = self.generate_config_stanza(obj, (system is None))
+        meta["kickstart_done"]  = self.generate_kickstart_signal(0, profile, system)
+        meta["kickstart_start"] = self.generate_kickstart_signal(1, profile, system)
+        meta["kernel_options"] = utils.hash_to_string(meta["kernel_options"])
+        # meta["config_template_files"] = self.generate_template_files_stanza(g, False)
+
+        try:
+            raw_data = utils.read_file_contents(kickstart_path, self.api.logger,
+                    self.settings.template_remote_kickstarts)
+            if raw_data is None:
+                return "# kickstart is sourced externally: %s" % meta["kickstart"]
+            data = self.templar.render(raw_data, meta, None, obj)
+            return data
+        except FileNotFoundException:
+            self.api.logger.warning("kickstart not found: %s" % meta["kickstart"])
+            return "# kickstart not found: %s" % meta["kickstart"]
+
+    def generate_kickstart_for_profile(self,g):
+
+        g = self.api.find_profile(name=g)
+        if g is None:
+           return "# profile not found"
+
+        distro = g.get_conceptual_parent()
+        if distro is None:
+           raise CX(_("profile %(profile)s references missing distro %(distro)s") % 
+                   { "profile" : g.name, "distro" : g.distro })
+
+        return self.generate_kickstart(profile=g)
 
     def get_last_errors(self):
         """
diff --git a/cobbler/settings.py b/cobbler/settings.py
index 2cd15b7..339e6f7 100644
--- a/cobbler/settings.py
+++ b/cobbler/settings.py
@@ -93,6 +93,7 @@ DEFAULTS = {
     "scm_track_mode"              : "git",
     "server"                      : "127.0.0.1",
     "snippetsdir"                 : "/var/lib/cobbler/snippets",
+    "template_remote_kickstarts"  : 0,
     "virt_auto_boot"              : 0,
     "webdir"                      : "/var/www/cobbler",
     "xmlrpc_port"                 : 25151,
diff --git a/cobbler/template_api.py b/cobbler/template_api.py
index 2ea3cd9..052c3fd 100644
--- a/cobbler/template_api.py
+++ b/cobbler/template_api.py
@@ -25,6 +25,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 import Cheetah.Template
 import os.path
 import re
+import utils
+from cexceptions import *
 
 CHEETAH_MACROS_FILE = '/etc/cobbler/cheetah_macros'
 
@@ -56,9 +58,9 @@ BuiltinTemplate = Cheetah.Template.Template.compile(source="\n".join([
     # general snippet. If none is found, a comment explaining the error is
     # substituted.
     "#def SNIPPET($file)",
-        "#set $fullpath = $find_snippet($file)",
-        "#if $fullpath",
-            "#include $fullpath",
+        "#set $snippet = $read_snippet($file)",
+        "#if $snippet",
+            "#include source=$snippet",
         "#else",
             "# Error: no snippet data for $file",
         "#end if",
@@ -125,9 +127,13 @@ class Template(BuiltinTemplate, MacrosTemplate):
         return Cheetah.Template.Template.compile(*args, **kwargs)
     compile = classmethod(compile)
     
-    def find_snippet(self, file):
+    def read_snippet(self, file):
         """
-        Locate the appropriate snippet for the current system and profile.
+        Locate the appropriate snippet for the current system and profile and
+        read it's contents.
+
+        This file could be located in a remote location.
+
         This will first check for a per-system snippet, a per-profile snippet,
         a distro snippet, and a general snippet. If no snippet is located, it
         returns None.
@@ -136,21 +142,29 @@ class Template(BuiltinTemplate, MacrosTemplate):
             if self.varExists('%s_name' % snipclass):
                 fullpath = '%s/per_%s/%s/%s' % (self.getVar('snippetsdir'),
                     snipclass, file, self.getVar('%s_name' % snipclass))
-                if os.path.exists(fullpath):
-                    return fullpath
-
-        return '%s/%s' % (self.getVar('snippetsdir'), file)
-    
-    # This may be a little frobby, but it's really cool. This is a pure python
-    # portion of SNIPPET that appends the snippet's searchList to the caller's
-    # searchList. This makes any #defs within a given snippet available to the
-    # template that included the snippet.
+                try:
+                    contents = utils.read_file_contents(fullpath, fetch_if_remote=True)
+                    return contents
+                except FileNotFoundException:
+                    pass
+
+        try: 
+            return utils.read_file_contents('%s/%s' % (self.getVar('snippetsdir'), 
+                file), fetch_if_remote=True)
+        except FileNotFoundException:
+            return None
 
     def SNIPPET(self, file):
         """
         Include the contents of the named snippet here. This is equivalent to
         the #include directive in Cheetah, except that it searches for system
         and profile specific snippets, and it includes the snippet's namespace.
+
+        This may be a little frobby, but it's really cool. This is a pure python
+        portion of SNIPPET that appends the snippet's searchList to the caller's
+        searchList. This makes any #defs within a given snippet available to the
+        template that included the snippet.
+
         """
         # First, do the actual inclusion. Cheetah (when processing #include)
         # will track the inclusion in self._CHEETAH__cheetahIncludes
@@ -159,13 +173,18 @@ class Template(BuiltinTemplate, MacrosTemplate):
         # Now do our dirty work: locate the new include, and append its
         # searchList to ours.
         # We have to compute the full path again? Eww.
-        fullpath = self.find_snippet(file);
-        if fullpath:
+
+        # This weird method is getting even weirder, the cheetah includes keys
+        # are no longer filenames but actual contents of snippets. Regardless
+        # this seems to work and hopefully it will be ok.
+
+        snippet_contents = self.read_snippet(file);
+        if snippet_contents:
             # Only include what we don't already have. Because Cheetah
             # passes our searchList into included templates, the snippet's
             # searchList will include this templates searchList. We need to
             # avoid duplicating entries.
-            childList = self._CHEETAH__cheetahIncludes[fullpath].searchList()
+            childList = self._CHEETAH__cheetahIncludes[snippet_contents].searchList()
             myList = self.searchList()
             for childElem in childList:
                 if not childElem in myList:
diff --git a/cobbler/utils.py b/cobbler/utils.py
index 7470c35..24ca4c6 100644
--- a/cobbler/utils.py
+++ b/cobbler/utils.py
@@ -47,6 +47,7 @@ import shlex
 import field_info
 import clogger
 import yaml
+import urllib2
 
 try:
     import hashlib as fiver
@@ -406,17 +407,81 @@ def find_kickstart(url):
     Check if a kickstart url looks like an http, ftp, nfs or local path.
     If a local path is used, cobbler will copy the kickstart and serve
     it over http.
+
+    Return None if the url format does not look valid.
     """
     if url is None:
         return None
     x = url.lower()
-    for y in ["http://","nfs://","ftp://","/"]:
+    for y in ["http://", "nfs://", "ftp://", "/"]:
        if x.startswith(y):
            if x.startswith("/") and not os.path.isfile(url):
                return None
            return url
     return None
 
+
+def read_file_contents(file_location, logger=None, fetch_if_remote=False):
+    """
+    Reads the contents of a file, which could be referenced locally
+    or as a URI.
+
+    Returns None if file is remote and templating of remote files is 
+    disabled.
+
+    Throws a FileNotFoundException if the file does not exist at the
+    specified location.
+    """
+
+    # Local files:
+    if file_location.startswith("/"):
+
+        if not os.path.exists(file_location):
+            if logger:
+                logger.warning("File does not exist: %s" % file_location)
+            raise FileNotFoundException("%s: %s" % (_("File not found"), 
+                file_location))
+
+        try:
+            f = open(file_location)
+            data = f.read()
+            f.close()
+            return data
+        except:
+            log_exc(logger)
+            raise
+
+    # Remote files:
+    if not fetch_if_remote:
+        return None
+
+    if file_is_remote(file_location):
+        try:
+            handler = urllib2.urlopen(file_location)
+            data = handler.read()
+            handler.close()
+            return data
+        except urllib2.HTTPError:
+            # File likely doesn't exist
+            if logger:
+                logger.warning("File does not exist: %s" % file_location)
+            raise FileNotFoundException("%s: %s" % (_("File not found"), 
+                file_location))
+
+
+def file_is_remote(file_location):
+    """ 
+    Returns true if the file is remote and referenced via a protocol
+    we support.
+    """
+    # TODO: nfs and ftp ok too?
+    file_loc_lc = file_location.lower()
+    for prefix in ["http://"]:
+        if file_loc_lc.startswith(prefix):
+            return True
+    return False
+
+
 def input_string_or_list(options):
     """
     Accepts a delimited list of stuff or a list, but always returns a list.
@@ -1569,6 +1634,7 @@ def to_datastruct_from_fields(obj, fields):
     # they are the only exception in Cobbler.
     if obj.COLLECTION_TYPE == "system":
         ds["interfaces"] = copy.deepcopy(obj.interfaces)
+
     return ds
 
 def printable_from_fields(obj, fields):
diff --git a/installer_templates/settings.template b/installer_templates/settings.template
index 2777b73..bb7d356 100644
--- a/installer_templates/settings.template
+++ b/installer_templates/settings.template
@@ -309,6 +309,13 @@ server: $server
 # this directory should not be required.
 snippetsdir: /var/lib/cobbler/snippets
 
+# Normally if a kickstart is specified at a remote location, this
+# URL will be passed directly to the kickstarting system, thus bypassing
+# the usual snippet templating Cobbler does for local kickstart files. If
+# this option is enabled, Cobbler will fetch the file contents internally
+# and serve a templated version of the file to the client.
+template_remote_kickstarts: 0
+
 # should new profiles for virtual machines default to auto booting with the physical host when the physical host reboots?
 # this can be overridden on each profile or system object.
 virt_auto_boot: 1
diff --git a/koan/app.py b/koan/app.py
index b173ada..1f08208 100755
--- a/koan/app.py
+++ b/koan/app.py
@@ -446,7 +446,7 @@ class Koan:
         if profile_data.get("kickstart","") != "":
 
             # fix URLs
-            if profile_data["kickstart"][0] == "/":
+            if profile_data["kickstart"][0] == "/" or profile_data["template_remote_kickstarts"]:
                if not self.system:
                    profile_data["kickstart"] = "http://%s/cblr/svc/op/ks/profile/%s" % (profile_data['http_server'], profile_data['name'])
                else:
