---
title: "Cách thiết lập Laravel, Nginx và MySQL với Docker Compose trên Ubuntu 20.04"
description: "Cách thiết lập Laravel, Nginx và MySQL với Docker Compose trên Ubuntu 20.04"
url: https://cloudfly.vn/techblog/cach-thiet-lap-laravel-nginx-va-mysql-voi-docker-compose-tren-ubuntu-2004
image: https://media.cloudfly.vn/posts/techblog_093I9Rt.png
---

# Cách thiết lập Laravel, Nginx và MySQL với Docker Compose trên Ubuntu 20.04

## Giới thiệu

Trong vài năm qua, Docker đã trở thành một giải pháp được sử dụng thường xuyên để triển khai các ứng dụng nhờ cách nó đơn giản hóa việc chạy và triển khai các ứng dụng trong các vùng chứa phù du. Ví dụ: khi bạn đang sử dụng LEMP application stack với PHP, Nginx, MySQL và Laravel framework, Docker có thể hợp lý hóa đáng kể quy trình thiết lập.

Docker Compose đã đơn giản hóa hơn nữa quy trình phát triển bằng cách cho phép các nhà phát triển xác định cơ sở hạ tầng của họ, bao gồm các dịch vụ ứng dụng, mạng và ổ đĩa, trong một tệp duy nhất. Docker Compose cung cấp một giải pháp thay thế hiệu quả để chạy nhiều lệnh `docker container create` và lệnh `docker container run`.

Trong hướng dẫn này, bạn sẽ xây dựng một ứng dụng web bằng cách sử dụng Laravel framework, với Nginx là máy chủ web và MySQL là cơ sở dữ liệu, tất cả đều nằm trong bộ chứa Docker. Bạn sẽ xác định toàn bộ cấu hình stack trong tệp `docker-compose`, cùng với các tệp cấu hình cho PHP, MySQL và Nginx.

## Điều kiện tiên quyết

Trước khi bắt đầu, bạn sẽ cần:

* Một máy chủ Ubuntu 20.04 và một non-`root` user có đặc quyền `sudo`. Làm theo hướng dẫn Thiết lập máy chủ ban đầu với Ubuntu 20.04 để thiết lập điều này.
* Docker đã được cài đặt, làm theo Bước 1 và 2 của Cách cài đặt và sử dụng Docker trên Ubuntu 20.04.
* Docker Compose đã được cài đặt, theo Bước 1 của Cách cài đặt Docker Compose trên Ubuntu 20.04.

## Bước 1 — Tải xuống Laravel và cài đặt các phụ thuộc

Bước đầu tiên, bạn sẽ nhận được phiên bản mới nhất của Laravel và cài đặt các phần phụ thuộc cho dự án, bao gồm Composer, trình quản lý gói cấp ứng dụng cho PHP. Chúng ta sẽ cài đặt các phụ thuộc này với Docker để tránh phải cài đặt Composer trên toàn cầu.

Trước tiên, hãy kiểm tra xem bạn có đang ở trong thư mục chính của mình không và sao chép bản phát hành Laravel mới nhất vào thư mục có tên `<^>laravel-app<^>`:
```command
cd ~
git clone https://github.com/laravel/laravel.git <^>laravel-app<^>
```

Di chuyển vào thư mục `<^>laravel-app<^>`:
```command
cd ~/<^>laravel-app<^>
```

Tiếp theo, sử dụng `composer` image của Docker để gắn các thư mục mà bạn sẽ cần cho dự án Laravel của mình và tránh chi phí cài đặt Composer trên toàn cầu:
```command
docker run --rm -v $(pwd):/app composer install
```

Sử dụng các cờ `-v` và `--rm` với `docker run` sẽ tạo ra một vùng chứa tạm thời sẽ được liên kết với thư mục hiện tại của bạn trước khi bị xóa. Điều này sẽ sao chép nội dung của thư mục `~/<^>laravel-app<^>` của bạn vào vùng chứa và cũng đảm bảo rằng thư mục `vendor` mà Composer tạo bên trong vùng chứa được sao chép vào thư mục hiện tại của bạn.

Bước cuối cùng, hãy đặt quyền trên thư mục dự án để nó thuộc sở hữu của non-**root** user của bạn:
```command
sudo chown -R <^>sammy<^>:<^>sammy<^> ~/laravel-app
```

Điều này sẽ rất quan trọng khi bạn viết Dockerfile cho application image của mình ở Bước 4, vì nó sẽ cho phép bạn làm việc với mã ứng dụng của mình và chạy các quy trình trong bộ chứa của bạn với tư cách là non-**root** user.

Với mã ứng dụng của bạn, bạn có thể chuyển sang xác định các dịch vụ của mình với Docker Compose.

## Bước 2 — Tạo Docker Compose File

