Mở đầu
Đôi khi chúng ta cần một web server đơn giản, public ra internet để thực thi vài tác vụ linh tinh, hoặc để hosting một số file khi cần. Tuy nhiên, với tư cách là một dev/pentester “nhà nghèo” thì việc có thẻ visa để đăng ký free cloud của Google, AWS, Oracle thôi nhiều khi đã là cả một vấn đề lớn. Đùa chút thôi, bài viết này mình sẽ giới thiệu Deta – một công cụ cho phép bạn nhanh chóng tạo micro-website/API và public ra internet. Here we go~
Deta
https://deta.sh là công cụ Cloud cá nhân miễn phí cho phép chúng ta xây dựng các ứng dụng, prototype rồi public ra internet một cách nhanh chóng.
Deta đi kèm với:
- Deta Base: NoSQL database (giống như MongoDB)
- Deta Micros: Cho phép bạn deploy ứng dụng của mình lên internet (giống như Heroku). Deta cho tạo thoải mái bao nhiêu micros cũng được hết
- Deta Drive: Cho phép lưu trữ file (giống như Google Drive và AWS S3)
Deta hiện đang hỗ trợ các ngôn ngữ: Python, Node.js, và Golang. Với mỗi ngôn ngữ, Deta cũng hỗ trợ các micro-framework ví dụ như Python là FastAPI hoặc Flask.
Để lấy ví dụ, mình sẽ xây dựng ứng dụng đơn giản dành cho pentester như sau:
- Cho phép tải file lên theo URL và MIME Type tùy ý. VD: truy cập vào link: “https://myfakeserver.com/aaa.png” nhưng trả ra content là
alert(origin)
và mime type lại là javascript (chứ không phải file ảnh như đuôi PNG). - Cho người dùng điền trực tiếp nội dung file.
- Cho phép xoá file.
Cài đặt
Tất cả hướng dẫn sử dụng (đầy đủ và chi tiết) đều có ở https://docs.deta.sh/docs/home
Trước hết là chúng ta cần đăng ký tài khoản. Màn hình quản lý nằm ở: https://web.deta.sh/home
Sau đó, ta tải về Deta CLI
rồi đăng nhập:
1 2 3 | <span class="token function">curl</span> -fsSL https://get.deta.dev/cli.sh <span class="token operator">|</span> <span class="token function">sh</span> deta login |
sau đó tạo một micro mới với framework là python:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | deta new payload-server --python Successfully created a new micro <span class="token punctuation">{</span> <span class="token string">"name"</span><span class="token builtin class-name">:</span> <span class="token string">"payload-server"</span>, <span class="token string">"id"</span><span class="token builtin class-name">:</span> <span class="token string">"xxxxxx"</span>, <span class="token string">"project"</span><span class="token builtin class-name">:</span> <span class="token string">"xxxxxxx"</span>, <span class="token string">"runtime"</span><span class="token builtin class-name">:</span> <span class="token string">"python3.9"</span>, <span class="token string">"endpoint"</span><span class="token builtin class-name">:</span> <span class="token string">"https://xxxxxxx.deta.dev"</span>, <span class="token string">"region"</span><span class="token builtin class-name">:</span> <span class="token string">"ap-southeast-1"</span>, <span class="token string">"visor"</span><span class="token builtin class-name">:</span> <span class="token string">"disabled"</span>, <span class="token string">"http_auth"</span><span class="token builtin class-name">:</span> <span class="token string">"disabled"</span> <span class="token punctuation">}</span> |
xem thử file vừa tạo:
1 2 3 4 | ➜ payload-server <span class="token function">cat</span> main.py def app<span class="token punctuation">(</span>event<span class="token punctuation">)</span>: <span class="token builtin class-name">return</span> <span class="token string">"Hello, world!"</span>% |
Ngay ở bước này chúng ta có thể chạy deta deploy
và app của chúng ta sẽ được deploy lên URL ở trên. Quá nhanh, quá nguy hiểm:
Chúng ta cũng có thể cài đặt thêm các thư viện, tạo file requirements.txt
và điền tên các thư viện vào, ở đây ta sẽ cần đến Flask và Deta
1 2 3 | flask deta |
Mỗi lần sửa code xong xuôi thì nhớ
deta deploy
để đẩy code lên nhé
Backend
Sửa lại file main.py
như sau, vì code cũng khá ngắn có 88 dòng và đơn giản nên mình sẽ không đi vào từng bước mà chỉ giải thích một số vị trí quan trọng.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 | <span class="token keyword">from</span> flask <span class="token keyword">import</span> Flask <span class="token keyword">from</span> flask <span class="token keyword">import</span> Flask<span class="token punctuation">,</span> request<span class="token punctuation">,</span> render_template<span class="token punctuation">,</span> abort<span class="token punctuation">,</span> Response<span class="token punctuation">,</span> flash<span class="token punctuation">,</span> redirect <span class="token keyword">from</span> deta <span class="token keyword">import</span> Deta <span class="token keyword">import</span> uuid app <span class="token operator">=</span> Flask<span class="token punctuation">(</span>__name__<span class="token punctuation">)</span> app<span class="token punctuation">.</span>secret_key <span class="token operator">=</span> <span class="token string">b'somethingrandom'</span> deta <span class="token operator">=</span> Deta<span class="token punctuation">(</span><span class="token string">"PROJECT_KEY_HERE"</span><span class="token punctuation">)</span> drive <span class="token operator">=</span> deta<span class="token punctuation">.</span>Drive<span class="token punctuation">(</span><span class="token string">"files"</span><span class="token punctuation">)</span> db <span class="token operator">=</span> deta<span class="token punctuation">.</span>Base<span class="token punctuation">(</span><span class="token string">"payload_db"</span><span class="token punctuation">)</span> <span class="token decorator annotation punctuation">@app<span class="token punctuation">.</span>route</span><span class="token punctuation">(</span><span class="token string">"/"</span><span class="token punctuation">,</span> defaults<span class="token operator">=</span><span class="token punctuation">{</span><span class="token string">"path"</span><span class="token punctuation">:</span> <span class="token string">""</span><span class="token punctuation">}</span><span class="token punctuation">,</span> methods<span class="token operator">=</span><span class="token punctuation">[</span><span class="token string">"GET"</span><span class="token punctuation">,</span> <span class="token string">"POST"</span><span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token decorator annotation punctuation">@app<span class="token punctuation">.</span>route</span><span class="token punctuation">(</span><span class="token string">"/<path:path>"</span><span class="token punctuation">)</span> <span class="token keyword">def</span> <span class="token function">catch_all</span><span class="token punctuation">(</span>path<span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword">if</span> path <span class="token operator">==</span> <span class="token string">""</span><span class="token punctuation">:</span> <span class="token keyword">if</span> request<span class="token punctuation">.</span>method <span class="token operator">==</span> <span class="token string">'POST'</span><span class="token punctuation">:</span> <span class="token keyword">return</span> upload<span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">else</span><span class="token punctuation">:</span> res <span class="token operator">=</span> db<span class="token punctuation">.</span>fetch<span class="token punctuation">(</span><span class="token punctuation">)</span> all_items <span class="token operator">=</span> res<span class="token punctuation">.</span>items <span class="token keyword">return</span> render_template<span class="token punctuation">(</span><span class="token string">"index.html"</span><span class="token punctuation">,</span> items<span class="token operator">=</span>all_items<span class="token punctuation">)</span> <span class="token keyword">elif</span> path <span class="token operator">==</span> <span class="token string">"delete"</span><span class="token punctuation">:</span> <span class="token keyword">return</span> delete<span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">else</span><span class="token punctuation">:</span> <span class="token keyword">return</span> download<span class="token punctuation">(</span>path<span class="token punctuation">)</span> <span class="token keyword">def</span> <span class="token function">upload</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token builtin">file</span> <span class="token operator">=</span> request<span class="token punctuation">.</span>files<span class="token punctuation">.</span>get<span class="token punctuation">(</span><span class="token string">"file"</span><span class="token punctuation">)</span> submitted_mime <span class="token operator">=</span> request<span class="token punctuation">.</span>form<span class="token punctuation">.</span>get<span class="token punctuation">(</span><span class="token string">"mime"</span><span class="token punctuation">)</span> submitted_path <span class="token operator">=</span> request<span class="token punctuation">.</span>form<span class="token punctuation">.</span>get<span class="token punctuation">(</span><span class="token string">"path"</span><span class="token punctuation">)</span> content <span class="token operator">=</span> request<span class="token punctuation">.</span>form<span class="token punctuation">.</span>get<span class="token punctuation">(</span><span class="token string">"content"</span><span class="token punctuation">)</span> mime <span class="token operator">=</span> <span class="token string">"text/plain"</span> <span class="token keyword">if</span> submitted_mime<span class="token punctuation">:</span> mime <span class="token operator">=</span> submitted_mime <span class="token keyword">if</span> <span class="token builtin">file</span><span class="token punctuation">:</span> mime <span class="token operator">=</span> <span class="token builtin">file</span><span class="token punctuation">.</span>content_type content <span class="token operator">=</span> <span class="token builtin">file</span> <span class="token keyword">elif</span> <span class="token keyword">not</span> content<span class="token punctuation">:</span> flash<span class="token punctuation">(</span><span class="token string">"[ERROR] No content!"</span><span class="token punctuation">)</span> <span class="token keyword">return</span> redirect<span class="token punctuation">(</span><span class="token string">"/"</span><span class="token punctuation">)</span> <span class="token keyword">if</span> <span class="token keyword">not</span> submitted_path<span class="token punctuation">:</span> flash<span class="token punctuation">(</span><span class="token string">"[ERROR] No path!"</span><span class="token punctuation">)</span> <span class="token keyword">return</span> redirect<span class="token punctuation">(</span><span class="token string">"/"</span><span class="token punctuation">)</span> <span class="token keyword">if</span> db<span class="token punctuation">.</span>fetch<span class="token punctuation">(</span><span class="token punctuation">{</span><span class="token string">"path"</span><span class="token punctuation">:</span> submitted_path<span class="token punctuation">}</span><span class="token punctuation">,</span> limit<span class="token operator">=</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">.</span>items<span class="token punctuation">:</span> flash<span class="token punctuation">(</span><span class="token string">"[ERROR] Duplicate path!"</span><span class="token punctuation">)</span> <span class="token keyword">return</span> redirect<span class="token punctuation">(</span><span class="token string">"/"</span><span class="token punctuation">)</span> filename <span class="token operator">=</span> <span class="token builtin">str</span><span class="token punctuation">(</span>uuid<span class="token punctuation">.</span>uuid4<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> db<span class="token punctuation">.</span>put<span class="token punctuation">(</span><span class="token punctuation">{</span><span class="token string">"path"</span><span class="token punctuation">:</span> submitted_path<span class="token punctuation">,</span> <span class="token string">"filename"</span><span class="token punctuation">:</span> filename<span class="token punctuation">,</span> <span class="token string">"mime"</span><span class="token punctuation">:</span> mime<span class="token punctuation">}</span><span class="token punctuation">)</span> res <span class="token operator">=</span> drive<span class="token punctuation">.</span>put<span class="token punctuation">(</span>filename<span class="token punctuation">,</span> content<span class="token punctuation">,</span> content_type<span class="token operator">=</span>mime<span class="token punctuation">)</span> <span class="token keyword">if</span> res<span class="token punctuation">:</span> flash<span class="token punctuation">(</span><span class="token string-interpolation"><span class="token string">f"[OK] file uploaded to path: </span><span class="token interpolation"><span class="token punctuation">{</span>submitted_path<span class="token punctuation">}</span></span><span class="token string">"</span></span><span class="token punctuation">)</span> <span class="token keyword">return</span> redirect<span class="token punctuation">(</span><span class="token string">"/"</span><span class="token punctuation">)</span> <span class="token keyword">def</span> <span class="token function">download</span><span class="token punctuation">(</span>path<span class="token punctuation">)</span><span class="token punctuation">:</span> items <span class="token operator">=</span> db<span class="token punctuation">.</span>fetch<span class="token punctuation">(</span><span class="token punctuation">{</span><span class="token string">"path"</span><span class="token punctuation">:</span> path<span class="token punctuation">}</span><span class="token punctuation">,</span> limit<span class="token operator">=</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">.</span>items <span class="token keyword">if</span> items<span class="token punctuation">:</span> <span class="token builtin">file</span> <span class="token operator">=</span> drive<span class="token punctuation">.</span>get<span class="token punctuation">(</span>items<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">[</span><span class="token string">'filename'</span><span class="token punctuation">]</span><span class="token punctuation">)</span> content <span class="token operator">=</span> <span class="token builtin">file</span><span class="token punctuation">.</span>read<span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token builtin">file</span><span class="token punctuation">.</span>close<span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">return</span> Response<span class="token punctuation">(</span>content<span class="token punctuation">,</span> mimetype<span class="token operator">=</span>items<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">[</span><span class="token string">'mime'</span><span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token keyword">else</span><span class="token punctuation">:</span> <span class="token keyword">return</span> abort<span class="token punctuation">(</span><span class="token number">404</span><span class="token punctuation">)</span> <span class="token keyword">def</span> <span class="token function">delete</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span> path <span class="token operator">=</span> request<span class="token punctuation">.</span>args<span class="token punctuation">.</span>get<span class="token punctuation">(</span><span class="token string">"p"</span><span class="token punctuation">)</span> items <span class="token operator">=</span> db<span class="token punctuation">.</span>fetch<span class="token punctuation">(</span><span class="token punctuation">{</span><span class="token string">"path"</span><span class="token punctuation">:</span> path<span class="token punctuation">}</span><span class="token punctuation">,</span> limit<span class="token operator">=</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">.</span>items <span class="token keyword">if</span> items<span class="token punctuation">:</span> db<span class="token punctuation">.</span>delete<span class="token punctuation">(</span>items<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">[</span><span class="token string">'key'</span><span class="token punctuation">]</span><span class="token punctuation">)</span> drive<span class="token punctuation">.</span>delete<span class="token punctuation">(</span>items<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">[</span><span class="token string">'filename'</span><span class="token punctuation">]</span><span class="token punctuation">)</span> flash<span class="token punctuation">(</span><span class="token string-interpolation"><span class="token string">f"[OK] path '</span><span class="token interpolation"><span class="token punctuation">{</span>path<span class="token punctuation">}</span></span><span class="token string">' deleted!"</span></span><span class="token punctuation">)</span> <span class="token keyword">return</span> redirect<span class="token punctuation">(</span><span class="token string">"/"</span><span class="token punctuation">)</span> <span class="token keyword">else</span><span class="token punctuation">:</span> <span class="token keyword">return</span> abort<span class="token punctuation">(</span><span class="token number">404</span><span class="token punctuation">)</span> <span class="token comment"># Uncomment this line to debug local</span> <span class="token comment"># app.run()</span> |
Ở đoạn này chúng ta cần tạo Project Keys
(tương tự API key) trong giao diện ở dưới, drive
và db
là các object giúp chúng ta tương tác với database và drive:
1 2 3 4 | deta <span class="token operator">=</span> Deta<span class="token punctuation">(</span><span class="token string">"PROJECT_KEY_HERE"</span><span class="token punctuation">)</span> drive <span class="token operator">=</span> deta<span class="token punctuation">.</span>Drive<span class="token punctuation">(</span><span class="token string">"files"</span><span class="token punctuation">)</span> db <span class="token operator">=</span> deta<span class="token punctuation">.</span>Base<span class="token punctuation">(</span><span class="token string">"payload_db"</span><span class="token punctuation">)</span> |
Phần route, chúng ta sẽ tạo một route dùng để catch all (bắt tất cả các request) rồi kiểm tra:
- Nếu là path
index
=> chuyển đến trang upload. - Nếu là path
delete
=> chuyển đến trang xoá file - Còn lại thì mặc định là xử lý trả về nội dung file (nếu có tồn tại)
Deta đã cũng cấp sẵn cho chúng ta các phương thức để tương tác với DB:
1 2 | db<span class="token punctuation">.</span>put<span class="token punctuation">(</span><span class="token punctuation">{</span><span class="token string">"path"</span><span class="token punctuation">:</span> submitted_path<span class="token punctuation">,</span> <span class="token string">"filename"</span><span class="token punctuation">:</span> filename<span class="token punctuation">,</span> <span class="token string">"mime"</span><span class="token punctuation">:</span> mime<span class="token punctuation">}</span><span class="token punctuation">)</span> |
Dùng để insert một bản ghi vào DB. Chúng ta sẽ lưu lại path
(để kiểm tra xem có bị trùng không), filename
thì sinh ngẫu nhiên bằng uuid
, mime
do người dùng tự nhập hoặc lấy ra từ file tải lên. Dữ liệu trong DB sẽ có dạng sau:
1 2 | {'filename': 'ee8945e3-b7aa-4d0a-829a-b472aecb1ef2', 'key': '2zd58xhd6hvi', 'path': 'abc.png'} |
1 2 | db<span class="token punctuation">.</span>fetch<span class="token punctuation">(</span><span class="token punctuation">{</span><span class="token string">"path"</span><span class="token punctuation">:</span> submitted_path<span class="token punctuation">}</span><span class="token punctuation">,</span> limit<span class="token operator">=</span><span class="token number">1</span><span class="token punctuation">)</span> |
dùng để lấy ra dữ liệu, có thể query chính xác hoặc theo syntax gần với MongoDB: https://docs.deta.sh/docs/base/queries.
1 2 | db<span class="token punctuation">.</span>delete<span class="token punctuation">(</span>items<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">[</span><span class="token string">'key'</span><span class="token punctuation">]</span><span class="token punctuation">)</span> |
Dùng để xóa file dựa theo key. Ta cũng có thể tương tác trực tiếp thông qua giao diện ở https://web.deta.sh/home:
Rất đơn giản đúng không nào? Tương tác với Drive cũng hoàn toàn tương tự:
1 2 3 4 5 6 7 8 9 10 11 | <span class="token comment"># Upload file</span> drive<span class="token punctuation">.</span>put<span class="token punctuation">(</span>filename<span class="token punctuation">,</span> content<span class="token punctuation">,</span> content_type<span class="token operator">=</span>mime<span class="token punctuation">)</span> <span class="token comment"># Đọc nội dung file</span> <span class="token builtin">file</span> <span class="token operator">=</span> drive<span class="token punctuation">.</span>get<span class="token punctuation">(</span>items<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">[</span><span class="token string">'filename'</span><span class="token punctuation">]</span><span class="token punctuation">)</span> content <span class="token operator">=</span> <span class="token builtin">file</span><span class="token punctuation">.</span>read<span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token builtin">file</span><span class="token punctuation">.</span>close<span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token comment"># Xóa file theo filename </span> drive<span class="token punctuation">.</span>delete<span class="token punctuation">(</span>items<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">[</span><span class="token string">'filename'</span><span class="token punctuation">]</span><span class="token punctuation">)</span> |
Drive cũng có giao diện trực quan:
Frontend
Không màu mè, hoa lá, giao diện thuần HTML, no CSS
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | <span class="token doctype"><span class="token punctuation"><!</span><span class="token doctype-tag">DOCTYPE</span> <span class="token name">html</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>html</span> <span class="token attr-name">lang</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>en<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>head</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>meta</span> <span class="token attr-name">charset</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>UTF-8<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>meta</span> <span class="token attr-name">http-equiv</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>X-UA-Compatible<span class="token punctuation">"</span></span> <span class="token attr-name">content</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>IE=edge<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>meta</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>viewport<span class="token punctuation">"</span></span> <span class="token attr-name">content</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>width=device-width, initial-scale=1.0<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>title</span><span class="token punctuation">></span></span>Payload Server<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>title</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>head</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>body</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>h1</span><span class="token punctuation">></span></span>Payload Server<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>h1</span><span class="token punctuation">></span></span> {% with messages = get_flashed_messages() %} {% if messages %} <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>ul</span><span class="token punctuation">></span></span> {% for message in messages %} <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>li</span><span class="token punctuation">></span></span>{{ message }}<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>li</span><span class="token punctuation">></span></span> {% endfor %} <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>ul</span><span class="token punctuation">></span></span> {% endif %} {% endwith %} <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>h2</span><span class="token punctuation">></span></span>Upload<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>h2</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>form</span> <span class="token attr-name">action</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>/<span class="token punctuation">"</span></span> <span class="token attr-name">enctype</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>multipart/form-data<span class="token punctuation">"</span></span> <span class="token attr-name">method</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>post<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>input</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>file<span class="token punctuation">"</span></span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>file<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>br</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>br</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>label</span> <span class="token attr-name">for</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>path<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>URL Path<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>label</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>input</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>path<span class="token punctuation">"</span></span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>text<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>br</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>br</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>label</span> <span class="token attr-name">for</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>mime<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>MIME (default to <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>code</span><span class="token punctuation">></span></span>text/plain<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>code</span><span class="token punctuation">></span></span> or file's mime)<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>label</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>input</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>mime<span class="token punctuation">"</span></span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>text<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>br</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>br</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>label</span> <span class="token attr-name">for</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>path<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Content (if no file is selected)<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>label</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>textarea</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>content<span class="token punctuation">"</span></span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>content<span class="token punctuation">"</span></span> <span class="token attr-name">cols</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>50<span class="token punctuation">"</span></span> <span class="token attr-name">rows</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>5<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>textarea</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>br</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>br</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>input</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>submit<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>form</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>h2</span><span class="token punctuation">></span></span>List payloads<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>h2</span><span class="token punctuation">></span></span> {% if items %} <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>ul</span><span class="token punctuation">></span></span> {% for item in items %} {% set p = item['path']%} <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>li</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>a</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>/{{p}}<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>/{{p}}<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>a</span><span class="token punctuation">></span></span> - <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>a</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>/delete?p={{p}}<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Delete<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>a</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>li</span><span class="token punctuation">></span></span> {% endfor %} <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>ul</span><span class="token punctuation">></span></span> {% endif %} <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>body</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>html</span><span class="token punctuation">></span></span> |
It’s Demo Time
Chạy deta deloy
và xem thành quả thôi: https://8r8cjf.deta.dev/
Giới hạn
Tất nhiên là với dịch vụ Free như thế này thì sẽ đi kèm với một số giới hạn chính sau:
- Các micros thực tế là chạy trên Lambda nên thời gian khởi động (sau khi sleep) sẽ có thể bị chậm.
- RAM chỉ có 512MB.
- Các request sẽ time-out sau 10 giây, nên không thể chạy các process trong thời gian dài.
- Nếu không upload lên Drive thì chỉ có thể upload lên thư mục
/tmp/
. - Drive có dung lượng 10GB.
- Thư viện tối đa 250 MB, source code tối đa 250MB.
Chi tiết hơn ở: https://docs.deta.sh/docs/micros/about
Nhưng với mục đích để prototype và demo thì thế này vẫn quá là OK la
Ngoài ra còn gì?
Deta còn cung cấp một số tiện ích khá hữu ích:
- Deta Crons cho phép chạy các task theo định kỳ (như cronjob trong Linux).
- Deta Visor cho phép chúng ta xem log request/response đến micro và log lỗi.
- Cho phép custom subdomain (VD: https://myserver.deta.dev/) và domain riêng, quá tiện lợi cho các anh em dev làm web mời cưới
Kết
Chúc mọi người tận dụng Deta hiệu quả và có nhiều ý tưởng hay ho nhá