diff --git a/libresonic-main/pom.xml b/libresonic-main/pom.xml
index 3f820085..499b9ffc 100644
--- a/libresonic-main/pom.xml
+++ b/libresonic-main/pom.xml
@@ -353,6 +353,19 @@
         
 
 
+        
+            org.apache.commons
+            commons-configuration2
+            2.1
+        
+        
+            commons-beanutils
+            commons-beanutils
+            1.9.2
+            
+            runtime
+        
+
     
 
     
diff --git a/libresonic-main/src/main/java/org/libresonic/player/service/ApacheCommonsConfigurationService.java b/libresonic-main/src/main/java/org/libresonic/player/service/ApacheCommonsConfigurationService.java
new file mode 100644
index 00000000..dc8e0f6e
--- /dev/null
+++ b/libresonic-main/src/main/java/org/libresonic/player/service/ApacheCommonsConfigurationService.java
@@ -0,0 +1,103 @@
+package org.libresonic.player.service;
+
+import com.google.common.collect.Lists;
+import org.apache.commons.configuration2.Configuration;
+import org.apache.commons.configuration2.FileBasedConfiguration;
+import org.apache.commons.configuration2.ImmutableConfiguration;
+import org.apache.commons.configuration2.MapConfiguration;
+import org.apache.commons.configuration2.PropertiesConfiguration;
+import org.apache.commons.configuration2.PropertiesConfigurationLayout;
+import org.apache.commons.configuration2.builder.FileBasedConfigurationBuilder;
+import org.apache.commons.configuration2.builder.fluent.Parameters;
+import org.apache.commons.configuration2.ex.ConfigurationException;
+import org.apache.commons.configuration2.sync.ReadWriteSynchronizer;
+import org.apache.commons.io.FileUtils;
+import org.libresonic.player.Logger;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.HashMap;
+
+public class ApacheCommonsConfigurationService {
+
+    private static final Logger LOG = Logger.getLogger(ApacheCommonsConfigurationService.class);
+
+    private final FileBasedConfigurationBuilder builder;
+
+    private final Configuration config;
+
+    public static final String HEADER_COMMENT = "Libresonic preferences.  NOTE: This file is automatically generated."
+                           + " Do not modify while application is running";
+
+    public ApacheCommonsConfigurationService() {
+        File propertyFile = SettingsService.getPropertyFile();
+        if(!propertyFile.exists()) {
+            try {
+                FileUtils.touch(propertyFile);
+            } catch (IOException e) {
+                throw new RuntimeException("Could not create new property file", e);
+            }
+        }
+        Parameters params = new Parameters();
+        PropertiesConfigurationLayout layout = new PropertiesConfigurationLayout();
+        // https://issues.apache.org/jira/browse/CONFIGURATION-644
+//        layout.setHeaderComment(HEADER_COMMENT);
+        layout.setGlobalSeparator("=");
+        builder = new FileBasedConfigurationBuilder(PropertiesConfiguration.class).configure(
+                params.properties()
+                      .setFile(propertyFile)
+                      .setSynchronizer(new ReadWriteSynchronizer())
+                      .setLayout(layout));
+        try {
+            config = builder.getConfiguration();
+        } catch (ConfigurationException e) {
+            throw new RuntimeException("Could not load property file at " + propertyFile, e);
+        }
+    }
+
+    public void save() {
+        try {
+            builder.save();
+        } catch (ConfigurationException e) {
+            LOG.error("Unable to write to property file.", e);
+        }
+    }
+
+    public Object getProperty(String key) {
+        return config.getProperty(key);
+    }
+
+    public boolean containsKey(String key) {
+        return config.containsKey(key);
+    }
+
+    public void clearProperty(String key) {
+        config.clearProperty(key);
+    }
+
+    public String getString(String key, String defaultValue) {
+        return config.getString(key, defaultValue);
+    }
+
+    public void setProperty(String key, Object value) {
+        config.setProperty(key, value);
+    }
+
+    public long getLong(String key, long defaultValue) {
+        return config.getLong(key, defaultValue);
+    }
+
+    public int getInteger(String key, int defaultValue) {
+        return config.getInteger(key, defaultValue);
+    }
+
+    public boolean getBoolean(String key, boolean defaultValue) {
+        return config.getBoolean(key, defaultValue);
+    }
+
+    public ImmutableConfiguration getImmutableSnapshot() {
+        MapConfiguration mapConfiguration = new MapConfiguration(new HashMap<>());
+        mapConfiguration.copy(config);
+        return mapConfiguration;
+    }
+}
diff --git a/libresonic-main/src/main/java/org/libresonic/player/service/SettingsService.java b/libresonic-main/src/main/java/org/libresonic/player/service/SettingsService.java
index 1f7185b7..25c8e534 100644
--- a/libresonic-main/src/main/java/org/libresonic/player/service/SettingsService.java
+++ b/libresonic-main/src/main/java/org/libresonic/player/service/SettingsService.java
@@ -19,29 +19,6 @@
  */
 package org.libresonic.player.service;
 
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.Date;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Locale;
-import java.util.Properties;
-import java.util.StringTokenizer;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-import java.util.concurrent.Executors;
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.ScheduledFuture;
-import java.util.concurrent.TimeUnit;
-
-import org.apache.commons.io.IOUtils;
 import org.apache.commons.lang.StringUtils;
 
 import org.libresonic.player.Logger;
@@ -61,6 +38,12 @@ import org.libresonic.player.util.FileUtil;
 import org.libresonic.player.util.StringUtil;
 import org.libresonic.player.util.Util;
 
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.*;
+import java.util.concurrent.*;
+
 /**
  * Provides persistent storage of application settings and preferences.
  *
@@ -219,13 +202,13 @@ public class SettingsService {
 
     private static final Logger LOG = Logger.getLogger(SettingsService.class);
 
-    private Properties properties = new Properties();
     private List themes;
     private List locales;
     private InternetRadioDao internetRadioDao;
     private MusicFolderDao musicFolderDao;
     private UserDao userDao;
     private AvatarDao avatarDao;
+    private ApacheCommonsConfigurationService configurationService;
     private VersionService versionService;
 
     private String[] cachedCoverArtFileTypesArray;
@@ -234,34 +217,33 @@ public class SettingsService {
     private List cachedMusicFolders;
     private final ConcurrentMap> cachedMusicFoldersPerUser = new ConcurrentHashMap>();
 
-    private static File libresonicHome;
-
-    private static final long LOCAL_IP_LOOKUP_DELAY_SECONDS = 60;
     private String localIpAddress;
 
-    public SettingsService() {
-        File propertyFile = getPropertyFile();
+    private void removeObseleteProperties() {
 
-        if (propertyFile.exists()) {
-            FileInputStream in = null;
-            try {
-                in = new FileInputStream(propertyFile);
-                properties.load(in);
-            } catch (Exception x) {
-                LOG.error("Unable to read from property file.", x);
-            } finally {
-                IOUtils.closeQuietly(in);
+        OBSOLETE_KEYS.forEach( oKey -> {
+            if(configurationService.containsKey(oKey)) {
+                LOG.info("Removing obsolete property [" + oKey + ']');
+                configurationService.clearProperty(oKey);
             }
+        });
 
-            // Remove obsolete properties.
-            for (Iterator