Merge pull request #889 from SkynetLabs/support-tus-with-multiple-servers-setup
Support tus with multiple servers setup
This commit is contained in:
commit
fbdae038df
|
@ -330,12 +330,13 @@ server {
|
||||||
proxy_request_buffering off; # stream uploaded files through the proxy as it comes in
|
proxy_request_buffering off; # stream uploaded files through the proxy as it comes in
|
||||||
proxy_set_header Expect $http_expect;
|
proxy_set_header Expect $http_expect;
|
||||||
|
|
||||||
|
# rewrite proxy request to use correct host uri from env variable (required to return correct location header)
|
||||||
|
set_by_lua $SKYNET_SERVER_API 'return os.getenv("SKYNET_SERVER_API")';
|
||||||
|
proxy_redirect https://siad $SKYNET_SERVER_API;
|
||||||
|
|
||||||
# proxy /skynet/tus requests to siad endpoint with all arguments
|
# proxy /skynet/tus requests to siad endpoint with all arguments
|
||||||
proxy_pass http://siad;
|
proxy_pass http://siad;
|
||||||
|
|
||||||
# rewrite tus headers to use correct uri
|
|
||||||
proxy_redirect https://siad/ https://$domain.$tld/;
|
|
||||||
|
|
||||||
# extract skylink from base64 encoded upload metadata and assign to a proper header
|
# extract skylink from base64 encoded upload metadata and assign to a proper header
|
||||||
header_filter_by_lua_block {
|
header_filter_by_lua_block {
|
||||||
if ngx.header["Upload-Metadata"] then
|
if ngx.header["Upload-Metadata"] then
|
||||||
|
|
|
@ -13,4 +13,4 @@ more_set_headers 'Access-Control-Allow-Origin: $http_origin';
|
||||||
more_set_headers 'Access-Control-Allow-Credentials: true';
|
more_set_headers 'Access-Control-Allow-Credentials: true';
|
||||||
more_set_headers 'Access-Control-Allow-Methods: GET, POST, HEAD, OPTIONS, PUT, PATCH, DELETE';
|
more_set_headers 'Access-Control-Allow-Methods: GET, POST, HEAD, OPTIONS, PUT, PATCH, DELETE';
|
||||||
more_set_headers 'Access-Control-Allow-Headers: DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,X-HTTP-Method-Override,upload-offset,upload-metadata,upload-length,tus-version,tus-resumable,tus-extension,tus-max-size,location';
|
more_set_headers 'Access-Control-Allow-Headers: DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,X-HTTP-Method-Override,upload-offset,upload-metadata,upload-length,tus-version,tus-resumable,tus-extension,tus-max-size,location';
|
||||||
more_set_headers 'Access-Control-Expose-Headers: Content-Length,Content-Range,Skynet-File-Metadata,Skynet-Skylink,Skynet-Portal-Api,upload-offset,upload-metadata,upload-length,tus-version,tus-resumable,tus-extension,tus-max-size,location';
|
more_set_headers 'Access-Control-Expose-Headers: Content-Length,Content-Range,Skynet-File-Metadata,Skynet-Skylink,Skynet-Portal-Api,Skynet-Server-Api,upload-offset,upload-metadata,upload-length,tus-version,tus-resumable,tus-extension,tus-max-size,location';
|
||||||
|
|
|
@ -25,8 +25,10 @@ worker_processes 1;
|
||||||
|
|
||||||
#pid logs/nginx.pid;
|
#pid logs/nginx.pid;
|
||||||
|
|
||||||
env SKYNET_PORTAL_API; # declare env variable to use it in config
|
# declare env variables to use it in config
|
||||||
env ACCOUNTS_ENABLED; # declare env variable to use it in config
|
env SKYNET_PORTAL_API;
|
||||||
|
env SKYNET_SERVER_API;
|
||||||
|
env ACCOUNTS_ENABLED;
|
||||||
|
|
||||||
events {
|
events {
|
||||||
worker_connections 1024;
|
worker_connections 1024;
|
||||||
|
@ -64,8 +66,11 @@ http {
|
||||||
|
|
||||||
#gzip on;
|
#gzip on;
|
||||||
|
|
||||||
# include skynet-portal-api header on every request
|
# include skynet-portal-api and skynet-server-api header on every request
|
||||||
header_filter_by_lua 'ngx.header["Skynet-Portal-Api"] = os.getenv("SKYNET_PORTAL_API")';
|
header_filter_by_lua_block {
|
||||||
|
ngx.header["Skynet-Portal-Api"] = os.getenv("SKYNET_PORTAL_API")
|
||||||
|
ngx.header["Skynet-Server-Api"] = os.getenv("SKYNET_SERVER_API")
|
||||||
|
}
|
||||||
|
|
||||||
include /etc/nginx/conf.d/*.conf;
|
include /etc/nginx/conf.d/*.conf;
|
||||||
include /etc/nginx/conf.extra.d/*.conf;
|
include /etc/nginx/conf.extra.d/*.conf;
|
||||||
|
|
|
@ -33,35 +33,60 @@ async function uploadCheck(done) {
|
||||||
|
|
||||||
// websiteCheck checks whether the main website is working
|
// websiteCheck checks whether the main website is working
|
||||||
async function websiteCheck(done) {
|
async function websiteCheck(done) {
|
||||||
return genericAccessCheck("website", process.env.SKYNET_PORTAL_API, done);
|
return done(await genericAccessCheck("website", process.env.SKYNET_PORTAL_API));
|
||||||
}
|
}
|
||||||
|
|
||||||
// downloadCheck returns the result of downloading the hard coded link
|
// downloadCheck returns the result of downloading the hard coded link
|
||||||
async function downloadCheck(done) {
|
async function downloadCheck(done) {
|
||||||
const url = await skynetClient.getSkylinkUrl(exampleSkylink);
|
const url = await skynetClient.getSkylinkUrl(exampleSkylink);
|
||||||
|
|
||||||
return genericAccessCheck("skylink", url, done);
|
return done(await genericAccessCheck("skylink", url));
|
||||||
}
|
}
|
||||||
|
|
||||||
// skylinkSubdomainCheck returns the result of downloading the hard coded link via subdomain
|
// skylinkSubdomainCheck returns the result of downloading the hard coded link via subdomain
|
||||||
async function skylinkSubdomainCheck(done) {
|
async function skylinkSubdomainCheck(done) {
|
||||||
const url = await skynetClient.getSkylinkUrl(exampleSkylink, { subdomain: true });
|
const url = await skynetClient.getSkylinkUrl(exampleSkylink, { subdomain: true });
|
||||||
|
|
||||||
return genericAccessCheck("skylink_via_subdomain", url, done);
|
return done(await genericAccessCheck("skylink_via_subdomain", url));
|
||||||
}
|
}
|
||||||
|
|
||||||
// handshakeSubdomainCheck returns the result of downloading the skylink via handshake domain
|
// handshakeSubdomainCheck returns the result of downloading the skylink via handshake domain
|
||||||
async function handshakeSubdomainCheck(done) {
|
async function handshakeSubdomainCheck(done) {
|
||||||
const url = await skynetClient.getHnsUrl("note-to-self", { subdomain: true });
|
const url = await skynetClient.getHnsUrl("note-to-self", { subdomain: true });
|
||||||
|
|
||||||
return genericAccessCheck("hns_via_subdomain", url, done);
|
return done(await genericAccessCheck("hns_via_subdomain", url));
|
||||||
}
|
}
|
||||||
|
|
||||||
// accountWebsiteCheck returns the result of accessing account dashboard website
|
// accountWebsiteCheck returns the result of accessing account dashboard website
|
||||||
async function accountWebsiteCheck(done) {
|
async function accountWebsiteCheck(done) {
|
||||||
const url = `${process.env.SKYNET_DASHBOARD_URL}/auth/login`;
|
const url = `${process.env.SKYNET_DASHBOARD_URL}/auth/login`;
|
||||||
|
|
||||||
return genericAccessCheck("account_website", url, done);
|
return done(await genericAccessCheck("account_website", url));
|
||||||
|
}
|
||||||
|
|
||||||
|
// directServerApiAccessCheck returns the basic server api check on direct server address
|
||||||
|
async function directServerApiAccessCheck(done) {
|
||||||
|
if (!process.env.SKYNET_SERVER_API) {
|
||||||
|
return done({ up: false, info: { message: "SKYNET_SERVER_API env variable not configured" } });
|
||||||
|
}
|
||||||
|
|
||||||
|
const [domainAccessCheck, directAccessCheck] = await Promise.all([
|
||||||
|
genericAccessCheck("portal_api_access", process.env.SKYNET_PORTAL_API),
|
||||||
|
genericAccessCheck("direct_server_api_access", process.env.SKYNET_SERVER_API),
|
||||||
|
]);
|
||||||
|
|
||||||
|
if (domainAccessCheck.ip !== directAccessCheck.ip) {
|
||||||
|
directAccessCheck.up = false;
|
||||||
|
directAccessCheck.info = {
|
||||||
|
message: "Access ip mismatch between domain and direct access",
|
||||||
|
response: {
|
||||||
|
domain: { name: process.env.SKYNET_PORTAL_API, ip: domainAccessCheck.ip },
|
||||||
|
domain: { name: process.env.SKYNET_SERVER_API, ip: directAccessCheck.ip },
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return done(directAccessCheck);
|
||||||
}
|
}
|
||||||
|
|
||||||
// accountHealthCheck returns the result of accounts service health checks
|
// accountHealthCheck returns the result of accounts service health checks
|
||||||
|
@ -86,7 +111,7 @@ async function accountHealthCheck(done) {
|
||||||
done({ name: "accounts", time: calculateElapsedTime(time), ...data });
|
done({ name: "accounts", time: calculateElapsedTime(time), ...data });
|
||||||
}
|
}
|
||||||
|
|
||||||
async function genericAccessCheck(name, url, done) {
|
async function genericAccessCheck(name, url) {
|
||||||
const time = process.hrtime();
|
const time = process.hrtime();
|
||||||
const data = { up: false, url };
|
const data = { up: false, url };
|
||||||
|
|
||||||
|
@ -103,10 +128,17 @@ async function genericAccessCheck(name, url, done) {
|
||||||
data.ip = error?.response?.ip ?? null;
|
data.ip = error?.response?.ip ?? null;
|
||||||
}
|
}
|
||||||
|
|
||||||
done({ name, time: calculateElapsedTime(time), ...data });
|
return { name, time: calculateElapsedTime(time), ...data };
|
||||||
}
|
}
|
||||||
|
|
||||||
const checks = [uploadCheck, websiteCheck, downloadCheck, skylinkSubdomainCheck, handshakeSubdomainCheck];
|
const checks = [
|
||||||
|
uploadCheck,
|
||||||
|
websiteCheck,
|
||||||
|
downloadCheck,
|
||||||
|
skylinkSubdomainCheck,
|
||||||
|
handshakeSubdomainCheck,
|
||||||
|
directServerApiAccessCheck,
|
||||||
|
];
|
||||||
|
|
||||||
if (process.env.ACCOUNTS_ENABLED === "1") {
|
if (process.env.ACCOUNTS_ENABLED === "1") {
|
||||||
checks.push(accountHealthCheck, accountWebsiteCheck);
|
checks.push(accountHealthCheck, accountWebsiteCheck);
|
||||||
|
|
|
@ -53,7 +53,7 @@ def setup():
|
||||||
bot_token = os.environ["DISCORD_BOT_TOKEN"]
|
bot_token = os.environ["DISCORD_BOT_TOKEN"]
|
||||||
|
|
||||||
global portal_name
|
global portal_name
|
||||||
portal_name = os.getenv("PORTAL_NAME")
|
portal_name = os.getenv("SKYNET_SERVER_API")
|
||||||
|
|
||||||
# Get a port or use default
|
# Get a port or use default
|
||||||
global port
|
global port
|
||||||
|
|
|
@ -22,15 +22,16 @@ docker-compose --version # sanity check
|
||||||
|
|
||||||
# Create dummy .env file for docker-compose usage with variables
|
# Create dummy .env file for docker-compose usage with variables
|
||||||
# * SSL_CERTIFICATE_STRING - certificate string that will be used to generate ssl certificates, read more in docker/caddy/Caddyfile
|
# * SSL_CERTIFICATE_STRING - certificate string that will be used to generate ssl certificates, read more in docker/caddy/Caddyfile
|
||||||
# * SKYNET_PORTAL_API - absolute url to the portal api ie. https://example.com
|
# * SKYNET_PORTAL_API - absolute url to the portal api ie. https://siasky.net (general portal address)
|
||||||
# * SKYNET_DASHBOARD_URL - (optional) absolute url to the portal dashboard ie. https://account.example.com
|
# * SKYNET_SERVER_API - absolute url to the server api ie. https://eu-ger-1.siasky.net (direct server address, if this is single server portal use the same address as SKYNET_PORTAL_API)
|
||||||
|
# * SKYNET_DASHBOARD_URL - (optional) absolute url to the portal dashboard ie. https://account.siasky.net
|
||||||
# * EMAIL_ADDRESS - this is the administrator contact email you need to supply for communication regarding SSL certification
|
# * EMAIL_ADDRESS - this is the administrator contact email you need to supply for communication regarding SSL certification
|
||||||
# * HSD_API_KEY - this is auto generated secure key for your handshake service integration
|
# * HSD_API_KEY - this is auto generated secure key for your handshake service integration
|
||||||
# * CLOUDFLARE_AUTH_TOKEN - (optional) if using cloudflare as dns loadbalancer (need to change it in Caddyfile too)
|
# * CLOUDFLARE_AUTH_TOKEN - (optional) if using cloudflare as dns loadbalancer (need to change it in Caddyfile too)
|
||||||
# * AWS_ACCESS_KEY_ID - (optional) if using route53 as a dns loadbalancer
|
# * AWS_ACCESS_KEY_ID - (optional) if using route53 as a dns loadbalancer
|
||||||
# * AWS_SECRET_ACCESS_KEY - (optional) if using route53 as a dns loadbalancer
|
# * AWS_SECRET_ACCESS_KEY - (optional) if using route53 as a dns loadbalancer
|
||||||
# * API_PORT - (optional) the port on which siad is listening, defaults to 9980
|
# * API_PORT - (optional) the port on which siad is listening, defaults to 9980
|
||||||
# * PORTAL_NAME - the name of the portal, required by the discord bot
|
# * PORTAL_NAME - a string representing name of your portal e.g. `siasky.xyz` or `my skynet portal` (internal use only)
|
||||||
# * DISCORD_BOT_TOKEN - (optional) only required if you're using the discord notifications integration
|
# * DISCORD_BOT_TOKEN - (optional) only required if you're using the discord notifications integration
|
||||||
# * SKYNET_DB_USER - (optional) if using `accounts` this is the MongoDB username
|
# * SKYNET_DB_USER - (optional) if using `accounts` this is the MongoDB username
|
||||||
# * SKYNET_DB_PASS - (optional) if using `accounts` this is the MongoDB password
|
# * SKYNET_DB_PASS - (optional) if using `accounts` this is the MongoDB password
|
||||||
|
@ -43,7 +44,7 @@ docker-compose --version # sanity check
|
||||||
# * CR_CLUSTER_NODES - (optional) if using `accounts` the list of servers (with ports) which make up your CockroachDB cluster, e.g. `helsinki.siasky.net:26257,germany.siasky.net:26257,us-east.siasky.net:26257`
|
# * CR_CLUSTER_NODES - (optional) if using `accounts` the list of servers (with ports) which make up your CockroachDB cluster, e.g. `helsinki.siasky.net:26257,germany.siasky.net:26257,us-east.siasky.net:26257`
|
||||||
if ! [ -f /home/user/skynet-webportal/.env ]; then
|
if ! [ -f /home/user/skynet-webportal/.env ]; then
|
||||||
HSD_API_KEY=$(openssl rand -base64 32) # generate safe random key for handshake
|
HSD_API_KEY=$(openssl rand -base64 32) # generate safe random key for handshake
|
||||||
printf "SSL_CERTIFICATE_STRING=example.com, *.example.com, *.hns.example.com\nSKYNET_PORTAL_API=https://example.com\nSKYNET_DASHBOARD_URL=https://account.example.com\nEMAIL_ADDRESS=email@example.com\nSIA_WALLET_PASSWORD=\nHSD_API_KEY=${HSD_API_KEY}\nCLOUDFLARE_AUTH_TOKEN=\nAWS_ACCESS_KEY_ID=\nAWS_SECRET_ACCESS_KEY=\nPORTAL_NAME=\nDISCORD_BOT_TOKEN=\n" > /home/user/skynet-webportal/.env
|
printf "SSL_CERTIFICATE_STRING=siasky.net, *.siasky.net, *.hns.siasky.net\nSKYNET_PORTAL_API=https://siasky.net\nSKYNET_SERVER_API=https://eu-dc-1.siasky.net\nSKYNET_DASHBOARD_URL=https://account.example.com\nEMAIL_ADDRESS=email@example.com\nSIA_WALLET_PASSWORD=\nHSD_API_KEY=${HSD_API_KEY}\nCLOUDFLARE_AUTH_TOKEN=\nAWS_ACCESS_KEY_ID=\nAWS_SECRET_ACCESS_KEY=\nPORTAL_NAME=\nDISCORD_BOT_TOKEN=\n" > /home/user/skynet-webportal/.env
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Start docker container with nginx and client
|
# Start docker container with nginx and client
|
||||||
|
|
Reference in New Issue