Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

allow https:// and wss:// servers #72

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,25 @@ Note: `./assets` is assumed to be the default asset directory. If you'd like to

Once the content server is available, you can use it by launching your local or dedicated server with `+set fs_cdn <server_address>`.

## Running Secure Servers (Content, Dedicated, and Web) Quick-Start

1. Follow the [baseq3 server, step-by-step](#baseq3-server-step-by-step) instructions to initialize your repo, get `base/` assets and start a dedicated server config.
2. Set up your `./assets` directory for the content server using the instructions in [Running a content server](#running-a-content-server).
3. Point all the `bin/*_secure.json` configs to your key and cert (if you don't already have some, you can get some for free using [certbot](https://certbot.eff.org/)). Also make sure to point the `web_secure.json` to your own domain for the content server.
4. `node bin/content.js --config ./content_secure.json`
5. `node build/ioq3ded_secure.js +set dedicated 1 +set fs_cdn <your_domain>:9000 +set fs_game baseq3 +exec server.cfg`
6. `node bin/wssproxy.js --config ./wssproxy.json`
7. `node bin/web.js --config ./web.json` (you may want to customize this server config so it serves on port 443)

You now have a content server running securely on port 9000, a dedicated server on (insecure) port 27960 (this one should be kept private, behind a firewall), a wss:// proxy running securely on port 27961, and a secure web server running on (ideally) port 443. Make sure ports 443, 9000, and 27961 are forwarded through your firewall so clients can connect to them.

Now you (and others) can connect to your secure dedicated server at `https://<SERVER_DOMAIN>/play?connect%20<SERVER_DOMAIN>:27961`, replacing `<SERVER_DOMAIN>` with the domain of your server (must match your SSL certificate).

### Notes

* Secure and insecure servers are incompatible. A secure web server cannot talk to an insecure content server, a secure content server cannot talk to an insecure dedicated server, etc.
* Master servers cannot work securely since they use IP addresses directly, so the browser would be unable to validate the SSL certificate. You can only connect directly to a known secure dedicated server using the URL above.

## License

MIT
19 changes: 16 additions & 3 deletions bin/content.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ var crc32 = require('buffer-crc32');
var express = require('express');
var fs = require('fs');
var http = require('http');
var https = require('https');
var logger = require('winston');
var opt = require('optimist');
var path = require('path');
Expand Down Expand Up @@ -161,11 +162,23 @@ function loadConfig(configPath) {
currentManifestTimestamp = new Date();
currentManifest = manifest;

// start listening
var server = http.createServer(app);
var server = null;
var serverType = null;
if (secure = config.key !== undefined && config.cert !== undefined) {
const opts = {
key: fs.readFileSync(config.key),
cert: fs.readFileSync(config.cert)
};
server = https.createServer(opts, app);
serverType = 'https';
} else {
server = http.createServer(app);
serverType = 'http';
}

// start listening
server.listen(config.port, function () {
logger.info('content server is now listening on port', server.address().address, server.address().port);
logger.info(serverType, 'content server is now listening on port', server.address().address, server.address().port);
});
});
})();
4 changes: 4 additions & 0 deletions bin/content_secure.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"key": "/etc/letsencrypt/live/quakejs.com/privkey.pem",
"cert": "/etc/letsencrypt/live/quakejs.com/fullchain.pem"
}
2 changes: 1 addition & 1 deletion bin/index.ejs
Original file line number Diff line number Diff line change
Expand Up @@ -104,5 +104,5 @@
ioq3.callMain(args);
};
</script>
<script type="text/javascript" src="/ioquake3.js"></script>
<script type="text/javascript" src="<%= ioquake3js %>"></script>
</html>
18 changes: 16 additions & 2 deletions bin/master.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
var _ = require('underscore');
var fs = require('fs');
var http = require('http');
var https = require('https');
var logger = require('winston');
var opt = require('optimist');
var url = require('url');
Expand Down Expand Up @@ -283,7 +285,19 @@ function loadConfig(configPath) {
}

