diff --git a/Gemfile b/Gemfile
index 0964f1f2f86c6442e9b75f8914d9269ddaa350a9..eace32a37898634d5ccd5038638d20d77a1d98ae 100644
--- a/Gemfile
+++ b/Gemfile
@@ -3,11 +3,6 @@ source "https://rubygems.org"
 gem "rails", "4.2.3"
 
 # Legacy Rails features, remove me!
-
-# caches_page
-gem "actionpack-action_caching"
-gem "actionpack-page_caching"
-
 # responders (class level)
 gem "responders", "2.1.0"
 
@@ -15,6 +10,10 @@ gem "responders", "2.1.0"
 
 gem "unicorn", "4.9.0", require: false
 
+# Federation
+
+gem "diaspora_federation-rails", "0.0.2"
+
 # API and JSON
 
 gem "acts_as_api", "0.4.2"
diff --git a/Gemfile.lock b/Gemfile.lock
index 141d14d61c171094b21c9a08af0e72e04e27eecf..87e856e95deb722c228018001d1d16ec78d9d506 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -16,10 +16,6 @@ GEM
       rack-test (~> 0.6.2)
       rails-dom-testing (~> 1.0, >= 1.0.5)
       rails-html-sanitizer (~> 1.0, >= 1.0.2)
-    actionpack-action_caching (1.1.1)
-      actionpack (>= 4.0.0, < 5.0)
-    actionpack-page_caching (1.0.2)
-      actionpack (>= 4.0.0, < 5)
     actionview (4.2.3)
       activesupport (= 4.2.3)
       builder (~> 3.1)
@@ -157,6 +153,11 @@ GEM
       eventmachine (>= 1.0.5, < 1.1)
       http_parser.rb (~> 0.6)
       nokogiri (~> 1.6)
+    diaspora_federation (0.0.2)
+      nokogiri (~> 1.6, >= 1.6.6)
+    diaspora_federation-rails (0.0.2)
+      diaspora_federation (= 0.0.2)
+      rails (~> 4.2)
     diff-lcs (1.2.5)
     docile (1.1.5)
     domain_name (0.5.24)
@@ -743,8 +744,6 @@ PLATFORMS
   ruby
 
 DEPENDENCIES
-  actionpack-action_caching
-  actionpack-page_caching
   active_model_serializers (= 0.9.3)
   activerecord-import (= 0.8.0)
   acts-as-taggable-on (= 3.5.0)
@@ -765,6 +764,7 @@ DEPENDENCIES
   devise_lastseenable (= 0.0.4)
   diaspora-vines (~> 0.1.27)
   entypo-rails (= 2.2.3)
+  diaspora_federation-rails (= 0.0.2)
   eye (= 0.7.pre)
   facebox-rails (= 0.2.0)
   factory_girl_rails (= 4.5.0)
diff --git a/app/controllers/publics_controller.rb b/app/controllers/publics_controller.rb
index af9d57f9c7d623862a3c44219a40c4de97651c80..cca482bbd2e537c5e90c71b9a8fe9d29c7f605c2 100644
--- a/app/controllers/publics_controller.rb
+++ b/app/controllers/publics_controller.rb
@@ -13,36 +13,8 @@ class PublicsController < ApplicationController
   respond_to :html
   respond_to :xml, :only => :post
 
-  caches_page :host_meta, :if => Proc.new{ Rails.env == 'production'}
-
   layout false
 
-  def hcard
-    @person = Person.find_by_guid_and_closed_account(params[:guid], false)
-
-    if @person.present? && @person.local?
-      render 'publics/hcard'
-    else
-      render :nothing => true, :status => 404
-    end
-  end
-
-  def host_meta
-    render 'host_meta', :content_type => 'application/xrd+xml'
-  end
-
-  def webfinger
-    @person = Person.local_by_account_identifier(params[:q]) if params[:q]
-
-    if @person.nil? || @person.closed_account?
-      render :nothing => true, :status => 404
-      return
-    end
-
-    logger.info "webfinger profile request for: #{@person.id}"
-    render 'webfinger', :content_type => 'application/xrd+xml'
-  end
-
   def hub
     render :text => params['hub.challenge'], :status => 202, :layout => false
   end
diff --git a/app/helpers/people_helper.rb b/app/helpers/people_helper.rb
index 63d39af2116e832da60ddfd77fdbc20cf9ff3304..e52612bf9d185961de3b22c04765af491e65283e 100644
--- a/app/helpers/people_helper.rb
+++ b/app/helpers/people_helper.rb
@@ -50,10 +50,6 @@ module PeopleHelper
     end
   end
 
