diff --git a/src/models/following.ts b/src/models/following.ts
index 3f8a9be50..fe9ce550d 100644
--- a/src/models/following.ts
+++ b/src/models/following.ts
@@ -2,6 +2,7 @@ import * as mongo from 'mongodb';
 import db from '../db/mongodb';
 
 const Following = db.get<IFollowing>('following');
+Following.createIndex(['followerId', 'followeeId'], { unique: true });
 export default Following;
 
 export type IFollowing = {
diff --git a/src/processor/http/follow.ts b/src/processor/http/follow.ts
index a7e4fa23d..7ec1ee675 100644
--- a/src/processor/http/follow.ts
+++ b/src/processor/http/follow.ts
@@ -1,7 +1,7 @@
 import { request } from 'https';
 import { sign } from 'http-signature';
 import { URL } from 'url';
-import User, { isLocalUser, pack as packUser, ILocalUser } from '../../models/user';
+import User, { isLocalUser, pack as packUser } from '../../models/user';
 import Following from '../../models/following';
 import event from '../../publishers/stream';
 import notify from '../../publishers/notify';
@@ -10,7 +10,7 @@ import render from '../../remote/activitypub/renderer/follow';
 import config from '../../config';
 
 export default ({ data }, done) => Following.findOne({ _id: data.following }).then(({ followerId, followeeId }) => {
-	const promisedFollower: Promise<ILocalUser> = User.findOne({ _id: followerId });
+	const promisedFollower = User.findOne({ _id: followerId });
 	const promisedFollowee = User.findOne({ _id: followeeId });
 
 	return Promise.all([
@@ -34,14 +34,18 @@ export default ({ data }, done) => Following.findOne({ _id: data.following }).th
 
 		// Publish follow event
 		Promise.all([promisedFollower, promisedFollowee]).then(([follower, followee]) => {
-			const followerEvent = packUser(followee, follower)
-				.then(packed => event(follower._id, 'follow', packed));
+			let followerEvent;
 			let followeeEvent;
 
+			if (isLocalUser(follower)) {
+				followerEvent = packUser(followee, follower)
+					.then(packed => event(follower._id, 'follow', packed));
+			}
+
 			if (isLocalUser(followee)) {
 				followeeEvent = packUser(follower, followee)
 					.then(packed => event(followee._id, 'followed', packed));
-			} else {
+			} else if (isLocalUser(follower)) {
 				followeeEvent = new Promise((resolve, reject) => {
 					const {
 						protocol,
diff --git a/src/remote/activitypub/act/follow.ts b/src/remote/activitypub/act/follow.ts
new file mode 100644
index 000000000..ec9e080df
--- /dev/null
+++ b/src/remote/activitypub/act/follow.ts
@@ -0,0 +1,51 @@
+import { MongoError } from 'mongodb';
+import parseAcct from '../../../acct/parse';
+import Following from '../../../models/following';
+import User from '../../../models/user';
+import config from '../../../config';
+import queue from '../../../queue';
+
+export default async (actor, activity) => {
+	const prefix = config.url + '/@';
+	const id = activity.object.id || activity.object;
+	let following;
+
+	if (!id.startsWith(prefix)) {
+		return null;
+	}
+
+	const { username, host } = parseAcct(id.slice(prefix.length));
+	if (host !== null) {
+		throw new Error();
+	}
+
+	const followee = await User.findOne({ username, host });
+	if (followee === null) {
+		throw new Error();
+	}
+
+	try {
+		following = await Following.insert({
+			createdAt: new Date(),
+			followerId: actor._id,
+			followeeId: followee._id
+		});
+	} catch (exception) {
+		// duplicate key error
+		if (exception instanceof MongoError && exception.code === 11000) {
+			return null;
+		}
+
+		throw exception;
+	}
+
+	await new Promise((resolve, reject) => {
+		queue.create('http', { type: 'follow', following: following._id }).save(error => {
+			if (error) {
+				reject(error);
+			} else {
+				resolve(null);
+			}
+		});
+	});
+};
diff --git a/src/remote/activitypub/act/index.ts b/src/remote/activitypub/act/index.ts
index 06d662c19..24320dcb1 100644
--- a/src/remote/activitypub/act/index.ts
+++ b/src/remote/activitypub/act/index.ts
@@ -1,4 +1,5 @@
 import create from './create';
+import follow from './follow';
 import createObject from '../create';
 import Resolver from '../resolver';
 
@@ -15,6 +16,9 @@ export default (actor, value, distribute) => {
 		case 'Create':
 			return create(resolver, actor, object, distribute);
 
+		case 'Follow':
+			return follow(actor, object);
+
 		default:
 			return null;
 		}