├── .gitignore ├── logo.png ├── admin ├── .env.template ├── Dockerfile └── default.conf ├── nuxt ├── Dockerfile └── .env.template ├── backend └── Dockerfile ├── frontend ├── Dockerfile ├── nginx.conf └── default.conf ├── NOTICE ├── README.md ├── LICENSE.md └── opencex.sh /.gitignore: -------------------------------------------------------------------------------- 1 | env.txt 2 | .idea 3 | -------------------------------------------------------------------------------- /logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Polygant/OpenCEX/HEAD/logo.png -------------------------------------------------------------------------------- /admin/.env.template: -------------------------------------------------------------------------------- 1 | const localConfig = { 2 | api: "https://${DOMAIN}/apiadmin/", 3 | base: "${ADMIN_BASE_URL}", 4 | title: "${PROJECT_NAME}" 5 | } 6 | export default localConfig; 7 | -------------------------------------------------------------------------------- /nuxt/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:14.18.1 2 | WORKDIR /app 3 | COPY package.json . 4 | COPY yarn.lock . 5 | COPY . . 6 | RUN yarn install 7 | RUN yarn build 8 | RUN yarn generate 9 | ENV HOST 0.0.0.0 10 | EXPOSE 3000 11 | CMD [ "yarn", "start" ] 12 | -------------------------------------------------------------------------------- /backend/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.8 2 | ENV PYTHONUNBUFFERED 1 3 | ENV PYTHONDONTWRITEBYTECODE 1 4 | WORKDIR /app 5 | COPY backend/ ./ 6 | RUN pip install setuptools==40 7 | RUN pip install -r /app/requirements.txt 8 | RUN apt-get update && apt-get install systemd wkhtmltopdf -y -------------------------------------------------------------------------------- /admin/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:18 as build 2 | WORKDIR /app 3 | ENV PATH /app/node_modules/.bin:$PATH 4 | COPY . . 5 | RUN yarn install 6 | RUN yarn build 7 | 8 | FROM nginx:alpine 9 | COPY deploy/default.conf /etc/nginx/conf.d/default.conf 10 | COPY --from=build /app/dist /usr/share/nginx/html 11 | CMD ["nginx", "-g", "daemon off;"] 12 | -------------------------------------------------------------------------------- /admin/default.conf: -------------------------------------------------------------------------------- 1 | server { 2 | set_real_ip_from 172.0.0.1/8; 3 | #real_ip_header X-Forwarded-For; 4 | real_ip_header CF-Connecting-IP; 5 | listen 80; 6 | server_name _; 7 | root /usr/share/nginx/html; 8 | index index.html; 9 | 10 | location / { 11 | } 12 | 13 | location /ADMIN_BASE_URL { 14 | alias /usr/share/nginx/html; 15 | try_files $uri $uri/ /index.html; 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /frontend/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:18 as build 2 | ARG localconfig 3 | WORKDIR /app 4 | ENV PATH /app/node_modules/.bin:$PATH 5 | COPY . . 6 | RUN yarn install 7 | RUN yarn build 8 | 9 | FROM nginx:alpine 10 | COPY deploy/default.conf /etc/nginx/conf.d/default.conf 11 | COPY deploy/nginx.conf /etc/nginx/nginx.conf 12 | COPY --from=build /app/dist /usr/share/nginx/html 13 | CMD ["nginx", "-g", "daemon off;"] 14 | -------------------------------------------------------------------------------- /NOTICE: -------------------------------------------------------------------------------- 1 | ========================================================================= 2 | == NOTICE file for use with the Apache License, Version 2.0, == 3 | ========================================================================= 4 | 5 | OpenCEX cryptocurrency platform 6 | Copyright 2023 Polygant (Webmart LLC, Stan Chernukhin). 7 | 8 | This product includes software developed at Polygant (https://polygant.net/). 9 | -------------------------------------------------------------------------------- /nuxt/.env.template: -------------------------------------------------------------------------------- 1 | ########################################################################### 2 | # OpenCEX Main configuration file. More info 3 | # https://polygant.notion.site/Settings-3f9e0aae880e433a9d23e76f62a4a456 4 | ########################################################################### 5 | 6 | 7 | API_URL="https://${DOMAIN}/" 8 | BROWSER_BASE_URL="https://${DOMAIN}" 9 | project_title="${PROJECT_NAME}" 10 | telegram="${TELEGRAM}" 11 | facebook="${FACEBOOK}" 12 | twitter="${TWITTER}" 13 | linkedin="${LINKEDIN}" 14 | logo="${LOGO}" -------------------------------------------------------------------------------- /frontend/nginx.conf: -------------------------------------------------------------------------------- 1 | user nginx; 2 | 3 | worker_processes auto; 4 | worker_rlimit_nofile 100000; 5 | 6 | events { 7 | multi_accept on; 8 | worker_connections 100000; 9 | } 10 | 11 | error_log stderr warn; 12 | pid /var/run/nginx.pid; 13 | 14 | http { 15 | sendfile on; 16 | tcp_nopush on; 17 | 18 | keepalive_timeout 30; 19 | keepalive_requests 256; 20 | 21 | proxy_connect_timeout 30; 22 | proxy_send_timeout 3600; 23 | proxy_read_timeout 3600; 24 | 25 | fastcgi_keep_conn on; 26 | fastcgi_connect_timeout 120; 27 | fastcgi_send_timeout 3600; 28 | fastcgi_read_timeout 3600; 29 | 30 | client_max_body_size 1536m; 31 | client_body_buffer_size 10m; 32 | proxy_buffers 512 16k; 33 | proxy_buffer_size 16k; 34 | fastcgi_buffers 256 16k; 35 | fastcgi_temp_file_write_size 256k; 36 | proxy_max_temp_file_size 0; 37 | 38 | server_tokens off; 39 | 40 | include mime.types; 41 | types { 42 | text/plain log; 43 | } 44 | default_type application/octet-stream; 45 | 46 | charset utf-8; 47 | 48 | # Cloudflare 49 | #real_ip_header CF-Connecting-IP; 50 | #set_real_ip_from 0.0.0.0/0; 51 | 52 | 53 | log_format main '$remote_addr - $remote_user [$time_local] "$request" ' 54 | '$status $body_bytes_sent "$http_referer" ' 55 | '"$http_user_agent" "$http_x_forwarded_for"'; 56 | 57 | access_log /dev/stdout main; 58 | #access_log /var/log/acces.log ; 59 | #error_log /var/log/error.log ; 60 | include /etc/nginx/conf.d/*.conf; 61 | 62 | 63 | } 64 | -------------------------------------------------------------------------------- /frontend/default.conf: -------------------------------------------------------------------------------- 1 | map $remote_addr $cond { 2 | "default" "0"; 3 | "0.0.0.0" "1"; 4 | } 5 | 6 | server { 7 | set_real_ip_from 172.0.0.1/8; 8 | #real_ip_header CF-Connecting-IP; 9 | real_ip_header X-Forwarded-For; 10 | add_header Content-Security-Policy "frame-ancestors *"; 11 | add_header X-Frame-Options "ALLOW-FROM opencex"; 12 | 13 | proxy_connect_timeout 600; 14 | proxy_send_timeout 600; 15 | proxy_read_timeout 600; 16 | send_timeout 600; 17 | 18 | fastcgi_connect_timeout 600s; 19 | fastcgi_send_timeout 600s; 20 | fastcgi_read_timeout 600s; 21 | 22 | 23 | #set $maintenance on; 24 | #set $cond "${cond}0"; 25 | 26 | 27 | location = /account/wizard { 28 | return 404; 29 | } 30 | location = /account/wizard/ { 31 | return 404; 32 | } 33 | 34 | 35 | 36 | 37 | if ($cond = 00) { 38 | return 403; 39 | } 40 | error_page 503 @maintenance; 41 | error_page 403 @maintenance; 42 | 43 | listen 80 default_server; 44 | 45 | server_name DOMAIN; 46 | root /usr/share/nginx/html; 47 | 48 | 49 | 50 | location /media { 51 | alias /app/media/ ; 52 | } 53 | 54 | 55 | location /account { 56 | root /usr/share/nginx/html; 57 | index index.html index.htm; 58 | try_files $uri $uri/ /index.html =404; 59 | } 60 | 61 | location /public { 62 | root /usr/share/nginx/html; 63 | index index.html index.htm; 64 | try_files $uri $uri/ =404; 65 | } 66 | 67 | location /assets { 68 | root /usr/share/nginx/html; 69 | index index.html index.htm; 70 | try_files $uri $uri/ /index.html =404; 71 | 72 | } 73 | 74 | 75 | 76 | location /wsapi { 77 | proxy_pass http://opencex-wss:8000; 78 | proxy_http_version 1.1; 79 | proxy_set_header Upgrade $http_upgrade; 80 | proxy_set_header Connection "upgrade"; 81 | 82 | proxy_redirect off; 83 | proxy_set_header Host $host; 84 | proxy_set_header X-Real-IP $remote_addr; 85 | proxy_set_header X-Forwarded-Proto https; 86 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 87 | proxy_set_header X-Forwarded-Host $server_name; 88 | } 89 | 90 | 91 | location /ADMIN_BASE_URL { 92 | 93 | proxy_pass http://admin:80; 94 | proxy_http_version 1.1; 95 | proxy_set_header Upgrade $http_upgrade; 96 | proxy_set_header Connection "upgrade"; 97 | 98 | proxy_redirect off; 99 | proxy_set_header Host $host; 100 | proxy_set_header X-Real-IP $remote_addr; 101 | proxy_set_header X-Forwarded-Proto https; 102 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 103 | proxy_set_header X-Forwarded-Host $server_name; 104 | 105 | } 106 | 107 | 108 | location / { 109 | 110 | proxy_pass http://nuxt:3000; 111 | proxy_http_version 1.1; 112 | proxy_set_header Upgrade $http_upgrade; 113 | proxy_set_header Connection "upgrade"; 114 | proxy_redirect off; 115 | proxy_set_header Host $host; 116 | proxy_set_header X-Real-IP $remote_addr; 117 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 118 | proxy_set_header X-Forwarded-Proto https; 119 | proxy_set_header X-Forwarded-Host $server_name; 120 | 121 | } 122 | 123 | 124 | location /upload { alias /app/media/; } 125 | 126 | location /robots.txt { alias /usr/share/nginx/html/static/robots.txt; } 127 | 128 | location /staticfiles/ { 129 | root /app/; 130 | try_files $uri =404; 131 | } 132 | 133 | 134 | location /apiadmin { 135 | proxy_pass http://opencex:8080; 136 | proxy_http_version 1.1; 137 | proxy_set_header Upgrade $http_upgrade; 138 | proxy_set_header Connection "upgrade"; 139 | 140 | proxy_redirect off; 141 | proxy_set_header Host $host; 142 | proxy_set_header X-Real-IP $remote_addr; 143 | proxy_set_header X-Forwarded-Proto https; 144 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 145 | proxy_set_header X-Forwarded-Host $server_name; 146 | } 147 | 148 | location /api { 149 | proxy_pass http://opencex:8080; 150 | proxy_http_version 1.1; 151 | proxy_set_header Upgrade $http_upgrade; 152 | proxy_set_header Connection "upgrade"; 153 | 154 | proxy_redirect off; 155 | proxy_set_header Host $host; 156 | proxy_set_header X-Real-IP $remote_addr; 157 | proxy_set_header X-Forwarded-Proto https; 158 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 159 | proxy_set_header X-Forwarded-Host $server_name; 160 | } 161 | 162 | 163 | 164 | 165 | 166 | 167 | location @proxy { 168 | 169 | 170 | proxy_pass http://opencex:8080; 171 | proxy_http_version 1.1; 172 | proxy_set_header Upgrade $http_upgrade; 173 | proxy_set_header Connection "upgrade"; 174 | 175 | proxy_redirect off; 176 | proxy_set_header Host $host; 177 | proxy_set_header X-Real-IP $remote_addr; 178 | proxy_set_header X-Forwarded-Proto https; 179 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 180 | proxy_set_header X-Forwarded-Host $server_name; 181 | 182 | 183 | 184 | 185 | 186 | 187 | if (-f $document_root/maintenance) { 188 | set $cond "${cond}0"; 189 | } 190 | 191 | 192 | 193 | } 194 | location @maintenance { 195 | root /usr/share/nginx/html/public; 196 | rewrite ^(.*)$ /dump.html break; 197 | } 198 | 199 | 200 | 201 | } 202 | 203 | 204 | 205 | 206 | 207 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 | OpenCEX Logo 4 | 5 |

6 | 7 |

8 | OpenCEX is a free and open source cryptocurrency exchange platform.
9 | Developed by Polygant. 10 | 11 |

12 | Live demo | OpenCEX documentation | Telegram chat 13 |

14 | 15 | ## Main features. 16 | 17 | - Custodial wallet supporting BTC, ETH, BNB, TRX, USDT (ERC-20, BEP-20, TRC-20). Deposit and withdrawal. 18 | - Order matching engine. Trading pairs BTC-USDT, ETH-USDT, BNB-USDT, TRX-USDT. 19 | - Professional exchange interface for placing orders. 20 | - Simplified interface for quick swap. 21 | - KYT transaction verification (requires Scorechain keys). 22 | - KYC verification of users (requires Sumsub keys). 23 | - SMS 2fa for users (requires Twilio keys). 24 | 25 | ## System requirements. 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 |
MinimumRecommended
CPU: 4 cores
RAM: 16 GB
Disks: 40 GB
OS: Ubuntu 22.04

https://www.hetzner.com/cloud
CPU: 8 cores
RAM: 64 Gb
Disks: 2x1Tb NVMe SSD
OS: Ubuntu 22.04

https://www.hetzner.com/dedicated-rootserver/ax51-nvme
37 | 38 | ## The software used. 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 |
DockerlatestOS-level virtualization
NGINX1.22.0Web server
Caddy2.6.2Router
Postgres14.5RDBMS
Redis server7.0.4RDBMS
RabbitMQ3.10.7Message-broker software
Python3.8Programming language
Django3.2.7Python framework
VUE.JS3.2.25JS framework
NUXT.JS2.15.7JS framework
Bitcoin CorelatestBitcoin node
53 | 54 | ## Before installing: 55 | 56 | - Watch the installation video [https://youtu.be/c-WnQkvBwf0](https://youtu.be/c-WnQkvBwf0) 57 | - Order a virtual or physical server, not below the minimum requirements. You will need full access to this server (root). Shared hosting will not work. 58 | - Bind the IPv4 address you received when purchasing the server to your domain. If you don't have a domain yet, you can use [https://nip.io/](https://nip.io/) or [https://sslip.io/](https://sslip.io/). 59 | - Sign up for a Google account and get reCAPTCHA V2 keys (invisible). [https://www.google.com/recaptcha/](https://www.google.com/recaptcha/) 60 | - Get the SMTP server credentials for sending emails (any will do, i.e. [https://www.mailgun.com/](https://www.mailgun.com/)). 61 | - Register an Infura account ([https://infura.io/](https://infura.io/)) and create an API key + secret. 62 | - Register an Etherscan account ([https://etherscan.io/](https://etherscan.io/)) and create an API key. 63 | - You will need BTC, ETH addresses and BNB, TRX addresses(optional) to collect cryptocurrency deposits (cold addresses). If you don't have it yet, you can use any multi-currency wallet like Trust Wallet and generate BTC, ETH, BNB, TRX addresses. 64 | - OPTIONAL. For BNB и BEP-20 support you will need Bscscan credentials (https://bscscan.com/) 65 | - OPTIONAL. For TRX and TRC-20 support you will need Trondrid credentials (https://www.trongrid.io/) 66 | - OPTIONAL. For SMS verification you will need Twilio credentials ([https://twilio.com](https://twilio.com)) 67 | - OPTIONAL. For KYT you need Scorechain credentials ([https://www.scorechain.com/](https://www.scorechain.com/)) 68 | - OPTIONAL. For KYC you will need Sumsub credentials ([https://sumsub.com/](https://sumsub.com/)) 69 | 70 | 71 | ## Installation 72 | 73 | You need to SSH into your server as root and run the following command: 74 | 75 | mkdir /app ; 76 | cd /app/ || exit ; 77 | git clone https://github.com/Polygant/OpenCEX.git ./deploy ; 78 | cd deploy ; 79 | chmod +x opencex.sh ; 80 | ./opencex.sh 2>&1 | tee /tmp/install.txt 81 | 82 | Installation time ~ 5 minutes. 83 | 84 | If something goes wrong you can clean the installation and try again 85 | 86 | cd /app/opencex && docker compose down ; 87 | rm -rf /app ; 88 | docker system prune -a 89 | 90 | 🥳 Congratulations, the exchange has been successfully installed! 91 | You can open it by your domain name. 92 | 93 | **After installation, you need to download the file /app/openex/backend/save_to_self_and_delete.txt and delete it from the server.** 94 | 95 | **Mind that BTC node will take up to 30 hours to fully sync. BTC transactions sent to user addresses in this period will be collected and credited only after a full sync.** 96 | 97 | ## Documentation 98 | - [OpenCEX Help Center](https://www.notion.so/polygant/OpenCEX-Help-Center-8cf8c842bde947c3818a615a88ceef9c) 99 | - [Admin panel Guide](https://docs.google.com/document/d/1VoBFEjzmGXzNHQYfvu8BYHvoSv9Sg73AV9wWGvsRJ04/edit#) 100 | 101 | ## Partners & Sponsors ❤️ 102 | Become a partner: [hello@polygant.net](mailto:hello@polygant.net) 103 | 104 | ## Donate 💰 105 | You like our product and want to support the team? Nothing could be easier :) 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 |
Bitcoin (BTC)USDT (TRC20)ETH, USDT, USDC (ERC20)
119 | 120 | BTC: 121 | **bc1qgdnah2uh49wgnlvpmpnf7jkwz6dm8teuf66ynt** 122 | 123 | USDT (TRC-20): 124 | **TShx7cEsDancuqU5PmVPCQ3bUMtZyiqQq2** 125 | 126 | ETH, USDT, USDC (ERC-20): 127 | **0x938209344aD987EFB91D7dc1F3957Ce3DD39b95** 128 | 129 | ## Community 130 | Ask questions at the official community Telegram chat. 131 | 132 | ## Contributing 133 | Thanks for all your wonderful PRs, issues and ideas. 134 | You’re always welcome to join: check out our contribution guides, open issues and the Telegram chat. 135 | 136 | ## Can I hire you guys? 137 | 138 | OpenCEX was created and backed by Polygant, and is supported through all the years. You can request a consultation or order web and mobile development services by Polygant, just visit our site. 😎 139 | 140 | Say hi: [hello@polygant.net](mailto:hello@polygant.net) . We will be happy to work with you! 141 | 142 | ## License 143 | Apache License, Version 2.0 144 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /opencex.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ $(dpkg-query -W -f='${Status}' docker-ce 2>/dev/null | grep -c "ok installed") -eq 0 ]; then 4 | echo "Docker not found, install docker..." 5 | sudo apt-get update > /dev/null 2>&1 6 | sudo apt-get install -y apt-transport-https ca-certificates curl gnupg lsb-release > /dev/null 2>&1 7 | curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor --yes -o /usr/share/keyrings/docker-archive-keyring.gpg 8 | echo "deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null 9 | sudo apt-get update > /dev/null 2>&1 10 | sudo apt-get install -y docker-ce docker-ce-cli containerd.io git docker-compose-plugin > /dev/null 2>&1 11 | sudo systemctl enable docker > /dev/null 2>&1 12 | sudo systemctl start docker > /dev/null 2>&1 13 | echo "Docker has been successfully installed." 14 | else 15 | echo "Docker already installed." 16 | fi 17 | 18 | 19 | mkdir /app/opencex -p 20 | cd /app/opencex || exit 21 | git clone https://github.com/Polygant/OpenCEX-backend.git ./backend 22 | git clone https://github.com/Polygant/OpenCEX-frontend.git ./frontend 23 | git clone https://github.com/Polygant/OpenCEX-static.git ./nuxt 24 | git clone https://github.com/Polygant/OpenCEX-JS-admin.git ./admin 25 | 26 | echo "`cat < /app/opencex/backend/.env 652 | 653 | fi 654 | 655 | source /app/opencex/backend/.env 656 | set -a 657 | cd /app/opencex/frontend || exit 658 | FILE=/app/opencex/frontend/src/local_config 659 | 660 | if test ! -f "$FILE"; then 661 | envsubst < /app/opencex/frontend/src/example.local_config.js > /app/opencex/frontend/src/local_config 662 | ### save to env 663 | 664 | cat << EOF >> /app/opencex/backend/.env 665 | 666 | 667 | #opencex frontend values 668 | RECAPTCHA=$RECAPTCHA 669 | TELEGRAM=$TELEGRAM 670 | TG_NEWS=$TG_NEWS 671 | SUPPORT_EMAIL=$SUPPORT_EMAIL 672 | FACEBOOK=$FACEBOOK 673 | TWITTER=$TWITTER 674 | LINKEDIN=$LINKEDIN 675 | EOF 676 | 677 | fi 678 | 679 | ################## 680 | # START BUILDING! 681 | ################## 682 | 683 | 684 | # build front 685 | mkdir -p /app/opencex/frontend/deploy/ 686 | cp /app/deploy/frontend/Dockerfile /app/opencex/frontend/deploy/Dockerfile 687 | cp /app/deploy/frontend/default.conf /app/opencex/frontend/deploy/default.conf 688 | cp /app/deploy/frontend/nginx.conf /app/opencex/frontend/deploy/nginx.conf 689 | sed -i "s/ADMIN_BASE_URL/$ADMIN_BASE_URL/g" /app/opencex/frontend/deploy/default.conf 690 | sed -i "s/DOMAIN/$DOMAIN/g" /app/opencex/frontend/deploy/default.conf 691 | docker build -t frontend -f deploy/Dockerfile . 692 | 693 | # build nuxt 694 | mkdir -p /app/opencex/nuxt/deploy/ 695 | cd /app/opencex/nuxt || exit 696 | cp /app/deploy/nuxt/.env.template /app/opencex/nuxt/ 697 | cp /app/deploy/nuxt/Dockerfile /app/opencex/nuxt/deploy/Dockerfile 698 | envsubst < /app/opencex/nuxt/.env.template > /app/opencex/nuxt/.env 699 | docker build -t nuxt -f deploy/Dockerfile . 700 | 701 | # build admin 702 | mkdir -p /app/opencex/admin/deploy/ 703 | cd /app/opencex/admin || exit 704 | cp /app/deploy/admin/Dockerfile /app/opencex/admin/deploy/Dockerfile 705 | cp /app/deploy/admin/default.conf /app/opencex/admin/deploy/default.conf 706 | cp /app/deploy/admin/.env.template /app/opencex/admin/ 707 | sed -i "s/ADMIN_BASE_URL/$ADMIN_BASE_URL/g" /app/opencex/admin/deploy/default.conf 708 | envsubst < /app/opencex/admin/.env.template > /app/opencex/admin/src/local_config.js 709 | docker build -t admin -f deploy/Dockerfile . 710 | 711 | 712 | # build backend 713 | cd /app/opencex/backend/ || exit 714 | chmod +x /app/opencex/backend/manage.py 715 | docker build -t opencex . 716 | 717 | 718 | ### install Caddy 719 | 720 | mkdir /app/opencex -p 721 | cd /app/opencex || exit 722 | mkdir caddy_data postgresql_data redis_data rabbitmq_data rabbitmq_logs bitcoind_data -p 723 | chmod 777 caddy_data postgresql_data redis_data rabbitmq_data rabbitmq_logs bitcoind_data 724 | docker network create caddy 725 | 726 | cat << EOF > docker-compose.yml 727 | version: "3.7" 728 | networks: 729 | caddy: 730 | external: true 731 | services: 732 | opencex: 733 | container_name: opencex 734 | image: opencex:latest 735 | command: gunicorn exchange.wsgi:application -b 0.0.0.0:8080 -w 2 --access-logfile - --error-logfile - 736 | # entrypoint: tail -f /dev/null 737 | restart: always 738 | volumes: 739 | - /app/opencex/backend:/app 740 | networks: 741 | - caddy 742 | depends_on: 743 | - postgresql 744 | - redis 745 | - rabbitmq 746 | - frontend 747 | - nuxt 748 | - caddy 749 | - bitcoind 750 | 751 | opencex-wss: 752 | container_name: opencex-wss 753 | image: opencex:latest 754 | command: daphne -b 0.0.0.0 exchange.asgi:application --ping-interval 600 --ping-timeout 600 755 | restart: always 756 | volumes: 757 | - /app/opencex/backend:/app 758 | networks: 759 | - caddy 760 | depends_on: 761 | - postgresql 762 | - redis 763 | - rabbitmq 764 | - frontend 765 | - nuxt 766 | - caddy 767 | - bitcoind 768 | - opencex 769 | 770 | opencex-cel: 771 | container_name: opencex-cel 772 | image: opencex:latest 773 | command: celery -A exchange worker -l info -n general -B -s /tmp/cebeat.db -X btc,eth_new_blocks,eth_deposits,eth_payouts,eth_check_balances,eth_accumulations,eth_tokens_accumulations,eth_send_gas,bnb_new_blocks,bnb_deposits,bnb_payouts,bnb_check_balances,bnb_accumulations,bnb_tokens_accumulations,bnb_send_gas,trx_new_blocks,trx_deposits,trx_payouts,trx_check_balances,trx_accumulations,trx_tokens_accumulations,matic_new_blocks,matic_deposits,matic_payouts,matic_check_balances,matic_accumulations,matic_tokens_accumulations 774 | restart: always 775 | volumes: 776 | - /app/opencex/backend:/app 777 | networks: 778 | - caddy 779 | depends_on: 780 | - postgresql 781 | - redis 782 | - rabbitmq 783 | - frontend 784 | - nuxt 785 | - caddy 786 | - bitcoind 787 | - opencex 788 | 789 | opencex-stack: 790 | container_name: opencex-stack 791 | image: opencex:latest 792 | command: python bin/stack.py 793 | restart: always 794 | volumes: 795 | - /app/opencex/backend:/app 796 | networks: 797 | - caddy 798 | depends_on: 799 | - postgresql 800 | - redis 801 | - rabbitmq 802 | - frontend 803 | - nuxt 804 | - caddy 805 | - bitcoind 806 | - opencex 807 | 808 | opencex-btc: 809 | container_name: opencex-btc 810 | image: opencex:latest 811 | command: /app/manage.py btcworker 812 | restart: always 813 | volumes: 814 | - /app/opencex/backend:/app 815 | networks: 816 | - caddy 817 | depends_on: 818 | - postgresql 819 | - redis 820 | - rabbitmq 821 | - frontend 822 | - nuxt 823 | - caddy 824 | - bitcoind 825 | - opencex 826 | 827 | opencex-eth-blocks: 828 | container_name: opencex-eth-blocks 829 | image: opencex:latest 830 | command: bash -c "celery -A exchange worker -l info -n eth_new_blocks -Q eth_new_blocks -c 1 " 831 | restart: always 832 | volumes: 833 | - /app/opencex/backend:/app 834 | networks: 835 | - caddy 836 | depends_on: 837 | - postgresql 838 | - redis 839 | - rabbitmq 840 | - frontend 841 | - nuxt 842 | - caddy 843 | - bitcoind 844 | - opencex 845 | 846 | opencex-bnb-blocks: 847 | container_name: opencex-bnb-blocks 848 | image: opencex:latest 849 | command: bash -c "celery -A exchange worker -l info -n bnb_new_blocks -Q bnb_new_blocks -c 1 " 850 | restart: always 851 | volumes: 852 | - /app/opencex/backend:/app 853 | networks: 854 | - caddy 855 | depends_on: 856 | - postgresql 857 | - redis 858 | - rabbitmq 859 | - frontend 860 | - nuxt 861 | - caddy 862 | - bitcoind 863 | - opencex 864 | 865 | opencex-trx-blocks: 866 | container_name: opencex-trx-blocks 867 | image: opencex:latest 868 | command: bash -c "celery -A exchange worker -l info -n trx_new_blocks -Q trx_new_blocks -c 1 " 869 | restart: always 870 | volumes: 871 | - /app/opencex/backend:/app 872 | networks: 873 | - caddy 874 | depends_on: 875 | - postgresql 876 | - redis 877 | - rabbitmq 878 | - frontend 879 | - nuxt 880 | - caddy 881 | - bitcoind 882 | - opencex 883 | 884 | opencex-matic-blocks: 885 | container_name: opencex-matic-blocks 886 | image: opencex:latest 887 | command: bash -c "celery -A exchange worker -l info -n matic_new_blocks -Q matic_new_blocks -c 1 " 888 | restart: always 889 | volumes: 890 | - /app/opencex/backend:/app 891 | networks: 892 | - caddy 893 | depends_on: 894 | - postgresql 895 | - redis 896 | - rabbitmq 897 | - frontend 898 | - nuxt 899 | - caddy 900 | - bitcoind 901 | - opencex 902 | 903 | opencex-deposits: 904 | container_name: opencex-deposits 905 | image: opencex:latest 906 | command: bash -c "celery -A exchange worker -l info -n deposits -Q trx_deposits,bnb_deposits,eth_deposits,matic_deposits -c 1 " 907 | restart: always 908 | volumes: 909 | - /app/opencex/backend:/app 910 | networks: 911 | - caddy 912 | depends_on: 913 | - postgresql 914 | - redis 915 | - rabbitmq 916 | - frontend 917 | - nuxt 918 | - caddy 919 | - bitcoind 920 | - opencex 921 | 922 | opencex-payouts: 923 | container_name: opencex-payouts 924 | image: opencex:latest 925 | command: bash -c "celery -A exchange worker -l info -n payouts -Q trx_payouts,eth_payouts,bnb_payouts,matic_payouts -c 1 " 926 | restart: always 927 | volumes: 928 | - /app/opencex/backend:/app 929 | networks: 930 | - caddy 931 | depends_on: 932 | - postgresql 933 | - redis 934 | - rabbitmq 935 | - frontend 936 | - nuxt 937 | - caddy 938 | - bitcoind 939 | - opencex 940 | 941 | opencex-balances: 942 | container_name: opencex-balances 943 | image: opencex:latest 944 | command: bash -c "celery -A exchange worker -l info -n check_balances -Q trx_check_balances,bnb_check_balances,eth_check_balances,matic_check_balances -c 1 " 945 | restart: always 946 | volumes: 947 | - /app/opencex/backend:/app 948 | networks: 949 | - caddy 950 | depends_on: 951 | - postgresql 952 | - redis 953 | - rabbitmq 954 | - frontend 955 | - nuxt 956 | - caddy 957 | - bitcoind 958 | - opencex 959 | 960 | opencex-coin-accumulations: 961 | container_name: opencex-coin-accumulations 962 | image: opencex:latest 963 | command: bash -c "celery -A exchange worker -l info -n coin_accumulations -Q trx_accumulations,bnb_accumulations,eth_accumulations,matic_accumulations -c 1 " 964 | restart: always 965 | volumes: 966 | - /app/opencex/backend:/app 967 | networks: 968 | - caddy 969 | depends_on: 970 | - postgresql 971 | - redis 972 | - rabbitmq 973 | - frontend 974 | - nuxt 975 | - caddy 976 | - bitcoind 977 | - opencex 978 | 979 | opencex-token-accumulations: 980 | container_name: opencex-token-accumulations 981 | image: opencex:latest 982 | command: bash -c "celery -A exchange worker -l info -n tokens_accumulations -Q trx_tokens_accumulations,bnb_tokens_accumulations,eth_tokens_accumulations,matic_tokens_accumulations -c 1 " 983 | restart: always 984 | volumes: 985 | - /app/opencex/backend:/app 986 | networks: 987 | - caddy 988 | depends_on: 989 | - postgresql 990 | - redis 991 | - rabbitmq 992 | - frontend 993 | - nuxt 994 | - caddy 995 | - bitcoind 996 | - opencex 997 | 998 | opencex-gas: 999 | container_name: opencex-gas 1000 | image: opencex:latest 1001 | command: bash -c "celery -A exchange worker -l info -n send_gas -Q trx_send_gas,bnb_send_gas,eth_send_gas,matic_send_gas -c 1 " 1002 | restart: always 1003 | volumes: 1004 | - /app/opencex/backend:/app 1005 | networks: 1006 | - caddy 1007 | depends_on: 1008 | - postgresql 1009 | - redis 1010 | - rabbitmq 1011 | - frontend 1012 | - nuxt 1013 | - caddy 1014 | - bitcoind 1015 | - opencex 1016 | 1017 | frontend: 1018 | image: frontend:latest 1019 | container_name: frontend 1020 | restart: always 1021 | volumes: 1022 | - /app/opencex/backend:/app 1023 | networks: 1024 | - caddy 1025 | labels: 1026 | caddy: $DOMAIN 1027 | caddy.reverse_proxy: "{{upstreams 80}}" 1028 | nuxt: 1029 | image: nuxt:latest 1030 | container_name: nuxt 1031 | restart: always 1032 | networks: 1033 | - caddy 1034 | admin: 1035 | image: admin:latest 1036 | container_name: admin 1037 | restart: always 1038 | networks: 1039 | - caddy 1040 | caddy: 1041 | image: lucaslorentz/caddy-docker-proxy:latest 1042 | restart: always 1043 | ports: 1044 | - 80:80 1045 | - 443:443 1046 | environment: 1047 | - CADDY_INGRESS_NETWORKS=caddy 1048 | networks: 1049 | - caddy 1050 | volumes: 1051 | - /var/run/docker.sock:/var/run/docker.sock 1052 | - ./caddy_data:/data 1053 | 1054 | postgresql: 1055 | container_name: postgresql 1056 | hostname: postgresql 1057 | restart: always 1058 | image: postgres:latest 1059 | shm_size: 1g 1060 | volumes: 1061 | - ./postgresql_data:/var/lib/postgresql/data 1062 | environment: 1063 | POSTGRES_USER: "$DB_USER" 1064 | POSTGRES_PASSWORD: "$DB_PASS" 1065 | POSTGRES_DB: "$DB_NAME" 1066 | networks: 1067 | - caddy 1068 | 1069 | redis: 1070 | container_name: redis 1071 | restart: always 1072 | image: redis:latest 1073 | volumes: 1074 | - ./redis_data:/data 1075 | entrypoint: redis-server 1076 | networks: 1077 | - caddy 1078 | rabbitmq: 1079 | hostname: rabbitmq 1080 | container_name: rabbitmq 1081 | restart: always 1082 | image: rabbitmq:3.9.22-management 1083 | volumes: 1084 | - ./rabbitmq_data/:/var/lib/rabbitmq/ 1085 | - ./rabbitmq_logs/:/var/log/rabbitmq/ 1086 | environment: 1087 | RABBITMQ_DEFAULT_USER: $AMQP_USER 1088 | RABBITMQ_DEFAULT_PASS: $AMQP_PASS 1089 | RABBITMQ_DEFAULT_VHOST: / 1090 | networks: 1091 | - caddy 1092 | labels: 1093 | caddy: $RMQDOMAIN 1094 | caddy.reverse_proxy: "{{upstreams http 15672}}" 1095 | bitcoind: 1096 | container_name: bitcoind 1097 | restart: always 1098 | image: lncm/bitcoind:v24.0.1 1099 | volumes: 1100 | - ./bitcoind_data/:/data/.bitcoin/ 1101 | networks: 1102 | - caddy 1103 | EOF 1104 | 1105 | # build hummingbot 1106 | if [ "$IS_HUMMINGBOT_ENABLED" = "True" ]; then 1107 | cd /app/opencex || exit 1108 | git clone https://github.com/Polygant/hummingbot.git ./hmbot 1109 | cd ./hmbot 1110 | docker build -t hummingbot:latest -f Dockerfile --target=release . 1111 | cat << EOF >> /app/opencex/docker-compose.yml 1112 | hummingbot: 1113 | container_name: hummingbot 1114 | hostname: hummingbot 1115 | restart: always 1116 | image: hummingbot:latest 1117 | volumes: 1118 | - /app/opencex/hmbot/conf:/home/hummingbot/conf 1119 | - /app/opencex/hmbot/conf/connectors:/home/hummingbot/conf/connectors 1120 | - /app/opencex/hmbot/conf/strategies:/home/hummingbot/conf/strategies 1121 | - /app/opencex/hmbot/logs:/home/hummingbot/logs 1122 | - /app/opencex/hmbot/data:/home/hummingbot/data 1123 | - /app/opencex/hmbot/scripts:/home/hummingbot/scripts 1124 | networks: 1125 | - caddy 1126 | tty: true 1127 | stdin_open: true 1128 | EOF 1129 | fi 1130 | cd /app/opencex 1131 | docker compose up -d 1132 | 1133 | docker stop opencex-cel opencex-wss 1134 | sleep 5; 1135 | docker exec -it opencex python ./manage.py migrate 1136 | docker exec -it opencex python ./manage.py collectstatic 1137 | docker compose up -d 1138 | 1139 | 1140 | 1141 | cd /app/opencex || exit 1142 | docker compose stop 1143 | cat << EOF > /app/opencex/bitcoind_data/bitcoin.conf 1144 | rpcuser=$BTC_NODE_USER 1145 | rpcpassword=$BTC_NODE_PASS 1146 | rpcallowip=0.0.0.0/0 1147 | rpcbind=0.0.0.0 1148 | rpcport=$BTC_NODE_PORT 1149 | prune=20000 1150 | wallet=/data/.bitcoin/opencex 1151 | 1152 | EOF 1153 | docker compose up -d 1154 | sleep 30; 1155 | docker exec -it bitcoind bitcoin-cli -named createwallet wallet_name="opencex" descriptors=false 1156 | docker restart bitcoind 1157 | sleep 30; 1158 | docker exec -it opencex python wizard.py 1159 | cd /app/opencex || exit 1160 | docker compose stop 1161 | docker compose up -d 1162 | 1163 | ### Registration of the installation OpenCEX 1164 | curl --location 'http://alertbot.plgdev.com/registration' \ 1165 | --header 'Content-Type: application/json' \ 1166 | --data "{\"domain\": \"${DOMAIN}\"}" 1167 | 1168 | 1169 | # cleanup 1170 | # cd /app/opencex && docker compose down 1171 | # rm -rf /app 1172 | # docker system prune -a 1173 | --------------------------------------------------------------------------------