diff --git a/src/store/modules/normalizers.js b/src/store/modules/normalizers.js
index 9a097ffdf4457c070bc2e93471b4ff5756d5fc9b..5b7f6ff1328425c87526c1ac23f9123df3c9e540 100644
--- a/src/store/modules/normalizers.js
+++ b/src/store/modules/normalizers.js
@@ -24,6 +24,8 @@ export const parseTuples = (tuples, key) => {
           return { key: name, value: icon[name], id: `f${(~~(Math.random() * 1e8)).toString(16)}` }
         })
       }, [])
+    } else if (item.tuple[0] === ':proxy_url') {
+      accum[item.tuple[0]] = parseProxyUrl(item.tuple[1])
     } else if ((item.tuple[0] === ':sslopts' && item.tuple[1].length === 0) || // should be removed
       (item.tuple[0] === ':tlsopts' && item.tuple[1].length === 0)) {
       accum[item.tuple[0]] = {}
@@ -70,6 +72,17 @@ const parseObject = object => {
   }, {})
 }
 
+const parseProxyUrl = value => {
+  if (!Array.isArray(value) && typeof value === 'object' && value.tuple.length === 3 && value.tuple[0] === ':socks5') {
+    const [, host, port] = value.tuple
+    return { socks5: true, host, port }
+  } else if (typeof value === 'string') {
+    const [host, port] = value.split(':')
+    return { socks5: false, host, port }
+  }
+  return { socks5: false, host: null, port: null }
+}
+
 export const partialUpdate = (group, key) => {
   if ((group === ':pleroma' && key === ':ecto_repos') ||
       (group === ':quack' && key === ':meta') ||
@@ -109,6 +122,8 @@ const wrapValues = settings => {
       return { 'tuple': [setting, wrapValues(value)] }
     } else if (type === 'atom') {
       return { 'tuple': [setting, `:${value}`] }
+    } else if (type.includes('tuple') && Array.isArray(value)) {
+      return { 'tuple': [setting, { 'tuple': value }] }
     } else if (type === 'map') {
       const objectValue = Object.keys(value).reduce((acc, key) => {
         acc[key] = value[key][1]
diff --git a/src/views/settings/components/Inputs.vue b/src/views/settings/components/Inputs.vue
index 91686720d08abcf0eb3a3d52d79fcd8dc759c107..b93f78945097a22e2f1a0e1e0d155bd3aa538ea8 100644
--- a/src/views/settings/components/Inputs.vue
+++ b/src/views/settings/components/Inputs.vue
@@ -104,19 +104,12 @@
         </div>
       </div>
     </div>
-    <div v-if="setting.key === ':proxy_url'" class="setting-input">
-      <el-checkbox v-model="proxyUrlTypeSocks5" class="name-input" border>Socks5</el-checkbox>
-      <el-input
-        :value="proxyUrlData"
-        :placeholder="setting.suggestions ? setting.suggestions[0] : ''"
-        class="value-input"
-        @input="updateSetting($event, settingGroup.group, settingGroup.key, setting.key)"/>
-    </div>
     <!-- special inputs -->
     <auto-linker-input v-if="settingGroup.group === ':auto_linker'" :data="data" :setting-group="settingGroup" :setting="setting"/>
     <mascots-input v-if="setting.key === ':mascots'" :data="data" :setting-group="settingGroup" :setting="setting"/>
     <editable-keyword-input v-if="editableKeyword(setting.key, setting.type)" :data="data" :setting-group="settingGroup" :setting="setting"/>
     <icons-input v-if="setting.key === ':icons'" :data="data[':icons']" :setting-group="settingGroup" :setting="setting"/>
+    <proxy-url-input v-if="setting.key === ':proxy_url'" :data="data[setting.key]" :setting-group="settingGroup" :setting="setting"/>
     <!-------------------->
     <p class="expl">{{ setting.description }}</p>
   </el-form-item>
@@ -126,7 +119,7 @@
 import AceEditor from 'vue2-ace-editor'
 import 'brace/mode/elixir'
 import 'default-passive-events'
-import { AutoLinkerInput, EditableKeywordInput, IconsInput, MascotsInput } from './inputComponents'
+import { AutoLinkerInput, EditableKeywordInput, IconsInput, MascotsInput, ProxyUrlInput } from './inputComponents'
 
 export default {
   name: 'Inputs',
@@ -135,7 +128,8 @@ export default {
     AutoLinkerInput,
     EditableKeywordInput,
     IconsInput,
-    MascotsInput
+    MascotsInput,
+    ProxyUrlInput
   },
   props: {
     customLabelWidth: {
@@ -203,18 +197,6 @@ export default {
     labelWidth() {
       return this.isMobile ? '100px' : '240px'
     },
-    proxyUrlData() {
-      if (!this.data[this.setting.key]) {
-        return null
-      } else {
-        return typeof this.data[this.setting.key] === 'string'
-          ? this.data[this.setting.key]
-          : `${this.data[this.setting.key][1]}:${this.data[this.setting.key][2]}`
-      }
-    },
-    proxyUrlTypeSocks5() {
-      return Array.isArray(this.data[this.setting.key]) && this.data[this.setting.key][0] === 'socks5'
-    },
     prune() {
       return this.data[this.setting.key] === ':disabled'
         ? ':disabled'
diff --git a/src/views/settings/components/inputComponents/ProxyUrlInput.vue b/src/views/settings/components/inputComponents/ProxyUrlInput.vue
new file mode 100644
index 0000000000000000000000000000000000000000..11335e4a459470d47b432a8d31574be6d63cb30a
--- /dev/null
+++ b/src/views/settings/components/inputComponents/ProxyUrlInput.vue
@@ -0,0 +1,66 @@
+<template>
+  <div class="setting-input">
+    <el-input
+      :value="data.host"
+      placeholder="host (e.g. localhost or 127.0.0.1)"
+      class="value-input"
+      @input="updateProxyUrl($event, 'host')"/> :
+    <el-input
+      :value="data.port"
+      placeholder="port (e.g 9020 or 3090)"
+      class="value-input"
+      @input="updateProxyUrl($event, 'port')"/>
+    <el-checkbox :value="data.socks5" class="name-input" @change="updateProxyUrl($event, 'socks5')">Socks5</el-checkbox>
+  </div>
+</template>
+
+<script>
+export default {
+  name: 'ProxyUrlInput',
+  props: {
+    data: {
+      type: Object || Array,
+      default: function() {
+        return {}
+      }
+    },
+    setting: {
+      type: Object,
+      default: function() {
+        return {}
+      }
+    },
+    settingGroup: {
+      type: Object,
+      default: function() {
+        return {}
+      }
+    }
+  },
+  methods: {
+    updateProxyUrl(value, inputType) {
+      let data
+      if (inputType === 'socks5') {
+        data = { ...this.data, socks5: value }
+      } else if (inputType === 'host') {
+        data = { ...this.data, host: value }
+      } else {
+        data = { ...this.data, port: value }
+      }
+      this.updateSetting(data, this.settingGroup.group, this.settingGroup.key, this.setting.key, this.setting.type)
+    },
+    updateSetting(value, group, key, input, type) {
+      const assembledData = value.socks5
+        ? [':socks5', value.host, value.port]
+        : `${value.host}:${value.port}`
+      this.$store.dispatch('UpdateSettings', { group, key, input, value: assembledData, type })
+      this.$store.dispatch('UpdateState', { group, key, input, value })
+    }
+  }
+}
+</script>
+
+<style rel='stylesheet/scss' lang='scss'>
+@import '../../styles/main';
+@include settings
+</style>
diff --git a/src/views/settings/components/inputComponents/index.js b/src/views/settings/components/inputComponents/index.js
index a505d73d28c5b7d9dafee119c4f1f9cc0cc554e4..7793db17e49544ccb150f2599a1d6b118b239145 100644
--- a/src/views/settings/components/inputComponents/index.js
+++ b/src/views/settings/components/inputComponents/index.js
@@ -2,3 +2,4 @@ export { default as AutoLinkerInput } from './AutoLinkerInput'
 export { default as MascotsInput } from './MascotsInput'
 export { default as EditableKeywordInput } from './EditableKeywordInput'
 export { default as IconsInput } from './IconsInput'
+export { default as ProxyUrlInput } from './ProxyUrlInput'
diff --git a/src/views/settings/styles/main.scss b/src/views/settings/styles/main.scss
index 15e62342ee5b4656182de836a6935b5b250bc6b8..41599bda766eb3d493778da3fe054147ac903770 100644
--- a/src/views/settings/styles/main.scss
+++ b/src/views/settings/styles/main.scss
@@ -147,7 +147,7 @@
     align-items: baseline;
   }
   .value-input {
-    width: 70%;
+    width: 35%;
     margin-left: 8px;
     margin-right: 10px
   }