diff --git a/.config/example.yml b/.config/example.yml
index c0afcc4a6e..0265c8cc2a 100644
--- a/.config/example.yml
+++ b/.config/example.yml
@@ -167,6 +167,3 @@ drive:
 #  external: true
 #  engine: http://vinayaka.distsn.org/cgi-bin/vinayaka-user-match-misskey-api.cgi?{{host}}+{{user}}+{{limit}}+{{offset}}
 #  timeout: 300000
-
-# Max allowed note text length in charactors
-maxNoteTextLength: 1000
diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml
index 2650d3c21c..577b68365d 100644
--- a/locales/ja-JP.yml
+++ b/locales/ja-JP.yml
@@ -1077,6 +1077,7 @@ admin/views/instance.vue:
   instance-name: "インスタンス名"
   instance-description: "インスタンスの紹介"
   banner-url: "バナー画像URL"
+  max-note-text-length: "投稿の最大文字数"
   disableRegistration: "ユーザー登録の受付を停止する"
   disableLocalTimeline: "ローカルタイムラインを無効にする"
   invite: "招待"
diff --git a/src/client/app/admin/views/instance.vue b/src/client/app/admin/views/instance.vue
index 85ef0a60c4..703d0f622b 100644
--- a/src/client/app/admin/views/instance.vue
+++ b/src/client/app/admin/views/instance.vue
@@ -6,6 +6,7 @@
 			<ui-input v-model="name">%i18n:@instance-name%</ui-input>
 			<ui-textarea v-model="description">%i18n:@instance-description%</ui-textarea>
 			<ui-input v-model="bannerUrl">%i18n:@banner-url%</ui-input>
+			<ui-input v-model="maxNoteTextLength">%i18n:@max-note-text-length%</ui-input>
 			<ui-button @click="updateMeta">%i18n:@save%</ui-button>
 		</section>
 	</ui-card>
@@ -39,6 +40,7 @@ export default Vue.extend({
 			bannerUrl: null,
 			name: null,
 			description: null,
+			maxNoteTextLength: null,
 			inviteCode: null,
 		};
 	},
@@ -48,6 +50,7 @@ export default Vue.extend({
 			this.bannerUrl = meta.bannerUrl;
 			this.name = meta.name;
 			this.description = meta.description;
+			this.maxNoteTextLength = meta.maxNoteTextLength;
 		});
 	},
 
@@ -69,7 +72,8 @@ export default Vue.extend({
 				disableLocalTimeline: this.disableLocalTimeline,
 				bannerUrl: this.bannerUrl,
 				name: this.name,
-				description: this.description
+				description: this.description,
+				maxNoteTextLength: parseInt(this.maxNoteTextLength, 10)
 			}).then(() => {
 				this.$swal({
 					type: 'success',
diff --git a/src/config/load.ts b/src/config/load.ts
index 5be52c0ee7..738d6427f3 100644
--- a/src/config/load.ts
+++ b/src/config/load.ts
@@ -49,8 +49,6 @@ export default function load() {
 	if (config.localDriveCapacityMb == null) config.localDriveCapacityMb = 256;
 	if (config.remoteDriveCapacityMb == null) config.remoteDriveCapacityMb = 8;
 
-	if (config.maxNoteTextLength == null) config.maxNoteTextLength = 1000;
-
 	return Object.assign(config, mixin);
 }
 
diff --git a/src/config/types.ts b/src/config/types.ts
index ce4ab3ec38..a3c761cc64 100644
--- a/src/config/types.ts
+++ b/src/config/types.ts
@@ -107,8 +107,6 @@ export type Source = {
 		engine: string;
 		timeout: number;
 	};
-
-	maxNoteTextLength?: number;
 };
 
 /**
diff --git a/src/models/meta.ts b/src/models/meta.ts
index 6d75258df8..d8a9b46037 100644
--- a/src/models/meta.ts
+++ b/src/models/meta.ts
@@ -43,4 +43,9 @@ export type IMeta = {
 	disableLocalTimeline?: boolean;
 	hidedTags?: string[];
 	bannerUrl?: string;
+
+	/**
+	 * Max allowed note text length in charactors
+	 */
+	maxNoteTextLength?: number;
 };
diff --git a/src/models/note.ts b/src/models/note.ts
index 6856d6d07d..516045225c 100644
--- a/src/models/note.ts
+++ b/src/models/note.ts
@@ -11,7 +11,6 @@ import Reaction from './note-reaction';
 import { packMany as packFileMany, IDriveFile } from './drive-file';
 import Favorite from './favorite';
 import Following from './following';
-import config from '../config';
 import Emoji from './emoji';
 
 const Note = db.get<INote>('notes');
@@ -27,10 +26,6 @@ Note.createIndex({ createdAt: -1 });
 Note.createIndex({ score: -1 }, { sparse: true });
 export default Note;
 
-export function isValidText(text: string): boolean {
-	return length(text.trim()) <= config.maxNoteTextLength && text.trim() != '';
-}
-
 export function isValidCw(text: string): boolean {
 	return length(text.trim()) <= 100;
 }
diff --git a/src/server/api/endpoints/admin/update-meta.ts b/src/server/api/endpoints/admin/update-meta.ts
index 26ade439ab..a0f2b329aa 100644
--- a/src/server/api/endpoints/admin/update-meta.ts
+++ b/src/server/api/endpoints/admin/update-meta.ts
@@ -59,6 +59,13 @@ export const meta = {
 				'ja-JP': 'インスタンスの紹介文'
 			}
 		},
+
+		maxNoteTextLength: {
+			validator: $.num.optional.min(1),
+			desc: {
+				'ja-JP': '投稿の最大文字数'
+			}
+		}
 	}
 };
 
