diff --git a/dap-sdk/core/include/dap_file_utils.h b/dap-sdk/core/include/dap_file_utils.h
index 92cfe9812c49b4540b6c1d608de58e3470ce7a3e..9bc55055d72e00a02bdfc5d0d30ac3cca3ab4060 100755
--- a/dap-sdk/core/include/dap_file_utils.h
+++ b/dap-sdk/core/include/dap_file_utils.h
@@ -44,6 +44,9 @@
 
 #else
 
+#ifndef O_BINARY
+# define O_BINARY 0
+#endif
 #define DAP_DIR_SEPARATOR '/'
 #define DAP_DIR_SEPARATOR_S "/"
 #define DAP_IS_DIR_SEPARATOR(c) ((c) == DAP_DIR_SEPARATOR)
@@ -102,4 +105,10 @@ char* dap_path_get_dirname(const char *a_file_name);
  */
 dap_list_name_directories_t *dap_get_subs(const char *a_path_name);
 
+
+/*
+ * Reads an entire file into allocated memory, with error checking.
+ */
+bool dap_file_get_contents(const char *filename, char **contents, size_t *length);
+
 #endif // _FILE_UTILS_H_
diff --git a/dap-sdk/core/src/dap_file_utils.c b/dap-sdk/core/src/dap_file_utils.c
index 910c64a79ee21dfc1aa2463b6cc3f39921b93894..b57a898265a98fe8433ef2e0fbf7744f3a22f332 100755
--- a/dap-sdk/core/src/dap_file_utils.c
+++ b/dap-sdk/core/src/dap_file_utils.c
@@ -25,6 +25,11 @@
 #include <stdlib.h>
 #include <stdint.h>
 #include <errno.h>
+#include <fcntl.h>
+#include <stdbool.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
 #if (OS_TARGET == OS_MACOS)
     #include <stdio.h>
 #else
@@ -404,3 +409,203 @@ dap_list_name_directories_t *dap_get_subs(const char *a_path_dir){
 #endif
     return list;
 }
