diff --git a/provider_base/services/_tor_common.json b/provider_base/services/_tor_common.json
new file mode 100644
index 0000000000000000000000000000000000000000..461232dc05e4cd1d710fa70dbdb2ee6801b36ce1
--- /dev/null
+++ b/provider_base/services/_tor_common.json
@@ -0,0 +1,8 @@
+{
+  "tor": {
+    "type": "disabled",
+    "contacts": "= [provider.contacts['tor'] || provider.contacts.default].flatten",
+    "nickname": "= (self.name + secret(:tor_family)).sub('_','')[0..18]",
+    "family": "= nodes[:services => 'tor'][:environment => '!local'].field('tor.nickname').join(',')"
+  }
+}
diff --git a/provider_base/services/hidden_service.json b/provider_base/services/hidden_service.json
new file mode 100644
index 0000000000000000000000000000000000000000..137932fa2577ed7911fad6e38f2828970428f3ac
--- /dev/null
+++ b/provider_base/services/hidden_service.json
@@ -0,0 +1,11 @@
+{
+  "tor": {
+    "hidden_service": {
+      "key_type": "RSA",
+      "public_key": "= tor_public_key_path(:node_tor_pub_key, tor.hidden_service.key_type)",
+      "private_key": "= tor_private_key_path(:node_tor_priv_key, tor.hidden_service.key_type)",
+      "address": "=> onion_address(:node_tor_pub_key)",
+      "single_hop": false
+    }
+  }
+}
diff --git a/provider_base/services/hidden_service.rb b/provider_base/services/hidden_service.rb
new file mode 100644
index 0000000000000000000000000000000000000000..5070168148356d18475fea537259c9e4f521b435
--- /dev/null
+++ b/provider_base/services/hidden_service.rb
@@ -0,0 +1,4 @@
+if self.services.include?("tor_exit") || self.services.include?("tor_relay")
+  LeapCli.log :error, "service `hidden_service` is not compatible with tor_exit or tor_relay (node #{self.name})."
+end
+self.tor['type'] = "hidden_service"
\ No newline at end of file
diff --git a/provider_base/services/tor_exit.json b/provider_base/services/tor_exit.json
new file mode 100644
index 0000000000000000000000000000000000000000..dab3b76f297069d414c2d71c336bce3e18f1e2a8
--- /dev/null
+++ b/provider_base/services/tor_exit.json
@@ -0,0 +1,5 @@
+{
+  "tor": {
+    "bandwidth_rate": 6550
+  }
+}
diff --git a/provider_base/services/tor_exit.rb b/provider_base/services/tor_exit.rb
new file mode 100644
index 0000000000000000000000000000000000000000..05c674383b8872ced0bd45ee86538305c5937d82
--- /dev/null
+++ b/provider_base/services/tor_exit.rb
@@ -0,0 +1,6 @@
+if self.services.include?("hidden_service") || self.services.include?("tor_relay")
+  LeapCli.log :error, "service `tor_exit` is not compatible with tor_relay or hidden_service (node #{self.name})."
+  exit(1)
+end
+apply_partial("_tor_common")
+self.tor['type'] = "exit"
diff --git a/provider_base/services/tor_relay.json b/provider_base/services/tor_relay.json
new file mode 100644
index 0000000000000000000000000000000000000000..dab3b76f297069d414c2d71c336bce3e18f1e2a8
--- /dev/null
+++ b/provider_base/services/tor_relay.json
@@ -0,0 +1,5 @@
+{
+  "tor": {
+    "bandwidth_rate": 6550
+  }
+}
diff --git a/provider_base/services/tor_relay.rb b/provider_base/services/tor_relay.rb
new file mode 100644
index 0000000000000000000000000000000000000000..42bafb945f0bd42558eb487f8e3202ad96e66087
--- /dev/null
+++ b/provider_base/services/tor_relay.rb
@@ -0,0 +1,6 @@
+
+if self.services.include?("tor_exit") || self.services.include?("hidden_service")
+  LeapCli.log :error, "service `tor_relay` is not compatible with tor_exit or hidden_service (node #{self.name})."
+end
+apply_partial("_tor_common")
+self.tor['type'] = "relay"
diff --git a/puppet/manifests/site.pp b/puppet/manifests/site.pp
index e243c5df78612c46cf5206e8716a2d63b251c47d..f3e752cca6afbcded67929c374dc92e471328ecb 100644
--- a/puppet/manifests/site.pp
+++ b/puppet/manifests/site.pp
@@ -44,10 +44,18 @@ node default {
     include site_nagios
   }
 
