diff --git a/src/remote/activitypub/kernel/accept/follow.ts b/src/remote/activitypub/kernel/accept/follow.ts
new file mode 100644
index 0000000000..9d425419ab
--- /dev/null
+++ b/src/remote/activitypub/kernel/accept/follow.ts
@@ -0,0 +1,27 @@
+import * as mongo from 'mongodb';
+import User, { IRemoteUser } from '../../../../models/user';
+import config from '../../../../config';
+import accept from '../../../../services/user/accept-follow-request';
+import { IFollow } from '../../type';
+
+export default async (actor: IRemoteUser, activity: IFollow): Promise<void> => {
+	const id = typeof activity.object == 'string' ? activity.object : activity.object.id;
+
+	if (!id.startsWith(config.url + '/')) {
+		return null;
+	}
+
+	const follower = await User.findOne({
+		_id: new mongo.ObjectID(id.split('/').pop())
+	});
+
+	if (follower === null) {
+		throw new Error('follower not found');
+	}
+
+	if (follower.host != null) {
+		throw new Error('フォローリクエストしたユーザーはローカルユーザーではありません');
+	}
+
+	await accept(actor, follower);
+};
diff --git a/src/remote/activitypub/kernel/accept/index.ts b/src/remote/activitypub/kernel/accept/index.ts
new file mode 100644
index 0000000000..b647df022e
--- /dev/null
+++ b/src/remote/activitypub/kernel/accept/index.ts
@@ -0,0 +1,35 @@
+import * as debug from 'debug';
+
+import Resolver from '../../resolver';
+import { IRemoteUser } from '../../../../models/user';
+import acceptFollow from './follow';
+import { IAccept } from '../../type';
+
+const log = debug('misskey:activitypub');
+
+export default async (actor: IRemoteUser, activity: IAccept): Promise<void> => {
+	const uri = activity.id || activity;
+
+	log(`Accept: ${uri}`);
+
+	const resolver = new Resolver();
+
+	let object;
+
+	try {
+		object = await resolver.resolve(activity.object);
+	} catch (e) {
+		log(`Resolution failed: ${e}`);
+		throw e;
+	}
+
+	switch (object.type) {
+	case 'Follow':
+	acceptFollow(resolver, actor, activity, object);
+		break;
+
+	default:
+		console.warn(`Unknown accept type: ${object.type}`);
+		break;
+	}
+};
diff --git a/src/remote/activitypub/renderer/follow.ts b/src/remote/activitypub/renderer/follow.ts
index bf8eeff06b..522422bcff 100644
--- a/src/remote/activitypub/renderer/follow.ts
+++ b/src/remote/activitypub/renderer/follow.ts
@@ -1,8 +1,8 @@
 import config from '../../../config';
-import { IRemoteUser, ILocalUser } from '../../../models/user';
+import { IUser, isLocalUser } from '../../../models/user';
 