+
+static bool get_contents_stdio(const char *filename, FILE *f, char **contents, size_t *length)
+{
+    char buf[4096];
+    size_t bytes; /* always <= sizeof(buf) */
+    char *str = NULL;
+    size_t total_bytes = 0;
+    size_t total_allocated = 0;
+    char *tmp;
+    assert(f != NULL);
+    while(!feof(f)) {
+        int save_errno;
+
+        bytes = fread(buf, 1, sizeof(buf), f);
+        save_errno = errno;
+
+        if(total_bytes > ULONG_MAX - bytes)
+            goto file_too_large;
+
+        /* Possibility of overflow eliminated above. */
+        while(total_bytes + bytes >= total_allocated) {
+            if(str) {
+                if(total_allocated > ULONG_MAX / 2)
+                    goto file_too_large;
+                total_allocated *= 2;
+            }
+            else {
+                total_allocated = MIN(bytes + 1, sizeof(buf));
+            }
+
+            tmp = DAP_REALLOC(str, total_allocated);
+
+            if(tmp == NULL)
+                goto error;
+
+            str = tmp;
+        }
+
+        if(ferror(f))
+            goto error;
+
+        assert(str != NULL);
+        memcpy(str + total_bytes, buf, bytes);
+        total_bytes += bytes;
+    }
+
+    fclose(f);
+
+    if(total_allocated == 0)
+            {
+        str = DAP_NEW_SIZE(char, 1);
+        total_bytes = 0;
+    }
+
+    str[total_bytes] = '\0';
+
+    if(length)
+        *length = total_bytes;
+
+    *contents = str;
+
+    return true;
+
+    file_too_large:
+    error:
+
+    DAP_DELETE(str);
+    fclose(f);
+    return false;
+}
+
+#ifndef _WIN32
+
+static bool dap_get_contents_regfile(const char *filename, struct stat *stat_buf, int fd, char **contents,
+        size_t *length)
+{
+    char *buf;
+    size_t bytes_read;
+    size_t size;
+    size_t alloc_size;
+
+    size = stat_buf->st_size;
+
+    alloc_size = size + 1;
+    buf = DAP_NEW_SIZE(char, alloc_size);
+
+    if(buf == NULL) {
+        goto error;
+    }
+
+    bytes_read = 0;
+    while(bytes_read < size) {
+        size_t rc;
+
+        rc = read(fd, buf + bytes_read, size - bytes_read);
+
+        if(rc < 0) {
+            if(errno != EINTR) {
+                DAP_DELETE(buf);
+                goto error;
+            }
+        }
+        else if(rc == 0)
+            break;
+        else
+            bytes_read += rc;
+    }
+
+    buf[bytes_read] = '\0';
+
+    if(length)
+        *length = bytes_read;
+
+    *contents = buf;
+
+    close(fd);
+
+    return true;
+
+    error:
+
+    close(fd);
+
+    return false;
+}
+
+static bool dap_get_contents_posix(const char *filename, char **contents, size_t *length)
+{
+    struct stat stat_buf;
+    int fd;
+
+    /* O_BINARY useful on Cygwin */
+    fd = open(filename, O_RDONLY | O_BINARY);
+
+    if(fd < 0)
+        return false;
+
+    /* I don't think this will ever fail, aside from ENOMEM, but. */
+    if(fstat(fd, &stat_buf) < 0) {
+        close(fd);
+        return false;
+    }
+
+    if(stat_buf.st_size > 0 && S_ISREG(stat_buf.st_mode)) {
+        bool retval = dap_get_contents_regfile(filename,
+                &stat_buf,
+                fd,
+                contents,
+                length);
+        return retval;
+    }
+    else {
+        FILE *f;
+        bool retval;
+        f = fdopen(fd, "r");
+        if(f == NULL)
+            return false;
+        retval = get_contents_stdio(filename, f, contents, length);
+        return retval;
+    }
+}
+
+#else  /* _WIN32 */
+
+static bool dap_get_contents_win32(const char *filename, char **contents, size_t *length)
+{
+    FILE *f;
+    bool retval;
+
+    f = fopen(filename, "rb");
+
+    if(f == NULL)
+    {
+        return false;
+    }
+    retval = get_contents_stdio (filename, f, contents, length, error);
+    return retval;
+}
+
+#endif
+
+/*
+ * Reads an entire file into allocated memory, with error checking.
+ */
+bool dap_file_get_contents(const char *filename, char **contents, size_t *length)
+{
+    dap_return_val_if_fail(filename != NULL, false);
+    dap_return_val_if_fail(contents != NULL, false);
+
+    *contents = NULL;
+    if(length)
+        *length = 0;
+
+#ifdef _WIN32
+  return dap_get_contents_win32 (filename, contents, length);
+#else
+    return dap_get_contents_posix(filename, contents, length);
+#endif
+}
+
diff --git a/modules/net/dap_chain_net_news.c b/modules/net/dap_chain_net_news.c
new file mode 100644
index 0000000000000000000000000000000000000000..9a132c43ce37f003602e2053f3627ab27f289903
--- /dev/null
+++ b/modules/net/dap_chain_net_news.c
@@ -0,0 +1,126 @@
+/*
+ * Authors:
+ * Alexander Lysikov <alexander.lysikov@demlabs.net>
+ * DeM Labs Inc.   https://demlabs.net
+ * Kelvin Project https://github.com/kelvinblockchain
+ * Copyright  (c) 2020
+ * All rights reserved.
+
+ This file is part of DAP (Deus Applications Prototypes) the open source project
+
+ DAP (Deus Applicaions Prototypes) is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ DAP is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with any DAP based project.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stddef.h>
+
+#include "dap_common.h"
+#include "dap_string.h"
+#include "dap_strfuncs.h"
+#include "dap_file_utils.h"
+#include "dap_config.h"
+
+#include "http_status_code.h"
+#include "dap_http_simple.h"
+#include "dap_enc_http.h"
+//#include "<dap_chain_global_db_driver.h>
+#include "dap_chain_global_db.h"
+#include "dap_chain_net_news.h"
+#define LOG_TAG "chain_net_news"
+
+#define NEWS_URL "/news"
+#define GROUP_NEWS "cdb.news"
+#define DEFAULT_LANG "en"
+
+/* Set news in the selected language
+ * a_lang - a language like "en", "ru", "fr"
+ * a_data_news - news data
+ * a_data_news_len length of news
+ */
+int dap_chain_net_news_write(char *a_lang, byte_t *a_data_news, size_t a_data_news_len)
+{
+    if(!a_data_news || !a_data_news_len)
+        return -2;
+    if(!a_lang)
+        a_lang = DEFAULT_LANG;
+    size_t l_data_len_out = 0;
+    if(dap_chain_global_db_gr_set(a_lang, a_data_news, a_data_news_len, GROUP_NEWS))
+        return 0;
+    return -1;
+}
+
+/* Get news in the selected language
+ * a_lang - a language like "en", "ru", "fr"
+ */
+byte_t* dap_chain_net_news_read(const char *a_lang, size_t *a_news_len)
+{
+    if(!a_lang)
+        return NULL;
+    byte_t *l_ret_data = NULL;
+    size_t l_data_len_num = 0;
+    dap_store_obj_t *l_obj = dap_chain_global_db_obj_gr_get(a_lang, &l_data_len_num, GROUP_NEWS);
+    if(l_obj && l_obj->value_len) {
+        l_ret_data = DAP_NEW_Z_SIZE(byte_t, l_obj->value_len);
+        memcpy(l_ret_data, l_obj->value, l_obj->value_len);
+        if(a_news_len)
+            *a_news_len = l_obj->value_len;
+    }
+    dap_store_obj_free(l_obj, l_data_len_num);
+    return l_ret_data;
+}
+
+/**
+ * @brief news_http_proc
+ * @param a_http_simple
+ * @param a_arg
+ */
+static void news_http_proc(struct dap_http_simple *a_http_simple, void * a_arg)
+{
+    log_it(L_DEBUG, "news_http_proc request");
+    http_status_code_t * return_code = (http_status_code_t*) a_arg;
+    const char *l_lang = DEFAULT_LANG;
+    if(dap_strcmp(a_http_simple->http->url_path, NEWS_URL)) {
+        l_lang = a_http_simple->http->url_path;
+    }
+
+    if(l_lang)
+    {
+        size_t l_news_data_len = 0;
+        // get news in the selected language
+        char *l_news_data = dap_chain_net_news_read(l_lang, &l_news_data_len);
+        // get news in the default language
+        if(!l_news_data && dap_strcmp(a_http_simple->http->in_query_string, "LocalNewsOnly"))
+            l_news_data = dap_chain_net_news_read(DEFAULT_LANG, &l_news_data_len);
+        a_http_simple->reply = l_news_data ? l_news_data : dap_strdup("no news");
+        a_http_simple->reply_size = l_news_data_len;
+        *return_code = Http_Status_OK;
+    }
+    else {
+        log_it(L_ERROR, "Wrong request. Must be %s/<lang_code>, example http:/<addr>%s/en", NEWS_URL, NEWS_URL);
+        a_http_simple->reply = dap_strdup_printf("Wrong request. Must be %s/<lang_code>, example http:/<addr>%s/en",
+        NEWS_URL, NEWS_URL);
+        a_http_simple->reply_size = strlen(a_http_simple->reply);
+        *return_code = Http_Status_NotFound;
+    }
+}
+
+/**
+ * @brief dap_chain_net_news_add_proc
+ * @param sh HTTP server instance
+ */
+void dap_chain_net_news_add_proc(struct dap_http * sh)
+{
+    const char * url = NEWS_URL;
+    dap_http_simple_proc_add(sh, url, 14096, news_http_proc);
+}
+
diff --git a/modules/net/dap_chain_net_news.h b/modules/net/dap_chain_net_news.h
new file mode 100644
index 0000000000000000000000000000000000000000..0982b05159e95c2af2484f1512deeb21a51c235f
--- /dev/null
+++ b/modules/net/dap_chain_net_news.h
@@ -0,0 +1,39 @@
+/*
+ * Authors:
+ * Alexander Lysikov <alexander.lysikov@demlabs.net>
+ * DeM Labs Inc.   https://demlabs.net
+ * Kelvin Project https://github.com/kelvinblockchain
+ * Copyright  (c) 2020
+ * All rights reserved.
+
+ This file is part of DAP (Deus Applications Prototypes) the open source project
+
+ DAP (Deus Applicaions Prototypes) is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ DAP is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with any DAP based project.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "dap_http.h"
+
+/* Set news in the selected language
+ * a_lang - a language like "en", "ru", "fr"
+ * a_data_news - news data
+ * a_data_news_len length of news
+ */
+int dap_chain_net_news_write(char *a_lang, byte_t *a_data_news, size_t a_data_news_len);
+
+/* Get news in the selected language
+ * a_lang - a language like "en", "ru", "fr"
+ */
+byte_t* dap_chain_net_news_read(const char *a_lang, size_t *a_news_len);
+
+void dap_chain_net_news_add_proc(struct dap_http * sh);
diff --git a/modules/net/dap_chain_node_cli.c b/modules/net/dap_chain_node_cli.c
index 3b742cf1404bdb19ba646cc8cbecbe078c580c00..1f4fe7696df1502b0356b1f51933ae1159fb1e56 100644
--- a/modules/net/dap_chain_node_cli.c
+++ b/modules/net/dap_chain_node_cli.c
@@ -1011,6 +1011,10 @@ int dap_chain_node_cli_init(dap_config_t * g_config)
     dap_chain_node_cli_cmd_item_create ("exit", com_exit, NULL, "Stop application and exit",
                 "exit\n" );
 
+    // News
+    dap_chain_node_cli_cmd_item_create("news", com_news, NULL, "Add News for VPN clients. Language code is a text code like \"en\", \"ru\", \"fr\"",
+            "news [-text <news text> | -file <filename with news>] -lang <language code> \n");
+
     // create thread for waiting of clients
     pthread_t l_thread_id;
 
diff --git a/modules/net/include/dap_chain_node_cli_cmd.h b/modules/net/include/dap_chain_node_cli_cmd.h
index 505911d1d5af8a0fee5bc35d09a802266fa7457b..cc6821e6f864c8df5ef0635916d200da3b98cdaf 100644
--- a/modules/net/include/dap_chain_node_cli_cmd.h
+++ b/modules/net/include/dap_chain_node_cli_cmd.h
@@ -133,6 +133,9 @@ int com_stats(int argc, char ** argv, void *arg_func, char **str_reply);
 
 int com_exit(int argc, char ** argv, void *arg_func, char **str_reply);
 
+// Add News for VPN clients
+int com_news(int a_argc, char ** a_argv, void *a_arg_func, char **a_str_reply);
+
 // vpn_client command
 int com_vpn_client(int a_argc, char ** a_argv, void *arg_func, char **a_str_reply);