-  if member($services, 'tor') {
+  if member($services, 'tor_relay') {
     include site_tor::relay
   }
 
+  if member($services, 'tor_exit') {
+    include site_tor::relay
+  }
+
+  if member($services, 'hidden_service') {
+    include site_tor::hidden_service
+  }
+
   if member($services, 'mx') {
     include site_mx
   }
diff --git a/puppet/modules/site_apache/templates/vhosts.d/hidden_service.conf.erb b/puppet/modules/site_apache/templates/vhosts.d/hidden_service.conf.erb
index 1d19094e21b8ca84997efd4f44193078e30e9f2b..ddf69a42c245d787daaa8fc06018dde95cd057d4 100644
--- a/puppet/modules/site_apache/templates/vhosts.d/hidden_service.conf.erb
+++ b/puppet/modules/site_apache/templates/vhosts.d/hidden_service.conf.erb
@@ -1,5 +1,5 @@
 <VirtualHost 127.0.0.1:80>
-  ServerName <%= @tor_domain %>
+  ServerName <%= @onion_domain %>
 
   <IfModule mod_headers.c>
     Header always unset X-Powered-By
diff --git a/puppet/modules/site_static/manifests/hidden_service.pp b/puppet/modules/site_static/manifests/hidden_service.pp
index 31cf328ef8924cf64e3f5534b20515ddbd319616..dcf3785eebb13e2749f2c001ee082aabc81221d6 100644
--- a/puppet/modules/site_static/manifests/hidden_service.pp
+++ b/puppet/modules/site_static/manifests/hidden_service.pp
@@ -23,7 +23,7 @@ class site_static::hidden_service ( $single_hop = false ) {
 
     '/var/lib/tor/static/hostname':
       ensure  => present,
-      content => "${::site_static::tor_domain}\n",
+      content => "${::site_static::onion_domain}\n",
       owner   => 'debian-tor',
       group   => 'debian-tor',
       mode    => '0600',
diff --git a/puppet/modules/site_static/manifests/init.pp b/puppet/modules/site_static/manifests/init.pp
index 96d92f74b1f6d7854f670381648647478b3aa7a5..4ddce5ed0c7582743f47e376a530547ecc34b582 100644
--- a/puppet/modules/site_static/manifests/init.pp
+++ b/puppet/modules/site_static/manifests/init.pp
@@ -12,10 +12,10 @@ class site_static {
   $formats        = $static['formats']
   $bootstrap      = $static['bootstrap_files']
   $tor            = hiera('tor', false)
-  if $tor and member($services, 'tor') and $tor['hidden_service']['active'] == true {
-    $tor_active = true
+  if $tor and member($services, 'hidden_service') {
+    $onion_active = true
   } else {
-    $tor_active = false
+    $onion_active = false
   }
 
   file {
@@ -76,9 +76,9 @@ class site_static {
     }
   }
 
-  if $tor_active {
+  if $onion_active {
     $hidden_service = $tor['hidden_service']
-    $tor_domain     = "${hidden_service['address']}.onion"
+    $onion_domain     = "${hidden_service['address']}.onion"
     class { 'site_static::hidden_service':
       single_hop => $hidden_service['single_hop']
     }
diff --git a/puppet/modules/site_static/templates/apache.conf.erb b/puppet/modules/site_static/templates/apache.conf.erb
index 75d834e7e7d802c9a5c77a1f41b47fb579176cab..716df437cf89080e180deea2ec7daa5edf4875b0 100644
--- a/puppet/modules/site_static/templates/apache.conf.erb
+++ b/puppet/modules/site_static/templates/apache.conf.erb
@@ -74,14 +74,14 @@
   Require all granted
 </Directory>
 
-<%- if @tor_active && (@always_use_hidden_service || @use_hidden_service) -%>
+<%- if @onion_active && (@always_use_hidden_service || @use_hidden_service) -%>
 ##
-## Tor
+## Hidden Service
 ##
 <VirtualHost 127.0.0.1:80>
-  ServerName <%= @tor_domain %>
+  ServerName <%= @onion_domain %>
 <%- if @www_alias -%>
-  ServerAlias www.<%= @tor_domain %>
+  ServerAlias www.<%= @onion_domain %>
 <%- end -%>
 
   <IfModule mod_headers.c>
@@ -105,7 +105,7 @@
 <VirtualHost *:80>
   ServerName <%= @domain %>
 <%- if @www_alias -%>
-  ServerAlias www.<%= @tor_domain %>
+  ServerAlias www.<%= @domain %>
 <%- end -%>
 <%- @aliases && @aliases.each do |domain_alias| -%>
   ServerAlias <%= domain_alias %>
@@ -127,7 +127,7 @@
 <VirtualHost *:443>
   ServerName <%= @domain %>
 <%- if @www_alias -%>
-  ServerAlias www.<%= @tor_domain %>
+  ServerAlias www.<%= @domain %>
 <%- end -%>
 <%- @aliases && @aliases.each do |domain_alias| -%>
   ServerAlias <%= domain_alias %>
diff --git a/puppet/modules/site_webapp/manifests/hidden_service.pp b/puppet/modules/site_webapp/manifests/hidden_service.pp
index 3f3f1d0c1ce6ae587a29a9cb9d01b70392700c8d..658d62f9121610967100b1c4eb7f1fc65b30b1e7 100644
--- a/puppet/modules/site_webapp/manifests/hidden_service.pp
+++ b/puppet/modules/site_webapp/manifests/hidden_service.pp
@@ -2,7 +2,7 @@
 class site_webapp::hidden_service {
   $tor              = hiera('tor')
   $hidden_service   = $tor['hidden_service']
-  $tor_domain       = "${hidden_service['address']}.onion"
+  $onion_domain     = "${hidden_service['address']}.onion"
 
   include site_apache::common
   include apache::module::headers
@@ -33,7 +33,7 @@ class site_webapp::hidden_service {
 
     '/var/lib/tor/webapp/hostname':
       ensure  => present,
-      content => "${tor_domain}\n",
+      content => "${onion_domain}\n",
       owner   => 'debian-tor',
       group   => 'debian-tor',
       mode    => '0600',
diff --git a/puppet/modules/site_webapp/manifests/init.pp b/puppet/modules/site_webapp/manifests/init.pp
index deb8e8c8072d41b1bc31c4739680cfc46950cee5..968859bf765a12a4104f46fc9d71a37e1d267188 100644
--- a/puppet/modules/site_webapp/manifests/init.pp
+++ b/puppet/modules/site_webapp/manifests/init.pp
@@ -177,11 +177,9 @@ class site_webapp {
       notify  => Service['apache'];
   }
 
-  if $tor {
+  if $tor and member($services, 'hidden_service') {
     $hidden_service = $tor['hidden_service']
-    if $hidden_service['active'] {
-      include ::site_webapp::hidden_service
-    }
+    include ::site_webapp::hidden_service
   }