Xây dựng các ứng dụng của bạn với Docker Compose đơn giản hóa quá trình thiết lập và tạo phiên bản cho cơ sở hạ tầng của bạn. Để thiết lập ứng dụng Laravel của bạn, bạn sẽ viết một tệp `docker-compose` xác định các dịch vụ máy chủ web, cơ sở dữ liệu và ứng dụng của bạn.

Mở tập tin:
```command
nano ~/laravel-app/docker-compose.yml
```

Trong tệp `docker-compose`, bạn sẽ xác định ba dịch vụ: `app`, `webserver`, và `db`. Thêm mã sau vào tệp, đảm bảo thay thế `MYSQL_ROOT_PASSWORD` được xác định là biến môi trường trong dịch vụ `db`, bằng mật khẩu mạnh do bạn chọn:
```nginx
[label ~/laravel-app/docker-compose.yml]
version: '3'
services:
  
  #PHP Service
  app:
    build:
      context: .
      dockerfile: Dockerfile
    image: digitalocean.com/php
    container_name: app
    restart: unless-stopped
    tty: true
    environment:
      SERVICE_NAME: app
      SERVICE_TAGS: dev
    working_dir: /var/www
    networks:
      - app-network

  #Nginx Service
  webserver:
    image: nginx:alpine
    container_name: webserver
    restart: unless-stopped
    tty: true
    ports:
      - "80:80"
      - "443:443"
    networks:
      - app-network

  #MySQL Service
  db:
    image: mysql:5.7.22
    container_name: db
    restart: unless-stopped
    tty: true
    ports:
      - "3306:3306"
    environment:
      MYSQL_DATABASE: <^>laravel<^>
      MYSQL_ROOT_PASSWORD: <^>MYSQL_ROOT_PASSWORD<^>
      SERVICE_TAGS: dev
      SERVICE_NAME: mysql
    networks:
      - app-network

#Docker Networks
networks:
  app-network:
    driver: bridge
```

Các dịch vụ được xác định ở đây bao gồm:

* `app`: Định nghĩa dịch vụ này chứa ứng dụng Laravel và chạy Docker image tùy chỉnh, `digitalocean.com/php`, mà bạn sẽ xác định trong Bước 4. Nó cũng đặt `working_dir` trong vùng chứa thành `/var/www`.
* `webserver`: Định nghĩa dịch vụ này lấy `nginx:alpine` image từ Docker và hiển thị các cổng `80` và `443`.
* `db`: Định nghĩa dịch vụ này lấy `mysql:5.7.22` image từ Docker và xác định một vài biến môi trường, bao gồm cơ sở dữ liệu có tên là `<^>laravel<^>` cho ứng dụng của bạn và mật khẩu **gốc** cho cơ sở dữ liệu. Bạn có thể tự do đặt tên cho cơ sở dữ liệu theo bất cứ điều gì bạn muốn và bạn nên thay thế `<^>your_mysql_root_password<^>` bằng mật khẩu mạnh của riêng bạn. Định nghĩa dịch vụ này cũng ánh xạ cổng `3306` trên máy chủ tới cổng `3306` trên vùng chứa.

Mỗi thuộc tính `container_name` xác định tên cho vùng chứa, tương ứng với tên của dịch vụ. Nếu bạn không xác định thuộc tính này, Docker sẽ gán tên cho từng vùng chứa bằng cách kết hợp tên của một người nổi tiếng trong lịch sử và một từ ngẫu nhiên được phân tách bằng dấu gạch dưới.

Để tạo điều kiện liên lạc giữa các vùng chứa, các dịch vụ được kết nối với một bridge network gọi là `app-network`. Bridge network sử dụng một phần mềm bridge cho phép các vùng chứa được kết nối với cùng một bridge network để giao tiếp với nhau. Trình điều khiển bridge tự động cài đặt các quy tắc trong máy chủ để các vùng chứa trên các bridge network khác nhau không thể giao tiếp trực tiếp với nhau. Điều này tạo ra mức độ bảo mật cao hơn cho các ứng dụng, đảm bảo rằng chỉ các dịch vụ liên quan mới có thể giao tiếp với nhau. Điều đó cũng có nghĩa là bạn có thể xác định nhiều mạng và dịch vụ kết nối với các chức năng liên quan: ví dụ các dịch vụ ứng dụng front-end có thể sử dụng mạng `frontend` và các dịch vụ back-end có thể sử dụng mạng `backend`.

Tiếp theo, bạn sẽ xem cách thêm ổ đĩa (volume) và bind mounts với định nghĩa dịch vụ của mình để duy trì dữ liệu ứng dụng của bạn.

## Bước 3 - Persisting Data

