diff --git a/src/server/activitypub.ts b/src/server/activitypub.ts
index 42d90ab91..9adc3dd94 100644
--- a/src/server/activitypub.ts
+++ b/src/server/activitypub.ts
@@ -83,7 +83,7 @@ router.get('/notes/:note', async (ctx, next) => {
 	}
 
 	ctx.body = pack(await renderNote(note, false));
-	ctx.set('Cache-Control', 'private, max-age=0, must-revalidate');
+	ctx.set('Cache-Control', 'public, max-age=180');
 	setResponseType(ctx);
 });
 
@@ -162,7 +162,9 @@ async function userInfo(ctx: Router.IRouterContext, user: IUser) {
 	setResponseType(ctx);
 }
 
-router.get('/users/:user', async ctx => {
+router.get('/users/:user', async (ctx, next) => {
+	if (!isActivityPubReq(ctx)) return await next();
+
 	if (!ObjectID.isValid(ctx.params.user)) {
 		ctx.status = 404;
 		return;
diff --git a/src/server/web/index.ts b/src/server/web/index.ts
index 998fd2adf..59b8390ab 100644
--- a/src/server/web/index.ts
+++ b/src/server/web/index.ts
@@ -148,6 +148,27 @@ router.get('/@:user', async (ctx, next) => {
 	}
 });
 
+router.get('/users/:user', async ctx => {
+	if (!ObjectID.isValid(ctx.params.user)) {
+		ctx.status = 404;
+		return;
+	}
+
+	const userId = new ObjectID(ctx.params.user);
+
+	const user = await User.findOne({
+		_id: userId,
+		host: null
+	});
+
+	if (user === null) {
+		ctx.status = 404;
+		return;
+	}
+
+	ctx.redirect(`/@${user.username}${ user.host == null ? '' : '@' + user.host}`);
+});
+
 // Note
 router.get('/notes/:note', async ctx => {
 	if (ObjectID.isValid(ctx.params.note)) {
@@ -159,7 +180,12 @@ router.get('/notes/:note', async ctx => {
 				note: _note,
 				summary: getNoteSummary(_note)
 			});
-			ctx.set('Cache-Control', 'private, max-age=0, must-revalidate');
+
+			if (['public', 'home'].includes(note.visibility)) {
+				ctx.set('Cache-Control', 'public, max-age=180');
+			} else {
+				ctx.set('Cache-Control', 'private, max-age=0, must-revalidate');
+			}
 
 			return;
 		}