linux服务器安装nodejs时因网络问题无法连接github或者fnm官网时候的一种解决方案

发现问题

在 ubuntu 服务器里想安装 nodejs,进入 nodejs 官网,打开下载页,选择版本,linux。目前官网推荐的是使用 fnm,nvm,docker 来安装。我这里选择的是 fnm。

选择好后会显示 bash 命令行

1
2
3
4
5
6
7
8
# Download and install fnm:
curl -o- https://fnm.vercel.app/install | bash
# Download and install Node.js:
fnm install 22
# Verify the Node.js version:
node -v # Should print "v22.14.0".
# Verify npm version:
npm -v # Should print "10.9.2".

服务器里运行发现,curl 的时候出错了,可能是无法访问造成的。

然后我在可以访问这个连接的地方访问了这个网站,发现里面是 bash 脚本。理解了他是下载这个脚本,然后使用 bash 运行,所以我手动复制了这个脚本下来,传到服务器里。

在服务器里运行,发现还是在 download 的时候报错,打开脚本仔细看,在download_fnm函数里

1
2
3
4
5
6
7
8
9
10
if [ "$RELEASE" = "latest" ]; then
URL="https://github.com/Schniz/fnm/releases/latest/download/$FILENAME.zip"
else
URL="https://github.com/Schniz/fnm/releases/download/$RELEASE/$FILENAME.zip"
fi

if ! curl --progress-bar --fail -L "$URL" -o "$DOWNLOAD_DIR/$FILENAME.zip"; then
echo "Download failed. Check that the release/filename are correct."
exit 1
fi

他还是要通过 github 下载,无法访问的话自然会下载失败。但是他会提示你正在哪个链接下载,比如https://github.com/Schniz/fnm/releases/latest/download/fnm-linux.zip
后面的那个 zip 文件就是需要下载的文件,所以去 fnm 的 github releases 里手动下载这个 zip 文件,然后传到服务器里。

然后继续回到 bash 脚本里,把 set_filename 这个函数注释了,因为已经明确的知道文件名了。

1
2
3
4
5
6
7
parse_args "$@"
# set_filename
check_dependencies
download_fnm
if [ "$SKIP_SHELL" != "true" ]; then
setup_shell
fi

然后进入download_fnm函数里

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 将下载相关的命令注释掉,不需要从github下载了
# if ! curl --progress-bar --fail -L "$URL" -o "$DOWNLOAD_DIR/$FILENAME.zip"; then
# echo "Download failed. Check that the release/filename are correct."
# exit 1
# fi

# 将 FILENAME 变量改为之前得到的文件名
FILENAME="fnm-linux"

# 新建一个 FILEPATH 变量,变量值是你传入到服务器里的zip文件路径
FILEPATH="$HOME/$FILENAME"

# 将你传到服务器里的文件,复制到临时目录里
cp "$FILEPATH.zip" "$DOWNLOAD_DIR"

# 随便写一个echo,提示正在解压文件
echo "Unziping $FILENAME"

unzip -q "$DOWNLOAD_DIR/$FILENAME.zip" -d "$DOWNLOAD_DIR"

然后 bash 里,运行最终修改好的脚本文件就安装好了

1
bash install.sh

完整代码,目前 fnm 版本是1.38.1,如果以后版本的安装脚本变动的话,需要根据需求重新改

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
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
#!/bin/bash

set -e

RELEASE="latest"
OS="$(uname -s)"

case "${OS}" in
MINGW* | Win*) OS="Windows" ;;
esac

if [ -d "$HOME/.fnm" ]; then
INSTALL_DIR="$HOME/.fnm"
elif [ -n "$XDG_DATA_HOME" ]; then
INSTALL_DIR="$XDG_DATA_HOME/fnm"
elif [ "$OS" = "Darwin" ]; then
INSTALL_DIR="$HOME/Library/Application Support/fnm"
else
INSTALL_DIR="$HOME/.local/share/fnm"
fi

# Parse Flags
parse_args() {
while [[ $# -gt 0 ]]; do
key="$1"

case $key in
-d | --install-dir)
INSTALL_DIR="$2"
shift # past argument
shift # past value
;;
-s | --skip-shell)
SKIP_SHELL="true"
shift # past argument
;;
--force-install | --force-no-brew)
echo "\`--force-install\`: I hope you know what you're doing." >&2
FORCE_INSTALL="true"
shift
;;
-r | --release)
RELEASE="$2"
shift # past release argument
shift # past release value
;;
*)
echo "Unrecognized argument $key"
exit 1
;;
esac
done
}

set_filename() {
if [ "$OS" = "Linux" ]; then
# Based on https://stackoverflow.com/a/45125525
case "$(uname -m)" in
arm | armv7*)
FILENAME="fnm-arm32"
;;
aarch* | armv8*)
FILENAME="fnm-arm64"
;;
*)
FILENAME="fnm-linux"
esac
elif [ "$OS" = "Darwin" ] && [ "$FORCE_INSTALL" = "true" ]; then
FILENAME="fnm-macos"
USE_HOMEBREW="false"
echo "Downloading the latest fnm binary from GitHub..."
echo " Pro tip: it's easier to use Homebrew for managing fnm in macOS."
echo " Remove the \`--force-no-brew\` so it will be easy to upgrade."
elif [ "$OS" = "Darwin" ]; then
USE_HOMEBREW="true"
echo "Downloading fnm using Homebrew..."
elif [ "$OS" = "Windows" ] ; then
FILENAME="fnm-windows"
echo "Downloading the latest fnm binary from GitHub..."
else
echo "OS $OS is not supported."
echo "If you think that's a bug - please file an issue to https://github.com/Schniz/fnm/issues"
exit 1
fi
}

