Arvancloud Edge Computing: An Unmatched Experience of Speed and Security
Free SSL Certificate
All domains added to the Edge Computing platform automatically receive free SSL certificates.
Fast and Easy Setup
With the Arvancloud panel or CLI, launch and deploy your business’s online services in less than 30 seconds.
Optimized Performance
All your business code is hosted on Arvancloud CDN PoPs and executed from the nearest point to the user.
High Security
Enjoy Arvancloud’s advanced CDN security features to develop your services in a safe and reliable environment.
Develop Your Online Services with Super Advanced Features
Serverless Solution
You can develop your online services without the need for a cloud or virtual server, and run the content from the nearest point to the user.
High Scalability
Use the unlimited resources of the content delivery network without server load balancing, or distribute traffic across multiple PoPs.
One-Click Deployment
With ready-to-use codes and templates, you can deploy your service with just one click and customize features based on your needs.
Cost-Effective
Deploying applications with Arvancloud Edge Computing allows you to deliver your services to users at minimal cost.
Debug Before Release
Easily edit and debug your final versions with the Console Log before launching your website or application to the public.
Quick Replies
With Arvancloud Edge Computing, respond to user requests from the nearest location, and boost your service delivery speed.
Over 40
99.99%
500 Million
Develop functional services with just a single click.
Round Robin Load balancer
Hotlink Protection
Basic Auth
SSR HTMX
With Round Robin Load Balancer, your incoming requests are evenly distributed across multiple servers. This offers balanced traffic distribution and better performance, and helps you remain available and stable under heavy traffic conditions.
View
'use strict';
// Upstream URLs
const UPSTREAM_URLS = [
new URL("http://localhost:4000"),
new URL("http://localhost:4001"),
new URL("http://localhost:4002"),
new URL("http://localhost:4003"),
];
let NEXT_UPSTREAM_INDEX = 0;
async function handleRequest(request) {
let upstreamIdx = NEXT_UPSTREAM_INDEX;
NEXT_UPSTREAM_INDEX = (NEXT_UPSTREAM_INDEX + 1) % UPSTREAM_URLS.length;
let upstream = UPSTREAM_URLS[upstreamIdx];
return await doRequest(request, upstream);
}
function doRequest(request, upstream) {
let newUrl = new URL(request.url);
newUrl.protocol = upstream.protocol;
newUrl.host = upstream.host;
let newReq = new Request(newUrl.toString(), request);
return fetch(newReq);
}
addEventListener("fetch", (event) => {
event.respondWith(handleRequest(event.request));
});
By enabling Hotlink Protection, you can protect your website images, videos, etc. from being misused on other websites. This not only reduces bandwidth consumption and costs but also improves your service’s security and protects your content.
View
'use strict';
// Your domains that is allowed to access hotlinks
const DOMAINS = ["time.ir", "fa.wikipedia.org"];
// Upstream url
const UPSTREAM_URL = "http://localhost:4000";
// File extensions that hotlink is against
const EXTENSIONS = ["jpg", "jpeg", "png", "ico", "gif"];
async function handleRequest(request) {
const fileExt = extractUrlFileExtension(request.url);
if (fileExt == null || !EXTENSIONS_SET.has(fileExt)) {
return await doRequest(request);
}
else {
return await checkReferrerAndDoRequest(request);
}
}
async function doRequest(request) {
let newUrl = new URL(request.url);
newUrl.protocol = UPSTREAM_PROTOCOL;
newUrl.host = UPSTREAM_HOST;
let newReq = new Request(newUrl.toString(), request);
return fetch(newReq);
}
async function checkReferrerAndDoRequest(request) {
let response;
const referrerHeader = request.headers.get("referer");
if (referrerHeader != null) {
let domain = extractDomainFromReferrer(referrerHeader);
if (domain == null || DOMAINS_SET.has(domain)) {
response = await doRequest(request);
}
else {
response = UNAUTHORIZED_RESPONSE;
}
}
else {
response = await doRequest(request);
}
return response;
}
function extractDomainFromReferrer(referrer) {
try {
return new URL(referrer).hostname;
}
catch (e) {
return null;
}
}
function extractUrlFileExtension(url) {
try {
let pathname = new URL(url).pathname;
let lastDotIdx = pathname.lastIndexOf(".");
if (lastDotIdx == -1) {
return null;
}
else {
return pathname.substring(1 + lastDotIdx);
}
}
catch (e) {
return null;
}
}
const DOMAINS_SET = (() => {
const set = new Set();
DOMAINS.forEach((i) => set.add(i));
return set;
})();
const EXTENSIONS_SET = (() => {
const set = new Set();
EXTENSIONS.forEach((i) => set.add(i));
return set;
})();
const UNAUTHORIZED_RESPONSE = new Response(null, {
status: 401,
});
const UPSTREAM_PROTOCOL = new URL(UPSTREAM_URL).protocol;
const UPSTREAM_HOST = new URL(UPSTREAM_URL).host;
addEventListener("fetch", (event) => {
event.respondWith(handleRequest(event.request));
});
The Basic Auth template allows you to easily control access to protected sections of your website with a simple username and password. This script is quick to implement and meets your service’s basic security needs.
View
'use strict';
// Credentials for users
const UserPassList = [{ user: "admin", pass: "adminpass" }];
// Upstream url
const UPSTREAM_URL = "http://localhost:4000";
async function handleRequest(request) {
const authHeader = request.headers.get("Authorization");
let response;
if (authHeader != null && authHeader.startsWith("Basic")) {
let encodedCredential = authHeader.substring(6);
if (CREDENTIALS.has(encodedCredential)) {
let newUrl = new URL(request.url);
newUrl.protocol = UPSTREAM_PROTOCOL;
newUrl.host = UPSTREAM_HOST;
let newReq = new Request(newUrl.toString(), request);
newReq.headers.delete("Authorization");
response = await fetch(newReq);
}
else {
response = UNAUTHORIZED_INVALID_CREDENTIALS_RESPONSE;
}
}
else {
response = UNAUTHORIZED_NEEDS_LOGIN_RESPONSE;
}
return response;
}
const UNAUTHORIZED_NEEDS_LOGIN_RESPONSE = new Response(null, {
//TODO: Add realm and/or charset if needed
headers: new Headers({
"WWW-Authenticate": "Basic",
}),
status: 401,
});
const UNAUTHORIZED_INVALID_CREDENTIALS_RESPONSE = new Response(null, {
status: 401,
});
// Key: Base64 encoded username:password
// Value: username
const CREDENTIALS = (() => {
const map = new Map();
for (let i of UserPassList) {
// TODO: this may not properly work with utf8
const encoded = btoa(`${i.user}:${i.pass}`);
map.set(encoded, i.user);
}
return map;
})();
const UPSTREAM_PROTOCOL = new URL(UPSTREAM_URL).protocol;
const UPSTREAM_HOST = new URL(UPSTREAM_URL).host;
addEventListener("fetch", (event) => {
event.respondWith(handleRequest(event.request));
});
With the Server-Side Rendering template in HTMX, you can dynamically render web pages from the server and update various sections without a full page reload. This will help improve loading speed and user experience.
View
'use strict';
const TODO_LIST = ["test"];
function createDb() {
return {
add: async (title) => {
TODO_LIST.push(title);
},
list: async () => TODO_LIST,
};
}
const DefaultDB = createDb();
var Index = "<!DOCTYPE html>\n<html lang=\"en\">\n\n<head>\n <title>Todo list</title>\n <script src=\"https://unpkg.com/htmx.org@1.9.5\"></script>\n <link rel=\"stylesheet\" href=\"/styles.css\">\n</head>\n\n<body>\n <div>\n <div>\n <h1>To-Do List</h1>\n </div>\n <form hx-post=\"/add\" hx-target=\"#list\" hx-swap=\"beforeend\">\n <div>\n <input type=\"text\" placeholder=\"Task title\" name=\"title\" required />\n <button type=\"submit\">Add</button>\n </div>\n </form>\n <div id=\"list\" hx-get=\"/list\" hx-trigger=\"load\"></div>\n </div>\n</body>\n\n</html>";
var Styles = "h1 {\n color: red;\n}\n";
async function handleRequest(request) {
// simple router:
let content = "";
const url = new URL(request.url);
switch (url.pathname) {
case "/":
content = Index;
break;
case "/styles.css":
return new Response(Styles, {
headers: { "Content-Type": "text/css" },
});
case "/add":
const data = await request.formData();
const title = data.get("title").toString();
await DefaultDB.add(title);
content = `<li>${title}</li>`;
break;
case "/list":
content = (await DefaultDB.list()).map((x) => `<li>${x}</li>`).join("");
break;
default:
content = "Not found :(";
}
if (request.url)
return new Response(content, {
headers: { "Content-Type": "text/html; charset=utf-8" },
});
}
addEventListener("fetch", (event) => {
event.respondWith(handleRequest(event.request));
});