-  def person_href(person, opts={})
-    "href=\"#{local_or_remote_person_path(person, opts)}\"".html_safe
-  end
-
   # Rails.application.routes.url_helpers is needed since this is indirectly called from a model
   def local_or_remote_person_path(person, opts={})
     opts.merge!(:protocol => AppConfig.pod_uri.scheme, :host => AppConfig.pod_uri.authority)
diff --git a/app/models/person.rb b/app/models/person.rb
index 814dfe1e0a270b16eadd335071c1a82345b16e56..e419cce30f0f1ef901a043273777ab87f1408767 100644
--- a/app/models/person.rb
+++ b/app/models/person.rb
@@ -28,7 +28,7 @@ class Person < ActiveRecord::Base
   xml_attr :profile, :as => Profile
   xml_attr :exported_key
 
-  has_one :profile, :dependent => :destroy
+  has_one :profile, dependent: :destroy
   delegate :last_name, :image_url, :tag_string, :bio, :location,
            :gender, :birthday, :formatted_birthday, :tags, :searchable,
            to: :profile
@@ -222,7 +222,7 @@ class Person < ActiveRecord::Base
   end
 
   def public_key_hash
-    Base64.encode64(OpenSSL::Digest::SHA256.new(self.exported_key).to_s)
+    Base64.encode64(OpenSSL::Digest::SHA256.new(serialized_public_key).to_s)
   end
 
   def public_key
@@ -238,15 +238,18 @@ class Person < ActiveRecord::Base
     serialized_public_key = new_key
   end
 
-  #database calls
+  # database calls
   def self.by_account_identifier(identifier)
-    identifier = identifier.strip.downcase.gsub('acct:', '')
-    self.where(:diaspora_handle => identifier).first
+    identifier = identifier.strip.downcase.sub("acct:", "")
+    find_by(diaspora_handle: identifier)
   end
 
-  def self.local_by_account_identifier(identifier)
-    person = self.by_account_identifier(identifier)
-   (person.nil? || person.remote?) ? nil : person
+  def self.find_local_by_diaspora_handle(handle)
+    where(diaspora_handle: handle, closed_account: false).where.not(owner: nil).take
+  end
+
+  def self.find_local_by_guid(guid)
+    where(guid: guid, closed_account: false).where.not(owner: nil).take
   end
 
   def self.create_from_webfinger(profile, hcard)