@@ -93,6 +100,10 @@ export default define(meta, (ps) => new Promise(async (res, rej) => {
 		set.description = ps.description;
 	}
 
+	if (ps.maxNoteTextLength) {
+		set.maxNoteTextLength = ps.maxNoteTextLength;
+	}
+
 	await Meta.update({}, {
 		$set: set
 	}, { upsert: true });
diff --git a/src/server/api/endpoints/meta.ts b/src/server/api/endpoints/meta.ts
index 34a62d6452..90a5952e9f 100644
--- a/src/server/api/endpoints/meta.ts
+++ b/src/server/api/endpoints/meta.ts
@@ -62,7 +62,7 @@ export default define(meta, (ps, me) => new Promise(async (res, rej) => {
 		swPublickey: config.sw ? config.sw.public_key : null,
 		hidedTags: (me && me.isAdmin) ? met.hidedTags : undefined,
 		bannerUrl: met.bannerUrl,
-		maxNoteTextLength: config.maxNoteTextLength,
+		maxNoteTextLength: met.maxNoteTextLength || 1000,
 
 		emojis: emojis,
 
diff --git a/src/server/api/endpoints/notes/create.ts b/src/server/api/endpoints/notes/create.ts
index 8a8813daba..f4d7e96265 100644
--- a/src/server/api/endpoints/notes/create.ts
+++ b/src/server/api/endpoints/notes/create.ts
@@ -1,10 +1,20 @@
 import $ from 'cafy'; import ID, { transform, transformMany } from '../../../../misc/cafy-id';
 const ms = require('ms');
-import Note, { INote, isValidText, isValidCw, pack } from '../../../../models/note';
+import { length } from 'stringz';
+import Note, { INote, isValidCw, pack } from '../../../../models/note';
 import User, { IUser } from '../../../../models/user';
 import DriveFile, { IDriveFile } from '../../../../models/drive-file';
 import create from '../../../../services/note/create';
 import define from '../../define';
+import Meta from '../../../../models/meta';
+
+let maxNoteTextLength = 1000;
+
+setInterval(() => {
+	Meta.findOne({}).then(m => {
+		if (m.maxNoteTextLength) maxNoteTextLength = m.maxNoteTextLength;
+	});
+}, 3000);
 
 export const meta = {
 	stability: 'stable',
@@ -40,7 +50,9 @@ export const meta = {
 		},
 
 		text: {
-			validator: $.str.optional.nullable.pipe(isValidText),
+			validator: $.str.optional.nullable.pipe(text =>
+				length(text.trim()) <= maxNoteTextLength && text.trim() != ''
+			),
 			default: null as any,
 			desc: {
 				'ja-JP': '投稿内容'