diff --git a/.gitignore b/.gitignore
index 3b71ae8dbefc0c4382cb82ecdc3cfebf75628cba..8d7e9c280b5a26fdbffb7db57fc517098e3908f2 100644
--- a/.gitignore
+++ b/.gitignore
@@ -54,5 +54,7 @@ test/fast/modules/crawler/block_pulling.js*
 test/fast/modules/crawler/block_pulling.d.ts
 test/fast/fork*.js*
 test/fast/fork*.d.ts
+test/fast/proxies*.js*
+test/fast/proxies*.d.ts
 test/fast/modules/ws2p/*.js*
 test/fast/modules/ws2p/*.d.ts
diff --git a/app/cli.ts b/app/cli.ts
index cedf3a7fa3b2bf3705896010e990d2474b85cbe4..26accf24f158facb605808a72bfaec2dfc9f2abd 100644
--- a/app/cli.ts
+++ b/app/cli.ts
@@ -49,6 +49,12 @@ export const ExecuteCommand = () => {
         .option('--nostdout', 'Disable stdout printing for `export-bc` command')
         .option('--noshuffle', 'Disable peers shuffling for `sync` command')
 
+        .option('--socks-proxy <host:port>', 'Use Socks Proxy')
+        .option('--tor-proxy <host:port>', 'Use Tor Socks Proxy')
+        .option('--reaching-clear-ep <clear|tor|none>', 'method for reaching an clear endpoint')
+        .option('--force-tor', 'force duniter to contact endpoint tor (if you redirect the traffic to tor yourself)')
+        .option('--rm-proxies', 'Remove all proxies')
+
         .option('--timeout <milliseconds>', 'Timeout to use when contacting peers', parseInt)
         .option('--httplogs', 'Enable HTTP logs')
         .option('--nohttplogs', 'Disable HTTP logs')
diff --git a/app/lib/common-libs/constants.ts b/app/lib/common-libs/constants.ts
index 14465aade0602c1525116e0c7fa7a210011373f6..89b6e7dba4952a541a4d0011ef93bdad4b48a52f 100644
--- a/app/lib/common-libs/constants.ts
+++ b/app/lib/common-libs/constants.ts
@@ -31,9 +31,13 @@ const UNLOCK       = "(SIG\\(" + INTEGER + "\\)|XHX\\(" + XUNLOCK + "\\))"
 const CONDITIONS   = "(&&|\\|\\|| |[()]|(SIG\\(" + PUBKEY + "\\)|(XHX\\([A-F0-9]{64}\\)|CLTV\\(" + CLTV_INTEGER + "\\)|CSV\\(" + CSV_INTEGER + "\\))))*"
 
 const BMA_REGEXP  = /^BASIC_MERKLED_API( ([a-z_][a-z0-9-_.]*))?( ([0-9.]+))?( ([0-9a-f:]+))?( ([0-9]+))$/
+const BMATOR_REGEXP = /^BMATOR( ([a-z0-9]{16})\.onion)( ([0-9.]+))?( ([0-9a-f:]+))?( ([0-9]+))$/
 const WS2P_REGEXP = /^WS2P ([a-f0-9]{8}) ([a-z_][a-z0-9-_.]*|[0-9.]+|[0-9a-f:]+) ([0-9]+)(?: (.+))?$/
+const WS2PTOR_REGEXP = /^WS2PTOR ([a-f0-9]{8}) ([a-z0-9-_.]*|[0-9.]+|[0-9a-f:]+.onion) ([0-9]+)(?: (.+))?$/
+const WS_FULL_ADDRESS_ONION_REGEX = /^(?:wss?:\/\/)(?:www\.)?([0-9a-z]{16}\.onion)(:[0-9]+)?$/
 const IPV4_REGEXP = /^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$/;
 const IPV6_REGEXP = /^((([0-9A-Fa-f]{1,4}:){7}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){6}:[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){5}:([0-9A-Fa-f]{1,4}:)?[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){4}:([0-9A-Fa-f]{1,4}:){0,2}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){3}:([0-9A-Fa-f]{1,4}:){0,3}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){2}:([0-9A-Fa-f]{1,4}:){0,4}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){6}((b((25[0-5])|(1d{2})|(2[0-4]d)|(d{1,2}))b).){3}(b((25[0-5])|(1d{2})|(2[0-4]d)|(d{1,2}))b))|(([0-9A-Fa-f]{1,4}:){0,5}:((b((25[0-5])|(1d{2})|(2[0-4]d)|(d{1,2}))b).){3}(b((25[0-5])|(1d{2})|(2[0-4]d)|(d{1,2}))b))|(::([0-9A-Fa-f]{1,4}:){0,5}((b((25[0-5])|(1d{2})|(2[0-4]d)|(d{1,2}))b).){3}(b((25[0-5])|(1d{2})|(2[0-4]d)|(d{1,2}))b))|([0-9A-Fa-f]{1,4}::([0-9A-Fa-f]{1,4}:){0,5}[0-9A-Fa-f]{1,4})|(::([0-9A-Fa-f]{1,4}:){0,6}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){1,7}:))$/;
+const HOST_ONION_REGEX = /^(?:www\.)?([0-9a-z]{16}\.onion)$/
 
 const MAXIMUM_LEN_OF_COMPACT_TX = 100
 const MAXIMUM_LEN_OF_OUTPUT = 2000
@@ -89,9 +93,13 @@ export const CommonConstants = {
   SWITCH_ON_BRANCH_AHEAD_BY_X_BLOCKS: 3,
 
   BMA_REGEXP,
+  BMATOR_REGEXP,
   WS2P_REGEXP,
+  WS2PTOR_REGEXP,
+  WS_FULL_ADDRESS_ONION_REGEX,
   IPV4_REGEXP,
   IPV6_REGEXP,
+  HOST_ONION_REGEX,
   PUBLIC_KEY: exact(PUBKEY),
   INTEGER: /^\d+$/,
   BASE58: exact(BASE58),
diff --git a/app/lib/constants.ts b/app/lib/constants.ts
index cac2f7a07204a72e2af657ee0b36282c85f4ab59..26180e81d5fb6efe6799f0096f9a914b0091d885 100644
--- a/app/lib/constants.ts
+++ b/app/lib/constants.ts
@@ -109,7 +109,8 @@ module.exports = {
     STATUS_INTERVAL: {
       UPDATE: 2, // Every X blocks
       MAX: 20 // MAX Y blocks
-    }
+    },
+    ONION_ENDPOINT_REGEX: new RegExp('(?:https?:\/\/)?(?:www)?(\S*?\.onion)(\/[-\w]*)*')
   },
   PROOF_OF_WORK: {
     EVALUATION: 1000,
diff --git a/app/lib/dal/fileDAL.ts b/app/lib/dal/fileDAL.ts
index 6281d83fbb597df5703258b7ffde398550a5ba07..6002261231996b2e8b4b2538b8d8349109ef127f 100644
--- a/app/lib/dal/fileDAL.ts
+++ b/app/lib/dal/fileDAL.ts
@@ -15,6 +15,7 @@ import {DBBlock} from "../db/DBBlock"
 import {DBMembership} from "./sqliteDAL/MembershipDAL"
 import {MerkleDTO} from "../dto/MerkleDTO"
 import {CommonConstants} from "../common-libs/constants"
+import { ProxiesConf } from '../proxy';
 
 const fs      = require('fs')
 const path    = require('path')
@@ -142,7 +143,7 @@ export class FileDAL {
   }
 
   async getWS2Peers() {
-    return this.peerDAL.getPeersWithEndpointsLike('WS2P ')
+    return  this.peerDAL.getPeersWithEndpointsLike('WS2P')
   }
 
   async getBlock(number:number) {
@@ -842,7 +843,11 @@ export class FileDAL {
     let conf = ConfDTO.complete(overrideConf || {});
     if (!defaultConf) {
       const savedConf = await this.confDAL.loadConf();
+      const savedProxyConf = _(savedConf.proxyConf).extend({});
       conf = _(savedConf).extend(overrideConf || {});
+      if (overrideConf.proxiesConf !== undefined) {} else {
+        conf.proxyConf = _(savedProxyConf).extend({});
+      }
     }
     if (this.loadConfHook) {
       await this.loadConfHook(conf)
diff --git a/app/lib/dto/ConfDTO.ts b/app/lib/dto/ConfDTO.ts
index 361eb49c9d0922b3e4fffb6b4e0c4bc9e25ce7ed..f6c57cc5eea581e96a0e188d4265941ceb79b239 100644
--- a/app/lib/dto/ConfDTO.ts
+++ b/app/lib/dto/ConfDTO.ts
@@ -1,4 +1,5 @@
 import {CommonConstants} from "../common-libs/constants"
+import { ProxiesConf } from '../proxy';
 const _ = require('underscore');
 const constants = require('../constants');
 
@@ -46,7 +47,9 @@ export interface KeypairConfDTO {
 }
 
 export interface NetworkConfDTO {
+  proxiesConf: ProxiesConf|undefined
   nobma: boolean
+  bmaWithCrawler: boolean
   remoteport: number
   remotehost: string|null
   remoteipv4: string|null
@@ -134,6 +137,8 @@ export class ConfDTO implements CurrencyConfDTO, KeypairConfDTO, NetworkConfDTO,
     public homename: string,
     public memory: boolean,
     public nobma: boolean,
+    public bmaWithCrawler: boolean,
+    public proxiesConf: ProxiesConf|undefined,
     public ws2p?: {
       privateAccess: boolean
       publicAccess: boolean
@@ -152,7 +157,7 @@ export class ConfDTO implements CurrencyConfDTO, KeypairConfDTO, NetworkConfDTO,
 ) {}
 
   static mock() {
-    return new ConfDTO("", "", [], [], 0, 0, 0.6, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, false, 0, false, 0, 0, 0, 0, 0, { pub:'', sec:'' }, null, "", "", 0, "", "", "", 0, "", "", null, false, "", true, true)
+    return new ConfDTO("", "", [], [], 0, 0, 0.6, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, false, 0, false, 0, 0, 0, 0, 0, { pub:'', sec:'' }, null, "", "", 0, "", "", "", 0, "", "", null, false, "", true, false, true, undefined)
   }
 
   static defaultConf() {
diff --git a/app/lib/dto/PeerDTO.ts b/app/lib/dto/PeerDTO.ts
index 738c540632ab7e831e6a501fde83d622a2e2d3a7..dc5754b6893349a0009b66e1cbb21c78d7b116a7 100644
--- a/app/lib/dto/PeerDTO.ts
+++ b/app/lib/dto/PeerDTO.ts
@@ -94,16 +94,30 @@ export class PeerDTO implements Cloneable {
     return bma || {};
   }
 
-  getWS2P() {
+  getWS2P(canReachTorEp:boolean, canReachClearEp:boolean) {
     let api:{ uuid:string, host:string, port:number, path:string }|null = null
+    const endpointRegexp = (canReachTorEp) ? CommonConstants.WS2PTOR_REGEXP:CommonConstants.WS2P_REGEXP
     for (const ep of this.endpoints) {
-      const matches:any = !api && ep.match(CommonConstants.WS2P_REGEXP)
-      if (matches) {
-        api = {
-          uuid: matches[1],
-          host: matches[2] || '',
-          port: parseInt(matches[3]) || 0,
-          path: matches[4]
+      if (canReachTorEp) {
+        const matches:any = ep.match(CommonConstants.WS2PTOR_REGEXP)
+        if (matches) {
+          return {
+            uuid: matches[1],
+            host: matches[2] || '',
+            port: parseInt(matches[3]) || 0,
+            path: matches[4]
+          }
+        }
+      }
+      if (canReachClearEp) {
+        const matches:any = !api && ep.match(CommonConstants.WS2P_REGEXP)
+        if (matches) {
+          api = {
+            uuid: matches[1],
+            host: matches[2] || '',
+            port: parseInt(matches[3]) || 0,
+            path: matches[4]
+          }
         }
       }
     }
diff --git a/app/lib/proxy.ts b/app/lib/proxy.ts
new file mode 100644
index 0000000000000000000000000000000000000000..340de605c58ebb5b84fec40fd73889acbb7339cd
--- /dev/null
+++ b/app/lib/proxy.ts
@@ -0,0 +1,52 @@
+import {CommonConstants} from "./common-libs/constants"
+
+const SocksProxyAgent = require('socks-proxy-agent');
+
+export class ProxiesConf {
+  public proxySocksAddress: string|undefined
+  public proxyTorAddress: string|undefined
+  public reachingClearEp: string
+  public forceTor: boolean
+
+  constructor () {
+    this.proxySocksAddress = undefined
+    this.proxyTorAddress = undefined
+    this.reachingClearEp = 'clear'
+    this.forceTor = false
+  }
+
+  static canReachClearEndpoint(proxiesConf: ProxiesConf|undefined):boolean {
+    return (proxiesConf === undefined || proxiesConf.reachingClearEp !== 'none')
+  }
+
+  static canReachTorEndpoint(proxiesConf: ProxiesConf|undefined):boolean {
+    return (proxiesConf !== undefined && (proxiesConf.forceTor || proxiesConf.proxyTorAddress !== undefined) )
+  }
+
+  static httpProxy(url:string, proxiesConf: ProxiesConf|undefined):string|undefined {
+    return ProxiesConf.chooseProxyAgent(url, proxiesConf, CommonConstants.HOST_ONION_REGEX)
+  }
+
+  static wsProxy(address:string, proxiesConf: ProxiesConf|undefined):string|undefined {
+    return ProxiesConf.chooseProxyAgent(address, proxiesConf, CommonConstants.WS_FULL_ADDRESS_ONION_REGEX)
+  }
+
+  private static chooseProxyAgent(address:string, proxiesConf: ProxiesConf|undefined,  onionRegex:RegExp):string|undefined {
+    if (proxiesConf !== undefined) {
+      if (address.match(onionRegex)) {
+        if (ProxiesConf.canReachTorEndpoint(proxiesConf)) {
+          return proxiesConf.proxyTorAddress
+        }
+      } else {
+        if (ProxiesConf.canReachClearEndpoint(proxiesConf)) {
+          if (proxiesConf.reachingClearEp == 'tor') {
+            return proxiesConf.proxyTorAddress
+          } else {
+            return proxiesConf.proxySocksAddress
+          }
+        }
+      }
+    }
+    return undefined
+  }
+}
\ No newline at end of file
diff --git a/app/modules/bma/index.ts b/app/modules/bma/index.ts
index 914a6ecf4465032babe6e223b09273bf017ef416..d9b4c2d023f256aaa4ce520b6180e40b0257b657 100644
--- a/app/modules/bma/index.ts
+++ b/app/modules/bma/index.ts
@@ -29,6 +29,8 @@ export const BmaDependency = {
       { value: '--noupnp', desc: 'Do not use UPnP to open remote port.' },
       { value: '--bma',   desc: 'Enables BMA API and its crawlers.' },
       { value: '--nobma', desc: 'Disables BMA API and its crawlers.' },
+      { value: '--bma-with-crawler',   desc: 'Enables BMA Crawler.' },
+      { value: '--bma-without-crawler', desc: 'Disable BMA Crawler.' },
       { value: '-p, --port <port>', desc: 'Port to listen for requests', parser: (val:string) => parseInt(val) },
       { value: '--ipv4 <address>', desc: 'IPv4 interface to listen for requests' },
       { value: '--ipv6 <address>', desc: 'IPv6 interface to listen for requests' },
@@ -73,6 +75,9 @@ export const BmaDependency = {
           }
         }
 
+        // If bmaWithCrawler hasn't been defined yet
+        if (conf.bmaWithCrawler === undefined) { conf.bmaWithCrawler = false }
+
         if (program.port !== undefined) conf.port = parseInt(program.port)
         if (program.ipv4 !== undefined) conf.ipv4 = program.ipv4;
         if (program.ipv6 !== undefined) conf.ipv6 = program.ipv6;
@@ -82,6 +87,8 @@ export const BmaDependency = {
         if (program.remotep !== undefined) conf.remoteport = parseInt(program.remotep)
         if (program.bma !== undefined) conf.nobma = false
         if (program.nobma !== undefined) conf.nobma = true
+        if (program.bmaWithCrawler !== undefined) conf.bmaWithCrawler = true
+        if (program.bmaWithoutCrawler !== undefined) conf.bmaWithCrawler = false
 
         if (!conf.ipv4) delete conf.ipv4;
         if (!conf.ipv6) delete conf.ipv6;
@@ -253,6 +260,9 @@ export class BMAPI extends stream.Transform {
 function getEndpoint(theConf:NetworkConfDTO) {
   let endpoint = 'BASIC_MERKLED_API';
   if (theConf.remotehost) {
+    if (theConf.remotehost.match(BMAConstants.HOST_ONION_REGEX)) {
+      endpoint = 'BMATOR';
+    }
     endpoint += ' ' + theConf.remotehost;
   }
   if (theConf.remoteipv4) {
diff --git a/app/modules/bma/lib/constants.ts b/app/modules/bma/lib/constants.ts
index 6caa2204bd605ba3eadce521da6eaea61a352c22..20a76a6eb9cc64e8a6710c5667c1129a836e7694 100644
--- a/app/modules/bma/lib/constants.ts
+++ b/app/modules/bma/lib/constants.ts
@@ -1,3 +1,4 @@
+import {CommonConstants} from "../../../lib/common-libs/constants"
 export const BMAConstants = {
 
   BMA_PORTS_START: 10901,
@@ -6,6 +7,7 @@ export const BMAConstants = {
   DEFAULT_PORT: 10901,
   IPV4_REGEXP: /^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$/,
   IPV6_REGEXP: /^((([0-9A-Fa-f]{1,4}:){7}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){6}:[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){5}:([0-9A-Fa-f]{1,4}:)?[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){4}:([0-9A-Fa-f]{1,4}:){0,2}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){3}:([0-9A-Fa-f]{1,4}:){0,3}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){2}:([0-9A-Fa-f]{1,4}:){0,4}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){6}((b((25[0-5])|(1d{2})|(2[0-4]d)|(d{1,2}))b).){3}(b((25[0-5])|(1d{2})|(2[0-4]d)|(d{1,2}))b))|(([0-9A-Fa-f]{1,4}:){0,5}:((b((25[0-5])|(1d{2})|(2[0-4]d)|(d{1,2}))b).){3}(b((25[0-5])|(1d{2})|(2[0-4]d)|(d{1,2}))b))|(::([0-9A-Fa-f]{1,4}:){0,5}((b((25[0-5])|(1d{2})|(2[0-4]d)|(d{1,2}))b).){3}(b((25[0-5])|(1d{2})|(2[0-4]d)|(d{1,2}))b))|([0-9A-Fa-f]{1,4}::([0-9A-Fa-f]{1,4}:){0,5}[0-9A-Fa-f]{1,4})|(::([0-9A-Fa-f]{1,4}:){0,6}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){1,7}:))$/,
+  HOST_ONION_REGEX: CommonConstants.HOST_ONION_REGEX,
   PORT_START: 15000,
   UPNP_INTERVAL: 300,
   UPNP_TTL: 600,
diff --git a/app/modules/bma/lib/network.ts b/app/modules/bma/lib/network.ts
index 33b994afed703260ca4ab2a28e235195608be799..3e9e026f966695db0dd83a977605e5a26c1f2439 100644
--- a/app/modules/bma/lib/network.ts
+++ b/app/modules/bma/lib/network.ts
@@ -337,7 +337,9 @@ async function upnpConf (noupnp:boolean, logger:any) {
   const publicPort = await getAvailablePort(client)
   const privatePort = publicPort
   const conf:NetworkConfDTO = {
+    proxiesConf: undefined,
     nobma: true,
+    bmaWithCrawler: false,
     port: privatePort,
     ipv4: '127.0.0.1',
     ipv6: '::1',
diff --git a/app/modules/crawler/lib/crawler.ts b/app/modules/crawler/lib/crawler.ts
index 44bf5a217fa08548046b2a2e297c9dd341db41c5..9520c5e3abbae6b58d033c04f7879ef051205b56 100644
--- a/app/modules/crawler/lib/crawler.ts
+++ b/app/modules/crawler/lib/crawler.ts
@@ -48,7 +48,7 @@ export class Crawler extends stream.Transform implements DuniterService {
   }
 
   startService() {
-    if (this.conf.nobma) {
+    if (this.conf.nobma || !this.conf.bmaWithCrawler) {
       return Promise.resolve()
     }
     return Promise.all([
@@ -60,7 +60,7 @@ export class Crawler extends stream.Transform implements DuniterService {
   }
 
   stopService() {
-    if (this.conf.nobma) {
+    if (this.conf.nobma || !this.conf.bmaWithCrawler) {
       return Promise.resolve()
     }
     return Promise.all([
diff --git a/app/modules/router.ts b/app/modules/router.ts
index 1530cc43e516b63511b385767f50390ebe88bcba..d6484f05ba8d3ef1a74e8440c44c25aae80af128 100644
--- a/app/modules/router.ts
+++ b/app/modules/router.ts
@@ -44,7 +44,7 @@ class Router extends stream.Transform {
   };
 
   async startService() {
-    if (this.server.conf.nobma) {
+    if (this.server.conf.nobma || !this.server.conf.bmaWithCrawler) {
       // Disable BMA
       return Promise.resolve()
     }
@@ -69,7 +69,7 @@ class Router extends stream.Transform {
   }
 
   async stopService() {
-    if (this.server.conf.nobma) {
+    if (this.server.conf.nobma || !this.server.conf.bmaWithCrawler) {
       // Disable BMA
       return Promise.resolve()
     }
diff --git a/app/modules/ws2p/index.ts b/app/modules/ws2p/index.ts
index 53e311b02d229b320107b38dcaddbc9ea031c009..a225e63ec314dc43e0dd77f308ec4cb7a5d2a58b 100644
--- a/app/modules/ws2p/index.ts
+++ b/app/modules/ws2p/index.ts
@@ -1,7 +1,8 @@
 "use strict";
+import { WS2PConstants } from './lib/constants';
 import {ConfDTO, WS2PConfDTO} from "../../lib/dto/ConfDTO"
 import {Server} from "../../../server"
-import * as stream from "stream"
+import * as stream from 'stream';
 import {WS2PCluster} from "./lib/WS2PCluster"
 import {WS2PUpnp} from "./lib/ws2p-upnp"
 import {CommonConstants} from "../../lib/common-libs/constants"
@@ -140,7 +141,7 @@ export const WS2PDependency = {
             const peers = await server.dal.getWS2Peers()
             for (const p of peers) {
               for (const ep of p.endpoints) {
-                if (ep.match(/^WS2P /)) {
+                if (ep.match(/^WS2P/)) {
                   console.log(p.pubkey, ep)
                 }
               }
@@ -242,22 +243,29 @@ export class WS2PAPI extends stream.Transform {
     // If WS2P defined and enabled
     if (this.server.conf.ws2p !== undefined && (this.server.conf.ws2p.publicAccess || this.server.conf.ws2p.privateAccess))
     {
+      let endpointType = "WS2P"
       if (this.server.conf.upnp && this.upnpAPI) {
         const config = this.upnpAPI.getCurrentConfig()
-        return !config ? '' : ['WS2P', this.server.conf.ws2p.uuid, config.remotehost, config.port].join(' ')
+        if (config) {
+          if (config.remotehost.match(WS2PConstants.HOST_ONION_REGEX)) { endpointType += "TOR"; }
+          return [endpointType, this.server.conf.ws2p.uuid, config.remotehost, config.port].join(' ')
+        } else {
+          return ''
+        }
       }
       else if (this.server.conf.ws2p.uuid
         && this.server.conf.ws2p.remotehost
         && this.server.conf.ws2p.remoteport) {
-        let ep = ['WS2P',
-          this.server.conf.ws2p.uuid,
-          this.server.conf.ws2p.remotehost,
-          this.server.conf.ws2p.remoteport
-        ].join(' ')
-        if (this.server.conf.ws2p.remotepath) {
-          ep += ` ${this.server.conf.ws2p.remotepath}`
-        }
-        return ep
+          if (this.server.conf.ws2p.remotehost.match(WS2PConstants.HOST_ONION_REGEX)) { endpointType += "TOR"; }
+          let ep = [endpointType,
+            this.server.conf.ws2p.uuid,
+            this.server.conf.ws2p.remotehost,
+            this.server.conf.ws2p.remoteport
+          ].join(' ')
+          if (this.server.conf.ws2p.remotepath) {
+            ep += ` ${this.server.conf.ws2p.remotepath}`
+          }
+          return ep
       }
     }
     return ''
diff --git a/app/modules/ws2p/lib/WS2PClient.ts b/app/modules/ws2p/lib/WS2PClient.ts
index 34710012a92988df92e4255bd6c2357c1381cebf..569609f6e1c06bbdef4b7c8c9fadfcf48569972c 100644
--- a/app/modules/ws2p/lib/WS2PClient.ts
+++ b/app/modules/ws2p/lib/WS2PClient.ts
@@ -1,3 +1,4 @@
+import { WS2PCluster } from './WS2PCluster';
 import {Server} from "../../../../server"
 import {WS2PConnection, WS2PPubkeyLocalAuth, WS2PPubkeyRemoteAuth} from "./WS2PConnection"
 import {Key} from "../../../lib/common-libs/crypto/keyring"
@@ -5,18 +6,21 @@ import {WS2PMessageHandler} from "./impl/WS2PMessageHandler"
 import {WS2PConstants} from "./constants"
 import {WS2PStreamer} from "./WS2PStreamer"
 import {WS2PSingleWriteStream} from "./WS2PSingleWriteStream"
+import { ProxiesConf } from '../../../lib/proxy';
+import { server } from '../../../../test/integration/tools/toolbox';
 
 export class WS2PClient {
 
   private constructor(public connection:WS2PConnection) {}
 
-  static async connectTo(server:Server, fullEndpointAddress:string, messageHandler:WS2PMessageHandler, expectedPub:string, allowKey:(pub:string)=>Promise<boolean> ) {
+  static async connectTo(server:Server, fullEndpointAddress:string, uuid:string, messageHandler:WS2PMessageHandler, expectedPub:string, allowKey:(pub:string)=>Promise<boolean> ) {
     const k2 = new Key(server.conf.pair.pub, server.conf.pair.sec)
     const c = WS2PConnection.newConnectionToAddress(
       fullEndpointAddress,
       messageHandler,
       new WS2PPubkeyLocalAuth(server.conf.currency , k2, allowKey),
       new WS2PPubkeyRemoteAuth(server.conf.currency, k2, allowKey),
+      ProxiesConf.wsProxy(fullEndpointAddress, server.conf.proxiesConf),
       {
         connectionTimeout: WS2PConstants.REQUEST_TIMEOUT,
         requestTimeout: WS2PConstants.REQUEST_TIMEOUT
diff --git a/app/modules/ws2p/lib/WS2PCluster.ts b/app/modules/ws2p/lib/WS2PCluster.ts
index 4ea5d7a21df56bf5c1def34fdab5088ecbaa36d5..70197333448da3996fb2eab262c2745616bd323c 100644
--- a/app/modules/ws2p/lib/WS2PCluster.ts
+++ b/app/modules/ws2p/lib/WS2PCluster.ts
@@ -13,9 +13,10 @@ import {OtherConstants} from "../../../lib/other_constants"
 import {Key, verify} from "../../../lib/common-libs/crypto/keyring"
 import {WS2PServerMessageHandler} from "./interface/WS2PServerMessageHandler"
 import {WS2PMessageHandler} from "./impl/WS2PMessageHandler"
-import { CommonConstants } from "../../../lib/common-libs/constants";
+import { CommonConstants } from '../../../lib/common-libs/constants';
 import { Package } from "../../../lib/common/package";
 import { Constants } from "../../prover/lib/constants";
+import { ProxiesConf } from '../../../lib/proxy';
 
 const es = require('event-stream')
 const nuuid = require('node-uuid')
@@ -290,17 +291,18 @@ export class WS2PCluster {
 
   async connectToRemoteWS(host: string, port: number, path:string, messageHandler:WS2PMessageHandler, expectedPub:string, ws2pEndpointUUID:string = ""): Promise<WS2PConnection> {
     const uuid = nuuid.v4()
-    let pub = "--------"
+    let pub = expectedPub.slice(0, 8)
+    const api:string = (host.match(WS2PConstants.HOST_ONION_REGEX) !== null) ? 'WS2PTOR':'WS2P'
     try {
       const fullEndpointAddress = WS2PCluster.getFullAddress(host, port, path)
-      const ws2pc = await WS2PClient.connectTo(this.server, fullEndpointAddress, messageHandler, expectedPub, (pub:string) => {
+      const ws2pc = await WS2PClient.connectTo(this.server, fullEndpointAddress, ws2pEndpointUUID, messageHandler, expectedPub, (pub:string) => {
         const connectedPubkeys = this.getConnectedPubkeys()
         return this.acceptPubkey(expectedPub, connectedPubkeys, () => this.clientsCount(), this.maxLevel1Size, (this.server.conf.ws2p && this.server.conf.ws2p.preferedNodes || []), ws2pEndpointUUID)
       })
       this.ws2pClients[uuid] = ws2pc
       pub = ws2pc.connection.pubkey
       ws2pc.connection.closed.then(() => {
-        this.server.logger.info('WS2P: connection [%s `WS2P %s %s`] has been closed', pub.slice(0, 8), host, port)
+        this.server.logger.info(api+': connection [%s `'+api+' %s %s`] has been closed', pub.slice(0, 8), host, port)
         this.server.push({
           ws2p: 'disconnected',
           peer: {
@@ -311,7 +313,7 @@ export class WS2PCluster {
           delete this.ws2pClients[uuid]
         }
       })
-      this.server.logger.info('WS2P: connected to peer %s using `WS2P %s %s`!', pub.slice(0, 8), host, port)
+      this.server.logger.info(api+': connected to peer %s using `'+api+' %s %s`!', pub.slice(0, 8), host, port)
       this.server.push({
         ws2p: 'connected',
         to: { host, port, pubkey: pub }
@@ -319,7 +321,7 @@ export class WS2PCluster {
       await this.server.dal.setPeerUP(pub)
       return ws2pc.connection
     } catch (e) {
-      this.server.logger.info('WS2P: Could not connect to peer %s using `WS2P %s %s: %s`', pub.slice(0, 8), host, port, (e && e.message || e))
+      this.server.logger.info(api+': Could not connect to peer %s using `'+api+' %s %s: %s`', pub.slice(0, 8), host, port, (e && e.message || e))
       throw e
     }
   }
@@ -330,21 +332,45 @@ export class WS2PCluster {
     const prefered = ((this.server.conf.ws2p && this.server.conf.ws2p.preferedNodes) || []).slice() // Copy
     // Our key is also a prefered one, so we connect to our siblings
     prefered.push(this.server.conf.pair.pub)
+    const canReachTorEndpoint = ProxiesConf.canReachTorEndpoint(this.server.conf.proxiesConf)
     peers.sort((a, b) => {
       const aIsPrefered = prefered.indexOf(a.pubkey) !== -1
       const bIsPrefered = prefered.indexOf(b.pubkey) !== -1
-      if ((aIsPrefered && bIsPrefered) || (!aIsPrefered && !bIsPrefered)) {
-        return 0
-      } else if (aIsPrefered) {
-        return -1
+
+      if (canReachTorEndpoint) {
+        const aAtWs2pTorEnpoint = a.endpoints.filter(function (element) { return element.match(CommonConstants.WS2PTOR_REGEXP); }).length > 0
+        const bAtWs2pTorEnpoint = b.endpoints.filter(function (element) { return element.match(CommonConstants.WS2PTOR_REGEXP); }).length > 0
+
+        if ( (aAtWs2pTorEnpoint && bAtWs2pTorEnpoint) || (!aAtWs2pTorEnpoint && !bAtWs2pTorEnpoint) ) {
+          if ((aIsPrefered && bIsPrefered) || (!aIsPrefered && !bIsPrefered))  {
+            return 0
+          } else if (aIsPrefered) {
+            return -1
+          } else {
+            return 1
+          }
+        } else {
+          if (aAtWs2pTorEnpoint) {
+            return -1
+          } else {
+            return 1
+          }
+        }
       } else {
-        return 1
+        if ((aIsPrefered && bIsPrefered) || (!aIsPrefered && !bIsPrefered))  {
+          return 0
+        } else if (aIsPrefered) {
+          return -1
+        } else {
+          return 1
+        }
       }
     })
     let i = 0
+    const canReachClearEndpoint = ProxiesConf.canReachClearEndpoint(this.server.conf.proxiesConf)
     while (i < peers.length && this.clientsCount() < this.maxLevel1Size) {
       const p = peers[i]
-      const api = p.getWS2P()
+      const api = p.getWS2P(canReachTorEndpoint, canReachClearEndpoint)
       if (api) {
         try {
           // We do not connect to local host
@@ -371,7 +397,7 @@ export class WS2PCluster {
         // New peer
         if (data.endpoints) {
           const peer = PeerDTO.fromJSONObject(data)
-          const ws2pEnpoint = peer.getWS2P()
+          const ws2pEnpoint = peer.getWS2P(ProxiesConf.canReachTorEndpoint(this.server.conf.proxiesConf), ProxiesConf.canReachClearEndpoint(this.server.conf.proxiesConf))
           if (ws2pEnpoint) {
             // Check if already connected to the pubkey (in any way: server or client)
             const connectedPubkeys = this.getConnectedPubkeys()
@@ -437,13 +463,14 @@ export class WS2PCluster {
   }
 
   private sayHeadChangedTo(number:number, hash:string) {
+    const api = (this.server.conf.ws2p && this.server.conf.ws2p.remotehost && this.server.conf.ws2p.remotehost.match(WS2PConstants.HOST_ONION_REGEX)) ? 'WS2P':'WS2P'
     const key = new Key(this.server.conf.pair.pub, this.server.conf.pair.sec)
     const pub = key.publicKey
     const software = 'duniter'
     const softVersion = Package.getInstance().version
     const ws2pId = (this.server.conf.ws2p && this.server.conf.ws2p.uuid) || '00000000'
     const prefix = this.server.conf.prefix || Constants.DEFAULT_PEER_ID
-    const message = `WS2P:HEAD:1:${pub}:${number}-${hash}:${ws2pId}:${software}:${softVersion}:${prefix}`
+    const message = `${api}:HEAD:1:${pub}:${number}-${hash}:${ws2pId}:${software}:${softVersion}:${prefix}`
     const sig = key.signSync(message)
     return { sig, message, pub }
   }
@@ -624,7 +651,7 @@ export class WS2PCluster {
 
   async startCrawling(waitConnection = false) {
     // For connectivity
-    this.reconnectionInteval = setInterval(() => this.server.push({ ws2p: 'disconnected' }), 1000 * 60 * 10)
+    this.reconnectionInteval = setInterval(() => this.server.push({ ws2p: 'disconnected' }), 1000 * WS2PConstants.RECONNEXION_INTERVAL_IN_SEC)
     // For blocks
     if (this.syncBlockInterval)
       clearInterval(this.syncBlockInterval);
diff --git a/app/modules/ws2p/lib/WS2PConnection.ts b/app/modules/ws2p/lib/WS2PConnection.ts
index e97bde407c0420f028f2c8e95ae0c907abc8017b..0595e5626b4e307fffdd2be5d149ce6d33323bd7 100644
--- a/app/modules/ws2p/lib/WS2PConnection.ts
+++ b/app/modules/ws2p/lib/WS2PConnection.ts
@@ -7,7 +7,9 @@ import {MembershipDTO} from "../../../lib/dto/MembershipDTO"
 import {TransactionDTO} from "../../../lib/dto/TransactionDTO"
 import {PeerDTO} from "../../../lib/dto/PeerDTO"
 import {WS2PConstants} from "./constants"
+import { ProxiesConf } from '../../../lib/proxy';
 const ws = require('ws')
+const SocksProxyAgent = require('socks-proxy-agent');
 const nuuid = require('node-uuid');
 const logger = require('../../../lib/logger').NewLogger('ws2p')
 
@@ -267,15 +269,22 @@ export class WS2PConnection {
     messageHandler:WS2PMessageHandler,
     localAuth:WS2PLocalAuth,
     remoteAuth:WS2PRemoteAuth,
+    proxySocksAddress:string|undefined = undefined,
     options:{
-      connectionTimeout:number
+      connectionTimeout:number,
       requestTimeout:number
     } = {
       connectionTimeout: REQUEST_TIMEOUT_VALUE,
       requestTimeout: REQUEST_TIMEOUT_VALUE
     },
     expectedPub:string = "") {
-    const websocket = new ws(address)
+      if (address.match(WS2PConstants.FULL_ADDRESS_ONION_REGEX)) {
+        options = {
+          connectionTimeout: WS2PConstants.CONNEXION_TOR_TIMEOUT,
+          requestTimeout: WS2PConstants.REQUEST_TOR_TIMEOUT
+        }
+      }
+      const websocket = (proxySocksAddress !== undefined) ? new ws(address, { agent: SocksProxyAgent("socks://"+proxySocksAddress) }):new ws(address)
     const onWsOpened:Promise<void> = new Promise(res => {
       websocket.on('open', () => res())
     })
diff --git a/app/modules/ws2p/lib/WS2PServer.ts b/app/modules/ws2p/lib/WS2PServer.ts
index c9d3dc9fb025dbcc318c7ef6ede9bbedf08c44de..ae79815fe93af6f0c24ebb355e7d404681165748 100644
--- a/app/modules/ws2p/lib/WS2PServer.ts
+++ b/app/modules/ws2p/lib/WS2PServer.ts
@@ -63,16 +63,23 @@ export class WS2PServer extends events.EventEmitter {
         }
         return await this.shouldAcceptConnection(pub, this.getConnexions().map(c => c.pubkey))
       }
+      let timeout = {
+        connectionTimeout: WS2PConstants.CONNEXION_TIMEOUT,
+        requestTimeout: WS2PConstants.REQUEST_TIMEOUT
+      }
+      if (this.server.conf.ws2p && this.server.conf.ws2p.remotehost && this.server.conf.ws2p.remotehost.match(WS2PConstants.HOST_ONION_REGEX)) {
+        timeout = {
+          connectionTimeout: WS2PConstants.CONNEXION_TOR_TIMEOUT,
+          requestTimeout: WS2PConstants.REQUEST_TOR_TIMEOUT
+        }
+      }
 
       const c = WS2PConnection.newConnectionFromWebSocketServer(
         ws,
         messageHandler,
         new WS2PPubkeyLocalAuth(this.server.conf.currency, key, acceptPubkey),
         new WS2PPubkeyRemoteAuth(this.server.conf.currency, key, acceptPubkey),
-        {
-          connectionTimeout: WS2PConstants.CONNEXION_TIMEOUT,
-          requestTimeout: WS2PConstants.REQUEST_TIMEOUT
-        }
+        timeout
       )
 
       try {
diff --git a/app/modules/ws2p/lib/constants.ts b/app/modules/ws2p/lib/constants.ts
index ace1fe96e1d5c67685ff2d36edbdd34a6002d541..51972d7f7d1dca2c5406d8f7af8fea58bfe740a0 100644
--- a/app/modules/ws2p/lib/constants.ts
+++ b/app/modules/ws2p/lib/constants.ts
@@ -6,8 +6,11 @@ export const WS2PConstants = {
   WS2P_PORTS_END: 20999,
   WS2P_UPNP_INTERVAL: 300,
 
-  CONNEXION_TIMEOUT: 10000,
-  REQUEST_TIMEOUT: 10000,
+  CONNEXION_TIMEOUT: 15000,
+  REQUEST_TIMEOUT: 15000,
+  CONNEXION_TOR_TIMEOUT: 30000,
+  REQUEST_TOR_TIMEOUT: 60000,
+  RECONNEXION_INTERVAL_IN_SEC: 60 * 10, // 10 minutes
 
   BLOCK_PULLING_INTERVAL: 300 * 2,    // 10 minutes
   DOCPOOL_PULLING_INTERVAL: 3600 * 4, // 4 hours
@@ -27,7 +30,7 @@ export const WS2PConstants = {
     + CommonConstants.FORMATS.BLOCKSTAMP
     + '$'),
 
-  HEAD_V1_REGEXP: new RegExp('^WS2P:HEAD:1:'
+  HEAD_V1_REGEXP: new RegExp('^WS2P(?:O[CT][SAM])?(?:I[CT])?:HEAD:1:'
   + '(' + CommonConstants.FORMATS.PUBKEY + '):'
   + '(' + CommonConstants.FORMATS.BLOCKSTAMP + '):'
   + '(' + CommonConstants.FORMATS.WS2PID + '):'
@@ -36,5 +39,8 @@ export const WS2PConstants = {
   + '(' + CommonConstants.FORMATS.POW_PREFIX + ')'
   + '$'),
 
+  HOST_ONION_REGEX: CommonConstants.HOST_ONION_REGEX,
+  FULL_ADDRESS_ONION_REGEX: CommonConstants.WS_FULL_ADDRESS_ONION_REGEX,
+
   HEADS_SPREAD_TIMEOUT: 100 // Wait 100ms before sending a bunch of signed heads
 }
\ No newline at end of file
diff --git a/index.ts b/index.ts
index 3c6b04bc5ad36d1aae2701a97854444164bb3c76..f9e3cf445157876a33b1c8d5be9335d121b6a070 100644
--- a/index.ts
+++ b/index.ts
@@ -8,6 +8,7 @@ import {CrawlerDependency} from "./app/modules/crawler/index"
 import {BmaDependency} from "./app/modules/bma/index"
 import {WS2PDependency} from "./app/modules/ws2p/index"
 import {Constants} from "./app/modules/prover/lib/constants"
+import { ProxiesConf } from './app/lib/proxy';
 
 const path = require('path');
 const _ = require('underscore');
@@ -440,7 +441,6 @@ class Stack {
 function commandLineConf(program:any, conf:any = {}) {
 
   conf = conf || {};
-  conf.sync = conf.sync || {};
   const cli = {
     currency: program.currency,
     cpu: program.cpu,
@@ -448,10 +448,12 @@ function commandLineConf(program:any, conf:any = {}) {
     server: {
       port: program.port,
     },
-    db: {
-      mport: program.mport,
-      mdb: program.mdb,
-      home: program.home
+    proxies: {
+      proxySocks: program.socksProxy,
+      proxyTor: program.torProxy,
+      reachingClearEp: program.reachingClearEp,
+      forceTor: program.forceTor,
+      rmProxies: program.rmProxies
     },
     logs: {
       http: program.httplogs,
@@ -465,19 +467,30 @@ function commandLineConf(program:any, conf:any = {}) {
     timeout: program.timeout
   };
 
-  // Update conf
-  if (cli.currency)                         conf.currency = cli.currency;
-  if (cli.server.port)                      conf.port = cli.server.port;
-  if (cli.cpu)                              conf.cpu = Math.max(0.01, Math.min(1.0, cli.cpu));
-  if (cli.prefix)                           conf.prefix = Math.max(Constants.MIN_PEER_ID, Math.min(Constants.MAX_PEER_ID, cli.prefix));
-  if (cli.logs.http)                        conf.httplogs = true;
-  if (cli.logs.nohttp)                      conf.httplogs = false;
-  if (cli.db.mport)                         conf.mport = cli.db.mport;
-  if (cli.db.home)                          conf.home = cli.db.home;
-  if (cli.db.mdb)                           conf.mdb = cli.db.mdb;
-  if (cli.isolate)                          conf.isolate = cli.isolate;
-  if (cli.timeout)                          conf.timeout = cli.timeout;
-  if (cli.forksize != null)                 conf.forksize = cli.forksize;
+  // Declare and update proxiesConf
+  if (cli.proxies.proxySocks || cli.proxies.proxyTor || cli.proxies.reachingClearEp || cli.proxies.forceTor || cli.proxies.rmProxies) {
+    conf.proxiesConf = new ProxiesConf()
+    if (cli.proxies.proxySocks) conf.proxiesConf.proxySocksAddress = cli.proxies.proxySocks;
+    if (cli.proxies.proxyTor)   conf.proxiesConf.proxyTorAddress = cli.proxies.proxyTor;
+    if (cli.proxies.reachingClearEp)  {
+      switch (cli.proxies.reachingClearEp) {
+        case 'tor': conf.proxiesConf.reachingClearEp = 'tor'; break;
+        case 'none': conf.proxiesConf.reachingClearEp = 'none'; break;
+      }
+    }
+    if (cli.proxies.forceTor) conf.proxiesConf.forceTor = true
+  }
+
+  // Update the rest of the conf
+  if (cli.currency)                             conf.currency = cli.currency;
+  if (cli.server.port)                          conf.port = cli.server.port;
+  if (cli.cpu)                                  conf.cpu = Math.max(0.01, Math.min(1.0, cli.cpu));
+  if (cli.prefix)                               conf.prefix = Math.max(Constants.MIN_PEER_ID, Math.min(Constants.MAX_PEER_ID, cli.prefix));
+  if (cli.logs.http)                            conf.httplogs = true;
+  if (cli.logs.nohttp)                          conf.httplogs = false;
+  if (cli.isolate)                              conf.isolate = cli.isolate;
+  if (cli.timeout)                              conf.timeout = cli.timeout;
+  if (cli.forksize != null)                     conf.forksize = cli.forksize;
 
   return conf;
 }
diff --git a/package.json b/package.json
index 524a17cfa687b9b29f3e0da2b9ac01553e6d770d..97649b31477ddaf8b6c30b6912a3e0c7182098f4 100644
--- a/package.json
+++ b/package.json
@@ -92,6 +92,7 @@
     "scryptb": "6.0.4",
     "seedrandom": "^2.4.3",
     "sha1": "1.1.1",
+    "socks-proxy-agent": "^3.0.1",
     "sqlite3": "3.1.4",
     "tail": "^1.2.1",
     "tweetnacl": "0.14.3",
diff --git a/server.ts b/server.ts
index 2f7fbc5c166fa0bc90875727e58b2d333c25716f..fff2e8accbe0ef6874ec7218559fdd0592bf3f65 100644
--- a/server.ts
+++ b/server.ts
@@ -24,6 +24,7 @@ import {PeerDTO} from "./app/lib/dto/PeerDTO"
 import {OtherConstants} from "./app/lib/other_constants"
 import {WS2PCluster} from "./app/modules/ws2p/lib/WS2PCluster"
 import {DBBlock} from "./app/lib/db/DBBlock"
+import { ProxiesConf } from './app/lib/proxy';
 
 export interface HookableServer {
   generatorGetJoinData: (...args:any[]) => Promise<any>
@@ -148,6 +149,7 @@ export class Server extends stream.Duplex implements HookableServer {
     logger.debug('Loading conf...');
     this.conf = await this.dal.loadConf(this.overrideConf, useDefaultConf)
     // Default values
+    this.conf.proxiesConf      = this.conf.proxiesConf === undefined ?       new ProxiesConf()                            : this.conf.proxiesConf
     this.conf.remoteipv6       = this.conf.remoteipv6 === undefined ?        this.conf.ipv6                               : this.conf.remoteipv6
     this.conf.remoteport       = this.conf.remoteport === undefined ?        this.conf.port                               : this.conf.remoteport
     this.conf.c                = this.conf.c === undefined ?                 constants.CONTRACT.DEFAULT.C                 : this.conf.c
diff --git a/test/fast/proxies.ts b/test/fast/proxies.ts
new file mode 100644
index 0000000000000000000000000000000000000000..73377bf219f4d62120022e781d1dc160a9088671
--- /dev/null
+++ b/test/fast/proxies.ts
@@ -0,0 +1,98 @@
+import * as assert from 'assert'
+import { ProxiesConf } from '../../app/lib/proxy';
+
+describe("Proxies Conf", function() {
+
+    // First conf : do not use any sock proxy
+    let proxiesConf1 = new ProxiesConf()
+    
+    // Second conf : use tor only to reach ".onion" endpoints
+    let proxiesConf2 = new ProxiesConf()
+    proxiesConf2.proxyTorAddress = "127.0.0.1:9050"
+
+    // Third conf : always use tor 
+    let proxiesConf3 = new ProxiesConf()
+    proxiesConf3.proxyTorAddress = "127.0.0.1:9050"
+    proxiesConf3.reachingClearEp = 'tor'
+
+    // Fourth conf : use classical socks proxy
+    let proxiesConf4 = new ProxiesConf()
+    proxiesConf4.proxySocksAddress = "127.0.0.1:8888"
+
+    // Fifth conf : use classical socks proxy + use tor proxy only to reach ".onion" endpoints
+    let proxiesConf5 = new ProxiesConf()
+    proxiesConf5.proxySocksAddress = "127.0.0.1:8888"
+    proxiesConf5.proxyTorAddress = "127.0.0.1:9050"
+
+    // Sixth conf : always use tor and contact only tor endpoints
+    let proxiesConf6 = new ProxiesConf()
+    proxiesConf6.proxyTorAddress = "127.0.0.1:9050"
+    proxiesConf6.reachingClearEp = 'none'
+
+    // Seventh conf : force duniter to contact endpoint tor (if user redirect the traffic to tor himself)
+    let proxiesConf7 = new ProxiesConf()
+    proxiesConf7.forceTor = true;
+
+    it('should do not use any sock proxy', () => {
+        assert.equal(ProxiesConf.canReachClearEndpoint(proxiesConf1), true)
+        assert.equal(ProxiesConf.canReachTorEndpoint(proxiesConf1), false)
+        assert.equal(ProxiesConf.httpProxy("3asufnydqmup533h.onion", proxiesConf1), undefined)
+        assert.equal(ProxiesConf.httpProxy("domain.tld", proxiesConf1), undefined)
+        assert.equal(ProxiesConf.wsProxy("ws://3asufnydqmup533h.onion:80", proxiesConf1), undefined)
+        assert.equal(ProxiesConf.wsProxy("ws://domain.tld:20900", proxiesConf1), undefined)
+    })
+
+    it('should use tor proxy only to reach ".onion" endpoints', () => {
+        assert.equal(ProxiesConf.canReachClearEndpoint(proxiesConf2), true)
+        assert.equal(ProxiesConf.canReachTorEndpoint(proxiesConf2), true)
+        assert.equal(ProxiesConf.httpProxy("3asufnydqmup533h.onion", proxiesConf2), proxiesConf2.proxyTorAddress)
+        assert.equal(ProxiesConf.httpProxy("domain.tld", proxiesConf2), undefined)
+        assert.equal(ProxiesConf.wsProxy("ws://3asufnydqmup533h.onion:80", proxiesConf2), proxiesConf2.proxyTorAddress)
+        assert.equal(ProxiesConf.wsProxy("ws://domain.tld:20900", proxiesConf2),  undefined)
+    })
+
+    it('should always use tor proxy', () => {
+        assert.equal(ProxiesConf.canReachClearEndpoint(proxiesConf3), true)
+        assert.equal(ProxiesConf.canReachTorEndpoint(proxiesConf3), true)
+        assert.equal(ProxiesConf.httpProxy("3asufnydqmup533h.onion", proxiesConf3), proxiesConf3.proxyTorAddress)
+        assert.equal(ProxiesConf.httpProxy("domain.tld", proxiesConf3), proxiesConf3.proxyTorAddress)
+        assert.equal(ProxiesConf.wsProxy("ws://3asufnydqmup533h.onion:80", proxiesConf3), proxiesConf3.proxyTorAddress)
+        assert.equal(ProxiesConf.wsProxy("ws://domain.tld:20900", proxiesConf3), proxiesConf3.proxyTorAddress)
+    })
+
+    it('should always use classical socks proxy', () => {
+        assert.equal(ProxiesConf.canReachClearEndpoint(proxiesConf4), true)
+        assert.equal(ProxiesConf.canReachTorEndpoint(proxiesConf4), false)
+        assert.equal(ProxiesConf.httpProxy("3asufnydqmup533h.onion", proxiesConf4), undefined)
+        assert.equal(ProxiesConf.httpProxy("domain.tld", proxiesConf4), proxiesConf4.proxySocksAddress)
+        assert.equal(ProxiesConf.wsProxy("ws://3asufnydqmup533h.onion:80", proxiesConf4), undefined)
+        assert.equal(ProxiesConf.wsProxy("ws://domain.tld:20900", proxiesConf4), proxiesConf4.proxySocksAddress)
+    })
+
+    it('should use tor proxy for ".onion" endpoints and classical socks proxy for everyone else', () => {
+        assert.equal(ProxiesConf.canReachClearEndpoint(proxiesConf5), true)
+        assert.equal(ProxiesConf.canReachTorEndpoint(proxiesConf5), true)
+        assert.equal(ProxiesConf.httpProxy("3asufnydqmup533h.onion", proxiesConf5), proxiesConf5.proxyTorAddress)
+        assert.equal(ProxiesConf.httpProxy("domain.tld", proxiesConf5), proxiesConf5.proxySocksAddress)
+        assert.equal(ProxiesConf.wsProxy("ws://3asufnydqmup533h.onion:80", proxiesConf5), proxiesConf5.proxyTorAddress)
+        assert.equal(ProxiesConf.wsProxy("ws://domain.tld:20900", proxiesConf5), proxiesConf5.proxySocksAddress)
+    })
+
+    it('should always use tor proxy and contact only tor endpoints', () => {
+        assert.equal(ProxiesConf.canReachClearEndpoint(proxiesConf6), false)
+        assert.equal(ProxiesConf.canReachTorEndpoint(proxiesConf6), true)
+        assert.equal(ProxiesConf.httpProxy("3asufnydqmup533h.onion", proxiesConf6), proxiesConf6.proxyTorAddress)
+        assert.equal(ProxiesConf.httpProxy("domain.tld", proxiesConf6), undefined)
+        assert.equal(ProxiesConf.wsProxy("ws://3asufnydqmup533h.onion:80", proxiesConf6), proxiesConf6.proxyTorAddress)
+        assert.equal(ProxiesConf.wsProxy("ws://domain.tld:20900", proxiesConf6), undefined)
+    })
+
+    it('should never use proxy and contact tor endpoints (user redirect the traffic to tor himself)', () => {
+        assert.equal(ProxiesConf.canReachClearEndpoint(proxiesConf7), true)
+        assert.equal(ProxiesConf.canReachTorEndpoint(proxiesConf7), true)
+        assert.equal(ProxiesConf.httpProxy("3asufnydqmup533h.onion", proxiesConf7), undefined)
+        assert.equal(ProxiesConf.httpProxy("domain.tld", proxiesConf7), undefined)
+        assert.equal(ProxiesConf.wsProxy("ws://3asufnydqmup533h.onion:80", proxiesConf7), undefined)
+        assert.equal(ProxiesConf.wsProxy("ws://domain.tld:20900", proxiesConf7), undefined)
+    })
+});
diff --git a/test/integration/forwarding.js b/test/integration/forwarding.js
index b550a400b3e7317832594088833bd0ed6d70f348..ba392a69af5d2b461920c09622ec5d2558d34215 100644
--- a/test/integration/forwarding.js
+++ b/test/integration/forwarding.js
@@ -19,7 +19,7 @@ describe("Forwarding", function() {
 
   describe("Nodes", function() {
 
-    const common = { currency: 'bb', nobma: false, ws2p: { upnp: false }, ipv4: '127.0.0.1', remoteipv4: '127.0.0.1', rootoffset: 0, sigQty: 1 };
+    const common = { currency: 'bb', nobma: false, bmaWithCrawler:true, ws2p: { upnp: false }, ipv4: '127.0.0.1', remoteipv4: '127.0.0.1', rootoffset: 0, sigQty: 1 };
 
     const node1 = node('db_1', _({ upnp: false, httplogs: false, port: 9600, remoteport: 9600, pair: { pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'} }).extend(common));
     const node2 = node('db_2', _({ upnp: false, httplogs: false, port: 9601, remoteport: 9601, pair: { pub: 'G2CBgZBPLe6FSFUgpx2Jf1Aqsgta6iib3vmDRA1yLiqU', sec: '58LDg8QLmF5pv6Dn9h7X4yFKfMTdP8fdAiWVcyDoTRJu454fwRihCLULH4MW37zncsg4ruoTGJPZneWk22QmG1w4'} }).extend(common));
diff --git a/test/integration/network.js b/test/integration/network.js
index 32c2fae9e9de7dfc8bcc710cf0d8362590c5564a..88a4afa84aaaecb944945bb20420712285d17b31 100644
--- a/test/integration/network.js
+++ b/test/integration/network.js
@@ -11,6 +11,7 @@ const expectAnswer = httpTest.expectAnswer;
 
 const MEMORY_MODE = true;
 const commonConf = {
+  bmaWithCrawler: true,
   ipv4: '127.0.0.1',
   remoteipv4: '127.0.0.1',
   currency: 'bb',
diff --git a/test/integration/peerings.js b/test/integration/peerings.js
index b9a7296136088877798cc6cabbfbc1394f39cc0f..da7f16c6e538c29d12a5e42e198e2f99d6e0c49c 100644
--- a/test/integration/peerings.js
+++ b/test/integration/peerings.js
@@ -22,6 +22,7 @@ const expectJSON     = httpTest.expectJSON;
 
 const MEMORY_MODE = true;
 const commonConf = {
+  bmaWithCrawler: true,
   ipv4: '127.0.0.1',
   remoteipv4: '127.0.0.1',
   currency: 'bb',
diff --git a/test/integration/start_generate_blocks.js b/test/integration/start_generate_blocks.js
index e700d38d5f0160607678a185eb2c5b4c72955cb3..c71bd8c808a9f997afed7a64d7f4861a6ac5e3c3 100644
--- a/test/integration/start_generate_blocks.js
+++ b/test/integration/start_generate_blocks.js
@@ -19,6 +19,7 @@ const expectJSON     = httpTest.expectJSON;
 
 const MEMORY_MODE = true;
 const commonConf = {
+  bmaWithCrawler: true,
   ipv4: '127.0.0.1',
   remoteipv4: '127.0.0.1',
   currency: 'bb',
diff --git a/test/integration/tools/toolbox.ts b/test/integration/tools/toolbox.ts
index fcf1e9670666bef7ca0b48139c49b1bbfc5d07bb..cbbe1d156eeff3f849dbfa850986bb6b96f83a88 100644
--- a/test/integration/tools/toolbox.ts
+++ b/test/integration/tools/toolbox.ts
@@ -170,7 +170,7 @@ export const fakeSyncServer = async (readBlocksMethod:any, readParticularBlockMe
     processRequest: () => { /* Does nothing */ }
   };
 