diff --git a/app/views/publics/hcard.haml b/app/views/publics/hcard.haml
deleted file mode 100644
index f19bffb35d5c271ebfeda8f6346861e89a8dd048..0000000000000000000000000000000000000000
--- a/app/views/publics/hcard.haml
+++ /dev/null
@@ -1,50 +0,0 @@
-#content
-  %h1= @person.name
-  #content_inner
-    #i.entity_profile.vcard.author
-      %h2 User profile
-
-      %dl.entity_nickname
-        %dt Nickname
-        %dd
-          %a.nickname.url.uid{:href=>@person.url, :rel=>'me'}= @person.name
-
-      %dl.entity_given_name
-        %dt First name
-        %dd
-          %span.given_name= @person.profile.first_name
-
-      %dl.entity_family_name
-        %dt Family name
-        %dd
-          %span.family_name= @person.last_name
-
-      %dl.entity_fn
-        %dt Full name
-        %dd
-          %span.fn= @person.name
-
-      %dl.entity_url
-        %dt URL
-        %dd
-          %a#pod_location.url{:href=>@person.url, :rel=>'me'}= @person.url
-
-      %dl.entity_photo
-        %dt Photo
-        %dd
-          %img.photo.avatar{:src=>@person.image_url, :width=>'300px', :height=>'300px'}
-
-      %dl.entity_photo_medium
-        %dt Photo
-        %dd
-          %img.photo.avatar{:src=>@person.image_url(:thumb_medium), :width=>'100px', :height=>'100px'}
-
-      %dl.entity_photo_small
-        %dt Photo
-        %dd
-          %img.photo.avatar{:src=>@person.image_url(:thumb_small), :width=>'50px', :height=>'50px'}
-
-      %dl.entity_searchable
-        %dt Searchable
-        %dd
-          %span.searchable= @person.searchable
diff --git a/app/views/publics/host_meta.erb b/app/views/publics/host_meta.erb
deleted file mode 100644
index f5efcab11a9f4efb49f2abef7a0675618db77918..0000000000000000000000000000000000000000
--- a/app/views/publics/host_meta.erb
+++ /dev/null
@@ -1,10 +0,0 @@
-<?xml version='1.0' encoding='UTF-8'?>
-<XRD xmlns='http://docs.oasis-open.org/ns/xri/xrd-1.0'>
-
-  <!-- Resource-specific Information -->
-
-  <Link rel='lrdd'
-        type='application/xrd+xml'
-        template='<%= AppConfig.pod_uri.to_s %>webfinger?q={uri}' />
-
-</XRD>
diff --git a/app/views/publics/webfinger.erb b/app/views/publics/webfinger.erb
deleted file mode 100644
index 3b8099441690cc2ed9e6649f739b5fbebad3dd82..0000000000000000000000000000000000000000
--- a/app/views/publics/webfinger.erb
+++ /dev/null
@@ -1,14 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<XRD xmlns="http://docs.oasis-open.org/ns/xri/xrd-1.0">
-  <Subject>acct:<%=@person.diaspora_handle%></Subject>
-  <Alias>"<%= @person.url %>"</Alias>
-  <Link rel="http://microformats.org/profile/hcard" type="text/html" href="<%=@person.url%>hcard/users/<%=@person.guid%>"/>
-  <Link rel="http://joindiaspora.com/seed_location" type = 'text/html' href="<%=@person.url%>"/>
-  <Link rel="http://joindiaspora.com/guid" type = 'text/html' href="<%=@person.guid%>"/>
-
-  <Link rel='http://webfinger.net/rel/profile-page' type='text/html' <%=person_href(@person, :absolute => true)%>/>
-  <Link rel="http://schemas.google.com/g/2010#updates-from" type="application/atom+xml" href="<%=@person.atom_url%>"/>
-  <Link rel="salmon" href="<%= @person.receive_url %>"/>
-
-  <Link rel="diaspora-public-key" type = 'RSA' href="<%=Base64.strict_encode64(@person.exported_key)%>"/>
-</XRD>
diff --git a/config/initializers/diaspora_federation.rb b/config/initializers/diaspora_federation.rb
new file mode 100644
index 0000000000000000000000000000000000000000..e0d16ee44de705942b21f5954434dc3def85b085
--- /dev/null
+++ b/config/initializers/diaspora_federation.rb
@@ -0,0 +1,47 @@
+# configure the federation engine
+DiasporaFederation.configure do |config|
+  # the pod url
+  config.server_uri = AppConfig.pod_uri
+
+  config.define_callbacks do
+    on :person_webfinger_fetch do |handle|
+      person = Person.find_local_by_diaspora_handle(handle)
+      if person
+        DiasporaFederation::WebFinger::WebFinger.new(
+          acct_uri:    "acct:#{person.diaspora_handle}",
+          alias_url:   url_to("/people/#{person.guid}"),
+          hcard_url:   url_to(DiasporaFederation::Engine.routes.url_helpers.hcard_path(person.guid)),
+          seed_url:    AppConfig.pod_uri,
+          profile_url: person.profile_url,
+          atom_url:    person.atom_url,
+          salmon_url:  person.receive_url,
+          guid:        person.guid,
+          public_key:  person.serialized_public_key
+        )
+      end
+    end
+
+    on :person_hcard_fetch do |guid|
+      person = Person.find_local_by_guid(guid)
+      if person
+        DiasporaFederation::WebFinger::HCard.new(
+          guid:             person.guid,
+          nickname:         person.username,
+          full_name:        "#{person.profile.first_name} #{person.profile.last_name}".strip,
+          url:              AppConfig.pod_uri,
+          photo_large_url:  person.image_url,
+          photo_medium_url: person.image_url(:thumb_medium),
+          photo_small_url:  person.image_url(:thumb_small),
+          public_key:       person.serialized_public_key,
+          searchable:       person.searchable,
+          first_name:       person.profile.first_name,
+          last_name:        person.profile.last_name
+        )
+      end
+    end
+  end
+
+  def url_to(path)
+    AppConfig.pod_uri.tap {|uri| uri.path = path }.to_s
+  end
+end
diff --git a/config/routes.rb b/config/routes.rb
index 2d88dc78abb3d0017db0c9b58a537de304f0863a..c0fd79d2b489852efd75bada72f4e2b26f568464 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -18,6 +18,8 @@ Diaspora::Application.routes.draw do
     mount Sidekiq::Web => '/sidekiq', :as => 'sidekiq'
   end
 
