You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Github Actions:部署Express至VPS时Secrets安全处理与Docker变量问题

关于CI/CD中Secrets与变量安全处理及.env文件自动创建失败的问题

部署场景:将Express应用部署至VPS,以Docker容器运行,需确保变量在容器中可用。

当前做法:将Secrets写入.env文件,并在docker-compose.yml中指定该文件为env_file,但担心服务器上明文存储的.env文件不够安全,想知道更优的最佳实践。

另外,使用如下CI/CD脚本的echo命令无法自动创建.env文件,必须手动在服务器上创建,求原因:

- name: Execute remote deployment script
    uses: appleboy/ssh-action@v1.0.3
    with:
      HOST: ${{ secrets.HOST }}
      USERNAME: ${{ secrets.USERNAME }}
      PORT: ${{ secrets.PORT }}
      KEY: ${{ secrets.SSH_KEY }}
      script: |

        # Change directory to the app folder
        cd /usr/src/app/

        # install dependencies
        npm ci --omit=dev

        # Stop and remove running containers
        docker-compose -f docker-compose.prod.yml down

        # Set environment variables stored in Github secrets
        echo "VITE_API_URL=${{ secrets.VITE_API_URL }}" > .env
        echo "DATABASE_URL=${{ secrets.DATABASE_URL }}" >> .env
        echo "SECRET_KEY=${{ secrets.SECRET_KEY }}" >> .env
        echo "REFRESH_SECRET_KEY=${{ secrets.REFRESH_SECRET_KEY }}" >> .env

        # start container and detach
        docker-compose -f docker-compose.prod.yml up -d

一、Secrets与变量的安全处理最佳实践

1. 直接通过docker-compose传递环境变量(无需生成.env文件)

跳过服务器本地存储.env文件的步骤,直接在启动容器时注入变量:

docker-compose -f docker-compose.prod.yml up -d \
  -e VITE_API_URL=${{ secrets.VITE_API_URL }} \
  -e DATABASE_URL=${{ secrets.DATABASE_URL }} \
  -e SECRET_KEY=${{ secrets.SECRET_KEY }} \
  -e REFRESH_SECRET_KEY=${{ secrets.REFRESH_SECRET_KEY }}

优势:服务器上不会留下明文敏感文件,变量仅在容器运行时生效,生命周期与容器绑定。

2. 使用Docker Secrets(适用于Swarm模式)

如果你的VPS采用Docker Swarm集群部署,可利用Docker原生的Secrets管理功能:

  • 在CI脚本中将Secrets写入Docker Secret:
    echo "${{ secrets.SECRET_KEY }}" | docker secret create secret_key -
    echo "${{ secrets.DATABASE_URL }}" | docker secret create database_url -
    
  • 在docker-compose.prod.yml中引用Secrets:
    services:
      your-express-app:
        secrets:
          - secret_key
          - database_url
        environment:
          SECRET_KEY_FILE: /run/secrets/secret_key
          DATABASE_URL_FILE: /run/secrets/database_url
    

优势:Docker会加密存储Secrets,容器内仅能读取解密后的内容,彻底避免明文泄露。

3. 利用VPS系统环境变量

将Secrets预先配置到VPS的系统环境中,比如写入/etc/environment:

# 在VPS上执行一次
echo "VITE_API_URL=xxx" >> /etc/environment
echo "DATABASE_URL=xxx" >> /etc/environment

之后在CI脚本中直接读取系统变量传递给容器:

docker-compose -f docker-compose.prod.yml up -d \
  -e VITE_API_URL=$VITE_API_URL \
  -e DATABASE_URL=$DATABASE_URL

优势:敏感数据存储在系统层面,权限控制更严格,无需每次部署传递变量。


二、echo命令无法自动创建.env文件的原因排查

1. 目录权限不足

执行cd /usr/src/app/后,当前SSH用户可能没有该目录的写入权限。可以在脚本中添加权限检查:

ls -ld /usr/src/app/

解决方法:给用户添加目录写入权限,或用sudo创建文件(注意sudo环境变量的继承问题):

sudo bash -c 'echo "VITE_API_URL=${{ secrets.VITE_API_URL }}" > /usr/src/app/.env'

2. 目标目录不存在

如果/usr/src/app/目录未创建,cd命令会失败,后续的echo自然无法生成文件。可以在脚本中先确保目录存在:

mkdir -p /usr/src/app/ && cd /usr/src/app/

3. CI变量替换异常

如果${{ secrets.XXX }}没有被正确替换(比如变量为空或CI配置错误),虽然不会导致文件无法创建,但会生成内容异常的.env文件。可以在脚本中添加调试输出:

echo "DEBUG: VITE_API_URL=${{ secrets.VITE_API_URL }}"

查看CI日志确认变量是否被正确注入。

4. SSH执行环境限制

appleboy/ssh-action默认使用非交互式shell,可能存在路径或环境变量差异。可以在脚本开头开启调试模式,查看每一步执行细节:

script: |
  set -x
  cd /usr/src/app/
  # 后续命令...

内容的提问来源于stack exchange,提问作者Louis Eiden

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 19:04:50