diff --git a/app/controllers/api/subscriptions_controller.rb b/app/controllers/api/subscriptions_controller.rb
index e923b9b663fc0ecc3320eacfd55e70390744f956..84b88765a4c3fab4b5ba3ba4bde5f703958a8193 100644
--- a/app/controllers/api/subscriptions_controller.rb
+++ b/app/controllers/api/subscriptions_controller.rb
@@ -4,6 +4,7 @@ class Api::SubscriptionsController < ApiController
 
   def show
     if @account.subscription(api_subscription_url(@account.id)).valid?(params['hub.topic'], params['hub.verify_token'])
+      @account.update(subscription_expires_at: Time.now + (params['hub.lease_seconds'].to_i).seconds)
       render plain: HTMLEntities.new.encode(params['hub.challenge']), status: 200
     else
       head 404
diff --git a/app/models/account.rb b/app/models/account.rb
index 6e96defe49b2032426867fd561ef131881006f8f..449075aa8a5cbab3e4facba4e049c7921380fc72 100644
--- a/app/models/account.rb
+++ b/app/models/account.rb
@@ -38,6 +38,12 @@ class Account < ApplicationRecord
 
   has_many :media_attachments, dependent: :destroy
 
+  scope :remote, -> { where.not(domain: nil) }
+  scope :local, -> { where(domain: nil) }
+  scope :without_followers, -> { where('(select count(f.id) from follows as f where f.target_account_id = accounts.id) = 0') }
+  scope :with_followers, -> { where('(select count(f.id) from follows as f where f.target_account_id = accounts.id) > 0') }
+  scope :expiring, -> (time) { where(subscription_expires_at: nil).or(where('subscription_expires_at < ?', time)).remote.with_followers }
+
   def follow!(other_account)
     self.active_relationships.where(target_account: other_account).first_or_create!(target_account: other_account)
   end
diff --git a/app/services/follow_remote_account_service.rb b/app/services/follow_remote_account_service.rb
index 00285f47a903d4ef0ac41df5340b339c1409ed8d..f3a384ecca3a7e48071eb8b9767ec7f106bfce38 100644
--- a/app/services/follow_remote_account_service.rb
+++ b/app/services/follow_remote_account_service.rb
@@ -3,22 +3,18 @@ class FollowRemoteAccountService < BaseService
   # When creating, look up the user's webfinger and fetch all
   # important information from their feed
   # @param [String] uri User URI in the form of username@domain
-  # @param [Boolean] subscribe Whether to initiate a PubSubHubbub subscription
   # @return [Account]
-  def call(uri, subscribe = true)
+  def call(uri)
     username, domain = uri.split('@')
 
     return Account.find_local(username) if domain == Rails.configuration.x.local_domain || domain.nil?
 
     account = Account.find_remote(username, domain)
 
-    if account.nil?
-      Rails.logger.debug "Creating new remote account for #{uri}"
-      account = Account.new(username: username, domain: domain)
-    elsif account.subscribed?
-      Rails.logger.debug "Already subscribed to remote account #{uri}"
-      return account
-    end
+    return account unless account.nil?
+
+    Rails.logger.debug "Creating new remote account for #{uri}"
+    account = Account.new(username: username, domain: domain)
 
     data = Goldfinger.finger("acct:#{uri}")
 
@@ -45,16 +41,6 @@ class FollowRemoteAccountService < BaseService
     get_profile(feed, account)
     account.save!
 
-    if subscribe
-      account.secret       = SecureRandom.hex
-      account.verify_token = SecureRandom.hex
-
-      subscription = account.subscription(api_subscription_url(account.id))
-      subscription.subscribe
-
-      account.save!
-    end
-
     return account
   end
 
@@ -90,8 +76,3 @@ class FollowRemoteAccountService < BaseService
   end
 end
 
-class NoAuthorFeedError < StandardError
-end
-
-class NoHubError < StandardError
-end
diff --git a/app/services/follow_service.rb b/app/services/follow_service.rb
index 45f145df3a1f2e297d6f9040e023239c6c6ef5e2..fb782e871081c31102f5c1955a272a5d6ac3829d 100644
--- a/app/services/follow_service.rb
+++ b/app/services/follow_service.rb
@@ -12,6 +12,7 @@ class FollowService < BaseService
     if target_account.local?
       NotificationMailer.follow(target_account, source_account).deliver_later
     else
