mirror of
https://github.com/openmhz/trunk-server.git
synced 2026-11-14 09:48:10 -05:00
Merge branch 'master' into donate
This commit is contained in:
34
README.md
34
README.md
@@ -14,7 +14,7 @@ There are a bunch of experiments lurking in the code. There is some code for add
|
|||||||
|
|
||||||
I haven't done a great job of keeping all the packages up to date... and I never got around to adding tests. Both of these would be great things for folks to go after.
|
I haven't done a great job of keeping all the packages up to date... and I never got around to adding tests. Both of these would be great things for folks to go after.
|
||||||
|
|
||||||
## PROD vs DEV Env
|
## PROD vs TEST Env
|
||||||
The Prod environment expects you to be using HTTPS for your domains. It is pretty easy to use Let's Encrypt to grab Certs for the domains you are using. If not, just run things using the `docker-test.sh` script.
|
The Prod environment expects you to be using HTTPS for your domains. It is pretty easy to use Let's Encrypt to grab Certs for the domains you are using. If not, just run things using the `docker-test.sh` script.
|
||||||
|
|
||||||
## Path Forward
|
## Path Forward
|
||||||
@@ -43,8 +43,9 @@ CNAMEs also need to be created for the various services. Create the CNAMEs below
|
|||||||
- api
|
- api
|
||||||
- account
|
- account
|
||||||
- admin
|
- admin
|
||||||
|
- www
|
||||||
|
|
||||||
After doing this, you should have the following domains: `api.domain.com`, `account.domain.com`, `admin.domain.com`
|
After doing this, you should have the following domains: `api.domain.com`, `account.domain.com`, `admin.domain.com`, `www.domain.com`
|
||||||
|
|
||||||
### S3 Storage
|
### S3 Storage
|
||||||
Currently, both **test** and **prod** expect to use S3-based storage instead of local storage. Switching to use local storage would be relatively easy - but for the sake of testing, let's just say use something S3-compatible. Make sure that ~/.aws/credentials has the credentials you'd like to use with your S3-compatible storage provider.. IE:
|
Currently, both **test** and **prod** expect to use S3-based storage instead of local storage. Switching to use local storage would be relatively easy - but for the sake of testing, let's just say use something S3-compatible. Make sure that ~/.aws/credentials has the credentials you'd like to use with your S3-compatible storage provider.. IE:
|
||||||
@@ -54,6 +55,29 @@ aws_access_key_id = [..]
|
|||||||
aws_secret_access_key = [..]
|
aws_secret_access_key = [..]
|
||||||
```
|
```
|
||||||
|
|
||||||
|
# Automatically renewing SSL Certificates
|
||||||
|
|
||||||
|
SSL certs are automatically fetched from Let's Encrypt using the CertBot tool. The approach taken is based on this [Medium post](https://pentacent.medium.com/nginx-and-lets-encrypt-with-docker-in-less-than-5-minutes-b4b8a60d3a71) and accompanying [GitHub repo](https://github.com/wmnnd/nginx-certbot/tree/master).
|
||||||
|
|
||||||
|
You do need to jump start the process and do an initial fetch. To get started, make sure you have your `prod.env` file filled out. If you don't, copy prod.env.example to prod.env and fill in the details. Make sure **DOMAIN_NAME** and **REACT_APP_ADMIN_EMAIL** are correct and are the version you want to use in production. Those values will be used when requesting an SSL cert from Let's Encrypt.
|
||||||
|
|
||||||
|
This script uses Let's Encrypt's [Certbot tool](https://eff-certbot.readthedocs.io/en/latest/).
|
||||||
|
|
||||||
|
In the main directory of the **Trunk Server** repo, run the following commands:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
source prod.env
|
||||||
|
docker compose -f certbot-compose.yml up
|
||||||
|
```
|
||||||
|
|
||||||
|
Check the output from CertBot - and when it is done, just hit `ctrl + c` to exit.
|
||||||
|
|
||||||
|
And then run the following to make sure everything has stopped:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker compose -f certbot-compose.yml down
|
||||||
|
```
|
||||||
|
|
||||||
### Configure
|
### Configure
|
||||||
The configurations for both **test** and **prod** come from environment variable files that are read in before the containers are started.
|
The configurations for both **test** and **prod** come from environment variable files that are read in before the containers are started.
|
||||||
Copy the example files and fill in the required info:
|
Copy the example files and fill in the required info:
|
||||||
@@ -218,14 +242,14 @@ It is a huge pain to upgrade MongoDB in place. It turns out to be easier to dump
|
|||||||
|
|
||||||
Rough Playbook (use common sense, I may not have this exact):
|
Rough Playbook (use common sense, I may not have this exact):
|
||||||
- get into the shell of the mongo container
|
- get into the shell of the mongo container
|
||||||
- `mongodump --db scanner —out /data/db/backup`
|
- `mongodump --uri="mongodb://127.0.0.1" --db scanner --out /data/db/backup`
|
||||||
- exit contianer and go back to host machine
|
- exit contianer and go back to host machine
|
||||||
- `cd data/db`
|
- `cd data/db`
|
||||||
- `rm *` erase everything... but not the sub-directories because that is where the backup is
|
- `rm *` erase everything... but not the sub-directories because that is where the backup is
|
||||||
- upgrade to the latest version of mongo
|
- upgrade to the latest version of mongo
|
||||||
- build and launch the mongo container, which will create an empty DB
|
- build and launch the mongo container, which will create an empty DB
|
||||||
- get into the shell of the mongo container
|
- get into the shell of the mongo container
|
||||||
- `mongorestore --db scanner --drop /data/db/backup/`
|
- `mongorestore --db scanner --drop /data/db/backup/scanner`
|
||||||
|
|
||||||
### Privlege Port Error
|
### Privlege Port Error
|
||||||
|
|
||||||
@@ -237,7 +261,7 @@ https://docs.docker.com/engine/security/rootless/#exposing-privileged-ports
|
|||||||
|
|
||||||
## Setting up Logging
|
## Setting up Logging
|
||||||
I have had good luck with Loggly. Their free tier provides enough capabilities for most small sites.
|
I have had good luck with Loggly. Their free tier provides enough capabilities for most small sites.
|
||||||
The Doocker Logging Driver works well and is easy to install:
|
The Docker Logging Driver works well and is easy to install:
|
||||||
|
|
||||||
https://documentation.solarwinds.com/en/Success_Center/loggly/Content/admin/docker-logging-driver.htm
|
https://documentation.solarwinds.com/en/Success_Center/loggly/Content/admin/docker-logging-driver.htm
|
||||||
|
|
||||||
|
|||||||
@@ -110,7 +110,7 @@ exports.deleteGroup = async function (req, res, next) {
|
|||||||
|
|
||||||
|
|
||||||
exports.reorderGroups = function (req, res, next) {
|
exports.reorderGroups = function (req, res, next) {
|
||||||
console.log(req.body)
|
|
||||||
//router.post('/system/:shortName/group_order', isLoggedIn, function(req, res) {
|
//router.post('/system/:shortName/group_order', isLoggedIn, function(req, res) {
|
||||||
process.nextTick(async function () {
|
process.nextTick(async function () {
|
||||||
const system = await System.findOne({ shortName: req.params.shortName.toLowerCase() });
|
const system = await System.findOne({ shortName: req.params.shortName.toLowerCase() });
|
||||||
@@ -131,7 +131,7 @@ exports.reorderGroups = function (req, res, next) {
|
|||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
console.log(req.body)
|
|
||||||
if (!req.body.groupOrder) {
|
if (!req.body.groupOrder) {
|
||||||
res.status(500);
|
res.status(500);
|
||||||
res.json({
|
res.json({
|
||||||
@@ -142,8 +142,6 @@ exports.reorderGroups = function (req, res, next) {
|
|||||||
}
|
}
|
||||||
var groupOrder = JSON.parse(req.body.groupOrder);
|
var groupOrder = JSON.parse(req.body.groupOrder);
|
||||||
for (var i = 0; i < groupOrder.length; i++) {
|
for (var i = 0; i < groupOrder.length; i++) {
|
||||||
|
|
||||||
console.log("in group: " + groupOrder[i] + " position: " + i);
|
|
||||||
const group = await Group.findOneAndUpdate(
|
const group = await Group.findOneAndUpdate(
|
||||||
{
|
{
|
||||||
_id: new mongoose.Types.ObjectId(groupOrder[i]),
|
_id: new mongoose.Types.ObjectId(groupOrder[i]),
|
||||||
@@ -177,10 +175,8 @@ exports.reorderGroups = function (req, res, next) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
exports.upsertGroup = function (req, res, next) {
|
exports.upsertGroup = function (req, res, next) {
|
||||||
console.log(req.body)
|
|
||||||
//router.post('/system/:shortName/group/:groupId?', isLoggedIn, function(req, res) {
|
//router.post('/system/:shortName/group/:groupId?', isLoggedIn, function(req, res) {
|
||||||
process.nextTick(async function () {
|
process.nextTick(async function () {
|
||||||
console.log(req.body)
|
|
||||||
let system = await System.findOne({ shortName: req.params.shortName.toLowerCase() });
|
let system = await System.findOne({ shortName: req.params.shortName.toLowerCase() });
|
||||||
|
|
||||||
if (!system) {
|
if (!system) {
|
||||||
|
|||||||
@@ -58,7 +58,6 @@ exports.listUserSystems = async function (req,res,next) {
|
|||||||
}
|
}
|
||||||
const users = await User.find({}, "_id email firstName lastName lastLogin");
|
const users = await User.find({}, "_id email firstName lastName lastLogin");
|
||||||
let list = [];
|
let list = [];
|
||||||
console.log(users);
|
|
||||||
for (let index = 0; index < users.length; index++) {
|
for (let index = 0; index < users.length; index++) {
|
||||||
let user = users[index].toObject();
|
let user = users[index].toObject();
|
||||||
const userId = new mongoose.Types.ObjectId(user._id);
|
const userId = new mongoose.Types.ObjectId(user._id);
|
||||||
|
|||||||
@@ -94,7 +94,6 @@ async function csv_import(shortName, filename, callback) {
|
|||||||
|
|
||||||
for (var i = 0; i < data.length; i++) {
|
for (var i = 0; i < data.length; i++) {
|
||||||
var row = data[i];
|
var row = data[i];
|
||||||
console.log(row)
|
|
||||||
if (!( "Decimal" in row) || !("Description" in row) || !("Alpha Tag" in row)) {
|
if (!( "Decimal" in row) || !("Description" in row) || !("Alpha Tag" in row)) {
|
||||||
console.error("Error: csv import column header error");
|
console.error("Error: csv import column header error");
|
||||||
callback("Column Headers are required - Required Columns: 'Decimal' 'Decscription' 'Alpha Tag' Optional Column: 'Priority' ", null);
|
callback("Column Headers are required - Required Columns: 'Decimal' 'Decscription' 'Alpha Tag' Optional Column: 'Priority' ", null);
|
||||||
|
|||||||
23
backend/agents/honeycomb-tracing.js
Normal file
23
backend/agents/honeycomb-tracing.js
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
// tracing.js
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
const { HoneycombSDK } = require('@honeycombio/opentelemetry-node');
|
||||||
|
const {
|
||||||
|
getNodeAutoInstrumentations,
|
||||||
|
} = require('@opentelemetry/auto-instrumentations-node');
|
||||||
|
|
||||||
|
// uses the HONEYCOMB_API_KEY and OTEL_SERVICE_NAME environment variables
|
||||||
|
const sdk = new HoneycombSDK({
|
||||||
|
sampleRate: 5,
|
||||||
|
instrumentations: [
|
||||||
|
getNodeAutoInstrumentations({
|
||||||
|
// we recommend disabling fs autoinstrumentation since it can be noisy
|
||||||
|
// and expensive during startup
|
||||||
|
'@opentelemetry/instrumentation-fs': {
|
||||||
|
enabled: false,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
sdk.start();
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
const { ObjectId } = require('mongodb');
|
const { ObjectId } = require('mongodb');
|
||||||
var { callModel: Call } = require("../models/call");
|
var { callModel: Call } = require("../models/call");
|
||||||
const Group = require("../models/group");
|
const Group = require("../models/group");
|
||||||
|
const opentelemetry = require('@opentelemetry/api');
|
||||||
var defaultNumResults = 50;
|
var defaultNumResults = 50;
|
||||||
|
|
||||||
var channels = {};
|
var channels = {};
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
var path = require('path');
|
var path = require('path');
|
||||||
var fs = require('fs');
|
var fs = require('fs');
|
||||||
|
const opentelemetry = require('@opentelemetry/api');
|
||||||
var sysStats = require("../sys_stats");
|
var sysStats = require("../sys_stats");
|
||||||
var System = require("../models/system");
|
var System = require("../models/system");
|
||||||
var Talkgroup = require("../models/talkgroup");
|
var Talkgroup = require("../models/talkgroup");
|
||||||
var { callModel: Call } = require("../models/call");
|
var { callModel: Call } = require("../models/call");
|
||||||
|
|
||||||
|
|
||||||
const { PutObjectCommand, S3Client } = require("@aws-sdk/client-s3");
|
const { PutObjectCommand, S3Client } = require("@aws-sdk/client-s3");
|
||||||
const { fromIni } = require("@aws-sdk/credential-providers");
|
const { fromIni } = require("@aws-sdk/credential-providers");
|
||||||
|
|
||||||
@@ -18,183 +20,236 @@ const client = new S3Client({
|
|||||||
credentials: fromIni({ profile: s3_profile }),
|
credentials: fromIni({ profile: s3_profile }),
|
||||||
endpoint: s3_endpoint,
|
endpoint: s3_endpoint,
|
||||||
region: s3_region,
|
region: s3_region,
|
||||||
maxAttempts: 1
|
maxAttempts: 3
|
||||||
});
|
});
|
||||||
|
|
||||||
exports.upload = async function (req, res, next) {
|
exports.upload = async function (req, res, next) {
|
||||||
process.nextTick( async () => {
|
|
||||||
if (!req.file || ((path.extname(req.file.originalname) != '.m4a') && (path.extname(req.file.originalname) != '.mp3'))) {
|
|
||||||
console.warn("[" + req.params.shortName + "] Error file name is wrong or file does not exist");
|
|
||||||
res.status(500);
|
|
||||||
res.send("Error, invalid filename:\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
var shortName = req.params.shortName.toLowerCase();
|
|
||||||
var apiKey = req.body.api_key;
|
|
||||||
let item = null;
|
|
||||||
|
|
||||||
try {
|
process.nextTick(async () => {
|
||||||
item = await System.findOne({ 'shortName': shortName }, ["key", "ignoreUnknownTalkgroup"]);
|
if (!req.file || ((path.extname(req.file.originalname) != '.m4a') && (path.extname(req.file.originalname) != '.mp3'))) {
|
||||||
} catch (err) {
|
console.warn("[" + req.params.shortName + "] Error file name is wrong or file does not exist");
|
||||||
console.warn("[" + req.params.shortName + "] Error /:shortName/upload - Error: " + err);
|
res.status(500);
|
||||||
res.status(500);
|
res.send("Error, invalid filename:\n");
|
||||||
res.send("Error, invalid shotName:\n" + err);
|
return;
|
||||||
return;
|
}
|
||||||
}
|
var shortName = req.params.shortName.toLowerCase();
|
||||||
|
var apiKey = req.body.api_key;
|
||||||
|
var talkgroupNum = parseInt(req.body.talkgroup_num);
|
||||||
|
var freq = parseFloat(req.body.freq);
|
||||||
|
var time = new Date(parseInt(req.body.start_time) * 1000);
|
||||||
|
var stopTime = new Date();
|
||||||
|
if (req.body.stop_time) {
|
||||||
|
var stopTime = new Date(parseInt(req.body.stop_time) * 1000);
|
||||||
|
}
|
||||||
|
var startTime = req.body.start_time;
|
||||||
|
var emergency = parseInt(req.body.emergency);
|
||||||
|
|
||||||
if (!item) {
|
let errorCount = parseInt(req.body.error_count);
|
||||||
console.info("[" + req.params.shortName + "] Error /:shortName/upload ShortName does not exist");
|
let spikeCount = parseInt(req.body.spike_count);
|
||||||
res.status(500);
|
|
||||||
res.send("ShortName does not exist: " + shortName + "\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (apiKey != item.key) {
|
|
||||||
console.warn("[" + req.params.shortName + "] Error /:shortName/upload API Key Mismatch - Provided key: " + apiKey);
|
|
||||||
res.status(500);
|
|
||||||
res.send("API Keys do not match!\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var talkgroupNum = parseInt(req.body.talkgroup_num);
|
if (Number.isNaN(errorCount)) {
|
||||||
var freq = parseFloat(req.body.freq);
|
errorCount = 0;
|
||||||
var time = new Date(parseInt(req.body.start_time) * 1000);
|
}
|
||||||
var stopTime = new Date();
|
if (Number.isNaN(spikeCount)) {
|
||||||
if (req.body.stop_time) {
|
spikeCount = 0;
|
||||||
var stopTime = new Date(parseInt(req.body.stop_time) * 1000);
|
}
|
||||||
}
|
|
||||||
var startTime = req.body.start_time;
|
|
||||||
var emergency = parseInt(req.body.emergency);
|
|
||||||
|
|
||||||
// Blocking sensitive talkgroups
|
try {
|
||||||
if ((shortName == "hennearmer") && ((talkgroupNum == 3421) || (talkgroupNum == 3423))) {
|
var srcList = JSON.parse(req.body.source_list);
|
||||||
res.status(200).end();
|
} catch (err) {
|
||||||
return;
|
var srcList = [];
|
||||||
}
|
console.warn("[" + req.params.shortName + "] Error /:shortName/upload Parsing Source/Freq List - Error: " + err);
|
||||||
|
res.status(500);
|
||||||
|
res.send("Error parsing sourcelist " + err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let item = null;
|
||||||
|
const span = opentelemetry.trace.getActiveSpan();
|
||||||
|
span.setAttribute('call.shortName', shortName);
|
||||||
|
span.setAttribute('call.talkgroupNum', talkgroupNum);
|
||||||
|
span.setAttribute('call.startTime', startTime);
|
||||||
|
|
||||||
|
|
||||||
if (item.ignoreUnknownTalkgroup == true) {
|
|
||||||
talkgroupExists = await Talkgroup.exists({
|
// Validate that the system exists and the API key is correct
|
||||||
'shortName': shortName,
|
|
||||||
'num': talkgroupNum
|
try {
|
||||||
|
item = await System.findOne({ 'shortName': shortName }, ["key", "ignoreUnknownTalkgroup"]);
|
||||||
|
} catch (err) {
|
||||||
|
span.setStatus({
|
||||||
|
code: opentelemetry.SpanStatusCode.ERROR,
|
||||||
|
message: "Error /:shortName/upload - Error: " + err,
|
||||||
|
});
|
||||||
|
console.warn("[" + req.params.shortName + "] Error /:shortName/upload - Error: " + err);
|
||||||
|
res.status(500);
|
||||||
|
res.send("Error, invalid shortName:\n" + err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!item) {
|
||||||
|
span.setStatus({
|
||||||
|
code: opentelemetry.SpanStatusCode.ERROR,
|
||||||
|
message: "Error /:shortName/upload API Key Mismatch - Provided key: " + apiKey,
|
||||||
|
});
|
||||||
|
console.info("[" + req.params.shortName + "] Error /:shortName/upload ShortName does not exist");
|
||||||
|
res.status(500);
|
||||||
|
res.send("ShortName does not exist: " + shortName + "\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (apiKey != item.key) {
|
||||||
|
span.setStatus({
|
||||||
|
code: opentelemetry.SpanStatusCode.ERROR,
|
||||||
|
message: "Error /:shortName/upload API Key Mismatch - Provided key: " + apiKey,
|
||||||
|
});
|
||||||
|
console.warn("[" + req.params.shortName + "] Error /:shortName/upload API Key Mismatch - Provided key: " + apiKey);
|
||||||
|
res.status(500);
|
||||||
|
res.send("API Keys do not match!\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Blocking sensitive talkgroups
|
||||||
|
if ((shortName == "hennearmer") && ((talkgroupNum == 3421) || (talkgroupNum == 3423))) {
|
||||||
|
span.setStatus({
|
||||||
|
code: opentelemetry.SpanStatusCode.ERROR,
|
||||||
|
message: "Sensitive Talkgroup",
|
||||||
|
});
|
||||||
|
res.status(200).end();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item.ignoreUnknownTalkgroup == true) {
|
||||||
|
talkgroupExists = await Talkgroup.exists({
|
||||||
|
'shortName': shortName,
|
||||||
|
'num': talkgroupNum
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!talkgroupExists) {
|
||||||
|
try {
|
||||||
|
fs.unlinkSync(req.file.path)
|
||||||
|
//file removed
|
||||||
|
} catch (err) {
|
||||||
|
console.log("[" + call.shortName + "] error deleting: " + req.file.path);
|
||||||
|
}
|
||||||
|
|
||||||
|
res.status(500);
|
||||||
|
res.send("Talkgroup does not exist, skipping.\n");
|
||||||
|
span.setStatus({
|
||||||
|
code: opentelemetry.SpanStatusCode.ERROR,
|
||||||
|
message: "Ignore Unknown Talkgroup Set - Talkgroup does not exist: " + talkgroupNum + " ShortName: " + shortName,
|
||||||
|
});
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Add in an API Key check
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
res.status(200).end();
|
||||||
|
|
||||||
|
|
||||||
|
var local_path = "/" + shortName + "/" + time.getFullYear() + "/" + (time.getMonth() + 1) + "/" + time.getDate() + "/";
|
||||||
|
var object_key = "media/" + shortName + "-" + talkgroupNum + "-" + startTime + path.extname(req.file.originalname);
|
||||||
|
|
||||||
|
var endpoint = s3_endpoint;
|
||||||
|
var bucket = s3_bucket;
|
||||||
|
var url = s3_endpoint + "/" + s3_bucket + "/" + object_key;
|
||||||
|
|
||||||
|
var call = new Call({
|
||||||
|
shortName: shortName,
|
||||||
|
talkgroupNum: talkgroupNum,
|
||||||
|
objectKey: object_key,
|
||||||
|
endpoint: endpoint,
|
||||||
|
bucket: bucket,
|
||||||
|
time: time,
|
||||||
|
name: talkgroupNum + "-" + startTime + ".m4a",
|
||||||
|
freq: freq,
|
||||||
|
errorCount: errorCount,
|
||||||
|
spikeCount: spikeCount,
|
||||||
|
url: url,
|
||||||
|
emergency: emergency,
|
||||||
|
path: local_path,
|
||||||
|
srcList: srcList,
|
||||||
|
len: -1
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!talkgroupExists) {
|
|
||||||
try {
|
try {
|
||||||
fs.unlinkSync(req.file.path)
|
if (req.body.call_length) {
|
||||||
//file removed
|
call.len = parseFloat(req.body.call_length);
|
||||||
} catch (err) {
|
} else {
|
||||||
console.log("[" + call.shortName + "] error deleting: " + req.file.path);
|
call.len = (stopTime - time) / 1000;
|
||||||
}
|
}
|
||||||
|
} catch (err) {
|
||||||
res.status(500);
|
console.error(err);
|
||||||
res.send("Talkgroup does not exist, skipping.\n");
|
}
|
||||||
|
let fileContent;
|
||||||
|
try {
|
||||||
|
fileContent = fs.readFileSync(req.file.path);
|
||||||
|
//s3Src = fs.createReadStream(req.file.path);
|
||||||
|
} catch (err) {
|
||||||
|
span.setStatus({
|
||||||
|
code: opentelemetry.SpanStatusCode.ERROR,
|
||||||
|
message: "Unable to open file: " + req.file.path + " Error: " + err,
|
||||||
|
});
|
||||||
|
console.error("[" + call.shortName + "] Unable to open file: " + req.file.path + " Error: " + err);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
const command = new PutObjectCommand({
|
||||||
// Add in an API Key check
|
Bucket: s3_bucket,
|
||||||
|
Key: object_key,
|
||||||
|
Body: fileContent,
|
||||||
|
ACL: 'public-read'
|
||||||
|
});
|
||||||
|
|
||||||
let errorCount = parseInt(req.body.error_count);
|
try {
|
||||||
let spikeCount = parseInt(req.body.spike_count);
|
await client.send(command);
|
||||||
|
|
||||||
if (Number.isNaN(errorCount)) {
|
} catch (err) {
|
||||||
errorCount = 0;
|
span.setStatus({
|
||||||
}
|
code: opentelemetry.SpanStatusCode.ERROR,
|
||||||
if (Number.isNaN(spikeCount)) {
|
message: "Upload Error: " + err + " Filename: " + call.name + " content-length: " + req.headers['content-length'] + " Key: " + object_key + " Bucket: " + s3_bucket,
|
||||||
spikeCount = 0;
|
});
|
||||||
}
|
console.warn("[" + call.shortName + "] Upload Error: " + err + " Filename: " + call.name + " content-length: " + req.headers['content-length'] + " Key: " + object_key + " Bucket: " + s3_bucket);
|
||||||
|
/*res.status(500);
|
||||||
try {
|
sysStats.addError(call.toObject());
|
||||||
var srcList = JSON.parse(req.body.source_list);
|
res.contentType('json');
|
||||||
} catch (err) {
|
res.status(500);
|
||||||
var srcList = [];
|
res.send(JSON.stringify({
|
||||||
console.warn("[" + req.params.shortName + "] Error /:shortName/upload Parsing Source/Freq List - Error: " + err);
|
success: false,
|
||||||
res.status(500);
|
error: "File Upload"
|
||||||
res.send("Error parsing sourcelist " + err);
|
}));*/
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
res.status(200).end();
|
|
||||||
|
|
||||||
var local_path = "/" + shortName + "/" + time.getFullYear() + "/" + (time.getMonth() + 1) + "/" + time.getDate() + "/";
|
|
||||||
var object_key = "media/" + shortName + "-" + talkgroupNum + "-" + startTime + path.extname(req.file.originalname);
|
|
||||||
|
|
||||||
var endpoint = s3_endpoint;
|
|
||||||
var bucket = s3_bucket;
|
|
||||||
var url = s3_endpoint + "/" + s3_bucket + "/" + object_key;
|
|
||||||
|
|
||||||
var call = new Call({
|
|
||||||
shortName: shortName,
|
|
||||||
talkgroupNum: talkgroupNum,
|
|
||||||
objectKey: object_key,
|
|
||||||
endpoint: endpoint,
|
|
||||||
bucket: bucket,
|
|
||||||
time: time,
|
|
||||||
name: talkgroupNum + "-" + startTime + ".m4a",
|
|
||||||
freq: freq,
|
|
||||||
errorCount: errorCount,
|
|
||||||
spikeCount: spikeCount,
|
|
||||||
url: url,
|
|
||||||
emergency: emergency,
|
|
||||||
path: local_path,
|
|
||||||
srcList: srcList,
|
|
||||||
len: -1
|
|
||||||
});
|
|
||||||
|
|
||||||
try {
|
|
||||||
if (req.body.call_length) {
|
|
||||||
call.len = parseFloat(req.body.call_length);
|
|
||||||
} else {
|
|
||||||
call.len = (stopTime - time) / 1000;
|
|
||||||
}
|
}
|
||||||
} catch (err) {
|
|
||||||
console.error(err);
|
try {
|
||||||
}
|
await call.save();
|
||||||
let fileContent;
|
sysStats.addCall(call.toObject());
|
||||||
try {
|
// we only want to notify clients if the clip is longer than 1 second.
|
||||||
fileContent = fs.readFileSync(req.file.path);
|
if (call.len >= 1) {
|
||||||
//s3Src = fs.createReadStream(req.file.path);
|
req.call = call.toObject();
|
||||||
} catch (err) {
|
next();
|
||||||
console.error("[" + call.shortName + "] Unable to open file: " + req.file.path + " Error: " + err);
|
}
|
||||||
return;
|
} catch (err) {
|
||||||
}
|
console.warn("[" + call.shortName + "] Error saving call: " + err);
|
||||||
const command = new PutObjectCommand({
|
span.setStatus({
|
||||||
Bucket: s3_bucket,
|
code: opentelemetry.SpanStatusCode.ERROR,
|
||||||
Key: object_key,
|
message: "Error saving call: " + err,
|
||||||
Body: fileContent,
|
});
|
||||||
ACL: 'public-read'
|
/*res.status(500);
|
||||||
});
|
sysStats.addError(call.toObject());
|
||||||
|
res.contentType('json');
|
||||||
try {
|
res.status(500);
|
||||||
await client.send(command);
|
res.send(JSON.stringify({
|
||||||
await call.save();
|
success: false,
|
||||||
sysStats.addCall(call.toObject());
|
error: "File Upload"
|
||||||
// we only want to notify clients if the clip is longer than 1 second.
|
}));*/
|
||||||
if (call.len >= 1) {
|
|
||||||
req.call = call.toObject();
|
|
||||||
next();
|
|
||||||
}
|
}
|
||||||
} catch (err) {
|
|
||||||
console.warn("[" + call.shortName + "] Upload Error: " + err + " Filename: " + call.name + " content-length: " + req.headers['content-length'] + " Key: " + object_key + " Bucket: " + s3_bucket);
|
|
||||||
/*res.status(500);
|
|
||||||
sysStats.addError(call.toObject());
|
|
||||||
res.contentType('json');
|
|
||||||
res.status(500);
|
|
||||||
res.send(JSON.stringify({
|
|
||||||
success: false,
|
|
||||||
error: "File Upload"
|
|
||||||
}));*/
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
fs.unlinkSync(req.file.path);
|
fs.unlinkSync(req.file.path);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.warn("There was an Error uploading an deleting: " + req.file.path);
|
console.warn("There was an Error uploading an deleting: " + req.file.path);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
|
const tracing = require("./agents/honeycomb-tracing");
|
||||||
var express = require("express");
|
var express = require("express");
|
||||||
var configureExpress = require("./config/express");
|
var configureExpress = require("./config/express");
|
||||||
|
|
||||||
|
|||||||
2631
backend/package-lock.json
generated
2631
backend/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -6,6 +6,9 @@
|
|||||||
"@aws-sdk/client-s3": "^3.309.0",
|
"@aws-sdk/client-s3": "^3.309.0",
|
||||||
"@aws-sdk/credential-provider-process": "^3.306.0",
|
"@aws-sdk/credential-provider-process": "^3.306.0",
|
||||||
"@aws-sdk/credential-providers": "^3.309.0",
|
"@aws-sdk/credential-providers": "^3.309.0",
|
||||||
|
"@honeycombio/opentelemetry-node": "^0.6.1",
|
||||||
|
"@opentelemetry/api": "^1.7.0",
|
||||||
|
"@opentelemetry/auto-instrumentations-node": "^0.41.0",
|
||||||
"adm-zip": "^0.5.10",
|
"adm-zip": "^0.5.10",
|
||||||
"aws-sdk": "^2.1353",
|
"aws-sdk": "^2.1353",
|
||||||
"axios": "1.3.5",
|
"axios": "1.3.5",
|
||||||
@@ -22,12 +25,12 @@
|
|||||||
"ffprobe-static": "3.1.0",
|
"ffprobe-static": "3.1.0",
|
||||||
"find-remove": "4.1.0",
|
"find-remove": "4.1.0",
|
||||||
"get-folder-size": "^4.0.0",
|
"get-folder-size": "^4.0.0",
|
||||||
"node-mailjet": "6.0.2",
|
|
||||||
"mkdirp": "^2.1.6",
|
"mkdirp": "^2.1.6",
|
||||||
"mongodb": "5.2.0",
|
"mongodb": "5.2.0",
|
||||||
"mongoose": "7.0.3",
|
"mongoose": "7.0.3",
|
||||||
"multer": "1.3.0",
|
"multer": "1.3.0",
|
||||||
"node-ffprobe": "https://github.com/ListenerApproved/node-ffprobe",
|
"node-ffprobe": "https://github.com/ListenerApproved/node-ffprobe",
|
||||||
|
"node-mailjet": "6.0.2",
|
||||||
"node-schedule": "2.1.1",
|
"node-schedule": "2.1.1",
|
||||||
"passport": "0.6.0",
|
"passport": "0.6.0",
|
||||||
"passport-local": "1.0.0",
|
"passport-local": "1.0.0",
|
||||||
|
|||||||
@@ -10,10 +10,7 @@ var spots = (24 * 60) / timePeriod; // the number of spots needed to keep track
|
|||||||
|
|
||||||
|
|
||||||
async function updateActiveSystems() {
|
async function updateActiveSystems() {
|
||||||
|
|
||||||
// Go through all of the Systems
|
// Go through all of the Systems
|
||||||
|
|
||||||
|
|
||||||
for await (let item of System.find()) {
|
for await (let item of System.find()) {
|
||||||
// go through all the systems
|
// go through all the systems
|
||||||
// if you have recieved some calls during that last period, make the system active
|
// if you have recieved some calls during that last period, make the system active
|
||||||
|
|||||||
37
certbot-compose.yml
Normal file
37
certbot-compose.yml
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
version: "3"
|
||||||
|
services:
|
||||||
|
nginx:
|
||||||
|
build:
|
||||||
|
context: ./nginx-proxy
|
||||||
|
args:
|
||||||
|
STAGE: "cert"
|
||||||
|
environment:
|
||||||
|
- DOMAIN_NAME
|
||||||
|
image: "nginx:${TAG}-cert"
|
||||||
|
networks:
|
||||||
|
- proxy
|
||||||
|
ports:
|
||||||
|
- "80:80"
|
||||||
|
restart: always
|
||||||
|
volumes:
|
||||||
|
- ${PWD}/data/log/syslog:/var/log/syslog
|
||||||
|
- ${PWD}/data/log/nginx:/var/log/nginx
|
||||||
|
- ${PWD}/data/certbot/www/:/var/www/certbot/:ro
|
||||||
|
- ${PWD}/data/certbot/conf/:/etc/letsencrypt/:ro
|
||||||
|
command: /bin/bash -c "envsubst '$$DOMAIN_NAME' < /etc/nginx/conf.d/site.template > /etc/nginx/conf.d/default.conf && while :; do sleep 6h & wait $${!}; nginx -s reload; done & nginx -g 'daemon off;'"
|
||||||
|
|
||||||
|
certbot:
|
||||||
|
image: certbot/certbot:latest
|
||||||
|
volumes:
|
||||||
|
- ${PWD}/data/certbot/www/:/var/www/certbot/:rw
|
||||||
|
- ${PWD}/data/certbot/conf/:/etc/letsencrypt/:rw
|
||||||
|
entrypoint: "certbot certonly --webroot -w /var/www/certbot \
|
||||||
|
--email ${REACT_APP_ADMIN_EMAIL} \
|
||||||
|
-d ${DOMAIN_NAME} -d www.${DOMAIN_NAME} -d api.${DOMAIN_NAME} -d admin.${DOMAIN_NAME} -d account.${DOMAIN_NAME} \
|
||||||
|
--rsa-key-size 4096 \
|
||||||
|
--agree-tos \
|
||||||
|
--force-renewal"
|
||||||
|
|
||||||
|
networks:
|
||||||
|
proxy:
|
||||||
|
node:
|
||||||
@@ -33,6 +33,10 @@ services:
|
|||||||
- ${PWD}/data/certbot/www/:/var/www/certbot/:rw
|
- ${PWD}/data/certbot/www/:/var/www/certbot/:rw
|
||||||
- ${PWD}/data/certbot/conf/:/etc/letsencrypt/:rw
|
- ${PWD}/data/certbot/conf/:/etc/letsencrypt/:rw
|
||||||
entrypoint: "/bin/sh -c 'trap exit TERM; while :; do certbot renew; sleep 12h & wait $${!}; done;'"
|
entrypoint: "/bin/sh -c 'trap exit TERM; while :; do certbot renew; sleep 12h & wait $${!}; done;'"
|
||||||
|
logging:
|
||||||
|
driver: syslog
|
||||||
|
options:
|
||||||
|
tag: "certbot"
|
||||||
|
|
||||||
mongo:
|
mongo:
|
||||||
build:
|
build:
|
||||||
@@ -73,6 +77,8 @@ services:
|
|||||||
- S3_BUCKET
|
- S3_BUCKET
|
||||||
- S3_PROFILE
|
- S3_PROFILE
|
||||||
- S3_REGION
|
- S3_REGION
|
||||||
|
- OTEL_SERVICE_NAME
|
||||||
|
- HONEYCOMB_API_KEY
|
||||||
volumes:
|
volumes:
|
||||||
- "~/.aws:/home/app/.aws"
|
- "~/.aws:/home/app/.aws"
|
||||||
depends_on:
|
depends_on:
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
source test.env
|
source test.env
|
||||||
|
echo "Domains: " $DOMAIN_NAME
|
||||||
|
echo "Protocol: " $PROTOCOL
|
||||||
echo "Docker Compose Command: " $@
|
echo "Docker Compose Command: " $@
|
||||||
docker compose -f docker-compose.yml -f test-compose.yml $@
|
docker compose -f docker-compose.yml -f test-compose.yml $@
|
||||||
|
|||||||
@@ -66,15 +66,17 @@ const MediaPlayer = (props) => {
|
|||||||
const audio = audioRef.current.audioEl.current;
|
const audio = audioRef.current.audioEl.current;
|
||||||
|
|
||||||
setSourceIndex(0);
|
setSourceIndex(0);
|
||||||
navigator.mediaSession.metadata = new MediaMetadata({
|
if ('mediaSession' in navigator) {
|
||||||
title: "Waiting for Call...",
|
navigator.mediaSession.metadata = new MediaMetadata({
|
||||||
album: 'OpenMHz',
|
title: "Waiting for Call...",
|
||||||
artwork: [
|
album: 'OpenMHz',
|
||||||
{ src: '/favicon-32x32.png', sizes: '32x32', type: 'image/png' },
|
artwork: [
|
||||||
{ src: '/android-chrome-192x192.png', sizes: '192x192', type: 'image/png' },
|
{ src: '/favicon-32x32.png', sizes: '32x32', type: 'image/png' },
|
||||||
{ src: '/android-chrome-192x192.png', sizes: '512x512', type: 'image/png' },
|
{ src: '/android-chrome-192x192.png', sizes: '192x192', type: 'image/png' },
|
||||||
]
|
{ src: '/android-chrome-192x192.png', sizes: '512x512', type: 'image/png' },
|
||||||
});
|
]
|
||||||
|
});
|
||||||
|
}
|
||||||
audio.src = "data:audio/mpeg;base64,SUQzBAAAAAAAI1RTU0UAAAAPAAADTGF2ZjU4Ljc2LjEwMAAAAAAAAAAAAAAA/+M4wAAAAAAAAAAAAEluZm8AAAAPAAAAAwAAAbAAqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq1dXV1dXV1dXV1dXV1dXV1dXV1dXV1dXV1dXV1dXV1dXV////////////////////////////////////////////AAAAAExhdmM1OC4xMwAAAAAAAAAAAAAAACQDkAAAAAAAAAGw9wrNaQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/+MYxAAAAANIAAAAAExBTUUzLjEwMFVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV/+MYxDsAAANIAAAAAFVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV/+MYxHYAAANIAAAAAFVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV";
|
audio.src = "data:audio/mpeg;base64,SUQzBAAAAAAAI1RTU0UAAAAPAAADTGF2ZjU4Ljc2LjEwMAAAAAAAAAAAAAAA/+M4wAAAAAAAAAAAAEluZm8AAAAPAAAAAwAAAbAAqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq1dXV1dXV1dXV1dXV1dXV1dXV1dXV1dXV1dXV1dXV1dXV////////////////////////////////////////////AAAAAExhdmM1OC4xMwAAAAAAAAAAAAAAACQDkAAAAAAAAAGw9wrNaQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/+MYxAAAAANIAAAAAExBTUUzLjEwMFVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV/+MYxDsAAANIAAAAAFVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV/+MYxHYAAANIAAAAAFVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV";
|
||||||
const playPromise = audio.play();
|
const playPromise = audio.play();
|
||||||
|
|
||||||
|
|||||||
@@ -1,91 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
# from https://github.com/wmnnd/nginx-certbot/blob/master/init-letsencrypt.sh
|
|
||||||
|
|
||||||
|
|
||||||
# Load environment variables from prod.env.example
|
|
||||||
if [ -f prod.env ]; then
|
|
||||||
source test.env
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Rest of the script...
|
|
||||||
|
|
||||||
if ! [ -x "$(command -v docker compose)" ]; then
|
|
||||||
echo 'Error: docker compose is not installed.' >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
domains=("$DOMAIN_NAME" "account.$DOMAIN_NAME" "admin.$DOMAIN_NAME" "api.$DOMAIN_NAME" "www.$DOMAIN_NAME")
|
|
||||||
|
|
||||||
rsa_key_size=4096
|
|
||||||
data_path="./data/certbot"
|
|
||||||
email=$REACT_APP_ADMIN_EMAIL
|
|
||||||
staging=0 # Set to 1 if you're testing your setup to avoid hitting request limits
|
|
||||||
|
|
||||||
if [ -d "$data_path" ]; then
|
|
||||||
read -p "Existing data found for $domains. Continue and replace existing certificate? (y/N) " decision
|
|
||||||
if [ "$decision" != "Y" ] && [ "$decision" != "y" ]; then
|
|
||||||
exit
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
|
|
||||||
if [ ! -e "$data_path/conf/options-ssl-nginx.conf" ] || [ ! -e "$data_path/conf/ssl-dhparams.pem" ]; then
|
|
||||||
echo "### Downloading recommended TLS parameters ..."
|
|
||||||
mkdir -p "$data_path/conf"
|
|
||||||
curl -s https://raw.githubusercontent.com/certbot/certbot/master/certbot-nginx/certbot_nginx/_internal/tls_configs/options-ssl-nginx.conf > "$data_path/conf/options-ssl-nginx.conf"
|
|
||||||
curl -s https://raw.githubusercontent.com/certbot/certbot/master/certbot/certbot/ssl-dhparams.pem > "$data_path/conf/ssl-dhparams.pem"
|
|
||||||
echo
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "### Creating dummy certificate for $domains ..."
|
|
||||||
path="/etc/letsencrypt/live/$domains"
|
|
||||||
mkdir -p "$data_path/conf/live/$domains"
|
|
||||||
docker compose -f docker-compose.yml -f test-compose.yml run --rm --entrypoint "\
|
|
||||||
openssl req -x509 -nodes -newkey rsa:$rsa_key_size -days 1\
|
|
||||||
-keyout '$path/privkey.pem' \
|
|
||||||
-out '$path/fullchain.pem' \
|
|
||||||
-subj '/CN=localhost'" certbot
|
|
||||||
echo
|
|
||||||
|
|
||||||
|
|
||||||
echo "### Starting nginx ..."
|
|
||||||
docker compose -f docker-compose.yml -f test-compose.yml up -d nginx
|
|
||||||
echo
|
|
||||||
|
|
||||||
echo "### Deleting dummy certificate for $domains ..."
|
|
||||||
docker compose -f docker-compose.yml -f test-compose.yml run --rm --entrypoint "\
|
|
||||||
rm -Rf /etc/letsencrypt/live/$domains && \
|
|
||||||
rm -Rf /etc/letsencrypt/archive/$domains && \
|
|
||||||
rm -Rf /etc/letsencrypt/renewal/$domains.conf" certbot
|
|
||||||
echo
|
|
||||||
|
|
||||||
|
|
||||||
echo "### Requesting Let's Encrypt certificate for $domains ..."
|
|
||||||
#Join $domains to -d args
|
|
||||||
domain_args=""
|
|
||||||
for domain in "${domains[@]}"; do
|
|
||||||
domain_args="$domain_args -d $domain"
|
|
||||||
done
|
|
||||||
|
|
||||||
# Select appropriate email arg
|
|
||||||
case "$email" in
|
|
||||||
"") email_arg="--register-unsafely-without-email" ;;
|
|
||||||
*) email_arg="--email $email" ;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
# Enable staging mode if needed
|
|
||||||
if [ $staging != "0" ]; then staging_arg="--staging"; fi
|
|
||||||
|
|
||||||
docker compose -f docker-compose.yml -f test-compose.yml run --rm --entrypoint "\
|
|
||||||
certbot certonly --webroot -w /var/www/certbot \
|
|
||||||
$staging_arg \
|
|
||||||
$email_arg \
|
|
||||||
$domain_args \
|
|
||||||
--rsa-key-size $rsa_key_size \
|
|
||||||
--agree-tos \
|
|
||||||
--force-renewal" certbot
|
|
||||||
echo
|
|
||||||
|
|
||||||
echo "### Reloading nginx ..."
|
|
||||||
docker compose -f docker-compose.yml -f test-compose.yml exec nginx nginx -s reload
|
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
#
|
#
|
||||||
# docker build -t mongo .
|
# docker build -t mongo .
|
||||||
|
|
||||||
FROM mongo:5.0
|
FROM mongo:7-jammy
|
||||||
|
|
||||||
MAINTAINER Luke Berndt <lukekb@gmail.com>
|
MAINTAINER Luke Berndt <lukekb@gmail.com>
|
||||||
|
|
||||||
|
|||||||
@@ -21,7 +21,6 @@ RUN apt-get update \
|
|||||||
|
|
||||||
# Add main NGINX config
|
# Add main NGINX config
|
||||||
COPY *.conf /etc/nginx/
|
COPY *.conf /etc/nginx/
|
||||||
COPY ${STAGE}/certs/ /etc/nginx/certs/
|
|
||||||
|
|
||||||
# Add virtual hosts
|
# Add virtual hosts
|
||||||
COPY ${STAGE}/vhosts/ /etc/nginx/conf.d/
|
COPY ${STAGE}/vhosts/ /etc/nginx/conf.d/
|
||||||
|
|||||||
8
nginx-proxy/cert/vhosts/site.template
Normal file
8
nginx-proxy/cert/vhosts/site.template
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
server_name account.${DOMAIN_NAME} api.${DOMAIN_NAME} admin.${DOMAIN_NAME} www.${DOMAIN_NAME} ${DOMAIN_NAME};
|
||||||
|
|
||||||
|
location /.well-known/acme-challenge/ {
|
||||||
|
root /var/www/certbot;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1 +0,0 @@
|
|||||||
# Copy your certs here
|
|
||||||
@@ -27,6 +27,10 @@ server {
|
|||||||
|
|
||||||
server_name ${DOMAIN_NAME} www.${DOMAIN_NAME};
|
server_name ${DOMAIN_NAME} www.${DOMAIN_NAME};
|
||||||
|
|
||||||
|
location /.well-known/acme-challenge/ {
|
||||||
|
root /var/www/certbot;
|
||||||
|
}
|
||||||
|
|
||||||
location /static {
|
location /static {
|
||||||
proxy_pass http://frontend:3000;
|
proxy_pass http://frontend:3000;
|
||||||
access_log off;
|
access_log off;
|
||||||
@@ -63,6 +67,10 @@ server {
|
|||||||
|
|
||||||
server_name api.${DOMAIN_NAME};
|
server_name api.${DOMAIN_NAME};
|
||||||
|
|
||||||
|
location /.well-known/acme-challenge/ {
|
||||||
|
root /var/www/certbot;
|
||||||
|
}
|
||||||
|
|
||||||
location /marcsip/upload {
|
location /marcsip/upload {
|
||||||
deny all;
|
deny all;
|
||||||
}
|
}
|
||||||
@@ -100,6 +108,10 @@ server {
|
|||||||
|
|
||||||
server_name account.${DOMAIN_NAME};
|
server_name account.${DOMAIN_NAME};
|
||||||
|
|
||||||
|
location /.well-known/acme-challenge/ {
|
||||||
|
root /var/www/certbot;
|
||||||
|
}
|
||||||
|
|
||||||
location / {
|
location / {
|
||||||
proxy_pass http://account:3009;
|
proxy_pass http://account:3009;
|
||||||
proxy_http_version 1.1;
|
proxy_http_version 1.1;
|
||||||
@@ -127,6 +139,10 @@ server {
|
|||||||
|
|
||||||
server_name admin.${DOMAIN_NAME};
|
server_name admin.${DOMAIN_NAME};
|
||||||
|
|
||||||
|
location /.well-known/acme-challenge/ {
|
||||||
|
root /var/www/certbot;
|
||||||
|
}
|
||||||
|
|
||||||
location / {
|
location / {
|
||||||
proxy_pass http://admin:3008;
|
proxy_pass http://admin:3008;
|
||||||
proxy_http_version 1.1;
|
proxy_http_version 1.1;
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
# Copy your certs here
|
|
||||||
@@ -1,8 +1,14 @@
|
|||||||
|
|
||||||
server {
|
server {
|
||||||
listen 80;
|
listen 80;
|
||||||
|
|
||||||
server_name ${DOMAIN_NAME} www.${DOMAIN_NAME};
|
server_name ${DOMAIN_NAME} www.${DOMAIN_NAME};
|
||||||
|
|
||||||
|
|
||||||
|
location /.well-known/acme-challenge/ {
|
||||||
|
root /var/www/certbot;
|
||||||
|
}
|
||||||
|
|
||||||
location /static {
|
location /static {
|
||||||
proxy_pass http://frontend:3000;
|
proxy_pass http://frontend:3000;
|
||||||
access_log off;
|
access_log off;
|
||||||
@@ -30,6 +36,10 @@ server {
|
|||||||
|
|
||||||
server_name account.${DOMAIN_NAME};
|
server_name account.${DOMAIN_NAME};
|
||||||
|
|
||||||
|
location /.well-known/acme-challenge/ {
|
||||||
|
root /var/www/certbot;
|
||||||
|
}
|
||||||
|
|
||||||
location / {
|
location / {
|
||||||
proxy_pass http://account:3009;
|
proxy_pass http://account:3009;
|
||||||
include /etc/nginx/proxy.conf;
|
include /etc/nginx/proxy.conf;
|
||||||
@@ -42,6 +52,10 @@ server {
|
|||||||
|
|
||||||
server_name admin.${DOMAIN_NAME};
|
server_name admin.${DOMAIN_NAME};
|
||||||
|
|
||||||
|
location /.well-known/acme-challenge/ {
|
||||||
|
root /var/www/certbot;
|
||||||
|
}
|
||||||
|
|
||||||
location / {
|
location / {
|
||||||
proxy_pass http://admin:3008;
|
proxy_pass http://admin:3008;
|
||||||
include /etc/nginx/proxy.conf;
|
include /etc/nginx/proxy.conf;
|
||||||
@@ -54,6 +68,10 @@ server {
|
|||||||
|
|
||||||
server_name api.${DOMAIN_NAME};
|
server_name api.${DOMAIN_NAME};
|
||||||
|
|
||||||
|
location /.well-known/acme-challenge/ {
|
||||||
|
root /var/www/certbot;
|
||||||
|
}
|
||||||
|
|
||||||
location / {
|
location / {
|
||||||
proxy_pass http://backend:3005;
|
proxy_pass http://backend:3005;
|
||||||
include /etc/nginx/proxy.conf;
|
include /etc/nginx/proxy.conf;
|
||||||
|
|||||||
Reference in New Issue
Block a user