Docker có các tính năng mạnh mẽ và thuận tiện để duy trì dữ liệu. Trong ứng dụng của bạn, bạn sẽ sử dụng các volume và bind mounts để duy trì cơ sở dữ liệu cũng như các tệp cấu hình và ứng dụng. Các ổ đĩa cung cấp tính linh hoạt cho các bản sao lưu và tính bền vững vượt ra ngoài vòng đời của bộ chứa, trong khi các bind mount tạo điều kiện thuận lợi cho các thay đổi mã trong quá trình phát triển, giúp các thay đổi đối với tệp máy chủ hoặc thư mục của bạn có sẵn ngay lập tức trong các bộ chứa của bạn. Thiết lập của bạn sẽ sử dụng cả hai.

<$>[warning]
**Cảnh báo:** Bằng cách sử dụng bind mounts, bạn có thể thay đổi hệ thống tệp máy chủ thông qua các quy trình đang chạy trong vùng chứa, bao gồm tạo, sửa đổi hoặc xóa các tệp hoặc thư mục hệ thống quan trọng. Đây là một khả năng mạnh mẽ có ý nghĩa bảo mật và có thể ảnh hưởng đến các quy trình không phải Docker trên hệ thống máy chủ. Sử dụng bind mounts cẩn thận.
<$>

Trong tệp `docker-compose`, hãy xác định một ổ có tên là `dbdata` theo định nghĩa dịch vụ `db` để duy trì cơ sở dữ liệu MySQL:
```nginx
[label ~/laravel-app/docker-compose.yml]
...
#MySQL Service
db:
  ...
    <^>volumes:<^>
      <^>- dbdata: /var/lib/mysql<^>
    networks:
      - app-network
  ...
```

Ổ đĩa được đặt tên `dbdata` lưu giữ nội dung của thư mục `/var/lib/mysql` hiện diện bên trong vùng chứa. Điều này cho phép bạn dừng và khởi động lại dịch vụ `db` mà không làm mất dữ liệu.

Ở dưới cùng của tệp, thêm định nghĩa cho ổ đĩa `dbdata`:
```nginx
[label ~/laravel-app/docker-compose.yml]
...
#Volumes
volumes:
  dbdata:
    driver: local
```

Với định nghĩa này, bạn sẽ có thể sử dụng tập đĩa này trên các dịch vụ.

Tiếp theo, thêm một liên kết gắn kết vào dịch vụ `db` cho các tệp cấu hình MySQL mà bạn sẽ tạo ở Bước 7:
```nginx
[label ~/laravel-app/docker-compose.yml]
...
#MySQL Service
db:
  ...
    volumes:
      - dbdata:/var/lib/mysql
      <^>- ./mysql/my.cnf:/etc/mysql/my.cnf<^>
  ...
```

Liên kết gắn kết này liên kết `~/laravel-app/mysql/my.cnf` với `/etc/mysql/my.cnf` trong vùng chứa.

Tiếp theo, thêm bind mounts vào dịch vụ `webserver`. Sẽ có hai cái: một cho mã ứng dụng của bạn và một cho Nginx configuration definition mà bạn sẽ tạo ở Bước 6:
```nginx
[label ~/laravel-app/docker-compose.yml]
#Nginx Service
webserver:
  ...
  <^>volumes:<^>
     <^>- ./:/var/www<^>
     <^>- ./nginx/conf.d/:/etc/nginx/conf.d/<^>
  networks:
      - app-network
```

Bind mount đầu tiên liên kết mã ứng dụng trong thư mục `~/laravel-app` với thư mục `/var/www` bên trong vùng chứa. Tệp cấu hình mà bạn sẽ thêm vào `~/laravel-app/nginx/conf.d/` cũng sẽ được gắn vào `/etc/nginx/conf.d/` trong vùng chứa, cho phép bạn thêm hoặc sửa đổi nội dung của thư mục cấu hình khi cần .

Cuối cùng, thêm các liên kết gắn kết sau vào dịch vụ `app` cho các tệp cấu hình và mã ứng dụng:
```nginx
[label ~/laravel-app/docker-compose.yml]
#PHP Service
app:
  ...
  <^>volumes:<^>
      <^>- ./:/var/www<^>
      <^>- ./php/local.ini:/usr/local/etc/php/conf.d/local.ini<^>
  networks:
      - app-network
```

Dịch vụ ứng dụng đang gắn kết thư mục `~/laravel-app` chứa mã ứng dụng vào thư mục `/var/www` trong vùng chứa. Điều này sẽ tăng tốc quá trình phát triển, vì bất kỳ thay đổi nào được thực hiện đối với thư mục ứng dụng cục bộ của bạn sẽ được phản ánh ngay lập tức bên trong vùng chứa. Bạn cũng đang ràng buộc tệp cấu hình PHP của mình, `~/laravel-app/php/local.ini`, với `/usr/local/etc/php/conf.d/local.ini` bên trong vùng chứa. Bạn sẽ tạo tệp cấu hình PHP cục bộ trong Bước 5.

