应佬友的要求再出一篇文章,前面薅了wispbyte.com的羊毛,但是吧容器比较弱小,强一点的就是huggingface.co的容器:
Free版本就是2vCPU和16GB RAM,就已经非常强了

那先介绍一下huggingface,其实这是一家非常强悍的公司,可以称作是“AI界的GitHub”,可以分享模型,数据集,然后演示应用。
我们用到的就是这个演示应用(Spaces)
首先注册好账号,然后右上角点击头像按钮,新建一个Space

然后填入必须项
- Space name:就写myhome
- Short description:Save Our Home
- License:MIT
- SDK:选择Docker
- Docker template: 选择Blank
- Space hardware:选择Free

其它都不选,最后CreateSpace即可
然后就建好了,其实是给你开了一个git的repo
我们到右上角,选择Files选项

然后打开的文件页面,只有两个文件

老套路,建立一个Dockerfile文件,就是容器的打包文件

Dockerfile的内容,编辑好,然后提交,注意:Linux有严格的大小写要求,务必遵守
FROM nikolaik/python-nodejs:python3.14-nodejs22
WORKDIR /tmp
COPY index.js /tmp/index.js
COPY package.json /tmp/package.json
COPY index.html /tmp/index.html
CMD npm install && node index.js

然后我们把index.js准备好,需要修改几个地方
const http = require('http');
const https = require('https');
const fs = require('fs');
const axios = require('axios');
const net = require('net');
const path = require('path');
const crypto = require('crypto');
const { Buffer } = require('buffer');
const { WebSocket, createWebSocketStream } = require('ws');
// 生成 UUID v4
function generateUUID() {
return crypto.randomUUID();
}
const UUID = process.env.UUID || generateUUID();
const DOMAIN = process.env.DOMAIN || '1234.abc.com'; // 填写项目域名
const WSPATH = process.env.WSPATH || UUID.slice(0, 8); // 节点路径,默认获取uuid前8位
const SUB_PATH = process.env.SUB_PATH || 'sub'; // 获取节点的订阅路径
const NAME = process.env.NAME || ''; // 节点名称
const PORT = process.env.PORT || 7860; // http和ws服务端口
const TLS_KEY_PATH = process.env.TLS_KEY_PATH || 'tls.key';
const TLS_CERT_PATH = process.env.TLS_CERT_PATH || 'tls.crt';
let ISP = '';
const GetISP = async () => {
try {
const res = await axios.get('https://api.ip.sb/geoip');
const data = res.data;
ISP = `${data.country_code}-${data.isp}`.replace(/ /g, '_');
} catch (e) {
ISP = 'Unknown';
}
}
GetISP();
function normalizeSecret(value) {
if (!value) return '';
return value.includes('\\n') ? value.replace(/\\n/g, '\n') : value;
}
function readOptionalFile(filePath) {
if (!filePath) return '';
const resolvedPath = path.isAbsolute(filePath) ? filePath : path.join(__dirname, filePath);
try {
return fs.readFileSync(resolvedPath, 'utf8');
} catch (error) {
console.warn(`Failed to read TLS file ${resolvedPath}: ${error.message}`);
return '';
}
}
function getTLSOptions() {
let key = normalizeSecret(process.env.TLS_KEY);
let cert = normalizeSecret(process.env.TLS_CERT);
if (!key) {
key = readOptionalFile(TLS_KEY_PATH);
}
if (!cert) {
cert = readOptionalFile(TLS_CERT_PATH);
}
if (key && cert) {
return { key, cert };
}
if (key || cert) {
console.warn('Both TLS key and certificate are required; falling back to HTTP.');
}
return null;
}
const requestHandler = (req, res) => {
if (req.url === '/') {
const filePath = path.join(__dirname, 'index.html');
fs.readFile(filePath, 'utf8', (err, content) => {
if (err) {
res.writeHead(200, { 'Content-Type': 'text/html' });
res.end('Hello world!');
return;
}
res.writeHead(200, { 'Content-Type': 'text/html' });
res.end(content);
});
return;
} else if (req.url === `/${SUB_PATH}`) {
const namePart = NAME ? `${NAME}-${ISP}` : ISP;
const vlessURL = `vless://${UUID}@${DOMAIN}?encryption=none&security=tls&sni=${DOMAIN}&fp=chrome&type=ws&host=${DOMAIN}&path=%2F${WSPATH}#${namePart}`;
const trojanURL = `trojan://${UUID}@${DOMAIN}?security=tls&sni=${DOMAIN}&fp=chrome&type=ws&host=${DOMAIN}&path=%2F${WSPATH}#${namePart}`;
const subscription = vlessURL + '\n' + trojanURL;
const base64Content = Buffer.from(subscription).toString('base64');
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end(base64Content + '\n');
} else {
res.writeHead(404, { 'Content-Type': 'text/plain' });
res.end('Not Found\n');
}
};
const tlsOptions = getTLSOptions();
const httpServer = tlsOptions ? https.createServer(tlsOptions, requestHandler) : http.createServer(requestHandler);
const wss = new WebSocket.Server({ server: httpServer });
const uuid = UUID.replace(/-/g, "");
const DNS_SERVERS = ['8.8.4.4', '1.1.1.1'];
// Custom DNS
function resolveHost(host) {
return new Promise((resolve, reject) => {
if (/^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/.test(host)) {
resolve(host);
return;
}
let attempts = 0;
function tryNextDNS() {
if (attempts >= DNS_SERVERS.length) {
reject(new Error(`Failed to resolve ${host} with all DNS servers`));
return;
}
const dnsServer = DNS_SERVERS[attempts];
attempts++;
const dnsQuery = `https://dns.google/resolve?name=${encodeURIComponent(host)}&type=A`;
axios.get(dnsQuery, {
timeout: 5000,
headers: {
'Accept': 'application/dns-json'
}
})
.then(response => {
const data = response.data;
if (data.Status === 0 && data.Answer && data.Answer.length > 0) {
const ip = data.Answer.find(record => record.type === 1);
if (ip) {
resolve(ip.data);
return;
}
}
tryNextDNS();
})
.catch(error => {
tryNextDNS();
});
}
tryNextDNS();
});
}
// VLE-SS处理
function handleVlessConnection(ws, msg) {
const [VERSION] = msg;
const id = msg.slice(1, 17);
if (!id.every((v, i) => v == parseInt(uuid.substr(i * 2, 2), 16))) return false;
let i = msg.slice(17, 18).readUInt8() + 19;
const port = msg.slice(i, i += 2).readUInt16BE(0);
const ATYP = msg.slice(i, i += 1).readUInt8();
const host = ATYP == 1 ? msg.slice(i, i += 4).join('.') :
(ATYP == 2 ? new TextDecoder().decode(msg.slice(i + 1, i += 1 + msg.slice(i, i + 1).readUInt8())) :
(ATYP == 3 ? msg.slice(i, i += 16).reduce((s, b, i, a) => (i % 2 ? s.concat(a.slice(i - 1, i + 1)) : s), []).map(b => b.readUInt16BE(0).toString(16)).join(':') : ''));
ws.send(new Uint8Array([VERSION, 0]));
const duplex = createWebSocketStream(ws);
resolveHost(host)
.then(resolvedIP => {
net.connect({ host: resolvedIP, port }, function() {
this.write(msg.slice(i));
duplex.on('error', () => {}).pipe(this).on('error', () => {}).pipe(duplex);
}).on('error', () => {});
})
.catch(error => {
net.connect({ host, port }, function() {
this.write(msg.slice(i));
duplex.on('error', () => {}).pipe(this).on('error', () => {}).pipe(duplex);
}).on('error', () => {});
});
return true;
}
// Tro-jan处理
function handleTrojanConnection(ws, msg) {
try {
if (msg.length < 58) return false;
const receivedPasswordHash = msg.slice(0, 56).toString();
const possiblePasswords = [
UUID,
];
let matchedPassword = null;
for (const pwd of possiblePasswords) {
const hash = crypto.createHash('sha224').update(pwd).digest('hex');
if (hash === receivedPasswordHash) {
matchedPassword = pwd;
break;
}
}
if (!matchedPassword) return false;
let offset = 56;
if (msg[offset] === 0x0d && msg[offset + 1] === 0x0a) {
offset += 2;
}
const cmd = msg[offset];
if (cmd !== 0x01) return false;
offset += 1;
const atyp = msg[offset];
offset += 1;
let host, port;
if (atyp === 0x01) {
host = msg.slice(offset, offset + 4).join('.');
offset += 4;
} else if (atyp === 0x03) {
const hostLen = msg[offset];
offset += 1;
host = msg.slice(offset, offset + hostLen).toString();
offset += hostLen;
} else if (atyp === 0x04) {
host = msg.slice(offset, offset + 16).reduce((s, b, i, a) =>
(i % 2 ? s.concat(a.slice(i - 1, i + 1)) : s), [])
.map(b => b.readUInt16BE(0).toString(16)).join(':');
offset += 16;
} else {
return false;
}
port = msg.readUInt16BE(offset);
offset += 2;
if (offset < msg.length && msg[offset] === 0x0d && msg[offset + 1] === 0x0a) {
offset += 2;
}
const duplex = createWebSocketStream(ws);
resolveHost(host)
.then(resolvedIP => {
net.connect({ host: resolvedIP, port }, function() {
if (offset < msg.length) {
this.write(msg.slice(offset));
}
duplex.on('error', () => {}).pipe(this).on('error', () => {}).pipe(duplex);
}).on('error', () => {});
})
.catch(error => {
net.connect({ host, port }, function() {
if (offset < msg.length) {
this.write(msg.slice(offset));
}
duplex.on('error', () => {}).pipe(this).on('error', () => {}).pipe(duplex);
}).on('error', () => {});
});
return true;
} catch (error) {
return false;
}
}
// Ws 连接处理
wss.on('connection', (ws, req) => {
const url = req.url || '';
ws.once('message', msg => {
if (msg.length > 17 && msg[0] === 0) {
const id = msg.slice(1, 17);
const isVless = id.every((v, i) => v == parseInt(uuid.substr(i * 2, 2), 16));
if (isVless) {
if (!handleVlessConnection(ws, msg)) {
ws.close();
}
return;
}
}
if (!handleTrojanConnection(ws, msg)) {
ws.close();
}
}).on('error', () => {});
});
httpServer.listen(PORT, () => {
const scheme = tlsOptions ? 'HTTPS/WSS' : 'HTTP/WS';
console.log(`Server is running on ${scheme} port ${PORT}`);
});
其中几个地方有修改,先看看huggingface给咱们的域名,右边,Settings右边的三个点按钮,
点开,然后点 Embed this Space

