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

Firebase云函数调用Shell脚本报错文件不存在,手动执行正常

问题原因与解决方案

核心原因

Firebase云函数默认运行在Google Cloud的托管环境中,并非你的EC2实例本地。这意味着云函数的代码完全无法访问EC2实例上的文件系统——不管是直接用fs.appendFile操作文件,还是调用./addvips.sh脚本,都找不到EC2上的/home/ubuntu/serverfiles/csgo/addons/sourcemod/configs/admins_simple.ini路径,因为这个路径只存在于你的EC2实例里,云函数的运行环境根本没有这个文件。

而你手动执行脚本时,是在EC2实例本地操作,自然能正常访问本地文件系统,所以不会报错。

解决方法

方法1:在EC2上搭建HTTP服务,云函数通过接口触发脚本

  1. 在你的EC2实例上部署一个简单的Node.js HTTP服务(比如用Express),暴露一个接口(比如POST /add-vip),接口内部执行addvips.sh脚本。
  2. 配置EC2的安全组,允许云函数的IP段或者公网访问这个接口(注意做好身份验证,比如API Key)。
  3. 修改Firebase云函数代码,用axios或fetch调用EC2上的这个接口,传递steamID参数。

示例EC2上的Express服务代码:

const express = require('express');
const { exec } = require('child_process');
const app = express();
app.use(express.json());

// 身份验证中间件,检查请求头里的API Key
const authMiddleware = (req, res, next) => {
  const apiKey = req.headers['x-api-key'];
  if (apiKey !== '你的安全密钥') {
    return res.status(403).send('Unauthorized');
  }
  next();
};

app.post('/add-vip', authMiddleware, (req, res) => {
  const { steamID } = req.body;
  // 用参数数组避免命令注入
  exec(`/home/ubuntu/addvips.sh ${steamID} a`, (err, stdout, stderr) => {
    if (err) {
      console.error(err);
      return res.status(500).send('执行失败');
    }
    res.send('Success: ' + stdout);
  });
});

app.listen(3000, () => {
  console.log('EC2服务运行在3000端口');
});

修改后的云函数代码:

const admin = require('firebase-admin');
const serviceAccount = require('./raniserverFBkey.json');
const functions = require('firebase-functions');
const axios = require('axios');

admin.initializeApp({
    credential: admin.credential.cert(serviceAccount),
});

exports.addSteamID1 = functions.firestore.document('steamIDs/{docID}')
    .onCreate(async (snap, context) => {
        const steamID = snap.data().steamID;
        try {
            await axios.post('http://你的EC2公网IP:3000/add-vip', 
                { steamID },
                { headers: { 'x-api-key': '你的安全密钥' } }
            );
            console.log('VIP添加成功');
        } catch (err) {
            console.error('调用EC2接口失败:', err);
        }
    });

方法2:云函数通过SSH连接EC2执行脚本

  1. 生成SSH密钥对,把公钥添加到EC2实例的~ubuntu/.ssh/authorized_keys里。
  2. 将私钥存储到Firebase Secrets中(避免硬编码)。
  3. 在云函数中使用ssh2之类的库,连接到EC2实例并执行脚本。

示例云函数代码(使用ssh2):

const admin = require('firebase-admin');
const serviceAccount = require('./raniserverFBkey.json');
const functions = require('firebase-functions');
const { Client } = require('ssh2');

admin.initializeApp({
    credential: admin.credential.cert(serviceAccount),
});

exports.addSteamID1 = functions.firestore.document('steamIDs/{docID}')
    .onCreate(async (snap, context) => {
        const steamID = snap.data().steamID;
        const privateKey = functions.config().ec2.ssh_key; // 从Firebase Secrets获取私钥

        const conn = new Client();
        conn.on('ready', () => {
            conn.exec(`/home/ubuntu/addvips.sh ${steamID} a`, (err, stream) => {
                if (err) throw err;
                stream.on('close', (code, signal) => {
                    console.log('脚本执行完成,退出码:', code);
                    conn.end();
                }).on('data', (data) => {
                    console.log('stdout:', data.toString());
                }).stderr.on('data', (data) => {
                    console.error('stderr:', data.toString());
                });
            });
        }).connect({
            host: '你的EC2公网IP',
            port: 22,
            username: 'ubuntu',
            privateKey: privateKey
        });
    });

关键注意事项

  • 确保EC2安全组配置正确,允许对应的请求(HTTP/SSH)进入。
  • 处理用户输入时必须做安全校验,比如对steamID进行转义,避免命令注入攻击(优先用exec的参数数组格式,而非字符串拼接)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 19:34:55