(function main() {
var server = http.createServer();
var server = null;
var serverType = null;
if (config.key !== undefined && config.cert !== undefined) {
const opts = {
key: fs.readFileSync(config.key),
cert: fs.readFileSync(config.cert)
};
server = https.createServer(opts);
serverType = 'https';
} else {
server = http.createServer();
serverType = 'http';
}

var wss = new WebSocketServer({
server: server
Expand Down Expand Up @@ -343,7 +357,7 @@ function loadConfig(configPath) {

// listen only on 0.0.0.0 to force ipv4
server.listen(config.port, '0.0.0.0', function() {
console.log('master server is listening on port ' + server.address().port);
console.log(serverType, 'master server is listening on port ' + server.address().port);
});

setInterval(pruneServers, pruneInterval);
Expand Down
4 changes: 4 additions & 0 deletions bin/master_secure.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"key": "/etc/letsencrypt/live/quakejs.com/privkey.pem",
"cert": "/etc/letsencrypt/live/quakejs.com/fullchain.pem"
}
21 changes: 19 additions & 2 deletions bin/web.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
var _ = require('underscore');
var express = require('express');
var http = require('http');
var https = require('https');
var logger = require('winston');
var opt = require('optimist');
var path = require('path');
var fs = require('fs');

var argv = require('optimist')
.describe('config', 'Location of the configuration file').default('config', './config.json')
Expand Down Expand Up @@ -37,6 +39,8 @@ function loadConfig(configPath) {
}

(function main() {
const secure = config.key !== undefined && config.cert !== undefined;

var app = express();

app.set('views', __dirname);
Expand All @@ -45,12 +49,25 @@ function loadConfig(configPath) {
app.use(express.static(path.join(__dirname, '..', 'build')));
app.use(function (req, res, next) {
res.locals.content = config.content;
res.locals.ioquake3js = secure ? '/ioquake3_secure.js' : '/ioquake3.js';
res.render('index');
});

var server = http.createServer(app);
var server = null;
var serverType = null;
if (secure) {
const opts = {
key: fs.readFileSync(config.key),
cert: fs.readFileSync(config.cert)
};
server = https.createServer(opts, app);
serverType = 'https';
} else {
server = http.createServer(app);
serverType = 'http';
}
server.listen(config.port, function () {
logger.info('web server is now listening on ' + server.address().address + ":" + server.address().port);
logger.info(serverType, 'web server is now listening on ' + server.address().address + ":" + server.address().port);
});

return server;
Expand Down
5 changes: 5 additions & 0 deletions bin/web_secure.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"content": "quakejs.com:9000",
"key": "/etc/letsencrypt/live/quakejs.com/privkey.pem",
"cert": "/etc/letsencrypt/live/quakejs.com/fullchain.pem"
}
65 changes: 65 additions & 0 deletions bin/wssproxy.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
// Copyright 2020 QuakeJS authors.

var _ = require('underscore');
var httpProxy = require('http-proxy');
var fs = require('fs');
var https = require('https');
var logger = require('winston');
var opt = require('optimist');

var argv = require('optimist')
.describe('config', 'Location of the configuration file').default('config', './config.json')
.argv;

if (argv.h || argv.help) {
opt.showHelp();
return;
}

logger.cli();
logger.level = 'debug';

var config = loadConfig(argv.config);

function loadConfig(configPath) {
var config = {
listenPort: 27961,
proxyAddr: 'localhost',
proxyPort: 27960,
key: "/etc/letsencrypt/live/quakejs.com/privkey.pem",
cert: "/etc/letsencrypt/live/quakejs.com/fullchain.pem"
};

try {
logger.info('loading config file from ' + configPath + '..');
var data = require(configPath);
_.extend(config, data);
} catch (e) {
logger.warn('failed to load config', e);
}

return config;
}

var proxy = new httpProxy.createProxyServer({
target: {
host: config.proxyAddr,
port: config.proxyPort
}
});

const opts = {
key: fs.readFileSync(config.key),
cert: fs.readFileSync(config.cert)
};
var proxyServer = https.createServer(opts, function (req, res) {
proxy.web(req, res);
});

proxyServer.on('upgrade', function (req, socket, head) {
proxy.ws(req, socket, head);
});

proxyServer.listen(config.listenPort, '0.0.0.0', function() {
logger.info('wssproxy server forwarding from wss://' + proxyServer.address().address + ":" + proxyServer.address().port + " to ws://" + config.proxyAddr + ":" + config.proxyPort);
});
4 changes: 4 additions & 0 deletions bin/wssproxy.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"key": "/etc/letsencrypt/live/quakejs.com/privkey.pem",
"cert": "/etc/letsencrypt/live/quakejs.com/fullchain.pem"
}
Loading