看src那里,大善人给了咱们一个免费的域名,这个域名是自带证书的!!!我们把域名拷贝下来

然后根据实际情况修改 index.js
const DOMAIN = process.env.DOMAIN || 'username-spacename.hf.space'; // 填写大善人给的域名域名
const SUB_PATH = process.env.SUB_PATH || 'sub'; // 获取节点的订阅路径,最好改掉
const TLS_KEY_PATH = process.env.TLS_KEY_PATH || ''; // 善人给了证书,就不用设置了,改成空
const TLS_CERT_PATH = process.env.TLS_CERT_PATH || ''; // 善人给了证书,就不用设置了,改成空
改完后是这样的:

然后改好了,别急着贴进去:
去到 去到 https://obfuscator.io/legacy-playground
贴进去代码,混淆一下,弄成谁也认不得的模样,然后Copy,再贴进去

然后再建立 package.json 文件
{
"name": "js02",
"version": "0.0.2",
"description": "Nodejs-server",
"main": "index.js",
"private": false,
"scripts": {
"start": "node index.js"
},
"dependencies": {
"ws": "^8.14.2",
"axios": "^1.12.2"
},
"engines": {
"node": ">=14"
}
}
再建立 index.html 文件, 这是个用来装饰的环保单页面,如果不加,就会显示hello world,太假了,可以让 gemini 给你生成一个,代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Green Network - Protect Earth</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}
:root {
--primary: #2e7d32;
--secondary: #4caf50;
--accent: #8bc34a;
--light: #e8f5e9;
--dark: #1b5e20;
--text: #333333;
--white: #ffffff;
}
body {
background-color: var(--light);
color: var(--text);
line-height: 1.7; /* Slightly increased line height for readability */
font-size: 16px;
}
header {
background: rgba(46, 125, 50, 0.95); /* Slightly transparent primary color */
color: var(--white);
padding: 1rem 0;
position: sticky;
top: 0;
z-index: 100;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); /* Enhanced shadow */
}
.container {
width: 90%;
max-width: 1200px;
margin: 0 auto;
}
.nav-container {
display: flex;
justify-content: space-between;
align-items: center;
}
.logo {
display: flex;
align-items: center;
gap: 10px;
font-size: 1.8rem;
font-weight: 700;
}
.logo i {
font-size: 2rem;
}
nav ul {
display: flex;
list-style: none;
}
nav ul li {
margin-left: 2rem;
}
nav ul li a {
color: var(--white);
text-decoration: none;
font-weight: 500;
transition: all 0.3s ease;
padding: 0.5rem 0;
position: relative;
}
nav ul li a:hover {
color: var(--accent);
}
nav ul li a::after {
content: '';
position: absolute;
bottom: 0;
left: 0;
width: 0;
height: 2px;
background-color: var(--accent);
transition: width 0.3s ease;
}
nav ul li a:hover::after {
width: 100%;
}
.hero {
background: linear-gradient(rgba(0, 0, 0, 0.6), rgba(0, 0, 0, 0.4)), url('https://images.unsplash.com/photo-1542601906990-b4d3fb778b09?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=2073&q=80');
background-size: cover;
background-position: center;
height: 80vh;
display: flex;
align-items: center;
text-align: center;
color: var(--white);
}
.hero-content {
max-width: 800px;
margin: 0 auto;
}
.hero h1 {
font-size: 3.5rem;
margin-bottom: 1rem;
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.5);
}
.hero p {
font-size: 1.3rem;
margin-bottom: 2rem;
}
.btn {
display: inline-block;
background-color: var(--accent);
color: var(--white);
padding: 0.9rem 2.2rem; /* Slightly larger padding */
border-radius: 8px; /* More modern rounded corners */
text-decoration: none;
font-weight: 600;
transition: all 0.3s ease;
border: none;
cursor: pointer;
box-shadow: 0 6px 10px rgba(0, 0, 0, 0.1); /* Slightly enhanced shadow */
}
.btn:hover {
background-color: var(--primary);
transform: translateY(-5px); /* More pronounced lift effect */
box-shadow: 0 8px 15px rgba(0, 0, 0, 0.2); /* Stronger hover shadow */
}
section {
padding: 5rem 0;
}
.section-title {
text-align: center;
margin-bottom: 3rem;
}
.section-title h2 {
font-size: 2.5rem;
color: var(--primary);
margin-bottom: 1rem;
position: relative;
display: inline-block;
}
.section-title h2::after {
content: '';
position: absolute;
bottom: -10px;
left: 50%;
transform: translateX(-50%);
width: 90px; /* Slightly wider underline */
height: 5px; /* Thicker underline */
background-color: var(--accent);
border-radius: 3px;
}
.section-title p {
color: var(--text);
max-width: 700px;
margin: 0 auto;
font-size: 1.1rem;
}
.about-content {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 3rem;
align-items: center;
}
.about-img {
border-radius: 12px; /* More rounded */
overflow: hidden;
box-shadow: 0 12px 25px rgba(0, 0, 0, 0.15); /* Enhanced shadow */
}
.about-img img {
width: 100%;
height: auto;
display: block;
transition: transform 0.5s ease;
}
.about-img:hover img {
transform: scale(1.08); /* More pronounced zoom */
}
.about-text h3 {
font-size: 2rem;
margin-bottom: 1.5rem;
color: var(--dark);
}
.about-text p {
margin-bottom: 1.5rem;
font-size: 1.05rem;
}
.stats {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 2rem;
margin-top: 4rem; /* More space */
}
.stat-item {
text-align: center;
padding: 2.5rem 1.5rem; /* More padding */
background-color: var(--white);
border-radius: 12px; /* More rounded */
box-shadow: 0 8px 20px rgba(0, 0, 0, 0.08); /* Enhanced shadow */
transition: transform 0.3s ease, box-shadow 0.3s ease;
}
.stat-item:hover {
transform: translateY(-12px); /* More pronounced lift */
box-shadow: 0 15px 30px rgba(0, 0, 0, 0.15); /* Stronger hover shadow */
}
.stat-item h3 {
font-size: 3rem; /* Larger numbers */
color: var(--dark);
margin-bottom: 0.8rem;
}
.stat-item p {
color: var(--text);
font-size: 1.1rem;
}
.initiatives {
background-color: var(--white);
}
.initiatives-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 2.5rem;
}
.initiative-card {
background-color: var(--light);
border-radius: 12px; /* More rounded */
overflow: hidden;
box-shadow: 0 8px 20px rgba(0, 0, 0, 0.08); /* Enhanced shadow */
transition: transform 0.3s ease, box-shadow 0.3s ease;
}
.initiative-card:hover {
transform: translateY(-12px); /* More pronounced lift */
box-shadow: 0 15px 30px rgba(0, 0, 0, 0.15); /* Stronger hover shadow */
}
.initiative-img {
height: 220px; /* Slightly taller images */
overflow: hidden;
}
.initiative-img img {
width: 100%;
height: 100%;
object-fit: cover;
transition: transform 0.5s ease;
}
.initiative-card:hover .initiative-img img {
transform: scale(1.15); /* More pronounced zoom */
}
.initiative-content {
padding: 2rem;
}
.initiative-content h3 {
font-size: 1.6rem;
margin-bottom: 1rem;
color: var(--dark);
}
.initiative-content p {
margin-bottom: 1.8rem;
font-size: 1.05rem;
}
.cta {
background: linear-gradient(to right, var(--primary), var(--secondary));
color: var(--white);
text-align: center;
padding: 6rem 0; /* More padding */
}
.cta h2 {
font-size: 3rem; /* Larger heading */
margin-bottom: 1.8rem;
}
.cta p {
font-size: 1.3rem;
margin-bottom: 2.5rem;
max-width: 700px;
margin-left: auto;
margin-right: auto;
}
.cta .btn {
background-color: var(--white);
color: var(--primary);
}
.cta .btn:hover {
background-color: var(--accent);
color: var(--white);
}
footer {
background-color: var(--dark);
color: var(--white);
padding: 4rem 0 2rem; /* More padding */
}
.footer-content {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 2.5rem; /* More gap */
margin-bottom: 2.5rem;
}
.footer-column h3 {
font-size: 1.4rem;
margin-bottom: 1.8rem;
position: relative;
padding-bottom: 12px;
}
.footer-column h3::after {
content: '';
position: absolute;
bottom: 0;
left: 0;
width: 50px; /* Wider underline */
height: 3px; /* Thicker underline */
background-color: var(--accent);
}
.footer-column p {
margin-bottom: 1.2rem;
}
.footer-links {
list-style: none;
}
.footer-links li {
margin-bottom: 1rem;
}
.footer-links li a {
color: var(--light);
text-decoration: none;
transition: all 0.3s ease;
}
.footer-links li a:hover {
color: var(--accent);
padding-left: 8px; /* More pronounced slide effect */
}
.social-links {
display: flex;
gap: 1.2rem;
margin-top: 1.5rem;
}
.social-links a {
display: inline-flex;
align-items: center;
justify-content: center;
width: 50px; /* Larger social buttons */
height: 50px;
background-color: rgba(255, 255, 255, 0.15); /* Slightly more visible background */
border-radius: 8px; /* Square with rounded corners */
color: var(--white);
text-decoration: none;
font-weight: 600;
transition: all 0.3s ease;
font-size: 0.9rem;
}
.social-links a:hover {
background-color: var(--accent);
transform: translateY(-7px); /* More pronounced lift */
}
.copyright {
text-align: center;
padding-top: 2.5rem;
border-top: 1px solid rgba(255, 255, 255, 0.15);
}
.mobile-menu {
display: none;
font-size: 1.5rem;
cursor: pointer;
padding: 0.5rem 1rem;
border: 1px solid rgba(255, 255, 255, 0.3);
border-radius: 5px;
transition: all 0.3s ease;
}
.mobile-menu:hover {
background-color: rgba(255, 255, 255, 0.1);
}
@media (max-width: 992px) {
.about-content {
grid-template-columns: 1fr;
}
.initiatives-grid {
grid-template-columns: repeat(2, 1fr);
}
.footer-content {
grid-template-columns: repeat(2, 1fr);
}
.stats {
grid-template-columns: repeat(2, 1fr);
}
}
@media (max-width: 768px) {
.hero h1 {
font-size: 2.8rem; /* Adjusted for better readability on smaller screens */
}
.hero p {
font-size: 1.2rem; /* Adjusted for better readability on smaller screens */
}
nav ul {
display: none;
position: absolute;
top: 100%;
left: 0;
width: 100%;
background-color: var(--primary);
flex-direction: column;
padding: 1rem 0;
text-align: center;
box-shadow: 0 5px 10px rgba(0, 0, 0, 0.1);
}
nav ul.active {
display: flex;
}
nav ul li {
margin: 0;
padding: 0.8rem 0;
}
.mobile-menu {
display: block;
font-size: 1.2rem; /* Slightly smaller for mobile */
padding: 0.4rem 0.8rem;
}
.initiatives-grid {
grid-template-columns: 1fr;
}
.footer-content {
grid-template-columns: 1fr;
}
.stats {
grid-template-columns: 1fr;
}
.social-links a {
width: 45px; /* Slightly smaller social buttons */
height: 45px;
font-size: 0.85rem;
}
}
/* Animation for stats counter */
.counter {
transition: all 0.5s ease;
}
</style>
</head>
<body>
<!-- Header -->
<header>
<div class="container nav-container">
<div class="logo">
<span>Green Network</span>
</div>
<nav>
<div class="mobile-menu">
Menu
</div>
<ul>
<li><a href="#home">Home</a></li>
<li><a href="#about">About</a></li>
<li><a href="#initiatives">Initiatives</a></li>
<li><a href="#get-involved">Get Involved</a></li>
<li><a href="#contact">Contact</a></li>
</ul>
</nav>
</div>
</header>
<!-- Hero Section -->
<section class="hero" id="home">
<div class="container hero-content">
<h1>Protect Our Planet, Preserve Our Future</h1>
<p>Join the global movement to create a sustainable world through conservation, education, and community action.</p>
<a href="#get-involved" class="btn">Join Our Network</a>
</div>
</section>
<!-- About Section -->
<section id="about">
<div class="container">
<div class="section-title">
<h2>About Green Network</h2>
<p>We are a global community dedicated to environmental protection and sustainable development.</p>
</div>
<div class="about-content">
<div class="about-img">
<img src="https://images.unsplash.com/photo-1507591064344-4c6ce005b128?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=2070&q=80" alt="Team planting trees">
</div>
<div class="about-text">
<h3>Our Mission</h3>
<p>Green Network is committed to creating a sustainable future by protecting natural ecosystems, promoting renewable energy, and empowering communities to take environmental action.</p>
<p>Founded in 2010, we've grown from a small grassroots organization to an international network with over 50,000 members across 120 countries.</p>
<p>Our approach combines scientific research, community engagement, and policy advocacy to address the most pressing environmental challenges of our time.</p>
<a href="#" class="btn">Learn More</a>
</div>
</div>
<div class="stats">
<div class="stat-item">
<h3 class="counter" data-target="2500000">0</h3>
<p>Trees Planted</p>
</div>
<div class="stat-item">
<h3 class="counter" data-target="50000">0</h3>
<p>Active Members</p>
</div>
<div class="stat-item">
<h3 class="counter" data-target="120">0</h3>
<p>Countries Reached</p>
</div>
<div class="stat-item">
<h3 class="counter" data-target="1500">0</h3>
<p>Cleanup Projects</p>
</div>
</div>
</div>
</section>
<!-- Initiatives Section -->
<section class="initiatives" id="initiatives">
<div class="container">
<div class="section-title">
<h2>Our Initiatives</h2>
<p>Discover the key programs and projects we're implementing to protect our planet.</p>
</div>
<div class="initiatives-grid">
<div class="initiative-card">
<div class="initiative-img">
<img src="https://dialogue.earth/content/uploads/2021/04/lessons-from-the-rush-to-reforest-china-dialogue-2400x1599.jpg" alt="Reforestation">
</div>
<div class="initiative-content">
<h3>Global Reforestation</h3>
<p>Planting millions of trees worldwide to restore ecosystems, combat climate change, and protect biodiversity.</p>
<a href="#" class="btn">Learn More</a>
</div>
</div>
<div class="initiative-card">
<div class="initiative-img">
<img src="https://images.unsplash.com/photo-1621451537084-482c73073a0f?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=1974&q=80" alt="Ocean Conservation">
</div>
<div class="initiative-content">
<h3>Ocean Conservation</h3>
<p>Protecting marine ecosystems, reducing plastic pollution, and promoting sustainable fishing practices.</p>
<a href="#" class="btn">Learn More</a>
</div>
</div>
<div class="initiative-card">
<div class="initiative-img">
<img src="https://images.unsplash.com/photo-1508514177221-188b1cf16e9d?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=2072&q=80" alt="Renewable Energy">
</div>
<div class="initiative-content">
<h3>Renewable Energy</h3>
<p>Promoting solar, wind, and other clean energy sources to reduce dependence on fossil fuels.</p>
<a href="#" class="btn">Learn More</a>
</div>
</div>
</div>
</div>
</section>
<!-- CTA Section -->
<section class="cta" id="get-involved">
<div class="container">
<h2>Join Our Global Movement</h2>
<p>Together, we can create a sustainable future for generations to come. Every action counts, no matter how small.</p>
<a href="#" class="btn">Become a Member</a>
</div>
</section>
<!-- Footer -->
<footer id="contact">
<div class="container">
<div class="footer-content">
<div class="footer-column">
<h3>Green Network</h3>
<p>We are dedicated to protecting our planet through collaborative action, education, and sustainable solutions.</p>
<div class="social-links">
<a href="#">Facebook</a>
<a href="#">Twitter</a>
<a href="#">Instagram</a>
<a href="#">LinkedIn</a>
</div>
</div>
<div class="footer-column">
<h3>Quick Links</h3>
<ul class="footer-links">
<li><a href="#home">Home</a></li>
<li><a href="#about">About Us</a></li>
<li><a href="#initiatives">Initiatives</a></li>
<li><a href="#get-involved">Get Involved</a></li>
<li><a href="#contact">Contact</a></li>
</ul>
</div>
<div class="footer-column">
<h3>Our Programs</h3>
<ul class="footer-links">
<li><a href="#">Reforestation</a></li>
<li><a href="#">Ocean Cleanup</a></li>
<li><a href="#">Wildlife Protection</a></li>
<li><a href="#">Climate Education</a></li>
<li><a href="#">Sustainable Agriculture</a></li>
</ul>
</div>
<div class="footer-column">
<h3>Contact Us</h3>
<p>Copper Creek Drive, New York</p>
<p>+1 (312) 171-0771</p>
<p>support@greennetwork.org</p>
</div>
</div>
<div class="copyright">
<p>© 2025 Green Network. All rights reserved.</p>
</div>
</div>
</footer>
<script>
// Mobile Menu Toggle
document.querySelector('.mobile-menu').addEventListener('click', function() {
document.querySelector('nav ul').classList.toggle('active');
});
// Counter Animation
function animateCounters() {
const counters = document.querySelectorAll('.counter');
const speed = 200; // The lower the slower
counters.forEach(counter => {
const target = +counter.getAttribute('data-target');
const count = +counter.innerText;
const inc = target / speed;
if(count < target) {
counter.innerText = Math.ceil(count + inc);
setTimeout(animateCounters, 1);
} else {
counter.innerText = target;
}
});
}
// Initialize counters when page loads
window.addEventListener('load', animateCounters);
// Smooth scrolling for navigation links
document.querySelectorAll('a[href^="#"]').forEach(anchor => {
anchor.addEventListener('click', function(e) {
e.preventDefault();
const targetId = this.getAttribute('href');
if(targetId === '#') return;
const targetElement = document.querySelector(targetId);
if(targetElement) {
window.scrollTo({
top: targetElement.offsetTop - 80,
behavior: 'smooth'
});
document.querySelector('nav ul').classList.remove('active');
}
});
});
</script>
</body>
</html>
那就一切完工,看下都有什么文件:

