diff --git a/README.md b/README.md
index 52666390e2cc6f79a29d5e2e1a44c591ccc8d128..32b86f8dc6825096ef6b55c1be5ea39f606da6bc 100644
--- a/README.md
+++ b/README.md
@@ -31,8 +31,7 @@ and more! You can touch with your own eyes at https://misskey.xyz/.
 2. `git clone git://github.com/syuilo/misskey.git`
 3. `cd misskey`
 4. `npm install`
-5. `npm run config`
-6. `npm run build`
+5. `npm run build`
 
 GLHF!
 
@@ -92,6 +91,7 @@ If you want to run misskey in production mode, add `--env NODE_ENV=production` l
 Note that `$(pwd)` is the working directory.
 
 ## Launch
+(初回起動時はまず `npm run config` してください)
 `sudo npm start`
 
 ## Debugging :bug:
diff --git a/src/web/app/boot.js b/src/web/app/boot.js
index 5fc7524626035a97da7e74eb4c7ad6998cc687d5..d39e46861cc398415d53615e0bf032fab1b87be3 100644
--- a/src/web/app/boot.js
+++ b/src/web/app/boot.js
@@ -17,11 +17,13 @@ require('./common/tags');
 
 "use strict";
 
+const CONFIG = require('./common/scripts/config');
+
 document.domain = CONFIG.host;
 
 // Set global configration
 riot.mixin({
-	CONFIG: CONFIG
+	CONFIG
 });
 
 // ↓ iOS待ちPolyfill (SEE: http://caniuse.com/#feat=fetch)
diff --git a/src/web/app/common/scripts/api.js b/src/web/app/common/scripts/api.js
index b549fe47b9df202eb994eaf0430dce33cee3bd96..be72f863d6c72e7b0d8d2ad464119bdecede30bc 100644
--- a/src/web/app/common/scripts/api.js
+++ b/src/web/app/common/scripts/api.js
@@ -2,6 +2,8 @@
  * API Request
  */
 
+const CONFIG = require('./config');
+
 let spinner = null;
 let pending = 0;
 
diff --git a/src/web/app/common/scripts/config.js b/src/web/app/common/scripts/config.js
new file mode 100644
index 0000000000000000000000000000000000000000..5123402414f7f4f02e7aa9ad25bedb7638db5ee7
--- /dev/null
+++ b/src/web/app/common/scripts/config.js
@@ -0,0 +1,18 @@
+const url = new URL(location.href);
+
+const isRoot = url.host.split('.')[0] == 'misskey';
+
+const host = isRoot ? url.host : url.host.substring(url.host.indexOf('.') + 1, url.host.length);
+const scheme = url.protocol;
+const apiUrl = `${scheme}//api.${host}`;
+const devUrl = `${scheme}//dev.${host}`;
+const aboutUrl = `${scheme}//about.${host}`;
+
+module.exports = {
+	host,
+	scheme,
+	apiUrl,
+	devUrl,
+	aboutUrl,
+	themeColor: '#f76d6c'
+};
diff --git a/src/web/app/common/scripts/messaging-stream.js b/src/web/app/common/scripts/messaging-stream.js
index 2c00c24024bd3ba3b410b8df67b2a9b5aaf182ee..0c8ce3c9d265a3f3c283c622c45146a0f173861d 100644
--- a/src/web/app/common/scripts/messaging-stream.js
+++ b/src/web/app/common/scripts/messaging-stream.js
@@ -1,5 +1,6 @@
 const ReconnectingWebSocket = require('reconnecting-websocket');
 const riot = require('riot');
