diff --git a/README.md b/README.md
index 14c4a2e44964e57145ffe117ae5589d5cd4ab3e5..17060444cea3021ea21a4129bc9e5c8ebb21315c 100644
--- a/README.md
+++ b/README.md
@@ -16,10 +16,13 @@
        * [`freeradius::client`](#freeradiusclient)
        * [`freeradius::config`](#freeradiusconfig)
        * [`freeradius::dictionary`](#freeradiusdictionary)
+       * [`freeradius::home_server`](#freeradiushomeserver)
+       * [`freeradius::home_server_pool`](#freeradiushomeserverpool)
        * [`freeradius::instantiate`](#freeradiusinstantiate)
        * [`freeradius::ldap`](#freeradiusldap)
        * [`freeradius::module`](#freeradiusmodule)
        * [`freeradius::policy`](#freeradiuspolicy)
+       * [`freeradius::realm`](#freeradiusrealm)
        * [`freeradius::site`](#freeradiussite)
        * [`freeradius::sql`](#freeradiussql)
        * [`freeradius::statusclient`](#freeradiusstatusclient)
@@ -259,6 +262,84 @@ freeradius::dictionary { 'mydict':
   source => 'puppet:///modules/site_freeradius/dictionary.mydict',
 }
 ```
+#### `freeradius::home_server`
+
+This section defines a "Home Server" which is another RADIUS server that gets sent proxied requests.
+
+##### `secret`
+
+The shared secret use to "encrypt" and "sign" packets between FreeRADIUS and the home server.
+
+##### `type`
+
+Home servers can be sent Access-Request packets or Accounting-Request packets. Allowed values are:
+* `auth` Handles Access-Request packets
+* `acct`  Handles Accounting-Request packets
+* `auth+acct` Handles Access-Request packets at "port" and Accounting-Request packets at "port + 1"
+* `coa` Handles CoA-Request and Disconnect-Request packets.
+
+Default: `auth`
+
+##### `ipaddr`
+
+IPv4 address or hostname of the home server. Specify one of `ipaddr`, `ipv6addr` or `virtual_server`
+
+##### `ipv6addr`
+
+IPv6 address or hostname of the home server. Specify one of `ipaddr`, `ipv6addr` or `virtual_server`
+
+##### `virtual_server`
+
+If you specify a virtual_server here, then requests will be proxied internally to that virtual server.
+These requests CANNOT be proxied again, however. The intent is to have the local server handle packets
+when all home servers are dead. Specify one of `ipaddr`, `ipv6addr` or `virtual_server`
+
+##### `port`
+
+The port to which packets are sent. Usually 1812 for type "auth", and  1813 for type "acct".
+Older servers may use 1645 and 1646. Use 3799 for type "coa" Default: `1812`
+
+##### `proto`
+The transport protocol. If unspecified, defaults to "udp", which is the traditional
+RADIUS transport. It may also be "tcp", in which case TCP will be used to talk to
+this home server. Default: `udp`
+
+
+#### `freeradius::home_server_pool`
+
+##### `home_server`
+
+An array of one or more home servers. The names of the home servers are NOT the hostnames, but the names
+of the sections. (e.g. `home_server foo {...}` has name "foo".
+
+Note that ALL home servers listed here have to be of the same type. i.e. they all have to be "auth", or they all have to
+be "acct", or they all have to be "auth+acct".
+
+
+##### `type`
+
+The type of this pool controls how home servers are chosen.
+
+* `fail-over` the request is sent to the first live home server in the list.  i.e. If the first home server is marked "dead", the second one is chosen, etc.
+* `load-balance` the least busy home server is chosen For non-EAP auth methods, and for acct packets, we recommend using "load-balance". It will ensure the highest availability for your network. 
+* `client-balance` the home server is chosen by hashing the source IP address of the packet. This configuration is most useful to do simple load balancing for EAP sessions
+* `client-port-balance` the home server is chosen by hashing the source IP address and source port of the packet.
+* `keyed-balance` the home server is chosen by hashing (FNV) the contents of the Load-Balance-Key attribute from the control items.
+
+The default type is `fail-over`.
+
+##### `virtual_server`
+
+A `virtual_server` may be specified here.  If so, the "pre-proxy" and "post-proxy" sections are called when
+the request is proxied, and when a response is received.
+
+##### `fallback`
+
+If ALL home servers are dead, then this "fallback" home server is used. If set, it takes precedence over any realm-based
+fallback, such as the DEFAULT realm.
+
+For reasons of stability, this home server SHOULD be a virtual server. Otherwise, the fallback may itself be dead!
+
 
 #### `freeradius::instantiate`
 
@@ -381,6 +462,37 @@ freeradius::policy { 'my-policies':
 }
 ```
 
+#### `freeradius::realm`
+
+Define a realm in `proxy.conf`. Realms point to pools of home servers.
+
+##### `virtual_server`
+
+Set this to "proxy" requests internally to a virtual server. The pre-proxy and post-proxy sections are run just as with any
+other kind of home server.  The virtual server then receives the request, and replies, just as with any other packet.
+Once proxied internally like this, the request CANNOT be proxied internally or externally.
+
+##### `auth_pool`
+
+For authentication, the `auth_pool` configuration item should point to a `home_server_pool` that was previously
+defined.  All of the home servers in the `auth_pool` must be of type `auth`.
+
+##### `acct_pool`
+
+For accounting, the `acct_pool` configuration item should point to a `home_server_pool` that was previously
+defined.  All of the home servers in the `acct_pool` must be of type `acct`.
+
+##### `pool`
+
+If you have a `home_server_pool` where all of the home servers are of type `auth+acct`, you can just use the `pool`
+configuration item, instead of specifying both `auth_pool` and `acct_pool`.
+
+##### `nostrip`
+
+Normally, when an incoming User-Name is matched against the realm, the realm name is "stripped" off, and the "stripped"
+user name is used to perform matches.If you do not want this to happen, set this to `true`. Default: `false`.
+
+
 #### `freeradius::script`
 
 Install a helper script, e.g. which might be called upon by a virtual server. These are
diff --git a/manifests/home_server.pp b/manifests/home_server.pp
new file mode 100644
index 0000000000000000000000000000000000000000..8152cd342a8fca7edf9b342c7e4fd8673e8629aa
--- /dev/null
+++ b/manifests/home_server.pp
@@ -0,0 +1,33 @@
+# Configure a home_server for proxy config
+define freeradius::home_server (
+  $secret,
+  $type = 'auth',
+  $ipaddr = '',
+  $ipv6addr = '',
+  $virtual_server = '',
+  $port = 1812,
+  $proto = 'udp',
+) {
+  $fr_basepath = $::freeradius::params::fr_basepath
+
+  # Validate multiple choice options
+  unless $type in ['auth', 'acct', 'auth+acct', 'coa'] {
+    fail('$type must be one of auth, acct, auth+acct, coa')
+  }
+  unless $proto in ['udp', 'tcp'] {
+    fail('$type must be one of udp, tcp')
+  }
+
+  # Validate integers
+  unless is_integer($port) {
+    fail('$port must be an integer')
+  }
+
+  # Configure config fragment for this home server
+  concat::fragment { "homeserver-${name}":
+    target  => "${fr_basepath}/proxy.conf",
+    content => template('freeradius/home_server.erb'),
+    order   => 10,
+  }
+}
+
diff --git a/manifests/home_server_pool.pp b/manifests/home_server_pool.pp
new file mode 100644
index 0000000000000000000000000000000000000000..e680ec014eb6442c6cb93c86458765cf6c21a427
--- /dev/null
+++ b/manifests/home_server_pool.pp
@@ -0,0 +1,22 @@
+# Configure home server pools
+define freeradius::home_server_pool (
+  $home_server,
+  $type = 'fail-over',
+  $virtual_server = '',
+  $fallback = '',
+) {
+  $fr_basepath = $::freeradius::params::fr_basepath
+
+  # Validate multi-value options
+  unless $type in ['fail-over', 'load-balance', 'client-balance', 'client-port-balance', 'keyed-balance'] {
+    fail('$type must be one of fail-over, load-balance, client-balance, client-port-balance, keyed-balance')
+  }
+
+  # Configure config fragment for this home server
+  concat::fragment { "homeserverpool-${name}":
+    target  => "${fr_basepath}/proxy.conf",
+    content => template('freeradius/home_server_pool.erb'),
+    order   => 20,
+  }
+}
+
diff --git a/manifests/init.pp b/manifests/init.pp
index a8607762e7c02c511a2d4f3aa92e6c4f28fc01b1..71fe7590256dc78604f378163186a52950f1e444 100644
--- a/manifests/init.pp
+++ b/manifests/init.pp
@@ -71,6 +71,7 @@ class freeradius (
     group   => $freeradius::fr_group,
     mode    => '0640',
     require => [Package[$freeradius::fr_package], Group[$freeradius::fr_group]],
+    notify  => Service[$freeradius::fr_service],
   }
   concat::fragment { 'policy_header':
     target  => "${freeradius::fr_basepath}/policy.conf",
@@ -83,6 +84,15 @@ class freeradius (
     order   => '99',
   }
 
+  # Set up concat proxy file
+  concat { "${freeradius::fr_basepath}/proxy.conf":
+    owner   => 'root',
+    group   => $freeradius::fr_group,
+    mode    => '0640',
+    require => [Package[$freeradius::fr_package], Group[$freeradius::fr_group]],
+    notify  => Service[$freeradius::fr_service],
+  }
+
   # Install a slightly tweaked stock dictionary that includes
   # our custom dictionaries
   concat { "${freeradius::fr_basepath}/dictionary":
@@ -264,7 +274,6 @@ class freeradius (
   file { [
     "${freeradius::fr_basepath}/sites-available/default",
     "${freeradius::fr_basepath}/sites-available/inner-tunnel",
-    "${freeradius::fr_basepath}/proxy.conf",
     "${freeradius::fr_basepath}/clients.conf",
     "${freeradius::fr_basepath}/sql.conf",
   ]:
diff --git a/manifests/realm.pp b/manifests/realm.pp
new file mode 100644
index 0000000000000000000000000000000000000000..ec67cb49df1c3076ae987dadef2aa556b2d3b121
--- /dev/null
+++ b/manifests/realm.pp
@@ -0,0 +1,22 @@
+# Set up proxy realms
+define freeradius::realm (
+  $virtual_server = '',
+  $auth_pool = '',
+  $acct_pool = '',
+  $pool = '',
+  $nostrip = false,
+) {
+  $fr_basepath = $::freeradius::params::fr_basepath
+
+  # Validate bools
+  unless is_bool($nostrip) {
+    fail('nostrip must be true or false')
+  }
+
+  # Configure config fragment for this realm
+  concat::fragment { "realm-${name}":
+    target  => "${fr_basepath}/proxy.conf",
+    content => template('freeradius/realm.erb'),
+    order   => 30,
+  }
+}
diff --git a/templates/home_server.erb b/templates/home_server.erb
new file mode 100644
index 0000000000000000000000000000000000000000..bd207df05334dc1486bce1e5622244ced3588f54
--- /dev/null
+++ b/templates/home_server.erb
@@ -0,0 +1,16 @@
+home_server <%= @name %> {
+	type = <%= @type %>
+<% if @ipaddr != '' -%>
+	ipaddr = <%= @ipaddr %>
+<% end -%>
+<% if @ipv6addr != '' -%>
+	ipv6addr = <%= @ipv6addr %>
+<% end -%>
+<% if @virtual_server != '' -%>
+	virtual_server = <%= @virtual_server %>
+<% end -%>
+	port = <%= @port %>
+	proto = <%= @proto %>
+	secret = <%= @secret %>
+}
+
diff --git a/templates/home_server_pool.erb b/templates/home_server_pool.erb
new file mode 100644
index 0000000000000000000000000000000000000000..e33132a7ab9fb0e061183019feb679684baca552
--- /dev/null
+++ b/templates/home_server_pool.erb
@@ -0,0 +1,13 @@
+home_server_pool <%= @name %> {
+	type = <%= @type %>
+<% if @virtual_server != '' -%>
+	virtual_server = <%= @virtual_server %>
+<% end -%>
+<% @home_server.each do |server| -%>
+	home_server = <%= server %>
+<% end -%>
+<% if @fallback != '' -%>
+	fallback = <%= @fallback %>
+<% end -%>
+}
+
diff --git a/templates/realm.erb b/templates/realm.erb
new file mode 100644
index 0000000000000000000000000000000000000000..59ae0203b7875fd467bdd2c66c83e1790e4ceb27
--- /dev/null
+++ b/templates/realm.erb
@@ -0,0 +1,18 @@
+realm <%= @name %> {
+<% if @virtual_server != '' -%>
+	virtual_server = <%= @virtual_server %>
+<% end -%>
+<% if @auth_pool != '' -%>
+	auth_pool = <%= @auth_pool %>
+<% end -%>
+<% if @acct_pool != '' -%>
+	acct_pool = <%= @acct_pool %>
+<% end -%>
+<% if @pool != '' -%>
+	pool = <%= @pool %>
+<% end %>
+<% if @nostrip -%>
+	nostrip
+<% end -%>
+}
+