-  const fakeServer = await Network.createServersAndListen("Fake Duniter Server", new Server("", true, {}), [{
+  const fakeServer = await Network.createServersAndListen("Fake Duniter Server", new Server("", true, ConfDTO.mock()), [{
     ip: host,
     port: port
   }], NO_HTTP_LOGS, logger, NO_STATIC_PATH, (app:any, httpMethods:any) => {
@@ -226,6 +226,7 @@ export const NewTestingServer = (conf:any) => {
   const port = conf.port || PORT++
   const commonConf = {
     nobma: false,
+    bmaWithCrawler: true,
     port: port,
     ipv4: host,
     remoteipv4: host,
@@ -696,6 +697,7 @@ export const simpleWS2PNetwork: (s1: TestingServer, s2: TestingServer) => Promis
 
 export function simpleTestingConf(now = 1500000000, pair:{ pub:string, sec:string }): any {
   return {
+    bmaWithCrawler: true,
     pair,
     nbCores: 1,
     udTime0: now,
diff --git a/test/integration/ws2p_connection.ts b/test/integration/ws2p_connection.ts
index 894c2ac29f61545f410ac88813d05dd84f208808..c84d9a42ecc109cd4dd0033d27d4229cd4e15671 100644
--- a/test/integration/ws2p_connection.ts
+++ b/test/integration/ws2p_connection.ts
@@ -95,7 +95,7 @@ describe('WS2P', () => {
 
       it('should refuse the connection if the server does not answer', async () => {
         const keypair = new Key('HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP')
-        const ws2p = WS2PConnection.newConnectionToAddress('ws://localhost:20903', new WS2PMutedHandler(), new WS2PPubkeyLocalAuth(gtest, keypair), new WS2PPubkeyRemoteAuth(gtest, keypair), {
+        const ws2p = WS2PConnection.newConnectionToAddress('ws://localhost:20903', new WS2PMutedHandler(), new WS2PPubkeyLocalAuth(gtest, keypair), new WS2PPubkeyRemoteAuth(gtest, keypair), undefined, {
           connectionTimeout: 100,
           requestTimeout: 100
         })
@@ -104,7 +104,7 @@ describe('WS2P', () => {
 
       it('should refuse the connection if the server answers with a wrong signature', async () => {
         const keypair = new Key('HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP')
-        const ws2p = WS2PConnection.newConnectionToAddress('ws://localhost:20903', new WS2PMutedHandler(), new WS2PPubkeyLocalAuth(gtest, keypair), new WS2PPubkeyRemoteAuth(gtest, keypair), {
+        const ws2p = WS2PConnection.newConnectionToAddress('ws://localhost:20903', new WS2PMutedHandler(), new WS2PPubkeyLocalAuth(gtest, keypair), new WS2PPubkeyRemoteAuth(gtest, keypair), undefined, {
           connectionTimeout: 100,
           requestTimeout: 100
         })
@@ -113,7 +113,7 @@ describe('WS2P', () => {
 
       it('should refuse the connection if the server refuses our signature', async () => {
         const keypair = new Key('HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP')
-        const ws2p = WS2PConnection.newConnectionToAddress('ws://localhost:20903', new WS2PMutedHandler(), new WS2PPubkeyLocalAuth(gtest, keypair), new WS2PPubkeyRemoteAuth(gtest, keypair), {
+        const ws2p = WS2PConnection.newConnectionToAddress('ws://localhost:20903', new WS2PMutedHandler(), new WS2PPubkeyLocalAuth(gtest, keypair), new WS2PPubkeyRemoteAuth(gtest, keypair), undefined, {
           connectionTimeout: 100,
           requestTimeout: 100
         })
@@ -123,7 +123,7 @@ describe('WS2P', () => {
 
       it('should accept the connection if the server answers with a good signature', async () => {
         const keypair = new Key('HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP')
-        const ws2p = WS2PConnection.newConnectionToAddress('ws://localhost:20903', new WS2PMutedHandler(), new WS2PPubkeyLocalAuth(gtest, keypair), new WS2PNoRemoteAuth(), {
+        const ws2p = WS2PConnection.newConnectionToAddress('ws://localhost:20903', new WS2PMutedHandler(), new WS2PPubkeyLocalAuth(gtest, keypair), new WS2PNoRemoteAuth(), undefined, {
           connectionTimeout: 1000,
           requestTimeout: 1000
         })