+      subscribe_service.(target_account)
       NotificationWorker.perform_async(follow.stream_entry.id, target_account.id)
     end
 
@@ -40,4 +41,8 @@ class FollowService < BaseService
   def follow_remote_account_service
     @follow_remote_account_service ||= FollowRemoteAccountService.new
   end
+
+  def subscribe_service
+    @subscribe_service ||= SubscribeService.new
+  end
 end
diff --git a/app/services/process_feed_service.rb b/app/services/process_feed_service.rb
index 5fde19547c03f0b527d76c6641e27f843afafa42..a692054947a00727122212fa3af2f04062431739 100644
--- a/app/services/process_feed_service.rb
+++ b/app/services/process_feed_service.rb
@@ -106,7 +106,7 @@ class ProcessFeedService < BaseService
   end
 
   def delete_post!(status)
-    RemoveStatusService.new.(status)
+    remove_status_service.(status)
   end
 
   def find_original_status(_xml, id)
@@ -126,7 +126,7 @@ class ProcessFeedService < BaseService
     account  = Account.find_by(username: username, domain: domain)
 
     if account.nil?
-      account = follow_remote_account_service.("#{username}@#{domain}", false)
+      account = follow_remote_account_service.("#{username}@#{domain}")
     end
 
     status = Status.new(account: account, uri: target_id(xml), text: target_content(xml), url: target_url(xml), created_at: published(xml), updated_at: updated(xml))
@@ -196,4 +196,8 @@ class ProcessFeedService < BaseService
   def update_remote_profile_service
     @update_remote_profile_service ||= UpdateRemoteProfileService.new
   end
+
+  def remove_status_service
+    @remove_status_service ||= RemoveStatusService.new
+  end
 end
diff --git a/app/services/process_interaction_service.rb b/app/services/process_interaction_service.rb
index 3266f73e3bb02459fba5c0e3b1eb9b57ae4483bc..1e3ed6b1279e1e960e069c3846d47dfda7590404 100644
--- a/app/services/process_interaction_service.rb
+++ b/app/services/process_interaction_service.rb
@@ -14,7 +14,7 @@ class ProcessInteractionService < BaseService
     account  = Account.find_by(username: username, domain: domain)
 
     if account.nil?
-      account = follow_remote_account_service.("#{username}@#{domain}", false)
+      account = follow_remote_account_service.("#{username}@#{domain}")
     end
 
     if salmon.verify(envelope, account.keypair)
@@ -71,7 +71,7 @@ class ProcessInteractionService < BaseService
     return if status.nil?
 
     if account.id == status.account_id
-      RemoveStatusService.new.(status)
+      remove_status_service.(status)
     end
   end
 
@@ -108,4 +108,8 @@ class ProcessInteractionService < BaseService
   def update_remote_profile_service
     @update_remote_profile_service ||= UpdateRemoteProfileService.new
   end
+
+  def remove_status_service
+    @remove_status_service ||= RemoveStatusService.new
+  end
 end