Tệp `docker-compose` của bạn bây giờ sẽ trông như thế này:
```nginx
[label ~/laravel-app/docker-compose.yml]
version: '3'
services:
  
  #PHP Service
  app:
    build:
      context: .
      dockerfile: Dockerfile
    image: digitalocean.com/php
    container_name: app
    restart: unless-stopped
    tty: true
    environment:
      SERVICE_NAME: app
      SERVICE_TAGS: dev
    working_dir: /var/www
    volumes:
      - ./:/var/www
      - ./php/local.ini:/usr/local/etc/php/conf.d/local.ini
    networks:
      - app-network

  #Nginx Service
  webserver:
    image: nginx:alpine
    container_name: webserver
    restart: unless-stopped
    tty: true
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./:/var/www
      - ./nginx/conf.d/:/etc/nginx/conf.d/
    networks:
      - app-network

  #MySQL Service
  db:
    image: mysql:5.7.22
    container_name: db
    restart: unless-stopped
    tty: true
    ports:
      - "3306:3306"
    environment:
      MYSQL_DATABASE: <^>laravel<^>
      MYSQL_ROOT_PASSWORD: <^>your_mysql_root_password<^>
      SERVICE_TAGS: dev
      SERVICE_NAME: mysql
    volumes:
      - dbdata:/var/lib/mysql/
      - ./mysql/my.cnf:/etc/mysql/my.cnf
    networks:
      - app-network

#Docker Networks
networks:
  app-network:
    driver: bridge
#Volumes
volumes:
  dbdata:
    driver: local
```

Lưu tệp và thoát khỏi trình chỉnh sửa của bạn khi bạn thực hiện xong các thay đổi.

Với tệp `docker-compose` của bạn được viết, giờ đây bạn có thể tạo hình ảnh tùy chỉnh cho ứng dụng của mình.

## Bước 4 — Tạo Dockerfile

Docker cho phép bạn chỉ định môi trường bên trong các vùng chứa riêng lẻ bằng Dockerfile. Dockerfile cho phép bạn tạo hình ảnh tùy chỉnh mà bạn có thể sử dụng để cài đặt phần mềm theo yêu cầu của ứng dụng và thiết lập cấu hình cài đặt dựa trên yêu cầu của bạn. Bạn có thể đẩy các hình ảnh tùy chỉnh mà bạn tạo lên Docker Hub hoặc bất kỳ sổ đăng ký riêng tư nào.

`Dockerfile` của bạn sẽ nằm trong thư mục `~/laravel-app` của bạn. Tạo tệp:
```command
nano ~/laravel-app/Dockerfile
```

`Dockerfile` này sẽ đặt base image và chỉ định các lệnh và hướng dẫn cần thiết để xây dựng Laravel application image. Thêm đoạn mã sau vào tệp:
```nginx
[label ~/laravel-app/php/Dockerfile]
FROM php:7.4-fpm

# Copy composer.lock and composer.json
COPY composer.lock composer.json /var/www/

# Set working directory
WORKDIR /var/www

# Install dependencies
RUN apt-get update && apt-get install -y \
    build-essential \
    libpng-dev \
    libjpeg62-turbo-dev \
    libfreetype6-dev \
    locales \
    zip \
    jpegoptim optipng pngquant gifsicle \
    vim \
    unzip \
    git \
    curl \
    libzip-dev

# Clear cache
RUN apt-get clean && rm -rf /var/lib/apt/lists/*

# Install extensions
RUN docker-php-ext-install pdo_mysql mbstring zip exif pcntl
RUN docker-php-ext-configure gd --with-gd --with-freetype-dir=/usr/include/ --with-jpeg-dir=/usr/include/ --with-png-dir=/usr/include/
RUN docker-php-ext-install gd

# Install composer
RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer

# Add user for laravel application
RUN groupadd -g 1000 www
RUN useradd -u 1000 -ms /bin/bash -g www www

# Copy existing application directory contents
COPY . /var/www

# Copy existing application directory permissions
COPY --chown=www:www . /var/www

# Change current user to www
USER www

# Expose port 9000 and start php-fpm server
EXPOSE 9000
CMD ["php-fpm"]
```

Đầu tiên, Dockerfile tạo một image trên `php:7.4-fpm` Docker image. Đây là một Debian-based image đã cài đặt PHP-FPM triển khai PHP FastCGI. Tệp này cũng cài đặt các gói điều kiện tiên quyết cho Laravel: `mcrypt`, `pdo_mysql`, `mbstring` và `imagick` với `composer`.

Chỉ thị `RUN` chỉ định các lệnh để cập nhật, cài đặt và thiết lập cấu hình cài đặt bên trong vùng chứa, bao gồm tạo nhóm và người dùng chuyên dụng có tên **www**. Lệnh `WORKDIR` chỉ định thư mục `/var/www` làm thư mục làm việc cho ứng dụng.

