Trong phần này, chúng ta sẽ tìm hiểu cách để cài đặt ứng dụng trên một server (máy chủ) sử dụng hệ điều hành Linux.
Để giúp cho bạn dễ theo dõi, sau đây là danh sách các bài viết trong loạt bài hướng dẫn này:
- Phần 1: Hello, World
- Phần 2: Tìm hiểu về template
- Phần 3: Tìm hiểu về Web Forms
- Phần 4: Sử dụng cơ sở dữ liệu
- Phần 5: Xử lý đăng nhập
- Phần 6: Hồ sơ cá nhân và ảnh đại diện
- Phần 7: Xử lý lỗi
- Phần 8: Tạo chức năng follower
- Phần 9: Phân trang
- Phần 10: Hỗ trợ email
- Phần 11: Nâng cấp giao diện
- Phần 12: Xử lý thời gian
- Phần 13: Hỗ trợ đa ngôn ngữ
- Phần 14: Sử dụng Ajax
- Phần 15: Tinh chỉnh cấu trúc ứng dụng
- Phần 16: Hỗ trợ tìm kiếm
- Phần 17: Triển khai ứng dụng trên Linux (Bài viết này)
- Phần 18: Triển khai ứng dụng với Heroku
- Phần 19: Triển khai ứng dụng với Docker
- Phần 20: JavaScript nâng cao
- Phần 21: Thông báo cho người sử dụng
- Phần 22: Tìm hiểu về tác vụ nền
- Phần 23: Xây dựng API
Bạn có thể truy cập mã nguồn cho phần này tại GitHub.
Trong phần này, chúng ta đã đặt một cột mốc quan trọng cho ứng dụng Myblog vì chúng ta sẽ tìm hiểu cách để triển khai ứng dụng này vào một máy chủ chính thức để mọi người có thể sử dụng nó.
Chủ đề về cài đặt ứng dụng rất rộng và chúng ta không thể thảo luận mọi vấn đề có liên quan. Trong phạm vi của bài viết này, chúng ta chỉ nói đến các lựa chọn liên quan đến cách triển khai truyền thống trên máy chủ. Cụ thể là trên một server Linux sử dụng hệ điều hành Ubuntu và các hệ thống máy tính mini rất phổ biến là Raspberry Pi. Chúng ta sẽ tìm hiểu về các chọn lựa cài đặt khác như là dịch vụ điện toán đám mây (cloud) hay container trong các phần sau.
Sử dụng dịch vụ máy chủ truyền thống
Khi nói đến dịch vụ máy chủ truyền thống, chúng ta đang nói đến việc cài đặt ứng dụng bằng phương pháp thủ công hay nhờ các mã kịch bản trên một máy chủ mới. Quá trình này bao gồm cài đặt ứng dụng và các thành phần liên quan, phần mềm Web server cho nhiều người sử dụng và cấu hình hệ thống cho mục đích bảo mật.
Vấn đề đầu tiên mà chúng ta phải giải quyết khi cài đặt dự án là tìm một server thích hợp. Hiện nay có rất nhiều dịch vụ cho thuê server giá rẻ. Ví dụ như bạn có thể thuê một server Linux ảo qua các nhà cung cấp như Digital Ocean, Linode hay Amazon Lightsail để thử nghiệm việc triển khai ứng dụng (Linode và Digital Ocean cung cấp các server cho mức sử dụng cơ bản với bộ nhớ 1GB, còn Amazon giới hạn ở mức 512MB). Còn nếu bạn muốn thử cài đặt ứng dụng miễn phí, Vagrant và VirtualBox là hai công cụ có thể giúp bạn tạo ra một server ảo tương tự như các server được cung cấp bởi các dịch vụ trên trong chính máy tính của bạn.
Về phần hệ điều hành, từ góc độ kỹ thuật thì ứng dụng của chúng ta có thể được cài đặt trên bất kỳ hệ điều hành phổ biến nào bao gồm một số lớn các bản phân phối mã nguồn mở của Linux và BSD hoặc các hệ điều hành thương mại như OS X và Microsoft Windows (nếu nói chính xác thì OS X là một hệ điều hành lai giữa mã nguồn mở và thương mại bởi vì nó được phát triển từ một dự án BSD mã nguồn mở tên là Darwin).
Vì OS X và Windows thích hợp hơn cho các máy trạm và không thật sự tối ưu cho các server, chúng ta sẽ không sử dụng các hệ điều hành này làm server của ứng dụng. Còn lại giữa Linux và các hệ BSD, chúng ta sẽ chọn Linux vì nó phổ biến hơn, cụ thể là chúng ta sẽ sử dụng bản phân phối Ubuntu.
Cài đặt máy chủ sử dụng Ubuntu
Nếu bạn muốn thực hành theo cách cài đặt và cấu hình máy chủ trong bài này, bạn sẽ cần một server. Nếu có khả năng trả phí, bạn có thể đăng ký một tài khoản tại Digital Ocean, Linode hay Amazon Light Sail và tạo một server ảo với phiên bản Ubuntu mới nhất (18.04 LTS tại thời điểm của bài viết này. Bạn cần lưu ý là các dịch vụ trên chỉ sử dụng các phiên bản Ubuntu được hỗ trợ dài hạn – LTS hay Long Term Support. Vì vậy, nó không nhất thiết là bản Ubuntu mới nhất). Vì chúng ta chỉ sử dụng với mục đích thực tập, bạn nên đăng ký tùy chọn server với cấu hình thấp nhất với giá tối đa là $5/tháng trong cả ba dịch vụ nói trên. Chi phí bạn phải trả tùy thuộc vào thời gian hoạt động của server. Vì vậy, nếu bạn chỉ tạo ra server mới và thực hành trong vài giờ và sau đó xóa bỏ nó, có thể bạn chỉ cần thanh toán ít hơn $1.
Còn nếu như bạn muốn tùy chọn hoàn toàn miễn phí, bạn có thể tạo ra và sử dụng các máy ảo trên máy tính của bạn với sự trợ giúp của Vagrant và Virtual Box. Để bắt đầu, bạn có thể cài đặt hai phần mềm này và tạo một file gọi là Vagrantfile để đặc tả cấu hình cho máy ảo của bạn với nội dung như sau:
Vagrantfile: Cấu hình máy ảo
1 2 3 4 5 6 7 |
Vagrant.configure("2") do |config| config.vm.box = "ubuntu/bionic64" config.vm.network "private_network", ip: "192.168.33.10" config.vm.provider "virtualbox" do |vb| vb.memory = "1024" end end |
File này sẽ đặc tả cấu hình cho một server chạy hệ điều hành Ubuntu 18.04 với 1GB RAM và cho phép bạn truy cập qua địa chỉ IP 192.168.33.2. Để khởi tạo máy ảo, chúng ta sẽ lưu file này vào một thư mục và thực hiện lệnh sau:
1 |
$ vagrant up |
Nếu cần biết thêm các tùy chọn dể quản lý máy ảo này bằng dòng lệnh, bạn có thể tham khảo tại trang tài liệu trực tuyến của Vagrant.
Sử dụng phần mềm SSH
Server của chúng ta sẽ không có giao diện đồ họa (headless), vì vậy bạn chỉ có thể kết nối với server qua phần mềm SSH và sử dụng dòng lệnh (command line) để giao tiếp với nó chứ không như các hệ điều hành thông thường mà bạn sử dụng. Nếu bạn đang sử dụng Linux hoặc Mac OS X, có nhiều khả năng máy của bạn đã có sẵn phần mềm để kết nối thông qua OpenSSH. Nếu bạn đang sử dụng Microsoft Windows, bạn có thể cài đặt thêm Cygwin, Git hoặc Windows Subsystem for Linux để sử dụng OpenSSH.
Nếu bạn có server ảo từ một trong các nhà cung cấp dịch vụ như đã đề cập ở trên, hệ thống sẽ cho biết địa chỉ IP cho server khi bạn khởi tạo nó. Bạn có thể truy cập vào chế độ dòng lệnh trên server mới này bằng lệnh sau:
1 |
$ ssh root@<địa-chỉ-ip-của-server> |
Hệ thống sẽ yêu cầu bạn nhập mật mã. Hệ thống sẽ tự tạo mật mã và gởi đến bạn hoặc cho phép bạn tự chọn mật mã của mình tùy theo dịch vụ mà bạn sử dụng.
Nếu bạn sử dụng máy ảo Vagrant, bạn có thể truy cập vào chế động dòng lệnh với lệnh sau:
1 |
$ vagrant ssh |
Nếu bạn đang sử dụng Windows với Vagrant, bạn cần phải chạy lệnh trên từ một cửa sổ lệnh có thể sử dụng lệnh ssh
.
Đăng nhập không cần mật mã
Nếu bạn đang sử dụng máy ảo Vagrant, bạn có thể bỏ qua phần này bởi vì Vagrant đã tự động thiết lập cấu hình để bạn có thể đăng nhập không cần mật mã với một tài khoản tên là ubuntu
.
Nếu bạn đang sử dụng một server ảo, bạn nên tạo một tài khoản bình thường để cài đặt và cấu hình ứng dụng và thiết lập sao cho bạn có thể đăng nhập vào server với tài khoản này mà không cần sử dụng mật mã. Thoạt nghe thì dường như đây là một ý tưởng tồi, nhưng thật ra thì việc này không những tiện lợi mà còn nâng cao tính bảo mật.
Chúng ta sẽ tạo ra một tài khoản tên là ubuntu
(bạn có thể chọn tên tài khoản mà bạn thích). Để tạo ra tài khoản này, bạn cần đăng nhập vào server với tài khoản root với lệnh ssh
như đã nói ở phần trên. Sau khi đăng nhập, bạn có thể sử dụng lệnh sau để khởi tạo tài khoản người dùng mới, cho phép sử dụng quyền sudo
và đăng nhập dưới tài khoản mới này:
1 2 3 |
$ adduser --gecos "" ubuntu $ usermod -aG sudo ubuntu $ su ubuntu |
Tiếp theo, chúng ta sẽ thiết lập cấu hình để sử dụng khóa công khai (public key) cho tài khoản ubuntu
và nhờ đó chúng ta có thể đăng nhập mà không cần dùng mật mã. Bạn mở thêm một cửa sổ lệnh (terminal) mới trên máy tính của bạn và giữ nguyên cửa sổ lệnh hiện hành. Nếu bạn sử dụng Windows, bạn phải dùng các cửa sổ lệnh có hỗ trợ lệnh ssh
(như là Git Bash trong phần mềm Git) và không phải là cửa sổ lệnh command prompt mặc định của Windows. Trong cửa sổ lệnh mới này, bạn cần kiểm tra các file trong thư mục ~/.ssh:
Tiếp theo, chúng ta sẽ thiết lập cấu hình để sử dụng khóa công khai (public key) cho tài khoản ubuntu và nhờ đó chúng ta có thể đăng nhập mà không cần dung mật mã. Bạn mở thêm một cửa sổ lệnh (terminal) mới trên máy tính của bạn và giữ nguyên cửa sổ lệnh hiện hành. Nếu bạn sử dụng Windows, bạn phải dùng các cửa sổ lệnh có hỗ trợ lệnh ssh (như là Git Bash trong phần mềm Git) và không phải là cửa sổ lệnh command prompt mặc định của Windows. Trong cửa sổ lệnh mới này, bạn cần kiểm tra các file trong thư mục ~/.ssh:
1 2 |
$ ls ~/.ssh id_rsa id_rsa.pub |
Nếu trong thư mục này có hai file id_rsa và id_rsa.pub như trên, bạn đã có khóa cần thiết. Nhưng nếu bạn không thấy hai file trên trong thư mục, hoặc bạn không tìm thấy thư mục ~/.ssh, bạn cần khởi tạo các khóa SSH bằng lệnh sau:
1 |
$ ssh-keygen |
Sau khi nhập lệnh trên, bạn sẽ phải trả lời một vài câu hỏi trước khi quá trình tạo khóa bắt đầu. Nếu không hiểu rõ các câu hỏi này, bạn nên chọn các giá trị mặc định bằng cách bấm phím Enter cho mỗi câu hỏi. Còn nếu bạn biết tác dụng của các câu hỏi này, bạn có thể trả lời chúng.
Sau khi lệnh được thực hiện thành công, bạn sẽ thấy hai file trên. File id_rsa.pub sẽ chứa khóa công khai (public key). Bạn sẽ cung cấp file này cho các ứng dụng để xác thực định danh của bạn. Còn file id_rsa sẽ chứa khóa bí mật (private key). Bạn không nên cho bất kỳ ai ngoài bạn biết nội dung của file này.
Tiếp theo, bạn cần thiết lập để khóa công khai được sử dụng để xác thực trên server của bạn. Để làm điều này, bạn có thể làm theo một trong hai phương pháp sau:
- Thủ công: trước hết bạn cần tìm nội dung của khóa công khai trên cửa sổ dòng lệnh từ máy tính của bạn với lệnh sau:
1 2 |
$ cat ~/.ssh/id_rsa.pub ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCjw....F8Xv4f/0+7WT thaipt@thaitpham.com |
Lệnh này sẽ in ra một chuỗi ký tự rất dài và có thể chiếm nhiều dòng. Bạn cần copy chuỗi này vào file ~/.ssh/authorized_keys tại server. Để làm điều này, bạn cần thực hiện các lệnh sau tại cửa sổ lệnh của server:
1 2 |
$ echo <nội-dung-của-file-id_rsa.pub> >> ~/.ssh/authorized_keys $ chmod 600 ~/.ssh/authorized_keys |
- Tự động: Bạn cũng có thể thực hiện việc copy khóa công khai từ cửa sổ lệnh trên máy tính của bạn thay vì vào cửa sổ lệnh trên server với lệnh
ssh-copy-id
như sau:
1 |
$ ssh-copy-id –I ~/.ssh/id_rsa.pub ubuntu@<địa-chỉ-ip-của-server> |
Khi thực hiện lệnh này, bạn sẽ phải nhập vào mật mã cho tài khoản ubuntu trên server mà chúng ta đã tạo ở trên.
Đến đây, quá trình thiết lập để đăng nhập không cần mật mã đã hoàn tất. Quá trình này sẽ cho phép chương trình ssh
trên máy của bạn xác thực với server qua các giao thức được mã hóa bằng khóa bí mật và server sẽ xác nhận định danh của bạn thông qua khóa công khai. Đây là quy trình sử dụng nguyên tắc mã hóa bất đối xứng (Asymmetrical Encryption). Bạn có thể tham khảo thêm về cách làm việc của ssh
tại đây. Bạn có thể kiểm tra quá trình thiết lập ssh
có thành công hay không bằng cách thoát khỏi các phiên làm việc hiện hành với tài khoản ubuntu
và root
trên server. Sau đó, từ một cửa sổ lệnh trên máy tính của bạn, thi hành lệnh sau đây để bắt đầu một phiên làm việc ssh
mới với tài khoản ubuntu
:
1 |
$ ssh ubuntu@<địa-chỉ-ip-của-server> |
Nếu bạn làm đúng các bước như ở trên, lần này bạn sẽ không cần phải nhập mật mã.
Các thiết lập bảo mật cho server
Để giảm thiểu khả năng server của bạn bị tấn công, bạn cần phải thực hiện một số quy trình nhất định để bảo đảm server của bạn không có “cửa sau” nào để kẻ xấu có thể lợi dụng được. Việc đầu tiên chúng ta cần làm là không cho tài khoản root
đăng nhập qua SSH. Hiện giờ bạn có thể đăng nhập qua SSH với tài khoản ubuntu và có thể thực hiện các lệnh dành cho quản trị viên với tài khoản này bằng lệnh sudo, vì vậy, chúng ta không cần phải sử dụng đến tài khoản root. Để vô hiệu hóa đăng nhập cho root
, bạn cần cập nhật file cấu hình cho SSH là /etc/ssh/sshd_config tại server. Để soạn thảo file này, bạn có thể dùng các chương trình soạn thảo văn bản vi
hoặc nano
(nếu bạn không quen thuộc với cả hai chương trình này thì bạn nên thử dùng nano
trước). Và để chạy các chương trình này, bạn cần đặt lệnh sudo
trước tên chương trình như sau:
1 |
$ sudo nano /etc/ssh/sshd_config |
Lý do là vì file này không cho phép các user bình thường cập nhật. Sau khi mở file với trình soạn thảo văn bản, bạn cần thay đổi một dòng như sau:
/etc/ssh/sshd_config: Không cho phép đăng nhập qua SSH với tài khoản root.
1 |
PermitRootLogin no |
Bạn cần tìm dòng bắt đầu với chuỗi PermitRootLogin
và thay đổi giá trị kèm theo thành no
.
Chúng ta còn cần phải thực hiện một thay đổi nữa trong file này để ngăn việc đăng nhập với mật mã cho tất cả tài khoản. Hiện giờ, chúng ta đã thiết lập quy trình đăng nhập không cần mật mã, vì vậy chúng ta không cần cho phép việc sử dụng mật mã để đăng nhập. Nếu bạn không cảm thấy tự tin với chế độ không sử dụng mật mã, bạn có thể bỏ qua bước này. Tuy nhiên, đây là một điều nên làm trong các hệ thống chính thức bởi vì các hacker có thể thử các tài khoản và mật mã ngẫu nhiên để đăng nhập. Để thiết lập chế độ này, bạn cần thay đổi dòng sau trong file /etc/ssh/sshd_config:
/etc/ssh/sshd_config: Không cho phép đăng nhập bằng mật mã
1 |
PasswordAuthentication no |
Sau khi bạn đã hoàn tất việc soạn thảo và lưu lại file, bạn cần khởi động lại dịch vụ SSH trên máy chủ để các thay đổi này có hiệu lực:
1 |
$ sudo systemctl restart ssh |
Thay đổi thứ ba mà chúng ta cần làm là cài đặt một chương trình firewall (tường lửa) cho server. Chương trình này sẽ chặn các truy cập đến các cổng không sử dụng và chỉ cho phép các kết nối đến các cổng được cho phép trên server:
1 2 3 4 5 6 |
$ sudo apt-get install -y ufw $ sudo ufw allow ssh $ sudo ufw allow http $ sudo ufw allow 443/tcp $ sudo ufw --force enable $ sudo ufw status |
Các lệnh trên sẽ cài đặt chương trình ufw (Uncomplicated Firewall) và thiết lập cấu hình để nó chỉ cho phép các kết nối đến các cổng 22 (ssh), 80 (http) và 443 (https). Toàn bộ các cổng khác sẽ bị khóa từ các truy cập bên ngoài.
Cài đặt các chương trình cơ bản
Nếu bạn theo đúng các bước chúng ta đã thực hiện từ đầu đến giờ, bạn sẽ có một hệ thống với Python 3.6. Và đây cũng sẽ là phiên bản Python mà chúng ta sẽ sử dụng với ứng dụng blog.
Ngoài ra, chúng ta cần cài đặt thêm một số gói khác. Theo mặc định, trình thông dịch Python có sẵn trên server của bạn. Nhưng nó sẽ không bao gồm một số các gói (package) hỗ trợ. Riêng về cơ sở dữ liệu, chúng ta sẽ đổi từ SQLite sang MySQL vì đây là môi trường chính thức (Production). Chúng ta cũng có cần thêm gói postfix để gởi email, gói supervisor để theo dõi ứng dụng Flask và tự động khởi động lại ứng dụng nếu nó bị ngừng đột ngột (vì lỗi hoặc các lý do khác như khi server được khởi động lại). Chương trình nginx là chương trình Web server và sẽ nhận các yêu cầu từ bên ngoài và đưa đến ứng dụng. Và cuối cùng, chúng ta sẽ sử dụng git
để tải ứng dụng trực tiếp từ GitHub:
1 2 3 |
$ sudo apt-get -y update $ sudo apt-get -y install python3 python3-venv python3-dev $ sudo apt-get -y install mysql-server postfix supervisor nginx git |
Hầu hết các lệnh trên sẽ cài đặt các gói mà không cần chúng ta phải can thiệp. Tuy nhiên, trong quá trình cài đặt MySQL trong dòng lệnh thứ ba ở trên, tùy theo các phiên bản Linux, bạn có thể sẽ phải chọn mật mã root
cho MySQL. Bạn cũng sẽ phải trả lời một vài câu hỏi trong quá trình cài đặt Postfix (bạn có thể chọn trả lời mặc định bằng cách nhấn Enter trong mỗi câu hỏi).
Lưu ý rằng chúng ta không cài đặt Elasticsearch. Lý do là chương trình này đòi hỏi nhiều bộ nhớ trong (RAM). Vì vậy, để tránh tình trạng hết bộ nhớ, bạn chỉ nên cài đặt nó khi server của bạn có nhiều hơn 2GB bộ nhớ trong. Trong trường hợp server của bạn cho phép, bạn có thể cài đặt Elasticsearch bằng cách tải về file .deb từ Website của Elasticsearch và làm theo các hướng dẫn cài đặt ở đó.
Bạn cũng nên lưu ý rằng cài đặt mặc định của postfix không đủ để bạn có thể gởi email trong môi trường chính thức. Để tránh các email rác, nhiều email server sẽ tiến hành xác thực server đã gởi mail qua các mở rộng bảo mật, và để đáp ứng yêu cầu này thì ít nhất server của bạn cần phải có một tên miền chính thức. Nếu bạn muốn biết cách để thiết lập cấu hình cho email server để vượt qua các kiểm tra bảo mật tiêu chuẩn, bạn có thể tham khảo các hướng dẫn của Digital Ocean:
Cài đặt ứng dụng
Tiếp theo chúng ta sẽ dùng git
để tải mã nguồn của ứng dụng từ GitHub. Nếu bạn chưa quen sử dụng git, bạn nên tham khảo các tài liệu về git cơ bản cho người mới bắt đầu (tiếng Việt hoặc tiếng Anh).
Để tải mã nguồn của ứng dụng về server, bạn cần chắc rằng đang ở tại thư mục gốc (home directory) của tài khoản ubuntu
và thực hiện các lệnh sau:
1 2 3 |
$ git clone https://github.com/thaipt/myblog.git $ cd myblog $ git checkout v0.17 |
Các lệnh này sẽ cài đặt mã nguồn trên server và đồng bộ hóa với mã nguồn của phần này. Nếu bạn sử dụng phiên bản riêng của bạn trên kho lưu trữ của chính bạn, bạn có thể thay thế địa chỉ đến GitHub ở trên bằng địa chỉ tương ứng của bạn và không cần sử dụng lệnh git checkout
.
Sau đó chúng ta cần tạo môi trường ảo và cài đặt các thư viện mở rộng cho ứng dụng được liệt kê trong tập tin requirements.txt trong Phần 15:
1 2 3 |
$ python3 -m venv myenv $ source myenv/bin/activate (myenv) $ pip3 install -r requirements.txt |
Ngoài ra, chúng ta cũng sẽ cài đặt thêm hai gói phần mềm cần thiết cho môi trường chính thức. Các gói này không có trong danh sách của file requirements.txt. Gói thứ nhất là gunicorn
và sẽ được dùng để làm phần mềm máy chủ Web (Web server) cho các ứng dụng Python trong môi trường chính thức. Gói thứ nhì là pymysql
có chứa trình điều khiển (driver) để cho phép SQLAlchemy làm việc với MySQL:
1 |
(myenv) $ pip3 install gunicorn pymysql |
Chúng ta cũng cần tạo ra file .env có chứa các biến môi trường:
/home/ubuntu/myblog/.env: Các tham số cấu hình.
1 2 3 4 5 |
SECRET_KEY=c330c3a8b0d84b01adc44548f232fb5f MAIL_SERVER=localhost MAIL_PORT=25 DATABASE_URL=mysql+pymysql://myblog:<mật-mã-truy-cập-cơ-sở-dữ-liệu-của-tài-khoản-myblog>@localhost:3306/myblog MS_TRANSLATOR_KEY=<khóa-API-từ-dịch-vụ-thông-dịch-của-Microsoft> |
Nội dung của file .env tương tự như ví dụ trong Phần 15, nhưng ở đây SECRET_KEY
được gán một chuỗi ngẫu nhiên được tạo ra với lệnh sau:
1 |
python3 -c "import uuid; print(uuid.uuid4().hex)" |
Chúng ta cũng gán địa chỉ của MySQL cho biến DATABASE_UR
L. Cách thiết lập cấu hình cho MySQL sẽ được giới thiệu trong trong phần tiếp theo.
Cuối cùng, chúng ta cần thiết lập biến môi trường FLASK_APP
để kích hoạt ứng dụng với lệnh flask. Tuy nhiên, biết này cần được thiết lập trước khi ứng dụng bắt đầu sử dụng file .env. Vì vậy chúng ta phải thiết lập thủ công. Để tránh việc phải thiết lập lại nhiều lần, chúng ta sẽ đưa lệnh này vào cuối file ~/.profile của tài khoản ubuntu
. Nhờ đó, biến môi trường này sẽ được tự động mỗi khi chúng ta đăng nhập:
1 |
$ echo "export FLASK_APP=myblog.py" >> ~/.profile |
Nếu bạn thoát khỏi phiên làm việc hiện tại trên máy chủ (log out) và đăng nhập (login) trở lại, biến FLASK_APP
sẽ được tạo ra với giá trị mà chúng ta đã thiết lập. Bạn có thể kiểm tra xem biến này có hay không bằng cách thực hiện lệnh flask –help
. Nếu các thông điệp trong chế độ giúp đỡ có hiển thị lệnh translate
mà chúng ta đã thêm vào ứng dụng trước đây, chúng ta biết rằng ứng dụng đã được tìm thấy.
Sau khi đã cài đặt các thành phần cần thiết và lệnh flask
đã sẵn sàng, chúng ta có thể thực hiện việc chuyển ngữ cho ứng dụng:
1 |
(myenv) $ flask translate compile |
Thiết lập cấu hình cho MySQL
Cơ sở dữ liệu SQLite mà chúng ta đang dùng để phát triển ứng dụng có ưu điểm là đơn giản và dễ sử dụng, nhưng lại không thích hợp cho các ứng dụng lớn đòi hỏi phải xử lý đồng thời một lượng lớn dữ liệu. Vì vậy, đã đến lúc chúng ta đổi sang một hệ cơ sở dữ liệu phù hợp hơn là MySQL. Chúng ta sẽ bắt đầu với việc tạo ra một cơ sở dữ liệu mới trong MySQL gọi là myblog
.
Để quản lý cơ sở dữ liệu, chúng ta sẽ sử dụng lệnh mysql
(có sẵn trong gói mysql-server mà chúng ta đã cài đặt ở phần trên).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
$ mysql -u root Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 9 Server version: 5.7.28-0ubuntu0.18.04.4 (Ubuntu) Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved. Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. mysql> |
Sau đây là các lệnh để tạo một cơ sở dữ liệu mới gọi là myblog
và một user cũng tên là myblog
với quyền truy cập đầy đủ:
1 2 3 4 5 |
mysql> create database myblog character set utf8 collate utf8_bin; mysql> create user 'myblog'@'localhost' identified by '<db-password>'; mysql> grant all privileges on myblog.* to 'myblog'@'localhost'; mysql> flush privileges; mysql> quit; |
Bạn phải thay thế
bằng một mật mã khác do bạn tự chọn. Đây là mật mã cho tài khoản myblog
, vì vậy bạn không nên dùng chung mật mã với tài khoản root
của MySQL. Mật mã cho user myblog
cũng là mật mã bạn khai báo trong biến DATABASE_URL
trong file .env.
Nếu bạn thực hiện chính xác các bước trên, bạn sẽ có thể bắt đầu quá trình chuyển đổi dữ liệu để tạo các bảng tương ứng:
1 |
(myenv) $ flask db upgrade |
Hãy chắc chắn rằng không có lỗi nào khi thực hiện lệnh trên.
Thiết lập cấu hình cho Gunicorn và Supervisor
Khi bạn dùng lệnh flask run
, bạn đang sử dụng một phần mềm máy chủ Web (Web server) có sẵn trong Flask. Phần mềm này rất hữu dụng trong quá trình phát triển ứng dụng, nhưng lại không phải là lý tưởng trong môi trường chính thức vì nó không bảo đảm được tính hiệu quả và tốc độ đáp ứng. Vì vậy, chúng ta sẽ không sử dụng nó mà thay thế bằng gunicorn. Đây cũng là một phần mềm máy chủ Web chuyên dụng cho các ứng dụng Python, nhưng không như Flask, nó là một phần mềm rất mạnh và dễ sử dụng dành cho các hệ thống chính thức. Đây cũng là một phần mềm rất phổ biến.
Để khởi động Myblog bằng gunicorn, bạn dùng lệnh sau:
1 |
(myenv) $ gunicorn -b localhost:8000 -w 4 myblog:app |
Tùy chọn –b
thông báo cho gunicorn phải sử dụng cổng nào để nhận các yêu cầu từ các trình duyệt của người sử dụng. Và như trên, chúng ta thiết lập cổng này là 8000 trong mạng nội bộ. Trong thực tế, chúng ta thường thiết lập các ứng dụng Web bằng Python cho mạng nội bộ và không cho phép các truy cập từ bên ngoài. Sau đó, chúng ta sẽ dùng một phần mềm máy chủ Web với tốc độ đáp ứng nhanh và được tối ưu cho các file tĩnh để nhận các yêu cầu từ mọi người sử dụng. Phần mềm máy chủ Web này sẽ phục vụ trực tiếp các yêu cầu với các file tĩnh, đồng thời gởi các yêu cầu đến ứng dụng cho gunicorn. Chúng ta sẽ tìm hiểu cách thiết lập nginx để đảm nhận vai trò này trong phần sau.
Tùy chọn –w
thiết lập số lượng các worker (các thực thể chịu trách nhiệm xử lý các yêu cầu riêng rẽ từ người sử dụng). Với bốn worker, chúng ta cho phép xử lý bốn kết nối đồng thời từ các user. Số lượng worker này là đủ để đáp ứng số lượng user trung bình trong các ứng dụng Web vì không phải user nào cũng liên tục phát ra các yêu cầu. Tùy theo lượng bộ nhớ RAM mà server của bạn có, bạn có thể điều chỉnh số lượng worker cho thích hợp để tránh tình trạng thiếu bộ nhớ.
Tham số myblog:app
báo cho gunicorn biết cách để tải ứng thực thể ứng dụng vào bộ nhớ. Phần trước dấu hai chấm trong htam số này là tên của module có chứa ứng dụng, và phần sau dấu hai chấm là tên của ứng dụng.
Dù việc thiết lập và khởi động gunicorn tương đối đơn giản, chúng ta không nên chạy phần mềm này từ dòng lệnh trên các server chính thức. Chúng ta sẽ phải tìm cách để phần mềm này chạy ở chế độ nền (background) và phải liên tục giám sát để nếu trong trường hợp có lỗi dẫn đến việc phần mềm ngừng hoạt động, hệ thống sẽ tự khởi động lại phần mềm này. Tương tự như vậy, trong trường hợp toàn bộ server được khởi động lại, chúng ta cũng muốn rằng phần mềm sẽ được thi hành trong quá trình khởi động hệ thống mà không cần sự can thiệp của chúng ta. Để làm điều này, chúng ta sẽ sử dụng gói supervisor đã được cài đặt ở phần trước.
Công cụ superviso sử dụng một số các file cấu hình để nhận ra các chương trình cần được giám sát và cách khởi động lại chúng khi cần thiết. Các file này phải được lưu trong thư mục /etc/supervisor/conf.d. Sau đây là file cấu hình cho Myblog mà chúng ta sẽ gọi là myblog.conf:
/etc/supervisor/conf.d/myblog.conf: File cấu hình cho Supervisor.
1 2 3 4 5 6 7 8 |
[program:myblog] command=/home/ubuntu/myblog/myenv/bin/gunicorn -b localhost:8000 -w 4 myblog:app directory=/home/ubuntu/myblog user=ubuntu autostart=true autorestart=true stopasgroup=true killasgroup=true |
Các thiết lập command
, directory
và user
sẽ thông báo với supervisor cách thực thi chương trình. Các thiết lập autostart
và autorestart
dùng để khởi động lại ứng dụng khi server khởi động hoặc ứng dụng ngừng hoạt động. Các tùy chọn stopasgroup
và killasgroup
dùng để báo cho supervisor biết khi nào cần ngưng ứng dụng để khởi động lại.
Sau khi lưu file cấu hình cho supervisor vào thư mục thích hợp, bạn cần phải khởi động lại supervisor để các thay đổi này có hiệu lực:
1 |
$ sudo supervisorctl reload |
Với phương pháp đơn giản này, chúng ta đã thành công trong việc chạy phần mềm máy chủ Web gunicorn, đồng thời giám sát các hoạt động của nó.
Thiết lập cấu hình cho Nginx
Hiện giờ, ứng dụng của chúng ta đang chạy trên gunicorn tại cổng 8000. Tuy nhiên, vì chúng ta thiết lập ứng dụng cho mạng nội bộ (localhost), các user từ các máy khác sẽ không thể truy cập ứng dụng. Việc chúng ta cần làm để các user từ bên ngoài có thể sử dụng ứng dụng này là xây dựng một cơ chế để ứng dụng có thể được truy cập từ bên ngoài qua các cổng tiêu chuẩn là 80 và 443. Đây cũng là hai cổng mà chúng ta đã mở firewall để cho phép các truy cập từ bên ngoài trong phần trước.
Vì tiêu chuẩn cho các ứng dụng Web hiện nay là truy cập qua giao thức bảo mật (https và sử dụng cổng 443), chúng ta sẽ thiết lập cấu hình để gởi tiếp (forward) các yêu cầu đến cổng 80 vào cổng 443 để được mã hóa. Bởi vì quá trình mã hóa đòi hỏi phải sử dụng các chứng chỉ (certificate) TLS (thuật ngữ cũ là SSL), chúng ta sẽ phải cung cấp các chứng chỉ này. Nếu có kinh phí, bạn có thể mua các certificate thương mại, nhưng với mục đích thử nghiệm, tạm thời chúng ta sẽ tạo ra một certificate TLS tự ký (self-signed). Các certificate loại này thích hợp cho thử nghiệm nhưng không nên sử dụng trong các sản phẩm và môi trường chính thức vì trình duyệt sẽ phát ra các thông báo cho user rằng các certificate này không được phát hành từ các nhà cung cấp certificate hợp pháp.
Để tạo ra certificate TLS cho Myblog, chúng ta sử dụng các lệnh sau:
1 2 3 |
$ mkdir certs $ openssl req -new -newkey rsa:4096 -days 365 -nodes -x509 \ -keyout certs/key.pem -out certs/cert.pem |
Khi thực hiện lệnh, chúng ta sẽ được hỏi một số thông tin về ứng dụng và chính chúng ta. Các thông tin này sẽ được đưa vào cerfiticate được tạo ra. Các trình duyệt cũng sẽ hiển thị các thông tin này nếu người sử dụng yêu cầu. Sau khi thi hành lệnh trên, chúng ta sẽ nhận được hai file là key.pem và cert.pem, và chúng ta sẽ đặt hai file này trong thư mục con certs ngay dưới thư mục gốc của ứng dụng Myblog.
Để dùng nginx cho Web site, chúng ta cần tạo ra một file cấu hình tương ứng. File cấu hình thường được lưu tại thư mục /etc/nginx/sites-enabled. Theo mặc định, nginx sẽ tạo một Web site đơn giản để kiểm tra hoạt động của nó tại vị trí này, chúng ta sẽ xóa bỏ Web site kiểm tra này vì chúng ta không cần nó:
1 |
$ sudo rm /etc/nginx/sites-enabled/default |
Sau đây là file cấu hình của nginx cho ứng dụng Myblog, chúng ta sẽ lưu file này tại thư mục /etc/nginx/sites-enabled/myblog:
/etc/nginx/sites-enabled/myblog: Cấu hình cho Nginx.
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 |
server { # listen on port 80 (http) listen 80; server_name _; location / { # redirect any requests to the same URL but on https return 301 https://$host$request_uri; } } server { # listen on port 443 (https) listen 443 ssl; server_name _; # location of the self-signed SSL certificate ssl_certificate /home/ubuntu/myblog/certs/cert.pem; ssl_certificate_key /home/ubuntu/myblog/certs/key.pem; # write access and error logs to /var/log access_log /var/log/myblog_access.log; error_log /var/log/myblog_error.log; location / { # forward application requests to the gunicorn server proxy_pass http://localhost:8000; proxy_redirect off; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } location /static { # handle static files directly, without forwarding to the application alias /home/ubuntu/myblog/app/static; expires 30d; } } |
Nội dung của file cấu hình tương đối phức tạp, nhưng không khó hiểu nếu bạn chịu khó đọc các chú thích kèm theo. Nếu muốn đi vào chi tiết, bạn có thể tham khảo trang tài liệu trực tuyến của nginx.
Sau khi đã có file này, bạn có thể khởi động lại nginx để kích hoạt các thay đổi:
1 |
$ sudo systemctl restart nginx |
Bây giờ thì ứng dụng của chúng ta đã chính thức hoạt động. Bạn có thể nhập địa chỉ IP của máy chủ của bạn (hoặc là 192.168.33.10 nếu bạn đang sử dụng máy ảo Vagrant) vào trình duyệt để truy cập ứng dụng. Tuy nhiên, bởi vì bạn đang sử dụng một certificate tự tạo, trình duyệt sẽ cảnh báo bạn về độ an toàn của Web site. Bạn có thể bỏ qua cảnh báo này.
Sau khi hoàn thành quá trình triển khai ứng dụng cho dự án của bạn theo các hướng dẫn trên, nếu có điều kiện, bạn nên thay thế chứng chỉ tự ký bằng một chứng chỉ thật để trình duyệt không cảnh báo với người dùng về Web site của bạn. Để có một chứng chỉ thật, bạn cần phải mua một tên miền (domain name) và thiết lập cấu hình để liên kết giữa tên miền địa chỉ IP của server của bạn. Sau khi đã có tên miền, bạn có thể yêu cầu một chứng chỉ TLS miễn phí của Let’s Encrypt. Chúng ta sẽ đi sâu hơn vào vấn đề này trong một bài viết khác.
Cập nhật ứng dụng
Vấn đề cuối cùng mà chúng ta sẽ thảo luận là làm thế nào để cập nhật ứng dụng trên server. Hiện giờ mã nguồn của ứng dụng được cài đặt qua git. Vì thế, khi nào bạn muốn sử dụng phiên bản mới nhất của mã nguồn, bạn chỉ cần thi hành lệnh git pull để cập nhật mã nguồn với các thay đổi kể từ lần triển khai ứng dụng cuối cùng.
Tuy nhiên, việc cập nhật mã nguồn chỉ là một phần của quá trình cập nhật ứng dụng. Sau khi mã nguồn được cập nhật, ứng dụng vẫn tiếp tục chạy với mã nguồn cũ trong bộ nhớ. Để ứng dụng có thể đọc và thi hành mã nguồn mới, bạn cần phải ngừng và khởi động lại ứng dụng.
Và hơn thế nữa, trong quá trình cập nhật ứng dụng, bạn có thể cần phải làm thêm một số việc trước khi khởi động lại ứng dụng như là chuyển đổi cơ sở dữ liệu (nếu có) hay cập nhật hỗ trợ về ngôn ngữ. Vì thế, trong thực tế, để thực hiện quá trình cập nhật ứng dụng, bạn cần thi hành một chuỗi lệnh như sau:
1 2 3 4 5 |
(myenv) $ git pull # sử dụng phiên bản mới nhất (myenv) $ sudo supervisorctl stop myblog # ngừng ứng dụng (myenv) $ flask db upgrade # cập nhật cơ sở dữ liệu (myenv) $ flask translate compile # chuyển ngữ (myenv) $ sudo supervisorctl start myblog # khởi động lại ứng dụng |
Cài đặt server với Raspberry Pi
Raspberry Pi là một máy tính loại nhỏ với mức tiêu thụ điện năng rất thấp và có khả năng chạy hệ điều hành Linux. Vì vậy, nó làm một chọn lựa hoàn hảo nếu bạn muốn cài đặt một máy chủ Web tại nhà 24/7 mà không cần phải sử dụng máy để bàn hoặc laptop. Có một vài bản phân phối Linux có thể chạy được trên Raspberry Pi. Nhưng chúng ta sẽ dùng hệ điều hành Raspbian, đây cũng là bản phân phối chính thức từ Raspberry Pi Foundation.
Để tiến hành việc cài đặt, chúng ta sử dụng phiên bản Raspbian Buster Lite September 2019. Tuy nhiên, tại thời điểm bạn đọc bài này, có nhiều khả năng là có phiên bản mới hơn, vì vậy bạn nên vào trang chủ của Raspbian để tải về phiên bản mới nhất.
Sau khi tải về, chúng ta sẽ cài đặt hệ điều hành này vào một thẻ nhớ SD và gắn vào hệ thống Raspberry Pi để khởi động. Bạn có thể làm theo các hướng dẫn chi tiết trên trang chủ của Raspberry Pi để cài đặt hệ điều hành Raspbian vào thẻ nhớ từ các hệ điều hành Windows, Mac OS X hoặc Linux.
Trước khi khởi động Raspberry Pi lần đầu, bạn cần gắn hệ thống với bàn phím và màn hình để có thể làm việc với hệ thống trong quá trình thiết lập cấu hình. Tối thiểu bạn cũng nên cài đặt SSH để có thể truy xuất hệ thống từ xa một cách dễ dàng.
Cũng như Ubuntu, Raspbian là một bản phân phối Linux có nguồn gốc từ Debian, vì vậy hầu hết các hướng dẫn trong phần này cũng có thể được sử dụng cho hệ thống Raspberry Pi của bạn. Tuy nhiên, bạn có thể bỏ qua một vài bước nếu bạn có kế hoạch chạy một ứng dụng nhỏ trong mạng nội bộ tại nhà (home network) và không có truy xuất từ bên ngoài. Ví dụ như bạn có thể không cần thiết lập firewall hay đăng nhập không cần mật mã. Và bạn có thể sử dụng SQLite thay vì MySQL. Bạn có thể không cần sử dụng nginx và để cho gunicorn xử lý trực tiếp các yêu cầu từ user. Bạn có thể chỉ cần một worker cho gunicorn. Tuy nhiên, chương trình supervisor khá hữu icsch để bảo đảm rằng ứng dụng luôn chạy, vì vậy, bạn nên dùng nó với Raspberry Pi.
Chúng ta sẽ tạm ngừng ở đây. Hẹn gặp bạn trong phần tiếp theo.
/home/ubuntu/microblog/.env
chổ này tôi chưa hiểu bạn chỉ rõ hơn được không
làm sao tạo file .env theo đường dẫn trên?
Cảm ơn bạn nhắn tin. Tôi có một lỗi đánh máy trong bài này, đường dẫn đúng phải là /home/ubuntu/myblog/.env . Nếu bạn tạo một Virtual Machine mới sử dụng Ubuntu 18.04 LTS và tạo account “ubuntu” đúng như hướng dẫn ở đầu bài viết, bạn sẽ có thư mục /home/ubuntu. Sau đó nếu bạn login với account “ubuntu” và chạy lệnh “git clone …” để download mã nguồn từ GitHub vào thư mục /home/ubuntu (thư mục gốc của account này và là thư mục mặc định khi bạn đăng nhập với username “ubuntu”), bạn sẽ có đường dẫn /home/ubuntu/myblog.
sudo service nginx restart
Job for nginx.service failed because the control process exited with error code.
See “systemctl status nginx.service” and “journalctl -xe” for details.
không khởi động được server nginx báo lổi như trên. Đã làm đúng theo hướng dẫn của bạn rồi
Đa số các bản phân phối Linux hiện nay không còn sử dụng lệnh “service” cho các phần mềm mà sử dụng lệnh “systemctl” của một hệ thống hỗ trợ gọi là systemd. Để khởi động lại nginx, bạn cần dùng lệnh “sudo systemctl restart nginx” chứ không phải là lệnh của bạn đang sử dụng. Trong bài viết tôi cũng dùng lệnh systemctl. Tôi không rõ tại sao bạn lại thấy hướng dẫn với lệnh trên. Bạn thử lại nhé.
Nếu vẫn còn gặp lỗi, bạn có thể thử chạy lệnh được gợi ý trong thông báo lỗi (systemctl status nginx.service và journalctl -xe) và gởi các output cho tôi qua email (thaipt@gmail.com)