download_fnm() {
if [ "$USE_HOMEBREW" = "true" ]; then
brew install fnm
else
if [ "$RELEASE" = "latest" ]; then
URL="https://github.com/Schniz/fnm/releases/latest/download/$FILENAME.zip"
else
URL="https://github.com/Schniz/fnm/releases/download/$RELEASE/$FILENAME.zip"
fi

DOWNLOAD_DIR=$(mktemp -d)

# echo "Downloading $URL..."

mkdir -p "$INSTALL_DIR" &>/dev/null

# if ! curl --progress-bar --fail -L "$URL" -o "$DOWNLOAD_DIR/$FILENAME.zip"; then
# echo "Download failed. Check that the release/filename are correct."
# exit 1
# fi

FILENAME="fnm-linux"

FILEPATH="$HOME/$FILENAME"

cp "$FILEPATH.zip" "$DOWNLOAD_DIR"

echo "Unziping $FILENAME"

unzip -q "$DOWNLOAD_DIR/$FILENAME.zip" -d "$DOWNLOAD_DIR"

if [ -f "$DOWNLOAD_DIR/fnm" ]; then
mv "$DOWNLOAD_DIR/fnm" "$INSTALL_DIR/fnm"
else
mv "$DOWNLOAD_DIR/$FILENAME/fnm" "$INSTALL_DIR/fnm"
fi

chmod u+x "$INSTALL_DIR/fnm"
fi
}

check_dependencies() {
echo "Checking dependencies for the installation script..."

echo -n "Checking availability of unzip... "
if hash unzip 2>/dev/null; then
echo "OK!"
else
echo "Missing!"
SHOULD_EXIT="true"
fi

if [ "$USE_HOMEBREW" = "true" ]; then
echo -n "Checking availability of Homebrew (brew)... "
if hash brew 2>/dev/null; then
echo "OK!"
else
echo "Missing!"
SHOULD_EXIT="true"
fi
fi

if [ "$SHOULD_EXIT" = "true" ]; then
echo "Not installing fnm due to missing dependencies."
exit 1
fi
}

ensure_containing_dir_exists() {
local CONTAINING_DIR
CONTAINING_DIR="$(dirname "$1")"
if [ ! -d "$CONTAINING_DIR" ]; then
echo " >> Creating directory $CONTAINING_DIR"
mkdir -p "$CONTAINING_DIR"
fi
}

setup_shell() {
CURRENT_SHELL="$(basename "$SHELL")"

if [ "$CURRENT_SHELL" = "zsh" ]; then
CONF_FILE=${ZDOTDIR:-$HOME}/.zshrc
ensure_containing_dir_exists "$CONF_FILE"
echo "Installing for Zsh. Appending the following to $CONF_FILE:"
{
echo ''
echo '# fnm'
echo 'FNM_PATH="'"$INSTALL_DIR"'"'
echo 'if [ -d "$FNM_PATH" ]; then'
echo ' export PATH="'$INSTALL_DIR':$PATH"'
echo ' eval "`fnm env`"'
echo 'fi'
} | tee -a "$CONF_FILE"

elif [ "$CURRENT_SHELL" = "fish" ]; then
CONF_FILE=$HOME/.config/fish/conf.d/fnm.fish
ensure_containing_dir_exists "$CONF_FILE"
echo "Installing for Fish. Appending the following to $CONF_FILE:"
{
echo ''
echo '# fnm'
echo 'set FNM_PATH "'"$INSTALL_DIR"'"'
echo 'if [ -d "$FNM_PATH" ]'
echo ' set PATH "$FNM_PATH" $PATH'
echo ' fnm env | source'
echo 'end'
} | tee -a "$CONF_FILE"

elif [ "$CURRENT_SHELL" = "bash" ]; then
if [ "$OS" = "Darwin" ]; then
CONF_FILE=$HOME/.profile
else
CONF_FILE=$HOME/.bashrc
fi
ensure_containing_dir_exists "$CONF_FILE"
echo "Installing for Bash. Appending the following to $CONF_FILE:"
{
echo ''
echo '# fnm'
echo 'FNM_PATH="'"$INSTALL_DIR"'"'
echo 'if [ -d "$FNM_PATH" ]; then'
echo ' export PATH="$FNM_PATH:$PATH"'
echo ' eval "`fnm env`"'
echo 'fi'
} | tee -a "$CONF_FILE"

else
echo "Could not infer shell type. Please set up manually."
exit 1
fi

echo ""
echo "In order to apply the changes, open a new terminal or run the following command:"
echo ""
echo " source $CONF_FILE"
}

parse_args "$@"
# set_filename
check_dependencies
download_fnm
if [ "$SKIP_SHELL" != "true" ]; then
setup_shell
fi