Việc tạo một người dùng và nhóm chuyên dụng với các quyền hạn chế sẽ giảm thiểu lỗ hổng vốn có khi chạy bộ chứa Docker, vốn chạy theo mặc định với quyền **root**. Thay vì chạy vùng chứa này với quyền **root**, bạn đã tạo người dùng **www**, người này có quyền truy cập đọc/ghi vào thư mục `/var/www` nhờ lệnh `COPY` mà bạn đang sử dụng với cờ `--chown` để sao chép các quyền của thư mục ứng dụng .

Cuối cùng, lệnh `EXPOSE` hiển thị một cổng trong vùng chứa, `9000`, cho máy chủ `php-fpm`. `CMD` chỉ định lệnh sẽ chạy sau khi vùng chứa được tạo. Tại đây, `CMD` chỉ định `"php-fpm"`, cái sẽ khởi động máy chủ.

Lưu tệp và thoát khỏi trình chỉnh sửa của bạn khi bạn thực hiện xong các thay đổi.

Bây giờ bạn có thể chuyển sang xác định cấu hình PHP của mình.

## Bước 5 — Thiết lập cấu hình PHP

Bây giờ bạn đã xác định cơ sở hạ tầng của mình trong tệp `docker-compose`, bạn có thể thiết lập cấu hình dịch vụ PHP để hoạt động như một bộ xử lý PHP cho các yêu cầu đến từ Nginx.

Để cấu hình PHP, bạn sẽ tạo tệp `local.ini` bên trong thư mục `php`. Đây là tệp mà bạn đã liên kết với `/usr/local/etc/php/conf.d/local.ini` bên trong vùng chứa ở Bước 2. Việc tạo tệp này sẽ cho phép bạn ghi đè lên tệp `php.ini` mặc định mà PHP đọc khi nó bắt đầu.

Tạo thư mục `php`:
```command
mkdir ~/laravel-app/php
```

Tiếp theo, mở tệp `local.ini`:
```command
nano ~/laravel-app/php/local.ini
```

Để trình bày cách thiết lập cấu hình PHP, bạn sẽ thêm đoạn mã sau để đặt giới hạn kích thước cho các tệp đã tải lên:
```nginx
[label ~/laravel-app/php/local.ini]
upload_max_filesize=40M
post_max_size=40M
```

Chỉ thị `upload_max_filesize` và `post_max_size` đặt kích thước tối đa được phép cho các tệp đã tải lên và trình bày cách bạn có thể đặt cấu hình `php.ini` từ tệp `local.ini` của mình. Bạn có thể đặt bất kỳ cấu hình dành riêng cho PHP nào mà bạn muốn ghi đè vào tệp `local.ini`.

Lưu tệp và thoát trình chỉnh sửa của bạn.

Với tệp PHP `local.ini` của bạn, bạn có thể chuyển sang cấu hình Nginx.

## Bước 6 - Thiết lập cấu hình Nginx

Với dịch vụ PHP được thiết lập cấu hình, bạn có thể sửa đổi dịch vụ Nginx để sử dụng PHP-FPM làm máy chủ FastCGI để phục vụ nội dung động. Máy chủ FastCGI dựa trên giao thức nhị phân để kết nối các chương trình tương tác với máy chủ web. Để biết thêm thông tin, vui lòng tham khảo bài viết này về Hiểu và Triển khai Proxy FastCGI trong Nginx.

Để thiết lập cấu hình Nginx, bạn sẽ tạo tệp `app.conf` với cấu hình dịch vụ trong thư mục `~/laravel-app/nginx/conf.d/`.

Đầu tiên, tạo thư mục `nginx/conf.d/`:
```command
mkdir -p ~/laravel-app/nginx/conf.d
```

Tiếp theo, tạo tệp cấu hình `app.conf`:
```command
nano ~/laravel-app/nginx/conf.d/app.conf
```

Thêm mã sau vào tệp để chỉ định cấu hình Nginx của bạn:
```nginx
[label ~/laravel-app/nginx/conf.d/app.conf]
server {
    listen 80;
    index index.php index.html;
    error_log  /var/log/nginx/error.log;
    access_log /var/log/nginx/access.log;
    root /var/www/public;
    location ~ \.php$ {
        try_files $uri =404;
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass app:9000;
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param PATH_INFO $fastcgi_path_info;
    }
    location / {
        try_files $uri $uri/ /index.php?$query_string;
        gzip_static on;
    }
}
```

Khối máy chủ xác định cấu hình cho máy chủ web Nginx với các chỉ thị sau:

* `listen`: Lệnh này xác định cổng mà máy chủ sẽ lắng nghe các yêu cầu gửi đến.
* `error_log` và `access_log`: Các lệnh này xác định các tệp để ghi nhật ký.
* `root`: Lệnh này đặt đường dẫn thư mục gốc, tạo thành đường dẫn đầy đủ tới bất kỳ tệp nào được yêu cầu trên hệ thống tệp cục bộ.

