diff --git a/.jenkins/config-mysql.json b/.jenkins/config-mysql.json deleted file mode 100644 index 19ad2237f..000000000 --- a/.jenkins/config-mysql.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "database": { - "engine": "mysql", - "host": "db", - "name": "npm", - "user": "npm", - "password": "npm", - "port": 3306 - } -} \ No newline at end of file diff --git a/.jenkins/config-sqlite.json b/.jenkins/config-sqlite.json deleted file mode 100644 index 97d688d21..000000000 --- a/.jenkins/config-sqlite.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "database": { - "engine": "knex-native", - "knex": { - "client": "sqlite3", - "connection": { - "filename": "/data/database.sqlite" - } - } - } -} diff --git a/.version b/.version index 097a15a2a..24ba9a38d 100644 --- a/.version +++ b/.version @@ -1 +1 @@ -2.6.2 +2.7.0 diff --git a/README.md b/README.md index 9fb93d717..a80d05243 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@
-
+
diff --git a/backend/index.js b/backend/index.js
index 0c08af328..50a263bac 100644
--- a/backend/index.js
+++ b/backend/index.js
@@ -2,7 +2,10 @@
const logger = require('./logger').global;
-function appStart () {
+async function appStart () {
+ // Create config file db settings if environment variables have been set
+ await createDbConfigFromEnvironment();
+
const migrate = require('./migrate');
const setup = require('./setup');
const app = require('./app');
@@ -10,6 +13,7 @@ function appStart () {
const internalCertificate = require('./internal/certificate');
const internalIpRanges = require('./internal/ip_ranges');
+
return migrate.latest()
.then(setup)
.then(() => {
@@ -39,6 +43,87 @@ function appStart () {
});
}
+async function createDbConfigFromEnvironment(){
+ return new Promise((resolve, reject) => {
+ const envMysqlHost = process.env.DB_MYSQL_HOST;
+ const envMysqlPort = process.env.DB_MYSQL_PORT;
+ const envMysqlUser = process.env.DB_MYSQL_USER;
+ const envMysqlName = process.env.DB_MYSQL_NAME;
+ const envSqliteFile = process.env.DB_SQLITE_FILE;
+ if ((envMysqlHost && envMysqlPort && envMysqlUser && envMysqlName) || envSqliteFile) {
+ const fs = require('fs');
+ const filename = (process.env.NODE_CONFIG_DIR || './config') + '/' + (process.env.NODE_ENV || 'default') + '.json';
+ let configData = {};
+
+ try {
+ configData = require(filename);
+ } catch (err) {
+ // do nothing
+ }
+
+ if (configData.database && configData.database.engine && !configData.database.fromEnv) {
+ logger.info('Manual db configuration already exists, skipping config creation from environment variables');
+ resolve();
+ return;
+ }
+
+ if (envMysqlHost && envMysqlPort && envMysqlUser && envMysqlName) {
+ const newConfig = {
+ fromEnv: true,
+ engine: 'mysql',
+ host: envMysqlHost,
+ port: envMysqlPort,
+ user: envMysqlUser,
+ password: process.env.DB_MYSQL_PASSWORD,
+ name: envMysqlName,
+ };
+
+ if (JSON.stringify(configData.database) === JSON.stringify(newConfig)) {
+ // Config is unchanged, skip overwrite
+ resolve();
+ return;
+ }
+
+ logger.info('Generating MySQL db configuration from environment variables');
+ configData.database = newConfig;
+
+ } else {
+ const newConfig = {
+ fromEnv: true,
+ engine: 'knex-native',
+ knex: {
+ client: 'sqlite3',
+ connection: {
+ filename: envSqliteFile
+ }
+ }
+ };
+ if (JSON.stringify(configData.database) === JSON.stringify(newConfig)) {
+ // Config is unchanged, skip overwrite
+ resolve();
+ return;
+ }
+
+ logger.info('Generating Sqlite db configuration from environment variables');
+ configData.database = newConfig;
+ }
+
+ // Write config
+ fs.writeFile(filename, JSON.stringify(configData, null, 2), (err) => {
+ if (err) {
+ logger.error('Could not write db config to config file: ' + filename);
+ reject(err);
+ } else {
+ logger.info('Wrote db configuration to config file: ' + filename);
+ resolve();
+ }
+ });
+ } else {
+ // resolve();
+ }
+ });
+}
+
try {
appStart();
} catch (err) {
diff --git a/backend/internal/certificate.js b/backend/internal/certificate.js
index 19e0592e9..3725c1c8f 100644
--- a/backend/internal/certificate.js
+++ b/backend/internal/certificate.js
@@ -216,6 +216,13 @@ const internalCertificate = {
return saved_row;
});
});
+ }).catch(async (error) => {
+ // Delete the certificate from the database if it was not created successfully
+ await certificateModel
+ .query()
+ .deleteById(certificate.id);
+
+ throw error;
});
} else {
return certificate;
diff --git a/docker/docker-compose.ci.yml b/docker/docker-compose.ci.yml
index 2228623f5..89c38572d 100644
--- a/docker/docker-compose.ci.yml
+++ b/docker/docker-compose.ci.yml
@@ -5,11 +5,15 @@ services:
fullstack-mysql:
image: ${IMAGE}:ci-${BUILD_NUMBER}
environment:
- - NODE_ENV=development
- - FORCE_COLOR=1
+ NODE_ENV: "development"
+ FORCE_COLOR: 1
+ DB_MYSQL_HOST: "db"
+ DB_MYSQL_PORT: 3306
+ DB_MYSQL_USER: "npm"
+ DB_MYSQL_PASSWORD: "npm"
+ DB_MYSQL_NAME: "npm"
volumes:
- npm_data:/data
- - ../.jenkins/config-mysql.json:/app/config/development.json
expose:
- 81
- 80
@@ -20,11 +24,11 @@ services:
fullstack-sqlite:
image: ${IMAGE}:ci-${BUILD_NUMBER}
environment:
- - NODE_ENV=development
- - FORCE_COLOR=1
+ NODE_ENV: "development"
+ FORCE_COLOR: 1
+ DB_SQLITE_FILE: "/data/database.sqlite"
volumes:
- npm_data:/data
- - ../.jenkins/config-sqlite.json:/app/config/development.json
expose:
- 81
- 80
diff --git a/docker/docker-compose.dev.yml b/docker/docker-compose.dev.yml
index 5668dbd27..a0b4547ba 100644
--- a/docker/docker-compose.dev.yml
+++ b/docker/docker-compose.dev.yml
@@ -14,10 +14,16 @@ services:
networks:
- nginx_proxy_manager
environment:
- - NODE_ENV=development
- - FORCE_COLOR=1
- - DEVELOPMENT=true
- #- DISABLE_IPV6=true
+ NODE_ENV: "development"
+ FORCE_COLOR: 1
+ DEVELOPMENT: "true"
+ DB_MYSQL_HOST: "db"
+ DB_MYSQL_PORT: 3306
+ DB_MYSQL_USER: "npm"
+ DB_MYSQL_PASSWORD: "npm"
+ DB_MYSQL_NAME: "npm"
+ # DB_SQLITE_FILE: "/data/database.sqlite"
+ # DISABLE_IPV6: "true"
volumes:
- npm_data:/data
- le_data:/etc/letsencrypt
diff --git a/docs/README.md b/docs/README.md
index 0ee8154ec..3f2f62822 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -45,21 +45,7 @@ footer: MIT Licensed | Copyright © 2016-present jc21.com
- [Docker Install documentation](https://docs.docker.com/install/)
- [Docker-Compose Install documentation](https://docs.docker.com/compose/install/)
-2. Create a config file for example
-```json
-{
- "database": {
- "engine": "mysql",
- "host": "db",
- "name": "npm",
- "user": "npm",
- "password": "npm",
- "port": 3306
- }
-}
-```
-
-3. Create a docker-compose.yml file similar to this:
+2. Create a docker-compose.yml file similar to this:
```yml
version: '3'
@@ -70,8 +56,13 @@ services:
- '80:80'
- '81:81'
- '443:443'
+ environment:
+ DB_MYSQL_HOST: "db"
+ DB_MYSQL_PORT: 3306
+ DB_MYSQL_USER: "npm"
+ DB_MYSQL_PASSWORD: "npm"
+ DB_MYSQL_NAME: "npm"
volumes:
- - ./config.json:/app/config/production.json
- ./data:/data
- ./letsencrypt:/etc/letsencrypt
db:
@@ -85,13 +76,13 @@ services:
- ./data/mysql:/var/lib/mysql
```
-4. Bring up your stack
+3. Bring up your stack
```bash
docker-compose up -d
```
-5. Log in to the Admin UI
+4. Log in to the Admin UI
When your docker container is running, connect to it on port `81` for the admin interface.
Sometimes this can take a little bit because of the entropy of keys.
diff --git a/docs/setup/README.md b/docs/setup/README.md
index 52160e177..8af7eee23 100644
--- a/docs/setup/README.md
+++ b/docs/setup/README.md
@@ -1,50 +1,5 @@
# Full Setup Instructions
-### Configuration File
-
-**The configuration file needs to be provided by you!**
-
-Don't worry, this is easy to do.
-
-The app requires a configuration file to let it know what database you're using. By default, this file is called `config.json`
-
-Here's an example configuration for `mysql` (or mariadb) that is compatible with the docker-compose example below:
-
-```json
-{
- "database": {
- "engine": "mysql",
- "host": "db",
- "name": "npm",
- "user": "npm",
- "password": "npm",
- "port": 3306
- }
-}
-```
-
-Alternatively if you would like to use a Sqlite database file:
-
-```json
-{
- "database": {
- "engine": "knex-native",
- "knex": {
- "client": "sqlite3",
- "connection": {
- "filename": "/data/database.sqlite"
- }
- }
- }
-}
-```
-
-Once you've created your configuration file it's easy to mount it in the docker container.
-
-**Note:** After the first run of the application, the config file will be altered to include generated encryption keys unique to your installation. These keys
-affect the login and session management of the application. If these keys change for any reason, all users will be logged out.
-
-
### MySQL Database
If you opt for the MySQL configuration you will have to provide the database server yourself. You can also use MariaDB. Here are the minimum supported versions:
@@ -61,7 +16,6 @@ When using a `mariadb` database, the NPM configuration file should still use the
:::
-
### Running the App
Via `docker-compose`:
@@ -70,7 +24,7 @@ Via `docker-compose`:
version: "3"
services:
app:
- image: jc21/nginx-proxy-manager:2
+ image: 'jc21/nginx-proxy-manager:latest'
restart: always
ports:
# Public HTTP Port:
@@ -80,11 +34,18 @@ services:
# Admin Web Port:
- '81:81'
environment:
+ # These are the settings to access your db
+ DB_MYSQL_HOST: "db"
+ DB_MYSQL_PORT: 3306
+ DB_MYSQL_USER: "npm"
+ DB_MYSQL_PASSWORD: "npm"
+ DB_MYSQL_NAME: "npm"
+ # If you would rather use Sqlite uncomment this
+ # and remove all DB_MYSQL_* lines above
+ # DB_SQLITE_FILE: "/data/database.sqlite"
# Uncomment this if IPv6 is not enabled on your host
# DISABLE_IPV6: 'true'
volumes:
- # Make sure this config.json file exists as per instructions above:
- - ./config.json:/app/config/production.json
- ./data:/data
- ./letsencrypt:/etc/letsencrypt
depends_on:
@@ -101,14 +62,14 @@ services:
- ./data/mysql:/var/lib/mysql
```
+_Please note, that `DB_MYSQL_*` environment variables will take precedent over `DB_SQLITE_*` variables. So if you keep the MySQL variables, you will not be able to use Sqlite._
+
Then:
```bash
docker-compose up -d
```
-The config file (config.json) must be present in this directory.
-
### Running on Raspberry PI / ARM devices
The docker images support the following architectures:
@@ -146,3 +107,49 @@ Password: changeme
```
Immediately after logging in with this default user you will be asked to modify your details and change your password.
+
+### Configuration File
+
+::: warning
+
+This section is meant for advanced users
+
+:::
+
+If you would like more control over the database settings you can define a custom config JSON file.
+
+
+Here's an example for `sqlite` configuration as it is generated from the environment variables:
+
+```json
+{
+ "database": {
+ "engine": "knex-native",
+ "knex": {
+ "client": "sqlite3",
+ "connection": {
+ "filename": "/data/database.sqlite"
+ }
+ }
+ }
+}
+```
+
+You can modify the `knex` object with your custom configuration, but note that not all knex clients might be installed in the image.
+
+Once you've created your configuration file you can mount it to `/app/config/production.json` inside you container using:
+
+```
+[...]
+services:
+ app:
+ image: 'jc21/nginx-proxy-manager:latest'
+ [...]
+ volumes:
+ - ./config.json:/app/config/production.json
+ [...]
+[...]
+```
+
+**Note:** After the first run of the application, the config file will be altered to include generated encryption keys unique to your installation.
+These keys affect the login and session management of the application. If these keys change for any reason, all users will be logged out.
diff --git a/frontend/js/app/nginx/certificates/delete.js b/frontend/js/app/nginx/certificates/delete.js
index 426e25064..89a2e5e83 100644
--- a/frontend/js/app/nginx/certificates/delete.js
+++ b/frontend/js/app/nginx/certificates/delete.js
@@ -16,6 +16,8 @@ module.exports = Mn.View.extend({
events: {
'click @ui.save': function (e) {
e.preventDefault();
+ this.ui.save.addClass('btn-loading');
+ this.ui.buttons.prop('disabled', true).addClass('btn-disabled');
App.Api.Nginx.Certificates.delete(this.model.get('id'))
.then(() => {
@@ -25,6 +27,7 @@ module.exports = Mn.View.extend({
.catch(err => {
alert(err.message);
this.ui.buttons.prop('disabled', false).removeClass('btn-disabled');
+ this.ui.save.removeClass('btn-loading');
});
}
}