diff --git a/locales/en.yml b/locales/en.yml
index 6104cbdc9d..e15a7c9ae4 100644
--- a/locales/en.yml
+++ b/locales/en.yml
@@ -243,6 +243,10 @@ desktop:
       title: "Notifications"
       settings: "Notification settings"
 
+    mk-server-home-widget:
+      title: "Server info"
+      toggle: "Toggle views"
+
     mk-activity-home-widget:
       title: "Activity"
       toggle: "Toggle views"
diff --git a/locales/ja.yml b/locales/ja.yml
index e83c0eb724..5ed1d4f1ee 100644
--- a/locales/ja.yml
+++ b/locales/ja.yml
@@ -243,6 +243,10 @@ desktop:
       title: "通知"
       settings: "通知の設定"
 
+    mk-server-home-widget:
+      title: "サーバー情報"
+      toggle: "表示を切り替え"
+
     mk-activity-home-widget:
       title: "アクティビティ"
       toggle: "表示を切り替え"
diff --git a/package.json b/package.json
index fd10ea50cb..93f87561fa 100644
--- a/package.json
+++ b/package.json
@@ -1,150 +1,153 @@
 {
-	"name": "misskey",
-	"author": "syuilo <i@syuilo.com>",
-	"version": "0.0.2038",
-	"license": "MIT",
-	"description": "A miniblog-based SNS",
-	"bugs": "https://github.com/syuilo/misskey/issues",
-	"repository": "https://github.com/syuilo/misskey.git",
-	"main": "./built/index.js",
-	"private": true,
-	"scripts": {
-		"config": "node ./tools/init.js",
-		"start": "node ./built",
-		"debug": "DEBUG=misskey:* node ./built",
-		"swagger": "node ./swagger.js",
-		"build": "gulp build",
-		"rebuild": "gulp rebuild",
-		"clean": "gulp clean",
-		"cleanall": "gulp cleanall",
-		"lint": "gulp lint",
-		"test": "gulp test"
-	},
-	"devDependencies": {
-		"@types/bcryptjs": "2.4.0",
-		"@types/body-parser": "1.16.3",
-		"@types/chai": "4.0.0",
-		"@types/chai-http": "0.0.30",
-		"@types/chalk": "0.4.31",
-		"@types/compression": "0.0.33",
-		"@types/cors": "2.8.1",
-		"@types/debug": "0.0.29",
-		"@types/deep-equal": "1.0.0",
-		"@types/elasticsearch": "5.0.13",
-		"@types/event-stream": "3.3.31",
-		"@types/express": "4.0.35",
-		"@types/gm": "1.17.31",
-		"@types/gulp": "4.0.3",
-		"@types/gulp-mocha": "0.0.30",
-		"@types/gulp-rename": "0.0.32",
-		"@types/gulp-replace": "0.0.30",
-		"@types/gulp-tslint": "3.6.31",
-		"@types/gulp-typescript": "2.13.0",
-		"@types/gulp-uglify": "0.0.30",
-		"@types/gulp-util": "3.0.31",
-		"@types/inquirer": "0.0.34",
-		"@types/is-root": "1.0.0",
-		"@types/is-url": "1.2.28",
-		"@types/js-yaml": "3.5.30",
-		"@types/mocha": "2.2.41",
-		"@types/mongodb": "2.2.3",
-		"@types/monk": "1.0.5",
-		"@types/morgan": "1.7.32",
-		"@types/ms": "0.7.29",
-		"@types/multer": "0.0.34",
-		"@types/node": "7.0.29",
-		"@types/ratelimiter": "2.1.28",
-		"@types/redis": "2.6.0",
-		"@types/request": "0.0.43",
-		"@types/rimraf": "0.0.28",
-		"@types/riot": "2.6.2",
-		"@types/serve-favicon": "2.2.28",
-		"@types/uuid": "3.0.0",
-		"@types/webpack": "2.2.15",
-		"@types/webpack-stream": "3.2.7",
-		"@types/websocket": "0.0.33",
-		"chai": "4.0.2",
-		"chai-http": "3.0.0",
-		"css-loader": "0.28.4",
-		"event-stream": "3.3.4",
-		"gulp": "3.9.1",
-		"gulp-cssnano": "2.1.2",
-		"gulp-imagemin": "3.3.0",
-		"gulp-mocha": "4.3.1",
-		"gulp-pug": "3.3.0",
-		"gulp-rename": "1.2.2",
-		"gulp-replace": "0.5.4",
-		"gulp-tslint": "8.1.1",
-		"gulp-typescript": "3.1.7",
-		"gulp-uglify": "3.0.0",
-		"gulp-util": "3.0.8",
-		"mocha": "3.4.2",
-		"riot-tag-loader": "1.0.0",
-		"string-replace-webpack-plugin": "0.1.3",
-		"style-loader": "0.18.2",
-		"stylus": "0.54.5",
-		"stylus-loader": "3.0.1",
-		"swagger-jsdoc": "1.9.4",
-		"tslint": "5.4.3",
-		"uglify-es": "3.0.15",
-		"uglify-es-webpack-plugin": "0.0.2",
-		"uglify-js": "git+https://github.com/mishoo/UglifyJS2.git#harmony",
-		"webpack": "2.6.1"
-	},
-	"dependencies": {
-		"accesses": "2.5.0",
-		"animejs": "2.0.2",
-		"autwh": "0.0.1",
-		"bcryptjs": "2.4.3",
-		"body-parser": "1.17.2",
-		"cafy": "2.4.0",
-		"chalk": "1.1.3",
-		"compression": "1.6.2",
-		"cors": "2.8.3",
-		"cropperjs": "1.0.0-rc.2",
-		"crypto": "0.0.3",
-		"debug": "2.6.8",
-		"deep-equal": "1.0.1",
-		"deepcopy": "0.6.3",
-		"download": "6.2.2",
-		"elasticsearch": "13.0.1",
-		"escape-regexp": "0.0.1",
-		"express": "4.15.3",
-		"file-type": "5.0.0",
-		"fuckadblock": "3.2.1",
-		"gm": "1.23.0",
-		"inquirer": "3.1.0",
-		"is-root": "1.0.0",
-		"is-url": "1.2.2",
-		"js-yaml": "3.8.4",
-		"mongodb": "2.2.28",
-		"monk": "6.0.0",
-		"morgan": "1.8.2",
-		"ms": "2.0.0",
-		"multer": "1.3.0",
-		"nprogress": "0.2.0",
-		"page": "1.7.1",
-		"pictograph": "2.0.4",
-		"prominence": "0.2.0",
-		"pug": "2.0.0-rc.2",
-		"ratelimiter": "3.0.3",
-		"recaptcha-promise": "0.1.2",
-		"reconnecting-websocket": "3.0.5",
-		"redis": "2.7.1",
-		"request": "2.81.0",
-		"rimraf": "2.6.1",
-		"riot": "3.6.0",
-		"rndstr": "1.0.0",
-		"s-age": "1.1.0",
-		"serve-favicon": "2.4.3",
-		"summaly": "2.0.3",
-		"syuilo-password-strength": "0.0.1",
-		"tcp-port-used": "0.1.2",
-		"textarea-caret": "3.0.2",
-		"ts-node": "3.0.6",
-		"typescript": "2.3.4",
-		"uuid": "3.0.1",
-		"vhost": "3.0.2",
-		"websocket": "1.0.24"
-	}
+  "name": "misskey",
+  "author": "syuilo <i@syuilo.com>",
+  "version": "0.0.2038",
+  "license": "MIT",
+  "description": "A miniblog-based SNS",
+  "bugs": "https://github.com/syuilo/misskey/issues",
+  "repository": "https://github.com/syuilo/misskey.git",
+  "main": "./built/index.js",
+  "private": true,
+  "scripts": {
+    "config": "node ./tools/init.js",
+    "start": "node ./built",
+    "debug": "DEBUG=misskey:* node ./built",
+    "swagger": "node ./swagger.js",
+    "build": "gulp build",
+    "rebuild": "gulp rebuild",
+    "clean": "gulp clean",
+    "cleanall": "gulp cleanall",
+    "lint": "gulp lint",
+    "test": "gulp test"
+  },
+  "devDependencies": {
+    "@types/bcryptjs": "2.4.0",
+    "@types/body-parser": "1.16.3",
+    "@types/chai": "4.0.0",
+    "@types/chai-http": "0.0.30",
+    "@types/chalk": "0.4.31",
+    "@types/compression": "0.0.33",
+    "@types/cors": "2.8.1",
+    "@types/debug": "0.0.29",
+    "@types/deep-equal": "1.0.0",
+    "@types/elasticsearch": "5.0.13",
+    "@types/event-stream": "3.3.31",
+    "@types/express": "4.0.35",
+    "@types/gm": "1.17.31",
+    "@types/gulp": "4.0.3",
+    "@types/gulp-mocha": "0.0.30",
+    "@types/gulp-rename": "0.0.32",
+    "@types/gulp-replace": "0.0.30",
+    "@types/gulp-tslint": "3.6.31",
+    "@types/gulp-typescript": "2.13.0",
+    "@types/gulp-uglify": "0.0.30",
+    "@types/gulp-util": "3.0.31",
+    "@types/inquirer": "0.0.34",
+    "@types/is-root": "1.0.0",
+    "@types/is-url": "1.2.28",
+    "@types/js-yaml": "3.5.30",
+    "@types/mocha": "2.2.41",
+    "@types/mongodb": "2.2.3",
+    "@types/monk": "1.0.5",
+    "@types/morgan": "1.7.32",
+    "@types/ms": "0.7.29",
+    "@types/multer": "0.0.34",
+    "@types/node": "7.0.29",
+    "@types/ratelimiter": "2.1.28",
+    "@types/redis": "2.6.0",
+    "@types/request": "0.0.43",
+    "@types/rimraf": "0.0.28",
+    "@types/riot": "2.6.2",
+    "@types/serve-favicon": "2.2.28",
+    "@types/uuid": "3.0.0",
+    "@types/webpack": "2.2.15",
+    "@types/webpack-stream": "3.2.7",
+    "@types/websocket": "0.0.33",
+    "chai": "4.0.2",
+    "chai-http": "3.0.0",
+    "css-loader": "0.28.4",
+    "event-stream": "3.3.4",
+    "gulp": "3.9.1",
+    "gulp-cssnano": "2.1.2",
+    "gulp-imagemin": "3.3.0",
+    "gulp-mocha": "4.3.1",
+    "gulp-pug": "3.3.0",
+    "gulp-rename": "1.2.2",
+    "gulp-replace": "0.5.4",
+    "gulp-tslint": "8.1.1",
+    "gulp-typescript": "3.1.7",
+    "gulp-uglify": "3.0.0",
+    "gulp-util": "3.0.8",
+    "mocha": "3.4.2",
+    "riot-tag-loader": "1.0.0",
+    "string-replace-webpack-plugin": "0.1.3",
+    "style-loader": "0.18.2",
+    "stylus": "0.54.5",
+    "stylus-loader": "3.0.1",
+    "swagger-jsdoc": "1.9.4",
+    "tslint": "5.4.3",
+    "uglify-es": "3.0.15",
+    "uglify-es-webpack-plugin": "0.0.2",
+    "uglify-js": "git+https://github.com/mishoo/UglifyJS2.git#harmony",
+    "webpack": "2.6.1"
+  },
+  "dependencies": {
+    "accesses": "2.5.0",
+    "animejs": "2.0.2",
+    "autwh": "0.0.1",
+    "bcryptjs": "2.4.3",
+    "body-parser": "1.17.2",
+    "cafy": "2.4.0",
+    "chalk": "1.1.3",
+    "compression": "1.6.2",
+    "cors": "2.8.3",
+    "cropperjs": "1.0.0-rc.2",
+    "crypto": "0.0.3",
+    "debug": "2.6.8",
+    "deep-equal": "1.0.1",
+    "deepcopy": "0.6.3",
+    "diskusage": "^0.2.2",
+    "download": "6.2.2",
+    "elasticsearch": "13.0.1",
+    "escape-regexp": "0.0.1",
+    "express": "4.15.3",
+    "file-type": "5.0.0",
+    "fuckadblock": "3.2.1",
+    "gm": "1.23.0",
+    "inquirer": "3.1.0",
+    "is-root": "1.0.0",
+    "is-url": "1.2.2",
+    "js-yaml": "3.8.4",
+    "mongodb": "2.2.28",
+    "monk": "6.0.0",
+    "morgan": "1.8.2",
+    "ms": "2.0.0",
+    "multer": "1.3.0",
+    "nprogress": "0.2.0",
+    "os-utils": "0.0.14",
+    "page": "1.7.1",
+    "pictograph": "2.0.4",
+    "prominence": "0.2.0",
+    "pug": "2.0.0-rc.2",
+    "ratelimiter": "3.0.3",
+    "recaptcha-promise": "0.1.2",
+    "reconnecting-websocket": "3.0.5",
+    "redis": "2.7.1",
+    "request": "2.81.0",
+    "rimraf": "2.6.1",
+    "riot": "3.6.0",
+    "rndstr": "1.0.0",
+    "s-age": "1.1.0",
+    "serve-favicon": "2.4.3",
+    "summaly": "2.0.3",
+    "syuilo-password-strength": "0.0.1",
+    "tcp-port-used": "0.1.2",
+    "textarea-caret": "3.0.2",
+    "ts-node": "3.0.6",
+    "typescript": "2.3.4",
+    "uuid": "3.0.1",
+    "vhost": "3.0.2",
+    "websocket": "1.0.24",
+    "xev": "^2.0.0"
+  }
 }
