diff --git a/src/server/index.ts b/src/server/index.ts
index 92d46d46a2..1874790116 100644
--- a/src/server/index.ts
+++ b/src/server/index.ts
@@ -10,6 +10,7 @@ import * as morgan from 'morgan';
 import Accesses from 'accesses';
 
 import activityPub from './activitypub';
+import webFinger from './webfinger';
 import log from './log-request';
 import config from '../conf';
 
@@ -55,6 +56,7 @@ app.use((req, res, next) => {
 app.use('/api', require('./api'));
 app.use('/files', require('./file'));
 app.use(activityPub);
+app.use(webFinger);
 app.use(require('./web'));
 
 function createServer() {
diff --git a/src/server/webfinger.ts b/src/server/webfinger.ts
new file mode 100644
index 0000000000..864bb4af52
--- /dev/null
+++ b/src/server/webfinger.ts
@@ -0,0 +1,47 @@
+import config from '../conf';
+import parseAcct from '../common/user/parse-acct';
+import User from '../models/user';
+const express = require('express');
+
+const app = express();
+
+app.get('/.well-known/webfinger', async (req, res) => {
+	if (typeof req.query.resource !== 'string') {
+		return res.sendStatus(400);
+	}
+
+	const resourceLower = req.query.resource.toLowerCase();
+	const webPrefix = config.url.toLowerCase() + '/@';
+	let acctLower;
+
+	if (resourceLower.startsWith(webPrefix)) {
+		acctLower = resourceLower.slice(webPrefix.length);
+	} else if (resourceLower.startsWith('acct:')) {
+		acctLower = resourceLower.slice('acct:'.length);
+	} else {
+		acctLower = resourceLower;
+	}
+
+	const parsedAcctLower = parseAcct(acctLower);
+	if (![null, config.host.toLowerCase()].includes(parsedAcctLower.host)) {
+		return res.sendStatus(422);
+	}
+
+	const user = await User.findOne({ usernameLower: parsedAcctLower.username, host: null });
+	if (user === null) {
+		return res.sendStatus(404);
+	}
+
+	return res.json({
+		subject: `acct:${user.username}@${config.host}`,
+		links: [
+			{
+				rel: 'self',
+				type: 'application/activity+json',
+				href: `${config.url}/@${user.username}`
+			}
+		]
+	});
+});
+
+export default app;