-
-
Notifications
You must be signed in to change notification settings - Fork 5.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1427 from louislam/cloudflared
Built-in ease-to-use reverse proxy with Cloudflare Tunnel
- Loading branch information
Showing
10 changed files
with
329 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,12 +1,26 @@ | ||
# DON'T UPDATE TO node:14-bullseye-slim, see #372. | ||
# If the image changed, the second stage image should be changed too | ||
FROM node:16-buster-slim | ||
ARG TARGETPLATFORM | ||
|
||
WORKDIR /app | ||
|
||
# Install Curl | ||
# Install Apprise, add sqlite3 cli for debugging in the future, iputils-ping for ping, util-linux for setpriv | ||
# Stupid python3 and python3-pip actually install a lot of useless things into Debian, specify --no-install-recommends to skip them, make the base even smaller than alpine! | ||
RUN apt update && \ | ||
apt --yes --no-install-recommends install python3 python3-pip python3-cryptography python3-six python3-yaml python3-click python3-markdown python3-requests python3-requests-oauthlib \ | ||
sqlite3 iputils-ping util-linux dumb-init && \ | ||
pip3 --no-cache-dir install apprise==0.9.7 && \ | ||
rm -rf /var/lib/apt/lists/* | ||
|
||
# Install cloudflared | ||
# dpkg --add-architecture arm: cloudflared do not provide armhf, this is workaround. Read more: https://github.com/cloudflare/cloudflared/issues/583 | ||
COPY extra/download-cloudflared.js ./extra/download-cloudflared.js | ||
RUN node ./extra/download-cloudflared.js $TARGETPLATFORM && \ | ||
dpkg --add-architecture arm && \ | ||
apt update && \ | ||
apt --yes --no-install-recommends install ./cloudflared.deb && \ | ||
rm -rf /var/lib/apt/lists/* && \ | ||
rm -f cloudflared.deb | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
// | ||
|
||
const http = require("https"); // or 'https' for https:// URLs | ||
const fs = require("fs"); | ||
|
||
const platform = process.argv[2]; | ||
|
||
if (!platform) { | ||
console.error("No platform??"); | ||
process.exit(1); | ||
} | ||
|
||
let arch = null; | ||
|
||
if (platform === "linux/amd64") { | ||
arch = "amd64"; | ||
} else if (platform === "linux/arm64") { | ||
arch = "arm64"; | ||
} else if (platform === "linux/arm/v7") { | ||
arch = "arm"; | ||
} else { | ||
console.error("Invalid platform?? " + platform); | ||
} | ||
|
||
const file = fs.createWriteStream("cloudflared.deb"); | ||
get("https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-" + arch + ".deb"); | ||
|
||
function get(url) { | ||
http.get(url, function (res) { | ||
if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) { | ||
console.log("Redirect to " + res.headers.location); | ||
get(res.headers.location); | ||
} else if (res.statusCode >= 200 && res.statusCode < 300) { | ||
res.pipe(file); | ||
|
||
res.on("end", function () { | ||
console.log("Downloaded"); | ||
}); | ||
} else { | ||
console.error(res.statusCode); | ||
process.exit(1); | ||
} | ||
}); | ||
} |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
const { checkLogin, setSetting, setting, doubleCheckPassword } = require("../util-server"); | ||
const { CloudflaredTunnel } = require("node-cloudflared-tunnel"); | ||
const { io } = require("../server"); | ||
|
||
const prefix = "cloudflared_"; | ||
const cloudflared = new CloudflaredTunnel(); | ||
|
||
cloudflared.change = (running, message) => { | ||
io.to("cloudflared").emit(prefix + "running", running); | ||
io.to("cloudflared").emit(prefix + "message", message); | ||
}; | ||
|
||
cloudflared.error = (errorMessage) => { | ||
io.to("cloudflared").emit(prefix + "errorMessage", errorMessage); | ||
}; | ||
|
||
module.exports.cloudflaredSocketHandler = (socket) => { | ||
|
||
socket.on(prefix + "join", async () => { | ||
try { | ||
checkLogin(socket); | ||
socket.join("cloudflared"); | ||
io.to(socket.userID).emit(prefix + "installed", cloudflared.checkInstalled()); | ||
io.to(socket.userID).emit(prefix + "running", cloudflared.running); | ||
io.to(socket.userID).emit(prefix + "token", await setting("cloudflaredTunnelToken")); | ||
} catch (error) { } | ||
}); | ||
|
||
socket.on(prefix + "leave", async () => { | ||
try { | ||
checkLogin(socket); | ||
socket.leave("cloudflared"); | ||
} catch (error) { } | ||
}); | ||
|
||
socket.on(prefix + "start", async (token) => { | ||
try { | ||
checkLogin(socket); | ||
if (token && typeof token === "string") { | ||
cloudflared.token = token; | ||
} else { | ||
cloudflared.token = null; | ||
} | ||
cloudflared.start(); | ||
} catch (error) { } | ||
}); | ||
|
||
socket.on(prefix + "stop", async (currentPassword, callback) => { | ||
try { | ||
checkLogin(socket); | ||
await doubleCheckPassword(socket, currentPassword); | ||
cloudflared.stop(); | ||
} catch (error) { | ||
callback({ | ||
ok: false, | ||
msg: error.message, | ||
}); | ||
} | ||
}); | ||
|
||
socket.on(prefix + "removeToken", async () => { | ||
try { | ||
checkLogin(socket); | ||
await setSetting("cloudflaredTunnelToken", ""); | ||
} catch (error) { } | ||
}); | ||
|
||
}; | ||
|
||
module.exports.autoStart = async (token) => { | ||
if (!token) { | ||
token = await setting("cloudflaredTunnelToken"); | ||
} else { | ||
// Override the current token via args or env var | ||
await setSetting("cloudflaredTunnelToken", token); | ||
console.log("Use cloudflared token from args or env var"); | ||
} | ||
|
||
if (token) { | ||
console.log("Start cloudflared"); | ||
cloudflared.token = token; | ||
cloudflared.start(); | ||
} | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,139 @@ | ||
<template> | ||
<div> | ||
<h4 class="mt-4">Cloudflare Tunnel</h4> | ||
|
||
<div class="my-3"> | ||
<div> | ||
cloudflared: | ||
<span v-if="installed === true" class="text-primary">{{ $t("Installed") }}</span> | ||
<span v-else-if="installed === false" class="text-danger">{{ $t("Not installed") }}</span> | ||
</div> | ||
|
||
<div> | ||
{{ $t("Status") }}: | ||
<span v-if="running" class="text-primary">{{ $t("Running") }}</span> | ||
<span v-else-if="!running" class="text-danger">{{ $t("Not running") }}</span> | ||
</div> | ||
|
||
<div v-if="false"> | ||
{{ message }} | ||
</div> | ||
|
||
<div v-if="errorMessage" class="mt-3"> | ||
Message: | ||
<textarea v-model="errorMessage" class="form-control" readonly></textarea> | ||
</div> | ||
|
||
<p v-if="installed === false">(Download cloudflared from <a href="https://developers.cloudflare.com/cloudflare-one/connections/connect-apps/install-and-setup/installation/">Cloudflare Website</a>)</p> | ||
</div> | ||
|
||
<!-- If installed show token input --> | ||
<div v-if="installed" class="mb-2"> | ||
<div class="mb-4"> | ||
<label class="form-label" for="cloudflareTunnelToken"> | ||
Cloudflare Tunnel {{ $t("Token") }} | ||
</label> | ||
<HiddenInput | ||
id="cloudflareTunnelToken" | ||
v-model="cloudflareTunnelToken" | ||
autocomplete="one-time-code" | ||
:readonly="running" | ||
/> | ||
<div class="form-text"> | ||
<div v-if="cloudflareTunnelToken" class="mb-3"> | ||
<span v-if="!running" class="remove-token" @click="removeToken">{{ $t("Remove Token") }}</span> | ||
</div> | ||
|
||
Don't know how to get the token? Please read the guide:<br /> | ||
<a href="https://github.com/louislam/uptime-kuma/wiki/Reverse-Proxy-with-Cloudflare-Tunnel" target="_blank"> | ||
https://github.com/louislam/uptime-kuma/wiki/Reverse-Proxy-with-Cloudflare-Tunnel | ||
</a> | ||
</div> | ||
</div> | ||
|
||
<div> | ||
<button v-if="!running" class="btn btn-primary" type="submit" @click="start"> | ||
{{ $t("Start") }} cloudflared | ||
</button> | ||
|
||
<button v-if="running" class="btn btn-danger" type="submit" @click="$refs.confirmStop.show();"> | ||
{{ $t("Stop") }} cloudflared | ||
</button> | ||
|
||
<Confirm ref="confirmStop" btn-style="btn-danger" :yes-text="$t('Stop') + ' cloudflared'" :no-text="$t('Cancel')" @yes="stop"> | ||
The current connection may be lost if you are currently connecting via Cloudflare Tunnel. Are you sure want to stop it? Type your current password to confirm it. | ||
|
||
<div class="mt-3"> | ||
<label for="current-password2" class="form-label"> | ||
{{ $t("Current Password") }} | ||
</label> | ||
<input | ||
id="current-password2" | ||
v-model="currentPassword" | ||
type="password" | ||
class="form-control" | ||
required | ||
/> | ||
</div> | ||
</Confirm> | ||
</div> | ||
</div> | ||
|
||
<h4 class="mt-4">Other Software</h4> | ||
<div> | ||
For example: nginx, Apache and Traefik. <br /> | ||
Please read <a href="https://github.com/louislam/uptime-kuma/wiki/Reverse-Proxy" target="_blank">https://github.com/louislam/uptime-kuma/wiki/Reverse-Proxy</a>. | ||
</div> | ||
</div> | ||
</template> | ||
|
||
<script> | ||
import HiddenInput from "../../components/HiddenInput.vue"; | ||
import Confirm from "../Confirm.vue"; | ||
const prefix = "cloudflared_"; | ||
export default { | ||
components: { | ||
HiddenInput, | ||
Confirm | ||
}, | ||
data() { | ||
// See /src/mixins/socket.js | ||
return this.$root.cloudflared; | ||
}, | ||
computed: { | ||
}, | ||
watch: { | ||
}, | ||
created() { | ||
this.$root.getSocket().emit(prefix + "join"); | ||
}, | ||
unmounted() { | ||
this.$root.getSocket().emit(prefix + "leave"); | ||
}, | ||
methods: { | ||
start() { | ||
this.$root.getSocket().emit(prefix + "start", this.cloudflareTunnelToken); | ||
}, | ||
stop() { | ||
this.$root.getSocket().emit(prefix + "stop", this.currentPassword, (res) => { | ||
this.$root.toastRes(res); | ||
}); | ||
}, | ||
removeToken() { | ||
this.$root.getSocket().emit(prefix + "removeToken"); | ||
this.cloudflareTunnelToken = ""; | ||
} | ||
} | ||
}; | ||
</script> | ||
|
||
<style lang="scss" scoped> | ||
.remove-token { | ||
text-decoration: underline; | ||
cursor: pointer; | ||
} | ||
</style> |
Oops, something went wrong.