-export default (follower: ILocalUser, followee: IRemoteUser) => ({
+export default (follower: IUser, followee: IUser) => ({
 	type: 'Follow',
-	actor: `${config.url}/users/${follower._id}`,
-	object: followee.uri
+	actor: isLocalUser(follower) ? `${config.url}/users/${follower._id}` : follower.uri,
+	object: isLocalUser(followee) ? `${config.url}/users/${followee._id}` : followee.uri
 });
diff --git a/src/server/api/endpoints/i/update.ts b/src/server/api/endpoints/i/update.ts
index 6e0c5b8515..5ca54d013c 100644
--- a/src/server/api/endpoints/i/update.ts
+++ b/src/server/api/endpoints/i/update.ts
@@ -12,50 +12,57 @@ import DriveFile from '../../../../models/drive-file';
 module.exports = async (params, user, app) => new Promise(async (res, rej) => {
 	const isSecure = user != null && app == null;
 
+	const updates = {} as any;
+
 	// Get 'name' parameter
 	const [name, nameErr] = $.str.optional().nullable().pipe(isValidName).get(params.name);
 	if (nameErr) return rej('invalid name param');
-	if (name) user.name = name;
+	if (name) updates.name = name;
 
 	// Get 'description' parameter
 	const [description, descriptionErr] = $.str.optional().nullable().pipe(isValidDescription).get(params.description);
 	if (descriptionErr) return rej('invalid description param');
-	if (description !== undefined) user.description = description;
+	if (description !== undefined) updates.description = description;
 
 	// Get 'location' parameter
 	const [location, locationErr] = $.str.optional().nullable().pipe(isValidLocation).get(params.location);
 	if (locationErr) return rej('invalid location param');
-	if (location !== undefined) user.profile.location = location;
+	if (location !== undefined) updates.profile.location = location;
 
 	// Get 'birthday' parameter
 	const [birthday, birthdayErr] = $.str.optional().nullable().pipe(isValidBirthday).get(params.birthday);
 	if (birthdayErr) return rej('invalid birthday param');
-	if (birthday !== undefined) user.profile.birthday = birthday;
+	if (birthday !== undefined) updates.profile.birthday = birthday;
 
 	// Get 'avatarId' parameter
 	const [avatarId, avatarIdErr] = $.type(ID).optional().get(params.avatarId);
 	if (avatarIdErr) return rej('invalid avatarId param');
-	if (avatarId) user.avatarId = avatarId;
+	if (avatarId) updates.avatarId = avatarId;
 
 	// Get 'bannerId' parameter
 	const [bannerId, bannerIdErr] = $.type(ID).optional().get(params.bannerId);
 	if (bannerIdErr) return rej('invalid bannerId param');
-	if (bannerId) user.bannerId = bannerId;
+	if (bannerId) updates.bannerId = bannerId;
+
+	// Get 'isLocked' parameter
+	const [isLocked, isLockedErr] = $.bool.optional().get(params.isLocked);
+	if (isLockedErr) return rej('invalid isLocked param');
+	if (isLocked != null) updates.isLocked = isLocked;
 
 	// Get 'isBot' parameter
 	const [isBot, isBotErr] = $.bool.optional().get(params.isBot);
 	if (isBotErr) return rej('invalid isBot param');
-	if (isBot != null) user.isBot = isBot;
+	if (isBot != null) updates.isBot = isBot;
 
 	// Get 'isCat' parameter
 	const [isCat, isCatErr] = $.bool.optional().get(params.isCat);
 	if (isCatErr) return rej('invalid isCat param');
-	if (isCat != null) user.isCat = isCat;
+	if (isCat != null) updates.isCat = isCat;
 
 	// Get 'autoWatch' parameter
 	const [autoWatch, autoWatchErr] = $.bool.optional().get(params.autoWatch);
 	if (autoWatchErr) return rej('invalid autoWatch param');
-	if (autoWatch != null) user.settings.autoWatch = autoWatch;
+	if (autoWatch != null) updates.settings.autoWatch = autoWatch;
 
 	if (avatarId) {
 		const avatar = await DriveFile.findOne({
@@ -63,7 +70,7 @@ module.exports = async (params, user, app) => new Promise(async (res, rej) => {
 		});
 
 		if (avatar != null && avatar.metadata.properties.avgColor) {
-			user.avatarColor = avatar.metadata.properties.avgColor;
+			updates.avatarColor = avatar.metadata.properties.avgColor;
 		}
 	}
 
@@ -73,23 +80,12 @@ module.exports = async (params, user, app) => new Promise(async (res, rej) => {
 		});
 
 		if (banner != null && banner.metadata.properties.avgColor) {
-			user.bannerColor = banner.metadata.properties.avgColor;
+			updates.bannerColor = banner.metadata.properties.avgColor;
 		}
 	}
 
 	await User.update(user._id, {
-		$set: {
-			name: user.name,
-			description: user.description,
-			avatarId: user.avatarId,
-			avatarColor: user.avatarColor,
-			bannerId: user.bannerId,
-			bannerColor: user.bannerColor,
-			profile: user.profile,
-			isBot: user.isBot,
-			isCat: user.isCat,
-			settings: user.settings
-		}
+		$set: updates
 	});
 
 	// Serialize
@@ -103,4 +99,9 @@ module.exports = async (params, user, app) => new Promise(async (res, rej) => {
 
 	// Publish i updated event
 	event(user._id, 'i_updated', iObj);
+
+	// 鍵垢を解除したとき、溜まっていたフォローリクエストがあるならすべて承認
+	if (user.isLocked && isLocked === false) {
+		acceptAllFollowRequests(user);
+	}
 });
diff --git a/src/services/following/create.ts b/src/services/following/create.ts
index 3424c55dae..03a8f399e8 100644
--- a/src/services/following/create.ts
+++ b/src/services/following/create.ts
@@ -8,72 +8,103 @@ import pack from '../../remote/activitypub/renderer';
 import renderFollow from '../../remote/activitypub/renderer/follow';
 import renderAccept from '../../remote/activitypub/renderer/accept';
 import { deliver } from '../../queue';
+import FollowRequest from '../../models/follow-request';
 
-export default async function(follower: IUser, followee: IUser, activity?) {
-	const following = await Following.insert({
-		createdAt: new Date(),
-		followerId: follower._id,
-		followeeId: followee._id,
-		stalk: true,
+export default async function(follower: IUser, followee: IUser) {
+	if (followee.isLocked) {
+		await FollowRequest.insert({
+			createdAt: new Date(),
+			followerId: follower._id,
+			followeeId: followee._id,
 
-		// 非正規化
-		_follower: {
-			host: follower.host,
-			inbox: isRemoteUser(follower) ? follower.inbox : undefined
-		},
-		_followee: {
-			host: followee.host,
-			inbox: isRemoteUser(followee) ? followee.inbox : undefined
+			// 非正規化
+			_follower: {
+				host: follower.host,
+				inbox: isRemoteUser(follower) ? follower.inbox : undefined
+			},
+			_followee: {
+				host: followee.host,
+				inbox: isRemoteUser(followee) ? followee.inbox : undefined
+			}
+		});
+
+		// Publish reciveRequest event
+		if (isLocalUser(followee)) {
+			packUser(follower, followee).then(packed => event(followee._id, 'reciveRequest', packed)),
+
+			// 通知を作成
+			notify(followee._id, follower._id, 'reciveRequest');
 		}
-	});
 
-	//#region Increment following count
-	User.update({ _id: follower._id }, {
-		$inc: {
-			followingCount: 1
+		if (isLocalUser(follower) && isRemoteUser(followee)) {
+			const content = pack(renderFollow(follower, followee));
+			deliver(follower, content, followee.inbox);
 		}
-	});
+	} else {
+		const following = await Following.insert({
+			createdAt: new Date(),
+			followerId: follower._id,
+			followeeId: followee._id,
 
-	FollowingLog.insert({
-		createdAt: following.createdAt,
-		userId: follower._id,
-		count: follower.followingCount + 1
-	});
-	//#endregion
+			// 非正規化
+			_follower: {
+				host: follower.host,
+				inbox: isRemoteUser(follower) ? follower.inbox : undefined
+			},
+			_followee: {
+				host: followee.host,
+				inbox: isRemoteUser(followee) ? followee.inbox : undefined
+			}
+		});
 
-	//#region Increment followers count
-	User.update({ _id: followee._id }, {
-		$inc: {
-			followersCount: 1
+		//#region Increment following count
+		User.update({ _id: follower._id }, {
+			$inc: {
+				followingCount: 1
+			}
+		});
+
+		FollowingLog.insert({
+			createdAt: following.createdAt,
+			userId: follower._id,
+			count: follower.followingCount + 1
+		});
+		//#endregion
+
+		//#region Increment followers count
+		User.update({ _id: followee._id }, {
+			$inc: {
+				followersCount: 1
+			}
+		});
+		FollowedLog.insert({
+			createdAt: following.createdAt,
+			userId: followee._id,
+			count: followee.followersCount + 1
+		});
+		//#endregion
+
+		// Publish follow event
+		if (isLocalUser(follower)) {
+			packUser(followee, follower).then(packed => event(follower._id, 'follow', packed));
 		}
-	});
-	FollowedLog.insert({
-		createdAt: following.createdAt,
-		userId: followee._id,
-		count: followee.followersCount + 1
-	});
-	//#endregion
 
-	// Publish follow event
-	if (isLocalUser(follower)) {
-		packUser(followee, follower).then(packed => event(follower._id, 'follow', packed));
-	}
+		// Publish followed event
+		if (isLocalUser(followee)) {
+			packUser(follower, followee).then(packed => event(followee._id, 'followed', packed)),
 
-	// Publish followed event
-	if (isLocalUser(followee)) {
-		packUser(follower, followee).then(packed => event(followee._id, 'followed', packed)),
+			// 通知を作成
+			notify(followee._id, follower._id, 'follow');
+		}
 
-		// 通知を作成
-		notify(followee._id, follower._id, 'follow');
-	}
+		if (isLocalUser(follower) && isRemoteUser(followee)) {
+			const content = pack(renderFollow(follower, followee));
+			deliver(follower, content, followee.inbox);
+		}
 
-	if (isLocalUser(follower) && isRemoteUser(followee)) {
-		const content = pack(renderFollow(follower, followee));
-		deliver(follower, content, followee.inbox);
-	}
-
-	if (isRemoteUser(follower) && isLocalUser(followee)) {
-		const content = pack(renderAccept(activity));
-		deliver(followee, content, follower.inbox);
+		if (isRemoteUser(follower) && isLocalUser(followee)) {
+			const content = pack(renderAccept(renderFollow(follower, followee)));
+			deliver(followee, content, follower.inbox);
+		}
 	}
 }
diff --git a/src/services/following/delete.ts b/src/services/following/delete.ts
index c0c99fbed5..4fc5d42476 100644
--- a/src/services/following/delete.ts
+++ b/src/services/following/delete.ts
@@ -8,7 +8,7 @@ import renderFollow from '../../remote/activitypub/renderer/follow';
 import renderUndo from '../../remote/activitypub/renderer/undo';
 import { deliver } from '../../queue';
 
-export default async function(follower: IUser, followee: IUser, activity?) {
+export default async function(follower: IUser, followee: IUser) {
 	const following = await Following.findOne({
 		followerId: follower._id,
 		followeeId: followee._id
diff --git a/src/services/user/accept-all-follow-requests.ts b/src/services/user/accept-all-follow-requests.ts
new file mode 100644
index 0000000000..fbb221e772
--- /dev/null
+++ b/src/services/user/accept-all-follow-requests.ts
@@ -0,0 +1,18 @@
+import User, { IUser } from "../../models/user";
+import FollowRequest from "../../models/follow-request";
+import accept from './accept-follow-request';
+
+/**
+ * 指定したユーザー宛てのフォローリクエストをすべて承認
+ * @param user ユーザー
+ */
+export default async function(user: IUser) {
+	const requests = await FollowRequest.find({
+		followeeId: user._id
+	});
+
+	requests.forEach(async request => {
+		const follower = await User.findOne({ _id: request.followerId });
+		accept(user, follower);
+	});
+}
diff --git a/src/services/user/accept-follow-request.ts b/src/services/user/accept-follow-request.ts
new file mode 100644
index 0000000000..8b5c82c84e
--- /dev/null
+++ b/src/services/user/accept-follow-request.ts
@@ -0,0 +1,64 @@
+import User, { IUser, isRemoteUser, ILocalUser } from "../../models/user";
+import FollowRequest from "../../models/follow-request";
+import pack from '../../remote/activitypub/renderer';
+import renderFollow from '../../remote/activitypub/renderer/follow';
+import renderAccept from '../../remote/activitypub/renderer/accept';
+import { deliver } from '../../queue';
+import Following from "../../models/following";
+import FollowingLog from "../../models/following-log";
+import FollowedLog from "../../models/followed-log";
+
+export default async function(followee: IUser, follower: IUser) {
+	const following = await Following.insert({
+		createdAt: new Date(),
+		followerId: follower._id,
+		followeeId: followee._id,
+
+		// 非正規化
+		_follower: {
+			host: follower.host,
+			inbox: isRemoteUser(follower) ? follower.inbox : undefined
+		},
+		_followee: {
+			host: followee.host,
+			inbox: isRemoteUser(followee) ? followee.inbox : undefined
+		}
+	});
+
+	if (isRemoteUser(follower)) {
+		const content = pack(renderAccept(renderFollow(follower, followee)));
+		deliver(followee as ILocalUser, content, follower.inbox);
+	}
+
+	FollowRequest.remove({
+		followeeId: followee._id,
+		followerId: follower._id
+	});
+
+	//#region Increment following count
+	User.update({ _id: follower._id }, {
+		$inc: {
+			followingCount: 1
+		}
+	});
+
+	FollowingLog.insert({
+		createdAt: following.createdAt,
+		userId: follower._id,
+		count: follower.followingCount + 1
+	});
+	//#endregion
+
+	//#region Increment followers count
+	User.update({ _id: followee._id }, {
+		$inc: {
+			followersCount: 1
+		}
+	});
+	FollowedLog.insert({
+		createdAt: following.createdAt,
+		userId: followee._id,
+		count: followee.followersCount + 1
+	});
+	//#endregion
+}