Skip to content

Commit fcb02ea

Browse files
committed
Make ADDRESS option optional, determined automatically if not provided.
The ADDRESS env variable is used for advertising the address of the service only. If it is not provided, it can be determined automatically using the HTTP Request headers 'Host' and 'X-Forwarded-*'. This approach uses ExpressJS provided functionality but requires 'trusting' headers forwarded from proxies. Deployers can control the trusted proxies using the TRUST_PROXY option, documented in the code only as it's very edge-case. This approach supports the best of both worlds; ADDRESS will use a logical (probably accurate) value by default, but can be overridden in the case of unusual proxy scenario or a canonical URL is preferred.
1 parent b03ba19 commit fcb02ea

2 files changed

Lines changed: 31 additions & 10 deletions

File tree

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,8 @@ This is the relay server for CrewLink, an Among Us proximity voice chat program.
4343
Optional environment variables:
4444

4545
- `PORT`: Specifies the port that the server runs on. Defaults to `443` if `HTTPS` is enabled, and `9736` if not.
46-
- `ADDRESS` **(REQUIRED)**: Specifies the server domain
47-
- `NAME`: Specifies the server name
46+
- `ADDRESS` : Specifies the server domain. If not provided, `ADDRESS` is determined automatically (and possibly incorrectly) from HTTP Request headers.
47+
- `NAME`: Specifies the server name.
4848
- `HTTPS`: Enables https. You must place `privkey.pem` and `fullchain.pem` in your CWD.
4949
- `SSLPATH`: Specifies an alternate path to SSL certificates.
5050

src/index.ts

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -42,25 +42,46 @@ interface Signal {
4242
to: string;
4343
}
4444

45-
app.set('view engine', 'pug')
46-
app.use(morgan('combined'))
45+
app.set('view engine', 'pug');
46+
app.use(morgan('combined'));
47+
48+
// TRUST_PROXY can be used to set which proxies can be trusted based on IP
49+
// address. This is an advanced, undocumented environment variable.
50+
// For more details see: https://expressjs.com/en/guide/behind-proxies.html
51+
app.set('trust proxy', process.env.TRUST_PROXY ?? true );
4752

4853
let connectionCount = 0;
4954
let address = process.env.ADDRESS;
55+
56+
/**
57+
* Derives the address used from ExpressJS Request properties.
58+
* The ExpressJS Request properties for hostname and protocol take into account
59+
* the x-forwarded- parameters, so the resulting address is proxy friendly.
60+
* @param req An HTTPRequest object.
61+
*/
62+
function addressFromRequest(req: express.Request) {
63+
let p = ( 'x-forwarded-port' in req.headers ? req.headers['x-forwarded-port'] : port);
64+
if ( p == '80' || p == '443' ) {
65+
return `${req.protocol}://${req.hostname}`;
66+
} else {
67+
return `${req.protocol}://${req.hostname}:${p}`
68+
}
69+
}
70+
5071
if (!address) {
51-
logger.error('You must set the ADDRESS environment variable.');
52-
process.exit(1);
72+
logger.info('ADDRESS environment variable not set.');
73+
logger.info('Advertised server address will be derived from HTTP request headers.');
5374
}
5475

55-
app.get('/', (_, res) => {
56-
res.render('index', { connectionCount, address });
76+
app.get('/', (req, res) => {
77+
res.render('index', { connectionCount, address: (address || addressFromRequest(req)), headers: req.headers });
5778
});
5879

5980
app.get('/health', (req, res) => {
6081
res.json({
6182
uptime: process.uptime(),
6283
connectionCount,
63-
address,
84+
address: (address || addressFromRequest(req)),
6485
name: process.env.NAME
6586
});
6687
})
@@ -168,5 +189,5 @@ io.on('connection', (socket: socketIO.Socket) => {
168189

169190
server.listen(port);
170191
(async () => {
171-
logger.info('CrewLink Server started: %s', address);
192+
logger.info('CrewLink Server started: %s', address || '[ADDRESS not set]');
172193
})();

0 commit comments

Comments
 (0)