+  mount DiasporaFederation::Engine => "/"
+
   get "/atom.xml" => redirect('http://blog.diasporafoundation.org/feed/atom') #too many stupid redirects :()
 
   get 'oembed' => 'posts#oembed', :as => 'oembed'
@@ -191,9 +193,6 @@ Diaspora::Application.routes.draw do
   # Federation
 
   controller :publics do
-    get 'webfinger'             => :webfinger
-    get 'hcard/users/:guid'     => :hcard
-    get '.well-known/host-meta' => :host_meta
     post 'receive/users/:guid'  => :receive
     post 'receive/public'       => :receive_public
     get 'hub'                   => :hub
diff --git a/spec/helpers/people_helper_spec.rb b/spec/helpers/people_helper_spec.rb
index 6d633097df405c040568a1d8933499d994bad0bb..d127ff244d273732061b58d2bafccd1662150d66 100644
--- a/spec/helpers/people_helper_spec.rb
+++ b/spec/helpers/people_helper_spec.rb
@@ -5,12 +5,12 @@
 require 'spec_helper'
 
 describe PeopleHelper, :type => :helper do
- before do
+  before do
     @user = alice
     @person = FactoryGirl.create(:person)
   end
 
- describe "#person_image_link" do
+  describe "#person_image_link" do
     it "returns an empty string if person is nil" do
       expect(person_image_link(nil)).to eq("")
     end
@@ -58,26 +58,12 @@ describe PeopleHelper, :type => :helper do
       @person.profile.last_name = "I'm <h1>Evil"
       expect(person_link(@person)).not_to include("<h1>")
     end
-    
+
     it 'links by id for a local user' do
       expect(person_link(@user.person)).to include "href='#{person_path(@user.person)}'"
     end
   end
 
-  describe "#person_href" do
-    it "calls local_or_remote_person_path and passes through the options" do
-      opts = {:absolute => true}
-
-      expect(self).to receive(:local_or_remote_person_path).with(@person, opts).exactly(1).times
-
-      person_href(@person, opts)
-    end
-
-    it "returns a href attribute" do
-      expect(person_href(@person)).to include "href="
-    end
-  end
-
   describe '#local_or_remote_person_path' do
     before do
       @user = FactoryGirl.create(:user)
diff --git a/spec/models/person_spec.rb b/spec/models/person_spec.rb
index 6433fafb37ff104c9826bb447655f3985a4d2919..b060569035eae14e515d598523a4aaaad7b1dc4a 100644
--- a/spec/models/person_spec.rb
+++ b/spec/models/person_spec.rb
@@ -457,27 +457,45 @@ describe Person, :type => :model do
         f = Person.by_account_identifier("tom@tom.joindiaspora.com")
         expect(f).to be nil
       end
+    end
 
+    describe ".find_local_by_diaspora_handle" do
+      it "should find local users person" do
+        person = Person.find_local_by_diaspora_handle(user.diaspora_handle)
+        expect(person).to eq(user.person)
+      end
+
+      it "should not find a remote person" do
+        person = Person.find_local_by_diaspora_handle(@person.diaspora_handle)
+        expect(person).to be nil
+      end
 
+      it "should not find a person with closed account" do
+        user.person.lock_access!
+        person = Person.find_local_by_diaspora_handle(user.diaspora_handle)
+        expect(person).to be nil
+      end
     end
 
-    describe '.local_by_account_identifier' do
-      it 'should find local users people' do
-        p = Person.local_by_account_identifier(user.diaspora_handle)
-        expect(p).to eq(user.person)
+    describe ".find_local_by_guid" do
+      it "should find local users person" do
+        person = Person.find_local_by_guid(user.guid)
+        expect(person).to eq(user.person)
       end
 
-      it 'should not find a remote person' do
-        p = Person.local_by_account_identifier(@person.diaspora_handle)
-        expect(p).to be nil
+      it "should not find a remote person" do
+        person = Person.find_local_by_guid(@person.guid)
+        expect(person).to be nil
       end
 
-      it 'should call .by_account_identifier' do
-        expect(Person).to receive(:by_account_identifier)
-        Person.local_by_account_identifier(@person.diaspora_handle)
+      it "should not find a person with closed account" do
+        user.person.lock_access!
+        person = Person.find_local_by_guid(user.guid)
+        expect(person).to be nil
       end
     end
   end
+
   describe '#has_photos?' do
     it 'returns false if the user has no photos' do
       expect(alice.person.has_photos?).to be false