Trong khối vị trí `php`, lệnh `fastcgi_pass` chỉ định rằng dịch vụ ứng dụng đang lắng nghe trên một TCP socket trên cổng `9000`. Điều này làm cho máy chủ PHP-FPM lắng nghe qua mạng thay vì trên một Unix socket. Mặc dù Unix socket có một chút lợi thế về tốc độ so với TCP socket, nhưng nó không có giao thức mạng và do đó bỏ qua network stack. Đối với trường hợp các máy chủ được đặt trên một máy, Unix socket có thể hợp lý, nhưng trong trường hợp bạn có các dịch vụ chạy trên các máy chủ khác nhau, TCP socket mang lại lợi thế cho phép bạn kết nối với các dịch vụ phân tán. Bởi vì vùng chứa ứng dụng của bạn đang chạy trên một máy chủ lưu trữ khác với vùng chứa máy chủ web của bạn, TCP socket có ý nghĩa nhất đối với cấu hình của bạn.

Lưu tệp và thoát khỏi trình chỉnh sửa của bạn khi bạn thực hiện xong các thay đổi.

Nhờ gắn kết liên kết mà bạn đã tạo ở Bước 2, mọi thay đổi bạn thực hiện bên trong thư mục `nginx/conf.d/` sẽ được phản ánh trực tiếp bên trong bộ chứa `webserver`.

Tiếp theo, bạn sẽ xem xét và thiết lập cấu hình cài đặt MySQL của mình.

## Bước 7 — Thiết lập cấu hình MySQL

Với cấu hình PHP và Nginx, bạn có thể kích hoạt MySQL hoạt động như cơ sở dữ liệu cho ứng dụng của mình.

Để cấu hình MySQL, bạn sẽ tạo tệp `my.cnf` trong thư mục `mysql`. Đây là tệp mà bạn gắn liên kết vào `/etc/mysql/my.cnf` bên trong vùng chứa ở Bước 2. Bind mount này cho phép bạn ghi đè cài đặt `my.cnf` khi được yêu cầu.

Để minh họa cách thức hoạt động của tính năng này, bạn sẽ thêm cài đặt vào tệp `my.cnf` để kích hoạt nhật ký truy vấn chung và chỉ định tệp nhật ký.

Đầu tiên, tạo thư mục `mysql`:
```command
mkdir ~/laravel-app/mysql
```

Tiếp theo, tạo tệp `my.cnf`:
```command
nano ~/laravel-app/mysql/my.cnf
```

Trong tệp, hãy thêm mã sau đây để bật nhật ký truy vấn và đặt vị trí tệp nhật ký:
```nginx
[label ~/laravel-app/mysql/my.cnf]
[mysqld]
general_log = 1
general_log_file = /var/lib/mysql/general.log
```

Tệp `my.cnf` này cho phép ghi nhật ký, xác định cài đặt `general_log` là `1` để cho phép ghi nhật ký chung. Cài đặt `general_log_file` chỉ định nơi lưu trữ nhật ký.

Lưu tệp và thoát trình chỉnh sửa của bạn.

Bước tiếp theo của bạn sẽ là khởi động các vùng chứa.

## Bước 8 - Sửa đổi cài đặt môi trường và chạy bộ chứa

Bây giờ bạn đã xác định tất cả các dịch vụ của mình trong tệp `docker-compose` và tạo các tệp cấu hình cho các dịch vụ này, bạn có thể khởi động các vùng chứa. Tuy nhiên, ở bước cuối cùng, bạn sẽ tạo một bản sao của tệp `.env.example` mà Laravel bao gồm theo mặc định và đặt tên cho bản sao là `.env`, đây là tệp mà Laravel muốn xác định môi trường của nó:
```command
cp .env.example .env
```

Giờ đây, bạn có thể sửa đổi tệp `.env` trên vùng chứa ứng dụng để bao gồm các chi tiết cụ thể về thiết lập của mình.

Mở tệp bằng `nano` hoặc trình soạn thảo văn bản bạn chọn:
```command
nano .env
```

Tìm khối chỉ định `DB_CONNECTION` và cập nhật khối đó để phản ánh các chi tiết cụ thể về thiết lập của bạn. Bạn sẽ sửa đổi các trường sau:

* `DB_HOST` sẽ là nơi chứa cơ sở dữ liệu `<^>db<^>` của bạn.
* `DB_DATABASE` sẽ là cơ sở dữ liệu của `<^>laravel<^>`.
* `DB_USERNAME` sẽ là tên người dùng bạn sẽ sử dụng cho cơ sở dữ liệu của mình. Trong trường hợp này, bạn sẽ sử dụng `<^>laraveluser<^>`.
* `DB_PASSWORD` sẽ là mật khẩu an toàn mà bạn muốn sử dụng cho tài khoản người dùng này.

```nginx
[label /var/www/.env]
DB_CONNECTION=mysql
DB_HOST=<^>db<^>
DB_PORT=3306
DB_DATABASE=<^>laravel<^>
DB_USERNAME=<^>laraveluser<^>
DB_PASSWORD=<^>your_laravel_db_password<^>
```