diff --git a/app/services/subscribe_service.rb b/app/services/subscribe_service.rb
new file mode 100644
index 0000000000000000000000000000000000000000..7ead559d5cfa2d811dfc1bd24e1efdd6d47b616d
--- /dev/null
+++ b/app/services/subscribe_service.rb
@@ -0,0 +1,20 @@
+class SubscribeService < BaseService
+  def call(account)
+    account.secret       = SecureRandom.hex
+    account.verify_token = SecureRandom.hex
+
+    subscription = account.subscription(api_subscription_url(account.id))
+    response = subscription.subscribe
+
+    unless response.successful?
+      account.secret       = ''
+      account.verify_token = ''
+
+      Rails.logger.debug "PuSH subscription request for #{account.acct} failed: #{response.message}"
+    end
+
+    account.save!
+  rescue HTTP::Error, OpenSSL::SSL::SSLError
+    Rails.logger.debug "PuSH subscription request for #{account.acct} could not be made due to HTTP or SSL error"
+  end
+end
diff --git a/db/migrate/20160919221059_add_subscription_expires_at_to_accounts.rb b/db/migrate/20160919221059_add_subscription_expires_at_to_accounts.rb
new file mode 100644
index 0000000000000000000000000000000000000000..5fd7f39e6a6189d558d86f91c686bf97f5631d83
--- /dev/null
+++ b/db/migrate/20160919221059_add_subscription_expires_at_to_accounts.rb
@@ -0,0 +1,5 @@
+class AddSubscriptionExpiresAtToAccounts < ActiveRecord::Migration[5.0]
+  def change
+    add_column :accounts, :subscription_expires_at, :datetime, null: true, default: nil
+  end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 4a3078e6421d8fd437db0168dc3b9f086ec90048..3179942c0130eaae02af5cc01e66d8c9209e7f02 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -10,26 +10,26 @@
 #
 # It's strongly recommended that you check this file into your version control system.
 
-ActiveRecord::Schema.define(version: 20160905150353) do
+ActiveRecord::Schema.define(version: 20160919221059) do
 
   # These are extensions that must be enabled in order to support this database
   enable_extension "plpgsql"
 
   create_table "accounts", force: :cascade do |t|
-    t.string   "username",            default: "", null: false
+    t.string   "username",                default: "", null: false
     t.string   "domain"
-    t.string   "verify_token",        default: "", null: false
-    t.string   "secret",              default: "", null: false
+    t.string   "verify_token",            default: "", null: false
+    t.string   "secret",                  default: "", null: false
     t.text     "private_key"
-    t.text     "public_key",          default: "", null: false
-    t.string   "remote_url",          default: "", null: false
-    t.string   "salmon_url",          default: "", null: false
-    t.string   "hub_url",             default: "", null: false
-    t.datetime "created_at",                       null: false
-    t.datetime "updated_at",                       null: false
-    t.text     "note",                default: "", null: false
-    t.string   "display_name",        default: "", null: false
-    t.string   "uri",                 default: "", null: false
+    t.text     "public_key",              default: "", null: false
+    t.string   "remote_url",              default: "", null: false
+    t.string   "salmon_url",              default: "", null: false
+    t.string   "hub_url",                 default: "", null: false
+    t.datetime "created_at",                           null: false
+    t.datetime "updated_at",                           null: false
+    t.text     "note",                    default: "", null: false
+    t.string   "display_name",            default: "", null: false
+    t.string   "uri",                     default: "", null: false
     t.string   "url"
     t.string   "avatar_file_name"
     t.string   "avatar_content_type"
@@ -40,6 +40,7 @@ ActiveRecord::Schema.define(version: 20160905150353) do
     t.integer  "header_file_size"
     t.datetime "header_updated_at"
     t.string   "avatar_remote_url"
+    t.datetime "subscription_expires_at"
     t.index ["username", "domain"], name: "index_accounts_on_username_and_domain", unique: true, using: :btree
   end
 
diff --git a/lib/tasks/mastodon.rake b/lib/tasks/mastodon.rake
index f59cdfcae21c1495e8e6e4e3511ad9f8debb6bca..5bc056a5657f39046f4f7d65e86d3ff5e4d8d35a 100644
--- a/lib/tasks/mastodon.rake
+++ b/lib/tasks/mastodon.rake
@@ -11,9 +11,16 @@ namespace :mastodon do
   namespace :push do
     desc 'Unsubscribes from PuSH updates of feeds nobody follows locally'
     task clear: :environment do
-      Account.where('(select count(f.id) from follows as f where f.target_account_id = accounts.id) = 0').where.not(domain: nil).find_each do |a|
+      Account.remote.without_followers.find_each do |a|
         a.subscription('').unsubscribe
-        a.update!(verify_token: '', secret: '')
+        a.update!(verify_token: '', secret: '', subscription_expires_at: nil)
+      end
+    end
+
+    desc 'Re-subscribes to soon expiring PuSH subscriptions'
+    task refresh: :environment do
+      Account.expiring(1.day.from_now).find_each do |a|
+        SubscribeService.new.(a)
       end
     end
   end