+const CONFIG = require('./config');
 
 class Connection {
 	constructor(me, otherparty) {
diff --git a/src/web/app/common/scripts/signout.js b/src/web/app/common/scripts/signout.js
index cd752423da5e73e4df04609ba2bb6845bd141f15..7242ebc5b036a50426cabcba2849705a4b014652 100644
--- a/src/web/app/common/scripts/signout.js
+++ b/src/web/app/common/scripts/signout.js
@@ -1,3 +1,5 @@
+const CONFIG = require('./config');
+
 module.exports = () => {
 	localStorage.removeItem('me');
 	document.cookie = `i=; domain=.${CONFIG.host}; expires=Thu, 01 Jan 1970 00:00:01 GMT;`;
diff --git a/src/web/app/common/scripts/stream.js b/src/web/app/common/scripts/stream.js
index 34ddc8447d289b37a15e7b23b2b240cddb22f1d5..fd7bac7faaec31b738b9d47773d745da605c76c3 100644
--- a/src/web/app/common/scripts/stream.js
+++ b/src/web/app/common/scripts/stream.js
@@ -1,5 +1,6 @@
 const ReconnectingWebSocket = require('reconnecting-websocket');
 const riot = require('riot');
+const CONFIG = require('./config');
 
 module.exports = me => {
 	let state = 'initializing';
diff --git a/src/web/app/common/scripts/text-compiler.js b/src/web/app/common/scripts/text-compiler.js
index 62e70463adb211ce830cc585e655bab56e685842..c9eb73e870f70532eb3bb74b65fef00d6ae78db1 100644
--- a/src/web/app/common/scripts/text-compiler.js
+++ b/src/web/app/common/scripts/text-compiler.js
@@ -1,5 +1,6 @@
 const riot = require('riot');
 const nyaize = require('nyaize').default;
+const CONFIG = require('./config');
 
 const escape = function(text) {
 	return text
diff --git a/src/web/app/common/tags/signup.tag b/src/web/app/common/tags/signup.tag
index f0358e2328c0661f46927cb8f293daae93e5891a..a70399a872daa4be6d18819495373ceba80f08c8 100644
--- a/src/web/app/common/tags/signup.tag
+++ b/src/web/app/common/tags/signup.tag
@@ -30,7 +30,7 @@
 		</label>
 		<label class="recaptcha">
 			<p class="caption"><i class="fa fa-toggle-on" if={ recaptchaed }></i><i class="fa fa-toggle-off" if={ !recaptchaed }></i>認証</p>
-			<div class="g-recaptcha" data-callback="onRecaptchaed" data-expired-callback="onRecaptchaExpired" data-sitekey={ CONFIG.recaptcha.siteKey }></div>
+			<div if={ recaptcha } class="g-recaptcha" data-callback="onRecaptchaed" data-expired-callback="onRecaptchaExpired" data-sitekey={ recaptcha.siteKey }></div>
 		</label>
 		<label class="agree-tou">
 			<input name="agree-tou" type="checkbox" autocomplete="off" required="required"/>
@@ -193,10 +193,20 @@
 		};
 
 		this.on('mount', () => {
-			const head = document.getElementsByTagName('head')[0];
-			const script = document.createElement('script');
-			script.setAttribute('src', 'https://www.google.com/recaptcha/api.js');
-			head.appendChild(script);
+			fetch('/config.json').then(res => {
+				res.json().then(conf => {
+					this.update({
+						recaptcha: {
+							siteKey: conf.recaptcha.siteKey
+						}
+					});
+
+					const head = document.getElementsByTagName('head')[0];
+					const script = document.createElement('script');
+					script.setAttribute('src', 'https://www.google.com/recaptcha/api.js');
+					head.appendChild(script);
+				});
+			});
 		});
 
 		this.onChangeUsername = () => {
diff --git a/src/web/app/desktop/scripts/update-avatar.js b/src/web/app/desktop/scripts/update-avatar.js
index c9bf8661506310e40ff24b1f3e949f28d0ca8ead..f3c4594ffd7a24f9234a47f001be1379905f13e5 100644
--- a/src/web/app/desktop/scripts/update-avatar.js
+++ b/src/web/app/desktop/scripts/update-avatar.js
@@ -1,4 +1,5 @@
 const riot = require('riot');
+const CONFIG = require('../../common/scripts/config');
 const dialog = require('./dialog');
 const api = require('../../common/scripts/api');
 
diff --git a/src/web/app/desktop/scripts/update-banner.js b/src/web/app/desktop/scripts/update-banner.js
index 2ee918db89d1ba28a502e2a57d5f4b37ed93410d..51a107cf4c2448f388d7ef6a5b94be03d1bff2bf 100644
--- a/src/web/app/desktop/scripts/update-banner.js
+++ b/src/web/app/desktop/scripts/update-banner.js
@@ -1,4 +1,5 @@
 const riot = require('riot');
+const CONFIG = require('../../common/scripts/config');
 const dialog = require('./dialog');
 const api = require('../../common/scripts/api');
 
diff --git a/src/web/server.ts b/src/web/server.ts
index 72f6df598301c88c0492ca96b4114a78a68755b7..70083753b230544c9dcb5c70de8081ca3b1c2ff4 100644
--- a/src/web/server.ts
+++ b/src/web/server.ts
@@ -51,6 +51,17 @@ app.get(/\/api:meta/, require('./meta'));
 app.get(/\/api:url/,  require('./service/url-preview'));
 app.post(/\/api:rss/, require('./service/rss-proxy'));
 
+/**
+ * Serve config
+ */
+app.get('/config.json', (req, res) => {
+	res.send({
+		recaptcha: {
+			siteKey: config.recaptcha.siteKey
+		}
+	});
+});
+
 /**
  * Subdomain
  */