Lưu các thay đổi của bạn và thoát khỏi trình chỉnh sửa của bạn.

Với tất cả các dịch vụ của bạn được xác định trong tệp `docker-compose` của bạn, hãy sử dụng lệnh đơn sau để bắt đầu tất cả các vùng chứa, tạo ổ đĩa, thiết lập và kết nối mạng:
```command
docker-compose up -d
```

Khi bạn chạy `docker-compose up` lần đầu tiên, nó sẽ tải xuống tất cả các Docker image cần thiết, có thể mất một lúc. Sau khi hình ảnh được tải xuống và lưu trữ trong máy cục bộ của bạn, Compose sẽ tạo vùng chứa của bạn. Cờ `-d` tạo nền tảng cho quy trình, chạy các vùng chứa của bạn ở chế độ nền.

Sau khi quá trình hoàn tất, hãy sử dụng lệnh sau để liệt kê tất cả các vùng chứa đang chạy:
```command
docker ps
```

Bạn sẽ thấy đầu ra sau đây với thông tin chi tiết về `app`, `webserver`, và vùng chứa `<^>db<^>` :
```
[secondary_label Output]
CONTAINER ID        NAMES               IMAGE                             STATUS              PORTS
c31b7b3251e0        db                  mysql:5.7.22                      Up 2 seconds        0.0.0.0:3306->3306/tcp
ed5a69704580        app                 digitalocean.com/php              Up 2 seconds        9000/tcp
5ce4ee31d7c0        webserver           nginx:alpine                      Up 2 seconds        0.0.0.0:80->80/tcp, 0.0.0.0:443->443/tcp
```

`CONTAINER ID` trong đầu ra này là mã định danh duy nhất cho từng vùng chứa, trong khi `NAMES` liệt kê tên dịch vụ được liên kết với từng vùng chứa. Bạn có thể sử dụng cả hai số nhận dạng này để truy cập các vùng chứa. `IMAGE` xác định tên hình ảnh cho từng vùng chứa, trong khi `STATUS` cung cấp thông tin về trạng thái của vùng chứa: nó đang chạy, đang khởi động lại hay đã dừng.

Bây giờ bạn sẽ sử dụng `docker-compose exec` để đặt khóa ứng dụng cho ứng dụng Laravel. Lệnh `docker-compose exec` cho phép bạn chạy các lệnh cụ thể trong vùng chứa.

Lệnh sau sẽ tạo khóa và sao chép khóa đó vào tệp `.env` của bạn, đảm bảo rằng các phiên người dùng và dữ liệu được mã hóa của bạn vẫn an toàn:
```command
docker-compose exec <^>app<^> php artisan key:generate
```

Bây giờ bạn có các cài đặt môi trường cần thiết để chạy ứng dụng của mình. Để lưu trữ các cài đặt này vào một tệp, tệp này sẽ tăng tốc độ tải của ứng dụng của bạn, hãy chạy:
```command
docker-compose exec <^>app<^> php artisan config:cache
```

Cài đặt cấu hình của bạn sẽ được tải vào `/var/www/bootstrap/cache/config.php` trên vùng chứa.

Bước cuối cùng, hãy truy cập `http://<^>your_server_ip<^>` trong trình duyệt. Bạn sẽ thấy trang chủ sau cho ứng dụng Laravel của mình:

