# CI/CD sử dụng GitHub Actions

<span style="color: rgb(255, 255, 255);">Phần này sẽ sử dụng GitHub Actions điều khiển DSM qua SSH và câp nhật file bằng rsync.</span>

### Cấu hình trên DSM

#### Tạo shared folder

<span style="white-space: pre-wrap;">Trên DSM </span>

- Control Panel &gt; Shared Folder &gt; Create Shared Folder &gt; Name: docker
- <span style="white-space: pre-wrap;">Trong folder tạo thêm folder cho các web khác nhau </span>
    - docker/Web/web\_x
    - docker/Web/web\_y
    - docker/Web/web\_z
- [![image.png](https://knowledge.thanhdv.com/uploads/images/gallery/2025-11/scaled-1680-/p6eimage.png)](https://knowledge.thanhdv.com/uploads/images/gallery/2025-11/p6eimage.png)

#### Tạo container web hosting

Trên DSM truy cập Container Manager. Tạo một project và sử dụng docker compose để cấu hình container mới.

<span style="white-space: pre-wrap;">Với web tĩnh chỉ có html thì sử dụng image </span>`<span class="editor-theme-code">nginx:alpine</span>`

```yaml
services:
  web-cv:
    image: nginx:alpine
    container_name: web-cv  # Tên container
    volumes:
      - /volume1/docker/Web/cv:/usr/share/nginx/html:ro  # thư mục code # ro = readonly
    ports:
      - "9901:80" # port để truy cập. Trong trường hợp này là 192.168.1.88:9901
    restart: unless-stopped
```

<span style="white-space: pre-wrap;">Với web động sử dụng php thì sử dụng image </span>`<span class="editor-theme-code">php:8.3-apache</span>`

```yaml
services:
  web-upkgs:
    image: php:8.3-apache
    container_name: web-upkgs
    volumes:
      - /volume1/docker/Web/upkgs:/var/www/html:rw # rw = read write
    ports:
      - "9902:80"
    restart: unless-stopped
```

<span style="color: rgb(241, 196, 15);">Cần chú ý map đúng thư mục code.</span>

Copy source code vào đúng thư mục đã mapping.

<span style="white-space: pre-wrap;">Chạy container mới tạo. Nếu truy cập được qua local (ex: </span>`<span class="editor-theme-code">192.168.1.88:9902</span>`) là thành công là thành công.

#### <span style="white-space: pre-wrap;">Tạo user </span>`<span class="editor-theme-code">deploy</span>`<span style="white-space: pre-wrap;"> và phân quyền</span>

<span style="white-space: pre-wrap;">Trên DSM tạo một user mới là </span>`<span class="editor-theme-code">deploy</span>`<span style="white-space: pre-wrap;"> để chùng cho việc deploy web</span>

<span style="color: rgb(241, 196, 15); white-space: pre-wrap;">User này cần phải có quyền </span>**administrators**<span style="color: rgb(241, 196, 15); white-space: pre-wrap;"> để có thể sử dụng được ssh</span>

#### Bật SSH

<span style="white-space: pre-wrap;">DSM &gt; Control Panle &gt; Terminal &amp; SNMP &gt; Enable SSH service &gt; </span>**Apply**

### Tạo SSH key cho GitHub Actions

- Trên máy tính Windows/macOS/Linux khác có ssh-keygen
    - `<span class="editor-theme-code">ssh-keygen -t ed25519 -C "github-actions-to-dsm"</span>`
    - Đặt tên cho key (ex: id\_ed25519\_web\_deploy)
    - Passphrase có thể để trống
    - Khi thành công sẽ có thông báo dạng như sau  
        `<span class="editor-theme-code">Your identification has been saved in id_ed25519_web_deploy</span>`  
        `<span class="editor-theme-code">Your public key has been saved in id_ed25519_web_deploy.pub</span>`
- Xem nội dung public key
    - `<span class="editor-theme-code">cat id_ed25519_web_deploy.pub</span>`

### <span style="white-space: pre-wrap;">Thêm public key vào user </span>`<span class="editor-theme-code">deploy</span>`

- <span style="white-space: pre-wrap;">Truy cập vào DSM thông qua ssh bằng user </span>`<span class="editor-theme-code">deploy</span>`  
    `<span class="editor-theme-code">ssh deploy@IP_CỦA_DSM</span>`
- <span style="white-space: pre-wrap;">Tạo thư mục </span>`<span class="editor-theme-code">.ssh</span>`<span style="white-space: pre-wrap;"> và file </span>`<span class="editor-theme-code">authorized_keys</span>`  
    `<span class="editor-theme-code">mkdir -p ~/.ssh</span>`  
    `<span class="editor-theme-code">chmod 700 ~/.ssh</span>`  
    `<span class="editor-theme-code">vi ~/.ssh/authorized_keys</span>`
- <span style="white-space: pre-wrap;">Dán nội dung </span>`<span class="editor-theme-code">id_ed25519_web_deploy.pub</span>`<span style="white-space: pre-wrap;"> đã tạo ở trên vào file này</span>
- <span style="white-space: pre-wrap;">Set quyền </span>`<span class="editor-theme-code">chmod 600 ~/.ssh/authorized_keys</span>`
- Thử đăng nhập bằng key  
    `<span class="editor-theme-code">ssh -i id_ed25519_dsm deploy@IP_CỦA_DSM</span>`
- Nếu login thành công mà không hỏi password là thành công.

Lưu ý

- `<span class="editor-theme-code">chmod 700</span>`<span style="white-space: pre-wrap;"> cấp quyền đọc ghi và thực thi cho chủ sở hữu</span>
- `<span class="editor-theme-code">chmod 600</span>`<span style="white-space: pre-wrap;"> cấp quyền đọc ghi cho chủ sử hữu</span>

Lưu ý

Nếu đăng nhập vào vẫn yêu cần password

- <span style="white-space: pre-wrap;">Cần đảm bảo chắc chắn user deploy có </span><span style="color: rgb(241, 196, 15);">quyền admin</span>
- <span style="white-space: pre-wrap;">Đảm bảo cấp đúng quyền </span>`<span class="editor-theme-code">chmod 700</span>`<span style="white-space: pre-wrap;"> và </span>`<span class="editor-theme-code">chmod 600</span>`
- <span style="white-space: pre-wrap;">Đảm bảo gõ đúng tên key đã đã tạo (ex </span>`<span class="editor-theme-code">id_ed25519_web_deploy</span>`<span style="white-space: pre-wrap;"> và </span>`<span class="editor-theme-code">id_ed25519_web_deploy.pub</span>`)
- <span style="white-space: pre-wrap;">Nếu vẫn không được thì dùng </span>`<span class="editor-theme-code">sudo grep -E "PubkeyAuthentication|AuthorizedKeysFile" /etc/ssh/sshd_config</span>`<span style="white-space: pre-wrap;"> để kiểm tra config</span>
    - Kết quả mong đợi  
        `<span class="editor-theme-code">PubkeyAuthentication yes</span>`  
        `<span class="editor-theme-code">AuthorizedKeysFile .ssh/authorized_keys</span>`
    - Nếu không đúng 100% (`<span class="editor-theme-code">PubkeyAuthentication no, AuthorizedKeysFile</span>`<span style="white-space: pre-wrap;"> không chính xác, có dấu </span>`<span class="editor-theme-code">#</span>`<span style="white-space: pre-wrap;"> comment phía trước) thì cần sửa lại cho đúng </span>`<span class="editor-theme-code">sudo vi /etc/ssh/sshd_config</span>`
    - <span style="white-space: pre-wrap;">Restart ssh </span>`<span class="editor-theme-code">sudo synosystemctl restart sshd</span>`
    - <span style="white-space: pre-wrap;">Thử truy cập lại </span>`<span class="editor-theme-code">ssh -i id_ed25519_web_deploy -o IdentitiesOnly=yes deploy@192.168.1.88</span>`
- Nếu vẫn chưa thành công
    - <span style="white-space: pre-wrap;">Thử kiểm tra quyền bằng lệnh </span>`<span class="editor-theme-code">ls -ld ~</span>`
    - Nếu quyền quá rộng  
        `<span class="editor-theme-code">777 (drwxrwxrwx)</span>`  
        `<span class="editor-theme-code">775 (drwxrwxr-x)</span>`  
        <span style="white-space: pre-wrap;">thì cần đưa về mặc định </span>`<span class="editor-theme-code">755 (drwxr-xr-x)</span>`  
        `<span class="editor-theme-code">sudo chmod 755 ~</span>`
    - <span style="white-space: pre-wrap;">Restart ssh </span>`<span class="editor-theme-code">sudo synosystemctl restart sshd</span>`
    - <span style="white-space: pre-wrap;">Thử truy cập lại </span>`<span class="editor-theme-code">ssh -i id_ed25519_web_deploy -o IdentitiesOnly=yes deploy@192.168.1.88</span>`

Lưu ý:

Để đảm bảo bảo mật hãy tắt PasswordAuthentication

- `<span class="editor-theme-code">sudo vi /etc/ssh/sshd_config</span>`
- <span style="white-space: pre-wrap;">Sửa </span>`<span class="editor-theme-code">PasswordAuthentication</span>`<span style="white-space: pre-wrap;"> thành </span>`<span class="editor-theme-code">no</span>`
- <span style="white-space: pre-wrap;">Restart ssh </span>`<span class="editor-theme-code">sudo synosystemctl restart sshd</span>`
- <span style="white-space: pre-wrap;">Thử truy cập lại </span>
    - `<span class="editor-theme-code">ssh -i id_ed25519_web_deploy -o IdentitiesOnly=yes deploy@192.168.1.88</span>`<span style="white-space: pre-wrap;"> =&gt; Thành công</span>
    - `<span class="editor-theme-code">ssh deploy@192.168.1.88</span>`<span style="white-space: pre-wrap;"> =&gt; Thất bại</span>

### Setup GitHub Secrets

#### Mở port

Trước tiên để GitHub có thể truy cập tới DSM thông qua SSH thì cần mở port 22 của máy chủ DSM. Có thể map bất kỳ cổng nào của router vào cổng 22 của DSM

[![image.png](https://knowledge.thanhdv.com/uploads/images/gallery/2025-11/scaled-1680-/6zximage.png)](https://knowledge.thanhdv.com/uploads/images/gallery/2025-11/6zximage.png)

#### Thêm secrets

Trên GitHub repo &gt; Settings &gt; Secrets and variables &gt; Actions &gt; New repository secret

- `<span class="editor-theme-code">DSM_HOST</span>`: IP của router (hoặc domain name)
- `<span class="editor-theme-code">DSM_PORT</span>`: Port vừa mở phía trên.
- `<span class="editor-theme-code">DSM_USER</span>`: Username của account deploy vừa tạo
- `<span class="editor-theme-code">DSM_PATH</span>`<span style="white-space: pre-wrap;">: Folder chứa source code trên DSM (ex: </span>`<span class="editor-theme-code">/volume1/docker/Web/cv</span>`)
- `<span class="editor-theme-code">DSM_SSH_KEY</span>`: Nội dung private key đã tạo
    - `<span class="editor-theme-code">cat id_ed25519_web_deploy</span>`<span style="white-space: pre-wrap;"> để xem nội dung private key</span>

### <span style="white-space: pre-wrap;">Tạo GitHub Actions </span>**(Từ phần này chỉ bao gồm lý thuyết, chưa test)**

<span style="white-space: pre-wrap;">Trong repo trên GitHub tạo file </span>`<span class="editor-theme-code">.github/workflows/deploy.yml</span>`

```yml
name: Deploy to DSM via SSH + rsync

on:
  push:
    branches: [ main ]    # đổi lại branch bạn dùng, ví dụ 'master' hoặc 'prod'
  workflow_dispatch:       # cho phép chạy tay từ tab Actions

jobs:
  deploy:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout code
        uses: actions/checkout@v4 

      - name: Start SSH agent
        uses: webfactory/ssh-agent@v0.9.0
        with:
          ssh-private-key: ${{ secrets.DSM_SSH_KEY }}

      - name: Add DSM host to known_hosts
        run: |
          mkdir -p ~/.ssh
          ssh-keyscan -p ${{ secrets.DSM_PORT }} ${{ secrets.DSM_HOST }} >> ~/.ssh/known_hosts

      - name: Deploy via rsync
        run: |
          rsync -avz --delete \
            --exclude ".git" \
            --exclude ".github" \
            ./ \
            ${{ secrets.DSM_USER }}@${{ secrets.DSM_HOST }}:${{ secrets.DSM_PATH }}

      # (Tùy chọn) Set lại owner cho đúng user chạy web trên DSM
      # Nếu cần, bỏ comment đoạn này và chỉnh 'http:http' theo user của Synology/Container
      # - name: Fix permissions on DSM
      #   run: |
      #     ssh ${{ secrets.DSM_USER }}@${{ secrets.DSM_HOST }} -p ${{ secrets.DSM_PORT }} \
      #       "chown -R http:http ${DSM_PATH}"

      # Giải thích nhanh:
      # actions/checkout@v4: clone code từ repo vào runner.
      # webfactory/ssh-agent: load private key vào ssh-agent để rsync/ssh dùng.
      # ssh-keyscan: thêm host DSM vào known_hosts để tránh prompt tương tác.
      # rsync -avz --delete:
      #   -a: archive (giữ permission, symlink, v.v…)
      #   -v: verbose
      #   -z: nén khi truyền
      #   --delete: xóa file trên DSM nếu đã xóa trong repo
      #   --exclude: không đẩy .git, .github lên DSM.
```

Ok như vậy là đã xong. Hãy đảm bảo đã mount chính xác folder cho các container php, nginx như bước đầu tiên

- <span style="white-space: pre-wrap;">php: </span>`<span class="editor-theme-code">/volume1/docker/webapp -> /var/www/html</span>`
- <span style="white-space: pre-wrap;">Nginx: </span>`<span class="editor-theme-code">/volume1/docker/webapp -> /usr/share/nginx/html</span>`

### Test

1. Thực hiện commit trên repo
2. Push lên main (hoặc branch đã chọn)
3. Vào tab Actions của repo → chọn workflow Deploy to DSM via SSH + rsync:
    - Xem log:
        - Nếu lỗi SSH: check lại DSM\_HOST, DSM\_PORT, firewall/router.
        - <span style="white-space: pre-wrap;">Nếu lỗi quyền: check quyền user </span>`<span class="editor-theme-code">deploy</span>`<span style="white-space: pre-wrap;"> với folder </span>`<span class="editor-theme-code">/volume1/docker/webapp.</span>`
4. Nếu job xanh (success), SSH vào DSM:
    - <span style="white-space: pre-wrap;">Kiểm tra: </span>
        - `<span class="editor-theme-code">ls -l /volume1/docker/Web/cv</span>`
        - Dùng DSM web truy cập tới thư mục được mount và kiểm tra.
        - Truy cập và kiểm tra thực tế trên web