一切就绪,点击App运行:

那会看到运行完毕,开了7860这个端口

那直接点击左上的myhome链接,就能看到环保页面了。

那大善人huggingface就弄好了。
解释一下具体原理:
huggingface 跑了个前置的Nginx代理,自动申请了证书,代理后端容器的7860端口,为什么是7860端口呢?
因为最常见的用途是托管基于 Gradio 构建的机器学习模型演示。Gradio 是一个非常流行的 Python 库,用于快速创建交互式 Web 界面来展示 ML 模型。它的默认启动端口就是7860。
那接着我们去薅大善人cloudflare,首先弄好一个域名并托管到CF上面,比如免费的qzz.io
点开左边的菜单:Build –> Compute & AI –> Workers & Pages

新建一个应用,Create application

然后选 Start with Hello World!

然后就会建出一个来,点击编辑代码,Edit Code

我们把以下代码贴进去,注意修改域名,只写域名,没有https的前缀,从huggingface得到的免费域名:
把代码中username-spacename.hf.space换成自己的域名
export default {
async fetch(request, env) {
let url = new URL(request.url);
if (url.pathname.startsWith('/')) {
var arrStr = [
'username-spacename.hf.space', // 此处单引号里填写你的节点伪装域名
];
url.protocol = 'https:'
url.hostname = getRandomArray(arrStr)
let new_request = new Request(url, request);
return fetch(new_request);
}
return env.ASSETS.fetch(request);
},
};
function getRandomArray(array) {
const randomIndex = Math.floor(Math.random() * array.length);
return array[randomIndex];
}
然后点 Deploy ,部署
返回这个worker的空间,点击Settings,下面的Domains & Routes ,右边点击 +Add

弹出的对话框,选择Custom domain

然后填入自己心满意足的域名

点击Add domain就完事了。
然后我们打开我们心满意足的域名:

环保页面,然后打开我们的订阅页面,缺省是/sub,当然改成只有自己知道的路径为好
出现订阅的Base64字符就ok了。

我们用v2rayN导入即可。
完工,还是说一下原理:
利用cf大善人的网络代理加速,利用hug大善人的免费域名和证书,达到我们的目的

最后,这个的index.js和上一篇的不同啊,唯一区别就是端口,hug端口肯定是443,而wispbyte的端口是非标的。
注意注意!!!