![description image](https://media.cloudfly.vn/posts/laravel_home.png)

Khi các vùng chứa của bạn đang chạy và thông tin cấu hình của bạn đã sẵn sàng, bạn có thể chuyển sang cấu hình thông tin người dùng của mình cho cơ sở dữ liệu `<^>laravel<^>` trên vùng chứa `<^>db<^>`.

## Bước 9 - Tạo người dùng cho MySQL

Cài đặt MySQL mặc định chỉ tạo tài khoản quản trị **root**, tài khoản này có đặc quyền không giới hạn trên máy chủ cơ sở dữ liệu. Nói chung, tốt hơn là tránh sử dụng tài khoản quản trị **root** khi tương tác với cơ sở dữ liệu. Thay vào đó, hãy tạo một người dùng cơ sở dữ liệu chuyên dụng cho cơ sở dữ liệu Laravel của ứng dụng của bạn.

Để tạo người dùng mới, hãy thực thi bash shell tương tác trên bộ chứa `<^>db<^>` với `docker-compose exec`:
```command
docker-compose exec <^>db<^> bash
```

Bên trong vùng chứa, đăng nhập vào tài khoản quản trị **root** của MySQL:
```custom_prefix(root@c31b7b3251e0:/#)
mysql -u root -p
```

Bạn sẽ được nhắc nhập mật khẩu mà bạn đã đặt cho tài khoản **root** MySQL trong khi cài đặt trong tệp `docker-compose` của mình.

Bắt đầu bằng cách kiểm tra cơ sở dữ liệu có tên là `<^>laravel<^>` mà bạn đã xác định trong tệp `docker-compose` của mình. Chạy lệnh `show databases` để kiểm tra các cơ sở dữ liệu hiện có:
```custom_prefix(mysql>)
show databases;
```

Bạn sẽ thấy cơ sở dữ liệu `<^>laravel<^>` được liệt kê trong đầu ra:
```
[secondary_label Output]
+--------------------+
| Database           |
+--------------------+
| information_schema |
| <^>laravel<^>      |
| mysql              |
| performance_schema |
| sys                |
+--------------------+
5 rows in set (0.00 sec)
```

Tiếp theo, tạo tài khoản người dùng sẽ được phép truy cập cơ sở dữ liệu này. Tên người dùng của bạn sẽ là `<^>laraveluser<^>`, tuy nhiên bạn có thể thay thế tên này bằng một tên khác nếu muốn. Chỉ cần đảm bảo rằng tên người dùng và mật khẩu của bạn ở đây khớp với các chi tiết bạn đã đặt trong tệp `.env` ở bước trước:
```custom_prefix(mysql>)
GRANT ALL ON laravel.* TO '<^>laraveluser<^>'@'%' IDENTIFIED BY '<^>your_laravel_db_password<^>';
```

Xóa các đặc quyền để thông báo cho máy chủ MySQL về các thay đổi:
```custom_prefix(mysql>)
FLUSH PRIVILEGES;
```

Thoát MySQL:
```custom_prefix(mysql>)
EXIT;
```

Cuối cùng, thoát khỏi vùng chứa:
```custom_prefix(root@c31b7b3251e0:/#)
exit
```

Bạn đã thiết lập cấu hình tài khoản người dùng cho cơ sở dữ liệu ứng dụng Laravel của mình và sẵn sàng di chuyển dữ liệu cũng như làm việc với bảng điều khiển Tinker.

## Bước 10 — Di chuyển dữ liệu và làm việc với Tinker Console

Khi ứng dụng của bạn đang chạy, bạn có thể di chuyển dữ liệu của mình và thử nghiệm với lệnh `tinker`, lệnh này sẽ khởi tạo bảng điều khiển PsySH với Laravel được tải sẵn. PsySH là bảng điều khiển dành cho nhà phát triển thời gian chạy và trình gỡ lỗi tương tác cho PHP và Tinker là một REPL dành riêng cho Laravel. Sử dụng lệnh `tinker` sẽ cho phép bạn tương tác với ứng dụng Laravel của mình từ dòng lệnh trong shell tương tác.

Trước tiên, hãy kiểm tra kết nối với MySQL bằng cách chạy lệnh Laravel `artisan migrate`, lệnh này sẽ tạo một bảng `migrations` trong cơ sở dữ liệu từ bên trong vùng chứa:
```command
docker-compose exec <^>app<^> php artisan migrate
```

Lệnh này sẽ di chuyển các bảng Laravel mặc định. Đầu ra xác nhận việc di chuyển sẽ như thế này:
```
[secondary_label Output]
Migration table created successfully.
Migrating: 2014_10_12_000000_create_users_table
Migrated:  2014_10_12_000000_create_users_table
Migrating: 2014_10_12_100000_create_password_resets_table
Migrated:  2014_10_12_100000_create_password_resets_table
```

Khi quá trình di chuyển hoàn tất, bạn có thể chạy truy vấn để kiểm tra xem mình có được kết nối đúng cách với cơ sở dữ liệu hay không bằng lệnh `tinker`:
```command
docker-compose exec <^>app<^> php artisan tinker
```

Kiểm tra kết nối MySQL bằng cách lấy dữ liệu bạn vừa di chuyển:
```custom_prefix(>>>)
\DB::table('migrations')->get();
```

Bạn sẽ thấy kết quả trông như thế này:
```
[secondary_label Output]
=> Illuminate\Support\Collection {#2856
     all: [
       {#2862
         +"id": 1,
         +"migration": "2014_10_12_000000_create_users_table",
         +"batch": 1,
       },
       {#2865
         +"id": 2,
         +"migration": "2014_10_12_100000_create_password_resets_table",
         +"batch": 1,
       },
     ],
   }
```

Bạn có thể sử dụng `tinker` để tương tác với cơ sở dữ liệu của mình và để thử nghiệm các dịch vụ và mô hình.

Với ứng dụng Laravel của bạn, bạn đã sẵn sàng để phát triển và thử nghiệm thêm.

## Kết luận

Bây giờ bạn có một ứng dụng LEMP stack đang chạy trên máy chủ của mình, bạn đã kiểm tra ứng dụng này bằng cách truy cập trang chào mừng của Laravel và tạo di chuyển cơ sở dữ liệu MySQL. Chìa khóa cho sự đơn giản của cài đặt này là Docker Compose, cho phép bạn tạo một nhóm bộ chứa Docker, được xác định trong một tệp duy nhất, bằng một lệnh duy nhất.