diff --git a/src/api/stream/server.ts b/src/api/stream/server.ts
new file mode 100644
index 0000000000..6de5337499
--- /dev/null
+++ b/src/api/stream/server.ts
@@ -0,0 +1,20 @@
+import * as websocket from 'websocket';
+import Xev from 'xev';
+
+const ev = new Xev();
+
+export default function homeStream(request: websocket.request, connection: websocket.connection): void {
+	const onStats = stats => {
+		connection.send(JSON.stringify({
+			type: 'stats',
+			body: stats
+		}));
+	};
+
+	ev.addListener('stats', onStats);
+
+	connection.on('close', () => {
+		console.log('yooo');
+		ev.removeListener('stats', onStats);
+	});
+}
diff --git a/src/api/streaming.ts b/src/api/streaming.ts
index e1d79481d3..c71132100c 100644
--- a/src/api/streaming.ts
+++ b/src/api/streaming.ts
@@ -8,6 +8,7 @@ import isNativeToken from './common/is-native-token';
 
 import homeStream from './stream/home';
 import messagingStream from './stream/messaging';
+import serverStream from './stream/server';
 
 module.exports = (server: http.Server) => {
 	/**
@@ -20,6 +21,11 @@ module.exports = (server: http.Server) => {
 	ws.on('request', async (request) => {
 		const connection = request.accept();
 
+		if (request.resourceURL.pathname === '/server') {
+			serverStream(request, connection);
+			return;
+		}
+
 		const user = await authenticate(connection, request.resourceURL.query.i);
 
 		if (user == null) {
diff --git a/src/index.ts b/src/index.ts
index 0b568b5d44..da83dde108 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -12,17 +12,20 @@ import * as chalk from 'chalk';
 // import portUsed = require('tcp-port-used');
 import isRoot = require('is-root');
 import { master } from 'accesses';
+import Xev from 'xev';
 
 import Logger from './utils/logger';
 import ProgressBar from './utils/cli/progressbar';
 import EnvironmentInfo from './utils/environmentInfo';
 import MachineInfo from './utils/machineInfo';
 import DependencyInfo from './utils/dependencyInfo';
+import stats from './utils/stats';
 
 import { Config, path as configPath } from './config';
 import loadConfig from './config';
 
 const clusterLog = debug('misskey:cluster');
+const ev = new Xev();
 
 process.title = 'Misskey';
 
@@ -35,6 +38,9 @@ main();
 function main() {
 	if (cluster.isMaster) {
 		masterMain();
+
+		ev.mount();
+		stats();
 	} else {
 		workerMain();
 	}
diff --git a/src/utils/stats.ts b/src/utils/stats.ts
new file mode 100644
index 0000000000..1615268310
--- /dev/null
+++ b/src/utils/stats.ts
@@ -0,0 +1,25 @@
+import * as os from 'os';
+const osUtils = require('os-utils');
+import * as diskusage from 'diskusage';
+import Xev from 'xev';
+
+const ev = new Xev();
+
+/**
+ * Report stats regularly
+ */
+export default function() {
+	setInterval(() => {
+		osUtils.cpuUsage(cpuUsage => {
+			const disk = diskusage.checkSync(os.platform() == 'win32' ? 'c:' : '/');
+			ev.emit('stats', {
+				cpu_usage: cpuUsage,
+				mem: {
+					total: os.totalmem(),
+					free: os.freemem()
+				},
+				disk
+			});
+		});
+	}, 1000);
+}
diff --git a/src/web/app/common/scripts/home-stream.js b/src/web/app/common/scripts/home-stream.js
new file mode 100644
index 0000000000..24f13cd291
--- /dev/null
+++ b/src/web/app/common/scripts/home-stream.js
@@ -0,0 +1,18 @@
+'use strict';
+
+import Stream from './stream';
+
+/**
+ * Home stream connection
+ */
+class Connection extends Stream {
+	constructor(me) {
+		super('', {
+			i: me.token
+		});
+
+		this.on('i_updated', me.update);
+	}
+}
+
+export default Connection;
diff --git a/src/web/app/common/scripts/messaging-stream.js b/src/web/app/common/scripts/messaging-stream.js
index 50d41c2be9..261525d5f6 100644
--- a/src/web/app/common/scripts/messaging-stream.js
+++ b/src/web/app/common/scripts/messaging-stream.js
@@ -1,42 +1,22 @@
-const ReconnectingWebSocket = require('reconnecting-websocket');
-import * as riot from 'riot';
-import CONFIG from './config';
+'use strict';
 
-class Connection {
+import Stream from './stream';
+
+/**
+ * Messaging stream connection
+ */
+class Connection extends Stream {
 	constructor(me, otherparty) {
-		// BIND -----------------------------------
-		this.onOpen =    this.onOpen.bind(this);
-		this.onMessage = this.onMessage.bind(this);
-		this.close =     this.close.bind(this);
-		// ----------------------------------------
+		super('messaging', {
+			i: me.token,
+			otherparty
+		});
 
-		this.event = riot.observable();
-		this.me = me;
-
-		const host = CONFIG.apiUrl.replace('http', 'ws');
-		this.socket = new ReconnectingWebSocket(`${host}/messaging?i=${me.token}&otherparty=${otherparty}`);
-		this.socket.addEventListener('open', this.onOpen);
-		this.socket.addEventListener('message', this.onMessage);
-	}
-
-	onOpen() {
-		this.socket.send(JSON.stringify({
-			i: this.me.token
-		}));
-	}
-
-	onMessage(message) {
-		try {
-			const msg = JSON.parse(message.data);
-			if (msg.type) this.event.trigger(msg.type, msg.body);
-		} catch(e) {
-			// noop
-		}
-	}
-
-	close() {
-		this.socket.removeEventListener('open', this.onOpen);
-		this.socket.removeEventListener('message', this.onMessage);
+		this.on('_connected_', () => {
+			this.send({
+				i: me.token
+			});
+		});
 	}
 }
 
diff --git a/src/web/app/common/scripts/server-stream.js b/src/web/app/common/scripts/server-stream.js
new file mode 100644
index 0000000000..a1c466b35d
--- /dev/null
+++ b/src/web/app/common/scripts/server-stream.js
@@ -0,0 +1,14 @@
+'use strict';
+
+import Stream from './stream';
+
+/**
+ * Server stream connection
+ */
+class Connection extends Stream {
+	constructor() {
+		super('server');
+	}
+}
+
+export default Connection;
diff --git a/src/web/app/common/scripts/stream.js b/src/web/app/common/scripts/stream.js
index ac3dd67153..981118b5de 100644
--- a/src/web/app/common/scripts/stream.js
+++ b/src/web/app/common/scripts/stream.js
@@ -5,10 +5,10 @@ import * as riot from 'riot';
 import CONFIG from './config';
 
 /**
- * Home stream connection
+ * Misskey stream connection
  */
 class Connection {
-	constructor(me) {
+	constructor(endpoint, params) {
 		// BIND -----------------------------------
 		this.onOpen =    this.onOpen.bind(this);
 		this.onClose =   this.onClose.bind(this);
@@ -20,16 +20,19 @@ class Connection {
 		riot.observable(this);
 
 		this.state = 'initializing';
-		this.me = me;
 		this.buffer = [];
 
 		const host = CONFIG.apiUrl.replace('http', 'ws');
-		this.socket = new ReconnectingWebSocket(`${host}?i=${me.token}`);
+		const query = params
+			? Object.keys(params)
+				.map(k => encodeURIComponent(k) + '=' + encodeURIComponent(params[k]))
+				.join('&')
+			: null;
+
+		this.socket = new ReconnectingWebSocket(`${host}/${endpoint}${query ? '?' + query : ''}`);
 		this.socket.addEventListener('open', this.onOpen);
 		this.socket.addEventListener('close', this.onClose);
 		this.socket.addEventListener('message', this.onMessage);
-
-		this.on('i_updated', me.update);
 	}
 
 	/**
diff --git a/src/web/app/common/tags/messaging/room.tag b/src/web/app/common/tags/messaging/room.tag
index bd49a4d782..93f07f2cee 100644
--- a/src/web/app/common/tags/messaging/room.tag
+++ b/src/web/app/common/tags/messaging/room.tag
@@ -137,8 +137,8 @@
 		this.connection = new MessagingStreamConnection(this.I, this.user.id);
 
 		this.on('mount', () => {
-			this.connection.event.on('message', this.onMessage);
-			this.connection.event.on('read', this.onRead);
+			this.connection.on('message', this.onMessage);
+			this.connection.on('read', this.onRead);
 
 			document.addEventListener('visibilitychange', this.onVisibilitychange);
 
@@ -153,8 +153,8 @@
 		});
 
 		this.on('unmount', () => {
-			this.connection.event.off('message', this.onMessage);
-			this.connection.event.off('read', this.onRead);
+			this.connection.off('message', this.onMessage);
+			this.connection.off('read', this.onRead);
 			this.connection.close();
 
 			document.removeEventListener('visibilitychange', this.onVisibilitychange);
@@ -174,10 +174,10 @@
 
 			this.messages.push(message);
 			if (message.user_id != this.I.id && !document.hidden) {
-				this.connection.socket.send(JSON.stringify({
+				this.connection.send({
 					type: 'read',
 					id: message.id
-				}));
+				});
 			}
 			this.update();
 
@@ -239,10 +239,10 @@
 			if (document.hidden) return;
 			this.messages.forEach(message => {
 				if (message.user_id !== this.I.id && !message.is_read) {
-					this.connection.socket.send(JSON.stringify({
+					this.connection.send({
 						type: 'read',
 						id: message.id
-					}));
+					});
 				}
 			});
 		};
diff --git a/src/web/app/desktop/tags/home-widgets/activity.tag b/src/web/app/desktop/tags/home-widgets/activity.tag
index 621702fa17..3a8afdfa33 100644
--- a/src/web/app/desktop/tags/home-widgets/activity.tag
+++ b/src/web/app/desktop/tags/home-widgets/activity.tag
@@ -100,6 +100,8 @@
 	</svg>
 	<style>
 		:scope
+			display block
+
 			> svg
 				display block
 				padding 10px
@@ -131,7 +133,7 @@
 </mk-activity-home-widget-calender>
 
 <mk-activity-home-widget-chart>
-	<svg riot-viewBox="0 0 { viewBoxX } 60" preserveAspectRatio="none" onmousedown={ onMousedown }>
+	<svg riot-viewBox="0 0 { viewBoxX } { viewBoxY }" preserveAspectRatio="none" onmousedown={ onMousedown }>
 		<polyline
 			riot-points={ pointsPost }
 			fill="none"
@@ -155,6 +157,8 @@
 	</svg>
 	<style>
 		:scope
+			display block
+
 			> svg
 				display block
 				padding 10px
@@ -163,6 +167,7 @@
 	</style>
 	<script>
 		this.viewBoxX = 140;
+		this.viewBoxY = 60;
 		this.zoom = 1;
 		this.pos = 0;
 
@@ -176,10 +181,10 @@
 
 		this.render = () => {
 			this.update({
-				pointsPost: this.data.map((d, i) => `${(i * this.zoom) + this.pos},${(1 - (d.posts / peak)) * 60}`).join(' '),
-				pointsReply: this.data.map((d, i) => `${(i * this.zoom) + this.pos},${(1 - (d.replies / peak)) * 60}`).join(' '),
-				pointsRepost: this.data.map((d, i) => `${(i * this.zoom) + this.pos},${(1 - (d.reposts / peak)) * 60}`).join(' '),
-				pointsTotal: this.data.map((d, i) => `${(i * this.zoom) + this.pos},${(1 - (d.total / peak)) * 60}`).join(' ')
+				pointsPost: this.data.map((d, i) => `${(i * this.zoom) + this.pos},${(1 - (d.posts / peak)) * this.viewBoxY}`).join(' '),
+				pointsReply: this.data.map((d, i) => `${(i * this.zoom) + this.pos},${(1 - (d.replies / peak)) * this.viewBoxY}`).join(' '),
+				pointsRepost: this.data.map((d, i) => `${(i * this.zoom) + this.pos},${(1 - (d.reposts / peak)) * this.viewBoxY}`).join(' '),
+				pointsTotal: this.data.map((d, i) => `${(i * this.zoom) + this.pos},${(1 - (d.total / peak)) * this.viewBoxY}`).join(' ')
 			});
 		};
 
diff --git a/src/web/app/desktop/tags/home-widgets/server.tag b/src/web/app/desktop/tags/home-widgets/server.tag
new file mode 100644
index 0000000000..7a51299585
--- /dev/null
+++ b/src/web/app/desktop/tags/home-widgets/server.tag
@@ -0,0 +1,177 @@
+<mk-server-home-widget>
+	<p class="title"><i class="fa fa-server"></i>%i18n:desktop.tags.mk-server-home-widget.title%</p>
+	<button onclick={ toggle } title="%i18n:desktop.tags.mk-server-home-widget.toggle%"><i class="fa fa-sort"></i></button>
+	<p class="initializing" if={ initializing }><i class="fa fa-spinner fa-pulse fa-fw"></i>%i18n:common.loading%<mk-ellipsis/></p>
+	<mk-server-home-widget-stats if={ !initializing && view == 0 }/>
+	<mk-server-home-widget-info if={ !initializing && view == 1 } meta={ meta }/>
+	<style>
+		:scope
+			display block
+			background #fff
+
+			> .title
+				z-index 1
+				margin 0
+				padding 0 16px
+				line-height 42px
+				font-size 0.9em
+				font-weight bold
+				color #888
+				box-shadow 0 1px rgba(0, 0, 0, 0.07)
+
+				> i
+					margin-right 4px
+
+			> button
+				position absolute
+				z-index 2
+				top 0
+				right 0
+				padding 0
+				width 42px
+				font-size 0.9em
+				line-height 42px
+				color #ccc
+
+				&:hover
+					color #aaa
+
+				&:active
+					color #999
+
+			> .initializing
+				margin 0
+				padding 16px
+				text-align center
+				color #aaa
+
+				> i
+					margin-right 4px
+
+	</style>
+	<script>
+		this.mixin('api');
+
+		this.initializing = true;
+		this.view = 0;
+
+		this.on('mount', () => {
+			this.api('meta').then(meta => {
+				this.update({
+					initializing: false,
+					meta
+				});
+			});
+		});
+
+		this.toggle = () => {
+			this.view++;
+			if (this.view == 2) this.view = 0;
+		};
+	</script>
+</mk-server-home-widget>
+
+<mk-server-home-widget-stats>
+	<svg riot-viewBox="0 0 { viewBoxX } { viewBoxY }" preserveAspectRatio="none">
+		<text dx="1" dy="5">CPU</text>
+		<polygon
+			riot-points={ cpuPolygonPoints }
+			riot-fill={ cpuColor }
+			fill-opacity="0.5"/>
+		<polyline
+			riot-points={ cpuPolylinePoints }
+			fill="none"
+			stroke-width="1"
+			riot-stroke={ cpuColor }/>
+	</svg>
+	<svg riot-viewBox="0 0 { viewBoxX } { viewBoxY }" preserveAspectRatio="none">
+		<text dx="1" dy="5">MEM</text>
+		<polygon
+			riot-points={ memPolygonPoints }
+			riot-fill={ memColor }
+			fill-opacity="0.5"/>
+		<polyline
+			riot-points={ memPolylinePoints }
+			fill="none"
+			stroke-width="1"
+			riot-stroke={ memColor }/>
+	</svg>
+	<style>
+		:scope
+			display block
+
+			> svg
+				display block
+				padding 10px
+				width 50%
+				float left
+
+				&:first-child
+					padding-right 5px
+
+				&:last-child
+					padding-left 5px
+
+				> text
+					font-size 5px
+					fill #7b7b7b
+
+			&:after
+				content ""
+				display block
+				clear both
+	</style>
+	<script>
+		import Connection from '../../../common/scripts/server-stream';
+
+		this.viewBoxX = 50;
+		this.viewBoxY = 30;
+		this.stats = [];
+		this.connection = new Connection();
+
+		this.on('mount', () => {
+			this.connection.on('stats', this.onStats);
+		});
+
+		this.on('unmount', () => {
+			this.connection.off('stats', this.onStats);
+			this.connection.close();
+		});
+
+		this.onStats = stats => {
+			this.stats.push(stats);
+			if (this.stats.length > 50) this.stats.shift();
+
+			const cpuPolylinePoints = this.stats.map((s, i) => `${this.viewBoxX - ((this.stats.length - 1) - i)},${(1 - s.cpu_usage) * this.viewBoxY}`).join(' ');
+			const memPolylinePoints = this.stats.map((s, i) => `${this.viewBoxX - ((this.stats.length - 1) - i)},${(s.mem.free / s.mem.total) * this.viewBoxY}`).join(' ');
+
+			const cpuPolygonPoints = `${this.viewBoxX - (this.stats.length - 1)},${ this.viewBoxY } ${ cpuPolylinePoints } ${ this.viewBoxX },${ this.viewBoxY }`;
+			const memPolygonPoints = `${this.viewBoxX - (this.stats.length - 1)},${ this.viewBoxY } ${ memPolylinePoints } ${ this.viewBoxX },${ this.viewBoxY }`;
+
+			const cpuColor = `hsl(${180 - (stats.cpu_usage * 180)}, 80%, 70%)`;
+			const memColor = `hsl(${180 - (stats.mem.free / stats.mem.total * 180)}, 80%, 70%)`;
+
+			this.update({
+				cpuPolylinePoints,
+				memPolylinePoints,
+				cpuPolygonPoints,
+				memPolygonPoints,
+				cpuColor,
+				memColor
+			});
+		};
+	</script>
+</mk-server-home-widget-stats>
+
+<mk-server-home-widget-info>
+	<p>Maintainer: { meta.maintainer }</p>
+	<style>
+		:scope
+			display block
+			padding 10px
+	</style>
+	<script>
+		this.meta = this.opts.meta;
+	</script>
+</mk-server-home-widget-info>
+
diff --git a/src/web/app/desktop/tags/home.tag b/src/web/app/desktop/tags/home.tag
index 0e4a2ced10..41053ccbbe 100644
--- a/src/web/app/desktop/tags/home.tag
+++ b/src/web/app/desktop/tags/home.tag
@@ -70,6 +70,7 @@
 				'rss-reader',
 				'trends',
 				'photo-stream',
+				'server',
 				'version'
 			],
 			right: [
diff --git a/src/web/app/desktop/tags/index.js b/src/web/app/desktop/tags/index.js
index 1e0ebd44cf..177ba41293 100644
--- a/src/web/app/desktop/tags/index.js
+++ b/src/web/app/desktop/tags/index.js
@@ -45,6 +45,7 @@ require('./home-widgets/version.tag');
 require('./home-widgets/recommended-polls.tag');
 require('./home-widgets/trends.tag');
 require('./home-widgets/activity.tag');
+require('./home-widgets/server.tag');
 require('./timeline.tag');
 require('./messaging/window.tag');
 require('./messaging/room-window.tag');
diff --git a/src/web/app/init.js b/src/web/app/init.js
index 17f9a2d09e..b442d36a15 100644
--- a/src/web/app/init.js
+++ b/src/web/app/init.js
@@ -8,7 +8,7 @@ import * as riot from 'riot';
 import api from './common/scripts/api';
 import signout from './common/scripts/signout';
 import checkForUpdate from './common/scripts/check-for-update';
-import Connection from './common/scripts/stream';
+import Connection from './common/scripts/home-stream';
 import mixin from './common/mixins';
 import generateDefaultUserdata from './common/scripts/generate-default-userdata';
 import CONFIG from './common/scripts/config';
@@ -95,7 +95,7 @@ export default callback => {
 			});
 		}
 
-		// Init stream connection
+		// Init home stream connection
 		const stream = me ? new Connection(me) : null;
 
 		// ミックスイン初期化