diff --git a/src/server/api/endpoints/notes/global-timeline.ts b/src/server/api/endpoints/notes/global-timeline.ts
index b7f765f27d1c46388f6281630db5c31748af8741..f5fd0d6dd8445288f998f6847a7d3eb20be2867b 100644
--- a/src/server/api/endpoints/notes/global-timeline.ts
+++ b/src/server/api/endpoints/notes/global-timeline.ts
@@ -4,6 +4,7 @@ import Mute from '../../../../models/mute';
 import { packMany } from '../../../../models/note';
 import define from '../../define';
 import { countIf } from '../../../../prelude/array';
+import fetchMeta from '../../../../misc/fetch-meta';
 
 export const meta = {
 	desc: {
@@ -51,6 +52,13 @@ export const meta = {
 };
 
 export default define(meta, (ps, user) => new Promise(async (res, rej) => {
+	const meta = await fetchMeta();
+	if (meta.disableLocalTimeline) {
+		if (user == null || (!user.isAdmin && !user.isModerator)) {
+			return rej('local timeline disabled');
+		}
+	}
+
 	// Check if only one of sinceId, untilId, sinceDate, untilDate specified
 	if (countIf(x => x != null, [ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate]) > 1) {
 		return rej('only one of sinceId, untilId, sinceDate, untilDate can be specified');
diff --git a/src/server/api/endpoints/notes/hybrid-timeline.ts b/src/server/api/endpoints/notes/hybrid-timeline.ts
index 7cf05cb9a82580fa55154dca2bb61d79d9b38472..20855e513927f50f1e0052be747491d25f6c7e43 100644
--- a/src/server/api/endpoints/notes/hybrid-timeline.ts
+++ b/src/server/api/endpoints/notes/hybrid-timeline.ts
@@ -5,6 +5,7 @@ import { getFriends } from '../../common/get-friends';
 import { packMany } from '../../../../models/note';
 import define from '../../define';
 import { countIf } from '../../../../prelude/array';
+import fetchMeta from '../../../../misc/fetch-meta';
 
 export const meta = {
 	desc: {
@@ -91,6 +92,11 @@ export const meta = {
 };
 
 export default define(meta, (ps, user) => new Promise(async (res, rej) => {
+	const meta = await fetchMeta();
+	if (meta.disableLocalTimeline && !user.isAdmin && !user.isModerator) {
+		return rej('local timeline disabled');
+	}
+
 	// Check if only one of sinceId, untilId, sinceDate, untilDate specified
 	if (countIf(x => x != null, [ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate]) > 1) {
 		return rej('only one of sinceId, untilId, sinceDate, untilDate can be specified');
diff --git a/src/server/api/endpoints/notes/local-timeline.ts b/src/server/api/endpoints/notes/local-timeline.ts
index 4446f52cdc8e59aaabe743733c510e70ec0735cd..30d2762ad543b7ef1f8345b3602fcc7099b1f786 100644
--- a/src/server/api/endpoints/notes/local-timeline.ts
+++ b/src/server/api/endpoints/notes/local-timeline.ts
@@ -4,6 +4,7 @@ import Mute from '../../../../models/mute';
 import { packMany } from '../../../../models/note';
 import define from '../../define';
 import { countIf } from '../../../../prelude/array';
+import fetchMeta from '../../../../misc/fetch-meta';
 
 export const meta = {
 	desc: {
@@ -66,6 +67,13 @@ export const meta = {
 };
 
 export default define(meta, (ps, user) => new Promise(async (res, rej) => {
+	const meta = await fetchMeta();
+	if (meta.disableLocalTimeline) {
+		if (user == null || (!user.isAdmin && !user.isModerator)) {
+			return rej('local timeline disabled');
+		}
+	}
+
 	// Check if only one of sinceId, untilId, sinceDate, untilDate specified
 	if (countIf(x => x != null, [ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate]) > 1) {
 		return rej('only one of sinceId, untilId, sinceDate, untilDate can be specified');
diff --git a/src/server/api/stream/channels/global-timeline.ts b/src/server/api/stream/channels/global-timeline.ts
index c5499801ed72e1d7df0b2ae9b32f014718a29194..611d5a6aef2c5ca458a34e6fbed30358f593ce4d 100644
--- a/src/server/api/stream/channels/global-timeline.ts
+++ b/src/server/api/stream/channels/global-timeline.ts
@@ -3,6 +3,7 @@ import Mute from '../../../../models/mute';
 import { pack } from '../../../../models/note';
 import shouldMuteThisNote from '../../../../misc/should-mute-this-note';
 import Channel from '../channel';
+import fetchMeta from '../../../../misc/fetch-meta';
 
 export default class extends Channel {
 	public readonly chName = 'globalTimeline';
@@ -13,6 +14,11 @@ export default class extends Channel {
 
 	@autobind
 	public async init(params: any) {
+		const meta = await fetchMeta();
+		if (meta.disableLocalTimeline) {
+			if (this.user == null || (!this.user.isAdmin && !this.user.isModerator)) return;
+		}
+
 		// Subscribe events
 		this.subscriber.on('globalTimeline', this.onNote);
 
diff --git a/src/server/api/stream/channels/hybrid-timeline.ts b/src/server/api/stream/channels/hybrid-timeline.ts
index 15a516b0c0e903f68fdc04de615de0cb3e9b7e52..e573d27ee89ec690bc2edd8c410d4ca1d466bf43 100644
--- a/src/server/api/stream/channels/hybrid-timeline.ts
+++ b/src/server/api/stream/channels/hybrid-timeline.ts
@@ -3,6 +3,7 @@ import Mute from '../../../../models/mute';
 import { pack } from '../../../../models/note';
 import shouldMuteThisNote from '../../../../misc/should-mute-this-note';
 import Channel from '../channel';
+import fetchMeta from '../../../../misc/fetch-meta';
 
 export default class extends Channel {
 	public readonly chName = 'hybridTimeline';
@@ -13,6 +14,9 @@ export default class extends Channel {
 
 	@autobind
 	public async init(params: any) {
+		const meta = await fetchMeta();
+		if (meta.disableLocalTimeline && !this.user.isAdmin && !this.user.isModerator) return;
+
 		// Subscribe events
 		this.subscriber.on('hybridTimeline', this.onNewNote);
 		this.subscriber.on(`hybridTimeline:${this.user._id}`, this.onNewNote);
diff --git a/src/server/api/stream/channels/local-timeline.ts b/src/server/api/stream/channels/local-timeline.ts
index a26f71af8eacfb6d5193c56327ef02d4f6d5bfdb..8e490677d3648e11234ce6ca061fd1ff7758594c 100644
--- a/src/server/api/stream/channels/local-timeline.ts
+++ b/src/server/api/stream/channels/local-timeline.ts
@@ -3,6 +3,7 @@ import Mute from '../../../../models/mute';
 import { pack } from '../../../../models/note';
 import shouldMuteThisNote from '../../../../misc/should-mute-this-note';
 import Channel from '../channel';
+import fetchMeta from '../../../../misc/fetch-meta';
 
 export default class extends Channel {
 	public readonly chName = 'localTimeline';
@@ -13,6 +14,11 @@ export default class extends Channel {
 
 	@autobind
 	public async init(params: any) {
+		const meta = await fetchMeta();
+		if (meta.disableLocalTimeline) {
+			if (this.user == null || (!this.user.isAdmin && !this.user.isModerator)) return;
+		}
+
 		// Subscribe events
 		this.subscriber.on('localTimeline', this.onNote);
 
diff --git a/src/stream.ts b/src/stream.ts
index 8ca8c3254c97fc56a6eebd63e90e14fed542e3f0..596cb98e72c02505507330289525a0f4aa308fab 100644
--- a/src/stream.ts
+++ b/src/stream.ts
@@ -1,31 +1,17 @@
 import * as mongo from 'mongodb';
 import redis from './db/redis';
 import Xev from 'xev';
-import { IMeta } from './models/meta';
-import fetchMeta from './misc/fetch-meta';
 
 type ID = string | mongo.ObjectID;
 
 class Publisher {
 	private ev: Xev;
-	private meta: IMeta;
 
 	constructor() {
 		// Redisがインストールされてないときはプロセス間通信を使う
 		if (redis == null) {
 			this.ev = new Xev();
 		}
-
-		setInterval(async () => {
-			this.meta = await fetchMeta();
-		}, 5000);
-	}
-
-	public fetchMeta = async () => {
-		if (this.meta != null) return this.meta;
-
-		this.meta = await fetchMeta();
-		return this.meta;
 	}
 
 	private publish = (channel: string, type: string, value?: any): void => {
@@ -83,14 +69,10 @@ class Publisher {
 	}
 
 	public publishLocalTimelineStream = async (note: any): Promise<void> => {
-		const meta = await this.fetchMeta();
-		if (meta.disableLocalTimeline) return;
 		this.publish('localTimeline', null, note);
 	}
 
 	public publishHybridTimelineStream = async (userId: ID, note: any): Promise<void> => {
-		const meta = await this.fetchMeta();
-		if (meta.disableLocalTimeline) return;
 		this.publish(userId ? `hybridTimeline:${userId}` : 'hybridTimeline', null, note);
 	}