Compare commits

...

278 Commits

Author SHA1 Message Date
jc21
63d06da8a8
Merge branch 'master' into develop 2024-07-01 16:12:21 +10:00
Jamie Curnow
b5a0d74654
Bump version 2024-07-01 16:09:33 +10:00
Jamie Curnow
99cce7e2b0
Fix command injection when passing bash commands into the dns provider configuration
- Use built in node functions to write the file
- And to delete the file
2024-07-01 16:08:01 +10:00
jc21
120d50e5c0
Merge pull request from kroegerama/kroegerama-patch-1
Add include for `root_top.conf` in the nginx.conf
2024-07-01 15:23:43 +10:00
jc21
5454fd61b3
Merge pull request from jinhei/patch-1
Remove spaces around Cloudflare API Credential
2024-07-01 15:22:43 +10:00
jc21
b33012705b
Merge pull request from DavidLievrouw/initial_admin
Read initial admin email and password from env vars
2024-07-01 15:22:15 +10:00
jc21
e948b60194
Merge pull request from NginxProxyManager/dependabot/npm_and_yarn/backend/braces-3.0.3
Bump braces from 3.0.2 to 3.0.3 in /backend
2024-07-01 15:20:48 +10:00
jc21
7913c9a07d
Merge pull request from Hadatko/feature/addWedosDns
Add wedos dns
2024-07-01 15:20:23 +10:00
jc21
d1c23b6286
Merge pull request from NginxProxyManager/dependabot/npm_and_yarn/backend/glob-parent-5.1.2
Bump glob-parent from 5.1.1 to 5.1.2 in /backend
2024-07-01 15:19:39 +10:00
jc21
c7e2946dbf
Merge pull request from Allesanddro/patch-1
Update README.md
2024-07-01 15:19:28 +10:00
jc21
8936402229
Merge pull request from jay-lab/feature/fix-syntax-cause-err
Fix syntax that causes errors (generateKeys log)
2024-07-01 15:19:00 +10:00
An Seongjin
001c77e686
Fix syntax that causes errors (generateKeys log) 2024-06-30 22:27:54 +09:00
Dusan Cervenka
5578e825b1 Update version
Signed-off-by: Dusan Cervenka <cervenka.dusan@gmail.com>
2024-06-29 21:30:27 +02:00
S.S
c93656a7a1
Update README.md
In 2020, the concept of a single compose specification was introduced, removing the need for versioning.
2024-06-28 20:04:31 +02:00
dependabot[bot]
50aeae234f
Bump glob-parent from 5.1.1 to 5.1.2 in /backend
Bumps [glob-parent](https://github.com/gulpjs/glob-parent) from 5.1.1 to 5.1.2.
- [Release notes](https://github.com/gulpjs/glob-parent/releases)
- [Changelog](https://github.com/gulpjs/glob-parent/blob/main/CHANGELOG.md)
- [Commits](https://github.com/gulpjs/glob-parent/compare/v5.1.1...v5.1.2)

---
updated-dependencies:
- dependency-name: glob-parent
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-06-27 18:24:09 +00:00
Dusan Cervenka
a5c06c1a34 Add wedos dns
Signed-off-by: Dusan Cervenka <cervenka.dusan@gmail.com>
2024-06-25 23:26:50 +02:00
jc21
51414ced3a
Merge pull request from Brendon-Mendicino/change_log_format_location
Changing `log_format proxy` default location
2024-06-25 10:17:04 +10:00
jc21
5e35e538af
Merge pull request from alexjsp/alex/hover-dns-plugin
Add Hover.com DNS plugin
2024-06-25 10:16:03 +10:00
Alex Stevenson-Price
13fec42d1f
Add Hover.com DNS plugin 2024-06-20 11:47:50 +01:00
Brendon Mendicino
b4560d7dde feat: changing log_format proxy default location
This is useful when some user would want to change the default
log format for each of the service, without the need of creating a
new `log_format custom` and changing the `access_log` for each
service.
2024-06-16 15:44:52 +02:00
dependabot[bot]
6f9eed8a61
Bump braces from 3.0.2 to 3.0.3 in /backend
Bumps [braces](https://github.com/micromatch/braces) from 3.0.2 to 3.0.3.
- [Changelog](https://github.com/micromatch/braces/blob/master/CHANGELOG.md)
- [Commits](https://github.com/micromatch/braces/compare/3.0.2...3.0.3)

---
updated-dependencies:
- dependency-name: braces
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-06-16 10:41:32 +00:00
David Lievrouw
d66e4e03e6 Attempt to make ci happy. 2024-06-03 13:44:08 +02:00
David Lievrouw
1d19c29bb0 Read initial admin email and password from env vars. 2024-06-03 13:32:23 +02:00
Nicholas Fong
e20a11de4a
Remove spaces around cloudflare api credential 2024-05-28 23:32:03 -04:00
Jamie Curnow
d3a654b546
Fix flakey CI due to full stack network determination 2024-05-23 08:12:51 +10:00
Jamie Curnow
bed387ebd4 Small fix for CI cleanup 2024-05-21 13:16:53 +10:00
Jamie Curnow
6ac9a82279 Major update to cypress
- Updated cypress
- Ground work for testing DNS certs in CI
2024-05-21 12:53:07 +10:00
kroegerama
ef23e796ec
update advanced config documentation
describe the `root_top.conf` file and add a snippet for enabling the geoip2 module
2024-05-20 10:35:36 +02:00
jc21
3754a569ba
Merge pull request from clhey/custom_proxy
move advanced_config section of /app/templates/_location.conf to top of default config
2024-05-20 13:53:09 +10:00
jc21
b383f46656
Merge pull request from ransbachm/develop
Fix Cloudflare DNS Auth
2024-05-20 13:46:39 +10:00
kroegerama
3ce477d350
add include for root_top.conf in the nginx.conf
Allow custom configuration of the root config in the top of the file. This can be used to load modules, which is not possible at the end of the config file.
There is already a `http_top.conf`, so `root_top.conf` is a logical addition.
2024-05-19 15:53:02 +02:00
ransbachm
516b4d991c
Pin version as requested by dep 2024-05-18 22:49:48 +02:00
jc21
12d77e3ab6
Merge pull request from NginxProxyManager/develop
Docs migration from vuepress to vitepress
2024-05-11 00:33:13 +10:00
Jamie Curnow
8d80af3a26
Fix CI 2024-05-11 00:15:44 +10:00
Jamie Curnow
1f45e6a5e9
Fix unescaped character in CI 2024-05-11 00:14:05 +10:00
Jamie Curnow
dcb9628c36
CI improvement: move docs upload to separate build 2024-05-11 00:13:11 +10:00
jc21
029b184398
Merge branch 'master' into develop 2024-05-10 23:31:28 +10:00
Jamie Curnow
2422587530
Updates to docs FAQ 2024-05-10 23:28:36 +10:00
Jamie Curnow
4ee940d3dc
Fix missing feature on docs homepage 2024-05-10 23:10:55 +10:00
Jamie Curnow
47dddc548b
Migrate from vuepress to vitepress for docs site 2024-05-10 23:00:27 +10:00
jc21
256a667e2c
Merge pull request from NginxProxyManager/develop
v2.11.2
2024-05-02 09:43:20 +10:00
jc21
79cd0c5294
Merge branch 'master' into develop 2024-05-02 08:40:10 +10:00
Jamie Curnow
09a03edfd7
Bump version 2024-05-02 08:21:32 +10:00
jc21
35f0fe745d
Merge pull request from NginxProxyManager/dependabot/npm_and_yarn/backend/ip-2.0.1
Bump ip from 2.0.0 to 2.0.1 in /backend
2024-05-02 08:19:02 +10:00
jc21
f1e433714e
Merge pull request from NginxProxyManager/dependabot/npm_and_yarn/docs/ip-2.0.1
Bump ip from 2.0.0 to 2.0.1 in /docs
2024-05-02 08:18:51 +10:00
jc21
035eaed0a4
Merge pull request from sdaqo/patch-1
Update certbot-dns-duckdns version (fix )
2024-05-02 08:18:32 +10:00
jc21
4b100a384d
Merge pull request from jdolderer/fix/update-certbot-dns-strato
fix: update certbot-dns-strato to latest version
2024-05-02 08:17:02 +10:00
jc21
c5c5fa0a5a
Merge pull request from Fuechslein/fix/certbot-dns-infomaniak
Update certbot-dns-infomaniak
2024-05-02 08:16:45 +10:00
clhey
280bac8b43 advanced config move to top of default confg 2024-04-28 18:18:38 +08:00
jc21
02aefa50cd
Merge pull request from woodmichl/fix-slow-startup
replaced chown with find -not -user -execdir chown
2024-04-19 21:00:31 +10:00
jc21
4d91cfc397
Merge pull request from wolviex/develop
Update certbot-dns-goddaddy
2024-04-19 20:59:09 +10:00
jc21
79a453f2fe
Merge pull request from leinelissen/fix/certbot-dns-transip
fix: update certbot-dns-transip to latest version
2024-04-19 20:56:59 +10:00
jc21
c62c09569d
Merge pull request from starsoccer/patch-1
Add DNS multi
2024-04-19 20:12:04 +10:00
jc21
09bcf4010c
Merge pull request from NginxProxyManager/dependabot/npm_and_yarn/backend/express-4.19.2
Bump express from 4.17.3 to 4.19.2 in /backend
2024-04-19 20:10:35 +10:00
jc21
6aeade6c98
Merge pull request from NginxProxyManager/dependabot/npm_and_yarn/docs/vite-5.0.13
Bump vite from 5.0.12 to 5.0.13 in /docs
2024-04-19 20:10:24 +10:00
jc21
8655b7d2db
Merge pull request from NginxProxyManager/dependabot/npm_and_yarn/frontend/tar-6.2.1
Bump tar from 6.1.11 to 6.2.1 in /frontend
2024-04-19 20:06:59 +10:00
jc21
2d929dffa8
Merge pull request from NginxProxyManager/dependabot/npm_and_yarn/docs/tar-6.2.1
Bump tar from 6.2.0 to 6.2.1 in /docs
2024-04-19 20:06:44 +10:00
dependabot[bot]
52eaa042d8
Bump tar from 6.2.0 to 6.2.1 in /docs
Bumps [tar](https://github.com/isaacs/node-tar) from 6.2.0 to 6.2.1.
- [Release notes](https://github.com/isaacs/node-tar/releases)
- [Changelog](https://github.com/isaacs/node-tar/blob/main/CHANGELOG.md)
- [Commits](https://github.com/isaacs/node-tar/compare/v6.2.0...v6.2.1)

---
updated-dependencies:
- dependency-name: tar
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-04-11 14:00:31 +00:00
dependabot[bot]
b35aa50b88
Bump tar from 6.1.11 to 6.2.1 in /frontend
Bumps [tar](https://github.com/isaacs/node-tar) from 6.1.11 to 6.2.1.
- [Release notes](https://github.com/isaacs/node-tar/releases)
- [Changelog](https://github.com/isaacs/node-tar/blob/main/CHANGELOG.md)
- [Commits](https://github.com/isaacs/node-tar/compare/v6.1.11...v6.2.1)

---
updated-dependencies:
- dependency-name: tar
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-04-10 21:18:28 +00:00
Fuechslein
c575a706b5
Update certbot-dns-plugins.json
Latest plugin version with several fixes
2024-04-09 10:12:55 +02:00
Jakob Dolderer
587b97c2d3
fix: update certbot-dns-strato to latest version 2024-04-04 12:27:16 +02:00
dependabot[bot]
317003beda
Bump vite from 5.0.12 to 5.0.13 in /docs
Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) from 5.0.12 to 5.0.13.
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/v5.0.13/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/v5.0.13/packages/vite)

---
updated-dependencies:
- dependency-name: vite
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-04-03 18:36:32 +00:00
dependabot[bot]
5a761236c5
Bump express from 4.17.3 to 4.19.2 in /backend
Bumps [express](https://github.com/expressjs/express) from 4.17.3 to 4.19.2.
- [Release notes](https://github.com/expressjs/express/releases)
- [Changelog](https://github.com/expressjs/express/blob/master/History.md)
- [Commits](https://github.com/expressjs/express/compare/4.17.3...4.19.2)

---
updated-dependencies:
- dependency-name: express
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-03-28 02:21:37 +00:00
starsoccer
b135527347
Fix version key 2024-03-20 11:58:47 -04:00
starsoccer
abca9cc89c
Add DNS multi
Credit to original PR 
2024-03-20 11:19:47 -04:00
Lei Nelissen
6721923601
fix: update certbot-dns-transip to latest version 2024-03-20 11:07:29 +01:00
Joe Manifold
a88f77c1a5
Update certbot-dns-plugins.json
Pinned certbot-dns-godaddy at 2.8.0
2024-03-19 10:18:41 -07:00
woodmichl
a5b21d0306
replaxed chown with find -not -user ... chown
chown -R tries to chown all files. find -not -user -execdir only chowns files not owned by PUID
2024-03-10 01:55:18 +01:00
sdaqo
8eab8d71f2
Update duckdns version 2024-03-03 20:57:53 +01:00
dependabot[bot]
d06572bb5f
Bump ip from 2.0.0 to 2.0.1 in /docs
Bumps [ip](https://github.com/indutny/node-ip) from 2.0.0 to 2.0.1.
- [Commits](https://github.com/indutny/node-ip/compare/v2.0.0...v2.0.1)

---
updated-dependencies:
- dependency-name: ip
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-02-27 01:45:05 +00:00
jc21
d40f9e06fc
Merge pull request from NginxProxyManager/dependabot/npm_and_yarn/docs/vite-5.0.12
Bump vite from 5.0.11 to 5.0.12 in /docs
2024-02-27 11:44:04 +10:00
jc21
69ec017a53
Merge pull request from setrin/websupport-fix
Updated certbot-dns-websupport plugin to 2.0.1 
2024-02-27 11:43:47 +10:00
jc21
fa67f257ef
Merge pull request from eltociear/patch-1
Update README.md
2024-02-27 11:43:24 +10:00
jc21
0dcd648c9d
Merge pull request from hywax/develop
Add DNS Provider TimeWeb Cloud
2024-02-27 11:41:56 +10:00
jc21
c989a282e3
Merge pull request from Habbie/jwt-not-gpg
the generated keys appear to be for JWT, not GPG
2024-02-27 11:41:28 +10:00
jc21
5aff969c04
Merge pull request from bricas/develop
Add FreeDNS certbot plugin
2024-02-27 11:38:12 +10:00
jc21
bfbf7519ec
Merge pull request from drachul/develop
Adding easyDNS provider.
2024-02-27 11:37:51 +10:00
jc21
bf36c7966a
Merge pull request from NginxProxyManager/dependabot/npm_and_yarn/frontend/ip-2.0.1
Bump ip from 2.0.0 to 2.0.1 in /frontend
2024-02-27 11:36:18 +10:00
jc21
63cd9ba08f
Merge pull request from davidindra/increase-max-domains-count
Fix: increase max number of domains to 100 (match with Let's Encrypt)
2024-02-27 11:36:04 +10:00
jc21
e3d4882c3d
Merge pull request from michto01/patch-1
Update README.md to support Podman
2024-02-27 11:35:23 +10:00
jc21
3e1b73143e
Merge pull request from timob/develop
Access-List fix so that nginx config is loaded after configuration happens
2024-02-27 11:34:52 +10:00
David Indra
10ece3548d Fixing "the map directive is not allowed here" at the validation stage (see https://github.com/NginxProxyManager/nginx-proxy-manager/pull/3478) 2024-02-27 00:42:58 +01:00
Tim
0503a6af75 Fix so that nginx config is loaded after configuration happens
M	backend/internal/access-list.js
2024-02-26 10:04:25 +11:00
Tomas Michalek
55d765e785
Update README.md to support Podman
Podman by default doesn't except the not fully qualified image urls. This commit adds the domain (docker.io) in order to resolve this issue.
2024-02-25 22:38:50 +01:00
David Indra
1fb9a75a33 Fix: increase max number of domains to 100 2024-02-23 15:37:32 +01:00
dependabot[bot]
9c2e838d61
Bump ip from 2.0.0 to 2.0.1 in /frontend
Bumps [ip](https://github.com/indutny/node-ip) from 2.0.0 to 2.0.1.
- [Commits](https://github.com/indutny/node-ip/compare/v2.0.0...v2.0.1)

---
updated-dependencies:
- dependency-name: ip
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-02-21 03:12:49 +00:00
dependabot[bot]
c55e47aacf
Bump ip from 2.0.0 to 2.0.1 in /backend
Bumps [ip](https://github.com/indutny/node-ip) from 2.0.0 to 2.0.1.
- [Commits](https://github.com/indutny/node-ip/compare/v2.0.0...v2.0.1)

---
updated-dependencies:
- dependency-name: ip
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-02-20 21:49:54 +00:00
Derek Rachul
40d81d6e44 Adding easyDNS provider. 2024-02-17 12:32:05 -08:00
Brian Cassidy
1c84eaac02
Add FreeDNS certbot plugin
Info from  and https://github.com/schleuss/certbot_dns_freedns
2024-02-15 23:43:53 -04:00
Alexander
577954ef8c
Bump version DNS Provider TimeWeb Cloud 2024-02-08 03:20:53 +05:00
Peter van Dijk
f0c75641d8 the generated keys appear to be for JWT, not GPG 2024-02-07 12:44:37 +01:00
hywax
e42e2acf12 Add DNS Provider TimeWeb Cloud 2024-02-07 13:12:20 +05:00
Ikko Eltociear Ashimine
eaa11fe460
Update README.md
a -> an
2024-02-04 18:50:50 +09:00
Setrin
5b53825ccb Fixed certbot-dns-websupport plugin name 2024-01-30 22:46:05 +01:00
Setrin
a94660120f Renamed certbot-dns-websupportsk plugin to certbot-dns-websupport & updatedcredentials 2024-01-30 22:17:33 +01:00
Setrin
39f4836485 Updated certbot-dns-webstorm plugin to 2.0.1 2024-01-30 20:57:19 +01:00
jc21
aec30207da
Merge pull request from NginxProxyManager/develop
v2.11.1
2024-01-21 21:17:30 +10:00
jc21
209c1b3334
Merge branch 'master' into develop 2024-01-21 21:16:30 +10:00
Jamie Curnow
58138fbac4
Bump version 2024-01-21 21:13:03 +10:00
Jamie Curnow
da820db4e1
Fix startup hang due to unresolved promise
Affects instances where there are certs but none
of them are dns validated
2024-01-21 20:48:53 +10:00
dependabot[bot]
47b868bfc6
Bump vite from 5.0.11 to 5.0.12 in /docs
Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) from 5.0.11 to 5.0.12.
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/v5.0.12/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/v5.0.12/packages/vite)

---
updated-dependencies:
- dependency-name: vite
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-01-19 22:36:30 +00:00
jc21
89a405f60c
Merge pull request from NginxProxyManager/develop
v2.11.0
2024-01-19 10:52:34 +10:00
Jamie Curnow
0353051436
Prevent installing same plugin over and over 2024-01-18 16:06:09 +10:00
Jamie Curnow
a3630a6286
Fix unused var 2024-01-18 15:17:27 +10:00
Jamie Curnow
10d9760242
Refactor certbot plugin install for setup 2024-01-18 15:13:16 +10:00
jc21
c722eb1cea
Merge branch 'master' into develop 2024-01-18 13:21:39 +10:00
Jamie Curnow
0472abacd2
Remove test file 2024-01-18 13:20:03 +10:00
Jamie Curnow
a2e85ceed8
Use certbot version for godaddy plugin, relates to 2024-01-18 13:08:16 +10:00
Jamie Curnow
cddd6fb985
certbot-dns-cloudns update 0.6.0 from PR by @existful 2024-01-18 13:01:05 +10:00
Jamie Curnow
db23c9a52f
Refactor certbot plugins install
- Added a script to install every single plugin, used in development and debugging
- Improved certbot plugin install commands
- Adjusted some version for plugins to install properly
- It's noted that some plugins require deps that do not match other plugins,
  however these use cases should be extremely rare
2024-01-18 12:26:55 +10:00
Jamie Curnow
8646cb5a19
Allow stale action to run manually 2024-01-16 07:57:38 +10:00
Jamie Curnow
fe0c04610f
Add stale github action and set a wide limit 2024-01-16 07:53:02 +10:00
jc21
9f16dae2ff
Merge pull request from iBobik/patch-1
Removed /etc/letsencrypt from explicit volumes
2024-01-15 09:12:44 +10:00
Jamie Curnow
00264bcfb2
Mount letsencrypt folder in CI 2024-01-15 08:18:48 +10:00
Jamie Curnow
834fb1a361
Add missing args to certbot command, was causing failures in rovokation 2024-01-12 17:04:55 +10:00
jc21
1be87f48c1
Merge pull request from stevecrozz/auto-renew-uses-bulitin-renew
Make auto-renew use built-in renew function
2024-01-12 12:15:37 +10:00
Stephen Crosby
9c54d1b718 Provide the token model for certificate renewal 2024-01-10 20:08:36 -08:00
Stephen Crosby
f7d1c490b3 Run renews sequentially 2024-01-10 20:08:36 -08:00
Stephen Crosby
fe4bd9fed6 Make auto-renew use built-in renew function 2024-01-10 20:08:29 -08:00
jc21
58ef9a688e
Merge pull request from tilalx/develop
Update the vuepress config.js to fix pr/3395
2024-01-10 20:43:33 +10:00
tilalx
d19ebf5925 Update the config.js to fix pr/3395 2024-01-10 11:06:40 +01:00
jc21
96fc6a20bb
Merge pull request from NginxProxyManager/bookworm-base
Use nginxproxymanager/nginx-full image base
2024-01-10 13:18:10 +10:00
Jamie Curnow
e69684919c
Use nginxproxymanager/nginx-full image base
which has been updated with bookworm, python 3.8, certbot 2.8.0 and node 20

Moved rootfs scripts as /bin is a symlink in bookworm
2024-01-10 12:59:51 +10:00
Jamie Curnow
be39253a6f
No need to use berry yarn for docs
as the ci image uses latest yarn
2024-01-10 09:39:25 +10:00
Jamie Curnow
30772a48bd
Fix jenkinsfile after messy merge - again 2024-01-10 09:29:05 +10:00
Jamie Curnow
33c867895c
Fix jenkinsfile after messy merge 2024-01-10 09:24:45 +10:00
Jamie Curnow
a7fe687bae
Fix permission recursiveness 2024-01-10 09:22:34 +10:00
jc21
4028120f55
Merge pull request from tilalx/develop
upgrade docs to vuepress v2.0.0-rc and implement dark mode
2024-01-10 09:21:10 +10:00
tilalx
d1119ec63f revert change 2024-01-09 09:35:16 +01:00
tilalx
4c906283df try to set the yarn version in jenkins 2024-01-09 09:35:15 +01:00
tilalx
8ec0c76f51 update docs-build and add yarn.lock 2024-01-09 09:31:39 +01:00
tilalx
c70f65d349 upgrade to v2.0.0-rc and implement dark mode 2024-01-09 09:27:34 +01:00
Jamie Curnow
883a272b0a
Bump version 2024-01-09 11:30:50 +10:00
Jamie Curnow
6aee2bbcba
Fix race condition with integration network 2024-01-09 10:57:47 +10:00
Jamie Curnow
025fc9776b
Pre-build cypress images before runnings integration tests 2024-01-09 10:32:58 +10:00
Jamie Curnow
b699f05f47
Run integration tests in parallel 2024-01-09 10:25:10 +10:00
Jamie Curnow
f7c87f63bd
Updated CI to run some things in parallel 2024-01-09 10:05:19 +10:00
Jamie Curnow
e4ef095254
Deploy develop docs in CI, updated readme 2024-01-09 08:36:32 +10:00
jc21
09d5e2c94f
Merge pull request from DarioViva42/hsts-only-with-https
only add hsts header with https.
2024-01-09 08:16:01 +10:00
jc21
459b7a2223
Merge pull request from timob/improve-container-start
Improve container startup time
2024-01-09 08:15:33 +10:00
jc21
9c813bcce3
Merge pull request from Encephala/fix-logrotate-docs
Fix typo in logrotate config path
2024-01-09 07:41:36 +10:00
jc21
b8596ac01c
Merge pull request from ej52/develop
chore: update Proxmox Scripts link
2024-01-09 07:40:50 +10:00
Encephala
082c4e1008 Fix typo in logrotate config path 2024-01-08 16:14:27 +01:00
jc21
2273eae6ee
Merge pull request from NginxProxyManager/dependabot/npm_and_yarn/docs/babel/traverse-7.23.7
Bump @babel/traverse from 7.11.0 to 7.23.7 in /docs
2024-01-08 11:16:53 +10:00
jc21
997e9d431b
Merge pull request from benhubert/2153_add-support-for-dns-hurricane-electric
added support for dns.he.net certbot plugin 
2024-01-08 10:49:27 +10:00
dependabot[bot]
b3564b6d4b
Bump @babel/traverse from 7.11.0 to 7.23.7 in /docs
Bumps [@babel/traverse](https://github.com/babel/babel/tree/HEAD/packages/babel-traverse) from 7.11.0 to 7.23.7.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.23.7/packages/babel-traverse)

---
updated-dependencies:
- dependency-name: "@babel/traverse"
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-01-08 00:35:43 +00:00
jc21
4e27cdabc4
Merge pull request from NginxProxyManager/dependabot/npm_and_yarn/frontend/babel/traverse-7.23.2
Bump @babel/traverse from 7.11.0 to 7.23.2 in /frontend
2024-01-08 10:34:03 +10:00
jc21
965873adc5
Merge pull request from jlesage/http2-support-fix
Fixed issue where the HTTP2 support was always enabled in nginx config
2024-01-08 10:33:47 +10:00
jc21
5de95a8c90
Merge pull request from r3na/patch-1
fix: increasing maxOptions (amount of domains) to 30
2024-01-08 10:26:01 +10:00
jc21
fa557d8159
Merge pull request from clord/clord/update-vultr
chore: bump version of vultr certbot
2024-01-08 10:19:58 +10:00
jc21
bc8211a6a9
Merge pull request from jlesage/reachability-test-fix
Fixes for the server reachability test.
2024-01-08 10:19:27 +10:00
jc21
1c498f84ad
Merge pull request from hywax/patch-1
Fix proxmox scripts link
2024-01-08 10:13:06 +10:00
jc21
ea6e9757e3
Merge pull request from JeremieA/certbot-dns-gandi-1.5.0
Update certbot-dns-plugins.js for gandi
2024-01-08 10:12:50 +10:00
jc21
1308ae42c2
Merge pull request from arussell/certbot-dns-plesk
Add support for certbot-dns-plesk
2024-01-08 10:12:24 +10:00
jc21
7be548575b
Merge pull request from Encephala/logrotate-docs
Add documentation on customising logrotate config
2024-01-08 10:12:03 +10:00
jc21
c6aab8d4e6
Merge pull request from Encephala/bump-year
Update year to 2024 in footer
2024-01-08 10:10:44 +10:00
Encephala
da55e93183 Update year to 2024 in footer 2024-01-03 16:48:58 +01:00
Encephala
af475ab5d4 Add documentation on customising logrotate config 2023-12-30 15:23:17 +01:00
Aaron B. Russell
7d85463dae
Add support for certbot-dns-plesk 2023-12-21 16:07:34 +00:00
Jeremie Allard
13d4f98fdb Update certbot-dns-plugins.js for gandi (deprecation of Apikey in favor of personal tokens) 2023-12-20 12:19:17 +01:00
Jocelyn Le Sage
388fff84f2 Fixes for the server reachability test.
- Do not apply HTTPs redirection for challenge used by the test.
- Set the `User-Agent` to avoid 403 answer from site24x7.com.
- Handle JSON parsing failure of the received body.
- Better handling of different error cases.
2023-12-19 17:22:33 -05:00
Alexander
49a765516c
Fix proxmox scripts link 2023-12-19 18:37:50 +05:00
Christopher Lord
27bc8c4e33
use same formatting 2023-12-13 15:15:02 -07:00
Christopher Lord
881a067aff
update to latest vultr certbot plugin
closes https://github.com/NginxProxyManager/nginx-proxy-manager/issues/3234
2023-12-13 15:11:56 -07:00
Renan Duarte
1975e4a151
fix: updating maxItems (schema/definitions) to 30 2023-12-12 12:45:35 +01:00
Renan Duarte
4704bd6a38 Merge branch 'develop' into patch-1 2023-12-12 12:38:42 +01:00
Renan Duarte
ca56e0483f
fix: updating default maxOptions to 30 (dead) 2023-12-12 12:37:06 +01:00
Renan Duarte
3b8cb86d72
fix: updating default maxOptions to 30 (redirection) 2023-12-12 12:36:32 +01:00
Renan Duarte
5165de4a91
fix: updating default maxOptions to 30 (proxy) 2023-12-12 12:36:05 +01:00
Renan Duarte
1ab3575c68
fix: increasing maxOptions (amount of domains) to 30 2023-12-12 09:39:28 +01:00
Jocelyn Le Sage
ccf9cce825 Fixed issue where the HTTP2 support was always enabled in nginx config, no matter what the user configured. 2023-12-09 11:16:37 -05:00
Elton Renda
3ad2188f78 chore: upddate Proxmox Scripts link 2023-12-04 10:31:26 +00:00
Tim O'Brien
33dbffb974 Improve container startup time
See https://github.com/NginxProxyManager/nginx-proxy-manager/issues/2991

Removes uneeded file permission changes in rootfs certbot install. Tested installing custom DNS provider plugins for certbot, works correctly.
2023-12-02 14:56:48 +11:00
Dario Viva
289e438c59 only add hsts header with https.
fixes https://github.com/NginxProxyManager/nginx-proxy-manager/issues/1005
for more information look at: https://websistent.com/add-the-hsts-header-only-for-https-requests-nginx/
2023-12-02 03:26:34 +01:00
Jamie Curnow
e08a4d4490
Update mariadb example to auto upgrade from latest image 2023-11-28 08:27:11 +10:00
jc21
d1d1819677
Merge pull request from nmatton/patch-1
update docker-compose execution
2023-11-22 10:06:55 +10:00
jc21
4e0768d56c
Merge pull request from NginxProxyManager/dependabot/npm_and_yarn/frontend/browserify-sign-4.2.2
Bump browserify-sign from 4.2.1 to 4.2.2 in /frontend
2023-11-22 10:06:30 +10:00
jc21
3666364418
Merge pull request from NginxProxyManager/dependabot/npm_and_yarn/docs/browserify-sign-4.2.2
Bump browserify-sign from 4.2.1 to 4.2.2 in /docs
2023-11-22 10:06:19 +10:00
jc21
9052502a17
Merge pull request from xiaoxinpro/develop
Replace the description string on the default-site page with i18n
2023-11-09 07:37:13 +10:00
jc21
b608d3392d
Merge pull request from AngusC222/develop
min/max ports added for Streams
2023-11-09 07:36:05 +10:00
Jamie Curnow
edb81ecce0
Fix CI branch names being incorrectly replaced 2023-11-09 07:35:24 +10:00
AngusC222
e24181936f
min/max ports added 2023-11-08 12:09:36 +00:00
chishin
940d06cac9 Replace the 'default-site' variable 'description' with the 'i18n' configuration 2023-10-29 10:50:45 +08:00
chishin
134902d127 Add a default-site-description string 2023-10-29 10:43:57 +08:00
dependabot[bot]
2df4620d05
Bump browserify-sign from 4.2.1 to 4.2.2 in /docs
Bumps [browserify-sign](https://github.com/crypto-browserify/browserify-sign) from 4.2.1 to 4.2.2.
- [Changelog](https://github.com/browserify/browserify-sign/blob/main/CHANGELOG.md)
- [Commits](https://github.com/crypto-browserify/browserify-sign/compare/v4.2.1...v4.2.2)

---
updated-dependencies:
- dependency-name: browserify-sign
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-27 13:36:54 +00:00
dependabot[bot]
f41b1069ae
Bump browserify-sign from 4.2.1 to 4.2.2 in /frontend
Bumps [browserify-sign](https://github.com/crypto-browserify/browserify-sign) from 4.2.1 to 4.2.2.
- [Changelog](https://github.com/browserify/browserify-sign/blob/main/CHANGELOG.md)
- [Commits](https://github.com/crypto-browserify/browserify-sign/compare/v4.2.1...v4.2.2)

---
updated-dependencies:
- dependency-name: browserify-sign
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-27 13:36:29 +00:00
nmatton
004a93fbc3
update docker-compose execution
As of Jun 2023, the docker-compose command has been deprecated in favor of the compose plugin.

https://docs.docker.com/compose/install/linux/
2023-10-24 22:47:42 +02:00
dependabot[bot]
2d9f04edcd
Bump @babel/traverse from 7.11.0 to 7.23.2 in /frontend
Bumps [@babel/traverse](https://github.com/babel/babel/tree/HEAD/packages/babel-traverse) from 7.11.0 to 7.23.2.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.23.2/packages/babel-traverse)

---
updated-dependencies:
- dependency-name: "@babel/traverse"
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-17 03:33:12 +00:00
Jamie Curnow
53dbe258a5
Fix CI compose project name not allowing dots 2023-10-17 11:57:14 +10:00
Honza Pobořil
e4ba22f0f8
Removed /etc/letsencrypt from explicit volumes
So it can be moved in other images using this as a base.

Fixes 
2023-10-15 08:55:36 +02:00
jc21
3197de41de
Merge pull request from devedse/develop
Added force renewal + --dns-duckdns-no-txt-restore
2023-10-03 18:54:02 +10:00
jc21
0f7be7987b
Merge pull request from AngusC222/develop
minimum/maximum ports added on frontend
2023-10-03 18:50:37 +10:00
jc21
853c48dff6
Merge pull request from OpenSourceSimon/patch-1
Add robots noindex meta tag to prevent indexing
2023-10-03 18:49:56 +10:00
jc21
410c3484ab
Merge pull request from zhzy0077/patch-1
certbot-dns-tencentcloud should be 2.0.2 or above.
2023-10-03 18:49:13 +10:00
jc21
44e9f377f9
Merge pull request from FlixMa/develop
Strato Certbot Plugin: 2FA and International Site Support
2023-10-03 18:48:42 +10:00
jc21
0f3b76f607
Merge pull request from FibreTTP/logrotate-perms
Make logrotate use the proper user and group.
2023-10-03 18:48:01 +10:00
FibreTTP
f426e64569 Add warning comment about changing the default user name and group name 2023-09-27 16:12:33 +10:00
FibreTTP
4867db078c Remove explicit user and group - add su directive for default user (npm). 2023-09-27 14:58:19 +10:00
FibreTTP
6b565e628f Change perms on logrotated logs to npm user 2023-09-27 14:25:04 +10:00
Felix Maaß
881d70502b
Add description for Strato 2FA and International Site Support
Tell users how to configure...
+ Two Factor authentication
+ Custom API Endpoint (mostly for international hosts like strato.es/strato.nl)
2023-09-24 19:17:53 +02:00
Zhiyuan Zheng
62e4edddf0
Update certbot-dns-plugins.js 2023-09-13 12:01:15 +08:00
Simon
4b9c02cc0c
Add robots noindex meta tag to prevent indexing 2023-09-10 12:08:28 +02:00
AngusC222
5af834e40b
mix/max ports 2023-09-09 13:44:16 +01:00
Devedse
6f8db95249 Added force renewal + --dns-duckdns-no-txt-restore 2023-08-24 13:21:01 +02:00
jc21
fe93cb3474
Merge pull request from NginxProxyManager/develop
v2.10.4
2023-08-02 11:44:02 +10:00
Jamie Curnow
fa851b61da
Bump version 2023-07-31 07:25:09 +10:00
jc21
3333a32612
Merge pull request from wolviex/certbot-dnsplugin-user-site-fix
drop --user on pip install dns plugin
2023-07-31 07:21:18 +10:00
jc21
9a79fce498
Merge pull request from andycandy-de/patch-1
Corrected docker-compose.yml
2023-07-26 10:27:30 +10:00
andycandy-de
b1180f5077
Corrected docker-compose.yml
The mysql folder should not be mounted to the npm container!
2023-07-25 18:00:48 +02:00
jc21
5454352fe5
Merge pull request from FlixMa/develop
Add strato.de to certbot dns plugins
2023-07-20 12:25:37 +10:00
jc21
aee93a2f6f
Merge pull request from nietzscheanic/patch-1
Fix for ignored ssl_protocols and ssl_ciphers directive in conf.d/inc…
2023-07-20 12:25:09 +10:00
jc21
f38cb5b500
Merge pull request from wrouesnel/444_default_support
Add support for nginx 444 default response
2023-07-20 12:23:57 +10:00
jc21
f1b7156c89
Merge pull request from xrh0905/xrh0905-patch-sed
Fix device or resource busy when patching IPv6 settings
2023-07-20 12:17:34 +10:00
jc21
98465cf1b0
Merge pull request from NginxProxyManager/dependabot/npm_and_yarn/docs/semver-7.5.2
Bump semver from 7.3.2 to 7.5.2 in /docs
2023-07-20 12:16:11 +10:00
jc21
137e865b66
Merge pull request from lug-gh/develop
update year 2022 -> 2023 in footer
2023-07-20 12:16:01 +10:00
lug-gh
e740fb4064
update year 2022 -> 2023 2023-07-19 13:27:17 +02:00
jc21
f91f0ee8db
Merge pull request from 6twenty/2741-suppress-s6-supervise-disk-writes
Fix  - Prevent excessive disk writes by only adding frontend service when in development
2023-07-19 13:09:12 +10:00
Mike Fulcher
1c9f751512 Fix path to frontend service 2023-07-19 14:05:57 +12:00
dependabot[bot]
a602bdd514
Bump semver from 7.3.2 to 7.5.2 in /docs
Bumps [semver](https://github.com/npm/node-semver) from 7.3.2 to 7.5.2.
- [Release notes](https://github.com/npm/node-semver/releases)
- [Changelog](https://github.com/npm/node-semver/blob/main/CHANGELOG.md)
- [Commits](https://github.com/npm/node-semver/compare/v7.3.2...v7.5.2)

---
updated-dependencies:
- dependency-name: semver
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-07-19 00:02:51 +00:00
jc21
f7b2be68cc
Merge pull request from NginxProxyManager/dependabot/npm_and_yarn/docs/tough-cookie-4.1.3
Bump tough-cookie from 4.0.0 to 4.1.3 in /docs
2023-07-19 10:02:40 +10:00
jc21
ab4586fc6b
Merge pull request from deftdawg/patch-1
Add bunny.net DNS to DNS challenges
2023-07-19 10:02:29 +10:00
jc21
a984a68065
Merge pull request from NginxProxyManager/dependabot/npm_and_yarn/backend/semver-5.7.2
Bump semver from 5.7.1 to 5.7.2 in /backend
2023-07-19 10:02:04 +10:00
jc21
52875fca6e
Merge pull request from NginxProxyManager/dependabot/npm_and_yarn/test/semver-7.5.4
Bump semver from 7.3.2 to 7.5.4 in /test
2023-07-19 10:01:55 +10:00
jc21
63b50fcd95
Merge pull request from NginxProxyManager/dependabot/npm_and_yarn/frontend/semver-5.7.2
Bump semver from 5.7.1 to 5.7.2 in /frontend
2023-07-19 10:01:47 +10:00
jc21
5ab4aea03f
Merge pull request from NginxProxyManager/dependabot/npm_and_yarn/test/word-wrap-1.2.4
Bump word-wrap from 1.2.3 to 1.2.4 in /test
2023-07-19 10:01:40 +10:00
jc21
d73135378e
Merge pull request from NginxProxyManager/dependabot/npm_and_yarn/backend/word-wrap-1.2.4
Bump word-wrap from 1.2.3 to 1.2.4 in /backend
2023-07-19 10:01:30 +10:00
jc21
e19d685cb6
Merge pull request from NginxProxyManager/dependabot/npm_and_yarn/frontend/word-wrap-1.2.4
Bump word-wrap from 1.2.3 to 1.2.4 in /frontend
2023-07-19 10:01:20 +10:00
dependabot[bot]
c8caaa56d9
Bump word-wrap from 1.2.3 to 1.2.4 in /backend
Bumps [word-wrap](https://github.com/jonschlinkert/word-wrap) from 1.2.3 to 1.2.4.
- [Release notes](https://github.com/jonschlinkert/word-wrap/releases)
- [Commits](https://github.com/jonschlinkert/word-wrap/compare/1.2.3...1.2.4)

---
updated-dependencies:
- dependency-name: word-wrap
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-07-18 20:59:11 +00:00
dependabot[bot]
11a98f4c12
Bump word-wrap from 1.2.3 to 1.2.4 in /frontend
Bumps [word-wrap](https://github.com/jonschlinkert/word-wrap) from 1.2.3 to 1.2.4.
- [Release notes](https://github.com/jonschlinkert/word-wrap/releases)
- [Commits](https://github.com/jonschlinkert/word-wrap/compare/1.2.3...1.2.4)

---
updated-dependencies:
- dependency-name: word-wrap
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-07-18 20:59:11 +00:00
dependabot[bot]
4a85d4ac4e
Bump word-wrap from 1.2.3 to 1.2.4 in /test
Bumps [word-wrap](https://github.com/jonschlinkert/word-wrap) from 1.2.3 to 1.2.4.
- [Release notes](https://github.com/jonschlinkert/word-wrap/releases)
- [Commits](https://github.com/jonschlinkert/word-wrap/compare/1.2.3...1.2.4)

---
updated-dependencies:
- dependency-name: word-wrap
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-07-18 20:59:08 +00:00
dependabot[bot]
3138ba46ce
Bump semver from 5.7.1 to 5.7.2 in /frontend
Bumps [semver](https://github.com/npm/node-semver) from 5.7.1 to 5.7.2.
- [Release notes](https://github.com/npm/node-semver/releases)
- [Changelog](https://github.com/npm/node-semver/blob/v5.7.2/CHANGELOG.md)
- [Commits](https://github.com/npm/node-semver/compare/v5.7.1...v5.7.2)

---
updated-dependencies:
- dependency-name: semver
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-07-12 05:37:17 +00:00
dependabot[bot]
cdd0b2e6d3
Bump semver from 7.3.2 to 7.5.4 in /test
Bumps [semver](https://github.com/npm/node-semver) from 7.3.2 to 7.5.4.
- [Release notes](https://github.com/npm/node-semver/releases)
- [Changelog](https://github.com/npm/node-semver/blob/main/CHANGELOG.md)
- [Commits](https://github.com/npm/node-semver/compare/v7.3.2...v7.5.4)

---
updated-dependencies:
- dependency-name: semver
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-07-12 02:34:02 +00:00
dependabot[bot]
f458730d87
Bump semver from 5.7.1 to 5.7.2 in /backend
Bumps [semver](https://github.com/npm/node-semver) from 5.7.1 to 5.7.2.
- [Release notes](https://github.com/npm/node-semver/releases)
- [Changelog](https://github.com/npm/node-semver/blob/v5.7.2/CHANGELOG.md)
- [Commits](https://github.com/npm/node-semver/compare/v5.7.1...v5.7.2)

---
updated-dependencies:
- dependency-name: semver
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-07-11 02:29:25 +00:00
deftdawg
d20873dcbb
Add bunny.net DNS to DNS challenges
- Add support for bunny.net DNS challenges using @mwt's certbot-dns-bunny plugin.
2023-07-08 22:48:54 -04:00
dependabot[bot]
d1e9407e4d
Bump tough-cookie from 4.0.0 to 4.1.3 in /docs
Bumps [tough-cookie](https://github.com/salesforce/tough-cookie) from 4.0.0 to 4.1.3.
- [Release notes](https://github.com/salesforce/tough-cookie/releases)
- [Changelog](https://github.com/salesforce/tough-cookie/blob/master/CHANGELOG.md)
- [Commits](https://github.com/salesforce/tough-cookie/compare/v4.0.0...v4.1.3)

---
updated-dependencies:
- dependency-name: tough-cookie
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-07-08 14:17:45 +00:00
xrh0905
63ee69f432
Fix device or resource busy when patching IPv6 settings 2023-06-15 11:17:02 +08:00
Joe Manifold
f39e527680
drop --user on pip install dns plugin godaddy
Do not install dns_plugin into the user site because it will lack sys.path precedence to urllib3 in /opt/certbot/lib/python3.7/site-packages
2023-06-01 11:02:06 -07:00
Will Rouesnel
2dd4434ceb
Add support for nginx 444 default response
The default nginx 444 response drops the inbound connection without
sending any response to the client.
2023-05-22 11:59:50 +10:00
nietzscheanic
81054631f9
Fix for ignored ssl_protocols and ssl_ciphers directive in conf.d/include/ssl-ciphers.conf
nginx only uses the `ssl_protocols` directive in the `server{}` block of the first processed host config, which is the default config in `/etc/nginx/conf.d/default.conf`. in version `v2.9.20` the default ssl site was dropped by using `ssl_reject_handshake on` in the default host config. but beside the include of `conf.d/include/ssl-ciphers.conf` was removed from the default host config. that's why `tlsv1.3` isn't applied by default anymore, same thing with the defined cipher suites. npm is so broken since `2023-03-16`.

commit that broke the config -> a7f0c3b730
2023-05-19 14:13:29 +02:00
Felix Maaß
53d61bd626
Try to fix linter error in certbot plugin definitions. 2023-05-18 14:14:38 +02:00
Felix Maaß
847e879b3f
Update certbot-dns-plugins.js
Add dns wildcard certificate support for strato.de using the provided certbot plugin
2023-05-18 13:44:52 +02:00
Benjamin Hubert
4c59400731 added support for dns.he.net certbot plugin 2023-05-16 22:38:43 +02:00
jc21
824c837a38
Merge pull request from NginxProxyManager/develop
Fix certbot plugins install when using PUID/PGID
2023-05-10 14:40:15 +10:00
jc21
2a06384a4a
Merge branch 'master' into develop 2023-05-10 14:40:06 +10:00
Jamie Curnow
05307aa253
Fix certbot plugins install when using PUID/PGID 2023-05-10 14:39:08 +10:00
jc21
3d2406ac3d
Merge pull request from NginxProxyManager/develop
v2.10.3
2023-05-10 14:09:04 +10:00
Jamie Curnow
0127dc7f03
Bump version 2023-05-10 11:32:22 +10:00
jc21
4349d42636
Merge pull request from NginxProxyManager/s6-verbose
Fixes for s6 timeout at startup
2023-05-10 11:31:17 +10:00
Jamie Curnow
4b6f9d9419
Remove s6 service timeout 2023-05-10 09:57:24 +10:00
Jamie Curnow
c3f019c911
Test ipv6 disabled in ci 2023-05-09 08:19:09 +10:00
Jamie Curnow
ecf0290203
Update s6-overlay 2023-05-09 08:15:44 +10:00
Jamie Curnow
4f41fe0c95
Update s6-overlay 2023-05-05 08:46:54 +10:00
Jamie Curnow
c3735fdbbb
Missed a file that was explicit verbose 2023-05-04 12:30:27 +10:00
Jamie Curnow
c432c34fb3
Small refactor of user/groups and add checks during startup. Only use -x in bash scripts when DEBUG=true set in env vars 2023-05-04 10:03:06 +10:00
Jamie Curnow
a1245bc161
Split up ownership to indentify point of failure 2023-05-04 08:27:38 +10:00
Jamie Curnow
db4ab1d548
Verbose debugging of s6 scripts 2023-05-03 16:01:27 +10:00
jc21
86ddd9c83c
Merge pull request from NginxProxyManager/develop
v2.10.2
2023-03-31 09:37:08 +10:00
jc21
67208e43cc
Merge branch 'master' into develop 2023-03-31 08:27:00 +10:00
Jamie Curnow
ddf80302c6
Bump version 2023-03-31 08:25:45 +10:00
jc21
5f2576946d
Merge pull request from NginxProxyManager/uidgid
Make PUID and PGID optional
2023-03-31 08:25:07 +10:00
Jamie Curnow
9fe07fa6c3
Update documentation 2023-03-30 15:37:59 +10:00
Jamie Curnow
d9b9af543e
Fix text replacement whoops 2023-03-30 15:03:57 +10:00
Jamie Curnow
eb2e2e0478
Throw in a docker restart during testing phase 2023-03-30 14:44:15 +10:00
Jamie Curnow
9225d5d442
Tweak test 2023-03-30 13:00:22 +10:00
Jamie Curnow
308a7149ed
Tweak test 2023-03-30 12:55:20 +10:00
Jamie Curnow
8a4a7d0caf
Allow 201 as success in test result 2023-03-30 12:51:26 +10:00
Jamie Curnow
5d03ede100
Add test for creating a host 2023-03-30 12:44:28 +10:00
Jamie Curnow
4a86bb42cc
Different approach, always create npmuser
even if the user id is zero, and then we'll always use it
2023-03-30 11:19:16 +10:00
Jamie Curnow
dad8561ea1
Use numbers for permissions in case npmuser doesn't exist 2023-03-30 10:20:20 +10:00
Jamie Curnow
56a92e5c0e
Run as root by default
Optionally run as another user/group only if
the env vars are specified. Should give flexibility
to those who need to run processes as root and open ports
without having to request additional priveleges
2023-03-30 09:04:37 +10:00
Jamie Curnow
9d672f5813
Own this nginx folder too 2023-03-29 14:04:48 +10:00
Jamie Curnow
d5ed70dbb6
Own this nginx folder too 2023-03-29 14:03:58 +10:00
jc21
c197e66d62
Merge pull request from NginxProxyManager/develop
v2.10.1
2023-03-29 08:54:30 +10:00
Jamie Curnow
91cf3c8873
Tweaks to docker compose ci after updates 2023-03-29 08:24:28 +10:00
Jamie Curnow
7f5e0414ac
Bump version 2023-03-29 07:22:15 +10:00
Jamie Curnow
d179887c15
Another fix for , only chown parts of /etc/nginx 2023-03-28 10:39:26 +10:00
Jamie Curnow
35abb4d7ae
Execute permissions missing on script 2023-03-28 09:33:30 +10:00
Jamie Curnow
61b290e220
Chown each folder on separately
Really not sure why this fixes  however it does actually
help the ownership script succeed specifically on arm7/raspbian
2023-03-28 08:50:10 +10:00
136 changed files with 5218 additions and 14372 deletions
.github/workflows
.gitignore.versionJenkinsfileREADME.md
backend
docker
docs
frontend
html/partials
js/app/nginx

21
.github/workflows/stale.yml vendored Normal file

@ -0,0 +1,21 @@
name: 'Close stale issues and PRs'
on:
schedule:
- cron: '30 1 * * *'
workflow_dispatch:
jobs:
stale:
runs-on: ubuntu-latest
steps:
- uses: actions/stale@v9
with:
stale-issue-label: 'stale'
stale-pr-label: 'stale'
stale-issue-message: 'Issue is now considered stale. If you want to keep it open, please comment :+1:'
stale-pr-message: 'PR is now considered stale. If you want to keep it open, please comment :+1:'
close-issue-message: 'Issue was closed due to inactivity.'
close-pr-message: 'PR was closed due to inactivity.'
days-before-stale: 182
days-before-close: 365
operations-per-run: 50

4
.gitignore vendored

@ -3,3 +3,7 @@
._*
.vscode
certbot-help.txt
test/node_modules
*/node_modules
docker/dev/dnsrouter-config.json.tmp
docker/dev/resolv.conf

@ -1 +1 @@
2.10.0
2.11.3

220
Jenkinsfile vendored

@ -17,13 +17,9 @@ pipeline {
IMAGE = 'nginx-proxy-manager'
BUILD_VERSION = getVersion()
MAJOR_VERSION = '2'
BRANCH_LOWER = "${BRANCH_NAME.toLowerCase().replaceAll('/', '-')}"
COMPOSE_PROJECT_NAME = "npm_${BRANCH_LOWER}_${BUILD_NUMBER}"
COMPOSE_FILE = 'docker/docker-compose.ci.yml'
BRANCH_LOWER = "${BRANCH_NAME.toLowerCase().replaceAll('\\\\', '-').replaceAll('/', '-').replaceAll('\\.', '-')}"
BUILDX_NAME = "npm_${BRANCH_LOWER}_${BUILD_NUMBER}"
COMPOSE_INTERACTIVE_NO_CLI = 1
BUILDX_NAME = "${COMPOSE_PROJECT_NAME}"
DOCS_BUCKET = 'jc21-npm-site'
DOCS_CDN = 'EN1G6DEWZUTDT'
}
stages {
stage('Environment') {
@ -62,99 +58,96 @@ pipeline {
}
}
}
stage('Build and Test') {
steps {
script {
// Frontend and Backend
def shStatusCode = sh(label: 'Checking and Building', returnStatus: true, script: '''
set -e
./scripts/ci/frontend-build > ${WORKSPACE}/tmp-sh-build 2>&1
./scripts/ci/test-and-build > ${WORKSPACE}/tmp-sh-build 2>&1
''')
shOutput = readFile "${env.WORKSPACE}/tmp-sh-build"
if (shStatusCode != 0) {
error "${shOutput}"
stage('Builds') {
parallel {
stage('Project') {
steps {
script {
// Frontend and Backend
def shStatusCode = sh(label: 'Checking and Building', returnStatus: true, script: '''
set -e
./scripts/ci/frontend-build > ${WORKSPACE}/tmp-sh-build 2>&1
./scripts/ci/test-and-build > ${WORKSPACE}/tmp-sh-build 2>&1
''')
shOutput = readFile "${env.WORKSPACE}/tmp-sh-build"
if (shStatusCode != 0) {
error "${shOutput}"
}
}
}
post {
always {
sh 'rm -f ${WORKSPACE}/tmp-sh-build'
}
failure {
npmGithubPrComment("CI Error:\n\n```\n${shOutput}\n```", true)
}
}
}
stage('Docs') {
steps {
dir(path: 'docs') {
sh 'yarn install'
sh 'yarn build'
}
}
}
}
post {
always {
sh 'rm -f ${WORKSPACE}/tmp-sh-build'
}
failure {
npmGithubPrComment("CI Error:\n\n```\n${shOutput}\n```", true)
}
}
}
stage('Integration Tests Sqlite') {
steps {
// Bring up a stack
sh 'docker-compose up -d fullstack-sqlite'
sh './scripts/wait-healthy $(docker-compose ps -q fullstack-sqlite) 120'
// Run tests
sh 'rm -rf test/results'
sh 'docker-compose up cypress-sqlite'
// Get results
sh 'docker cp -L "$(docker-compose ps -q cypress-sqlite):/test/results" test/'
stage('Test Sqlite') {
environment {
COMPOSE_PROJECT_NAME = "npm_${BRANCH_LOWER}_${BUILD_NUMBER}_sqlite"
COMPOSE_FILE = 'docker/docker-compose.ci.yml:docker/docker-compose.ci.sqlite.yml'
}
post {
always {
// Dumps to analyze later
sh 'mkdir -p debug'
sh 'docker-compose logs fullstack-sqlite > debug/docker_fullstack_sqlite.log'
sh 'docker-compose logs db > debug/docker_db.log'
// Cypress videos and screenshot artifacts
dir(path: 'test/results') {
archiveArtifacts allowEmptyArchive: true, artifacts: '**/*', excludes: '**/*.xml'
}
junit 'test/results/junit/*'
}
}
}
stage('Integration Tests Mysql') {
steps {
// Bring up a stack
sh 'docker-compose up -d fullstack-mysql'
sh './scripts/wait-healthy $(docker-compose ps -q fullstack-mysql) 120'
// Run tests
sh 'rm -rf test/results'
sh 'docker-compose up cypress-mysql'
// Get results
sh 'docker cp -L "$(docker-compose ps -q cypress-mysql):/test/results" test/'
}
post {
always {
// Dumps to analyze later
sh 'mkdir -p debug'
sh 'docker-compose logs fullstack-mysql > debug/docker_fullstack_mysql.log'
sh 'docker-compose logs db > debug/docker_db.log'
// Cypress videos and screenshot artifacts
dir(path: 'test/results') {
archiveArtifacts allowEmptyArchive: true, artifacts: '**/*', excludes: '**/*.xml'
}
junit 'test/results/junit/*'
}
}
}
stage('Docs') {
when {
not {
equals expected: 'UNSTABLE', actual: currentBuild.result
}
}
steps {
dir(path: 'docs') {
sh 'yarn install'
sh 'yarn build'
sh 'rm -rf ./test/results/junit/*'
sh './scripts/ci/fulltest-cypress'
}
post {
always {
// Dumps to analyze later
sh 'mkdir -p debug/sqlite'
sh 'docker logs $(docker-compose ps --all -q fullstack) > debug/sqlite/docker_fullstack.log 2>&1'
sh 'docker logs $(docker-compose ps --all -q stepca) > debug/sqlite/docker_stepca.log 2>&1'
sh 'docker logs $(docker-compose ps --all -q pdns) > debug/sqlite/docker_pdns.log 2>&1'
sh 'docker logs $(docker-compose ps --all -q pdns-db) > debug/sqlite/docker_pdns-db.log 2>&1'
sh 'docker logs $(docker-compose ps --all -q dnsrouter) > debug/sqlite/docker_dnsrouter.log 2>&1'
junit 'test/results/junit/*'
sh 'docker-compose down --remove-orphans --volumes -t 30 || true'
}
dir(path: 'docs/.vuepress/dist') {
sh 'tar -czf ../../docs.tgz *'
}
}
stage('Test Mysql') {
environment {
COMPOSE_PROJECT_NAME = "npm_${BRANCH_LOWER}_${BUILD_NUMBER}_mysql"
COMPOSE_FILE = 'docker/docker-compose.ci.yml:docker/docker-compose.ci.mysql.yml'
}
when {
not {
equals expected: 'UNSTABLE', actual: currentBuild.result
}
}
steps {
sh 'rm -rf ./test/results/junit/*'
sh './scripts/ci/fulltest-cypress'
}
post {
always {
// Dumps to analyze later
sh 'mkdir -p debug/mysql'
sh 'docker logs $(docker-compose ps --all -q fullstack) > debug/mysql/docker_fullstack.log 2>&1'
sh 'docker logs $(docker-compose ps --all -q stepca) > debug/mysql/docker_stepca.log 2>&1'
sh 'docker logs $(docker-compose ps --all -q pdns) > debug/mysql/docker_pdns.log 2>&1'
sh 'docker logs $(docker-compose ps --all -q pdns-db) > debug/mysql/docker_pdns-db.log 2>&1'
sh 'docker logs $(docker-compose ps --all -q dnsrouter) > debug/mysql/docker_dnsrouter.log 2>&1'
junit 'test/results/junit/*'
sh 'docker-compose down --remove-orphans --volumes -t 30 || true'
}
archiveArtifacts(artifacts: 'docs/docs.tgz', allowEmptyArchive: false)
}
}
stage('MultiArch Build') {
@ -170,52 +163,55 @@ pipeline {
}
}
}
stage('Docs Deploy') {
when {
allOf {
branch 'master'
not {
equals expected: 'UNSTABLE', actual: currentBuild.result
stage('Docs / Comment') {
parallel {
stage('Docs Job') {
when {
allOf {
branch pattern: "^(develop|master)\$", comparator: "REGEXP"
not {
equals expected: 'UNSTABLE', actual: currentBuild.result
}
}
}
steps {
build wait: false, job: 'nginx-proxy-manager-docs', parameters: [string(name: 'docs_branch', value: "$BRANCH_NAME")]
}
}
}
steps {
npmDocsRelease("$DOCS_BUCKET", "$DOCS_CDN")
}
}
stage('PR Comment') {
when {
allOf {
changeRequest()
not {
equals expected: 'UNSTABLE', actual: currentBuild.result
stage('PR Comment') {
when {
allOf {
changeRequest()
not {
equals expected: 'UNSTABLE', actual: currentBuild.result
}
}
}
steps {
script {
npmGithubPrComment("Docker Image for build ${BUILD_NUMBER} is available on [DockerHub](https://cloud.docker.com/repository/docker/jc21/${IMAGE}) as `jc21/${IMAGE}:github-${BRANCH_LOWER}`\n\n**Note:** ensure you backup your NPM instance before testing this PR image! Especially if this PR contains database changes.", true)
}
}
}
}
steps {
script {
npmGithubPrComment("Docker Image for build ${BUILD_NUMBER} is available on [DockerHub](https://cloud.docker.com/repository/docker/jc21/${IMAGE}) as `jc21/${IMAGE}:github-${BRANCH_LOWER}`\n\n**Note:** ensure you backup your NPM instance before testing this PR image! Especially if this PR contains database changes.", true)
}
}
}
}
post {
always {
sh 'docker-compose down --remove-orphans --volumes -t 30'
sh 'echo Reverting ownership'
sh 'docker run --rm -v $(pwd):/data jc21/ci-tools chown -R $(id -u):$(id -g) /data'
sh 'docker run --rm -v "$(pwd):/data" jc21/ci-tools chown -R "$(id -u):$(id -g)" /data'
}
success {
juxtapose event: 'success'
sh 'figlet "SUCCESS"'
}
failure {
archiveArtifacts(artifacts: 'debug/**.*', allowEmptyArchive: true)
archiveArtifacts(artifacts: 'debug/**/*.*', allowEmptyArchive: true)
juxtapose event: 'failure'
sh 'figlet "FAILURE"'
}
unstable {
archiveArtifacts(artifacts: 'debug/**.*', allowEmptyArchive: true)
archiveArtifacts(artifacts: 'debug/**/*.*', allowEmptyArchive: true)
juxtapose event: 'unstable'
sh 'figlet "UNSTABLE"'
}

@ -1,7 +1,7 @@
<p align="center">
<img src="https://nginxproxymanager.com/github.png">
<br><br>
<img src="https://img.shields.io/badge/version-2.10.0-green.svg?style=for-the-badge">
<img src="https://img.shields.io/badge/version-2.11.3-green.svg?style=for-the-badge">
<a href="https://hub.docker.com/repository/docker/jc21/nginx-proxy-manager">
<img src="https://img.shields.io/docker/stars/jc21/nginx-proxy-manager.svg?style=for-the-badge">
</a>
@ -19,7 +19,7 @@ running at home or otherwise, including free SSL, without having to know too muc
## Project Goal
I created this project to fill a personal need to provide users with a easy way to accomplish reverse
I created this project to fill a personal need to provide users with an easy way to accomplish reverse
proxying hosts with SSL termination and it had to be so easy that a monkey could do it. This goal hasn't changed.
While there might be advanced options they are optional and the project should be as simple as possible
so that the barrier for entry here is low.
@ -56,10 +56,9 @@ I won't go in to too much detail here but here are the basics for someone new to
2. Create a docker-compose.yml file similar to this:
```yml
version: '3.8'
services:
app:
image: 'jc21/nginx-proxy-manager:latest'
image: 'docker.io/jc21/nginx-proxy-manager:latest'
restart: unless-stopped
ports:
- '80:80'
@ -98,7 +97,18 @@ Password: changeme
Immediately after logging in with this default user you will be asked to modify your details and change your password.
## Contributors
## Contributing
All are welcome to create pull requests for this project, against the `develop` branch. Official releases are created from the `master` branch.
CI is used in this project. All PR's must pass before being considered. After passing,
docker builds for PR's are available on dockerhub for manual verifications.
Documentation within the `develop` branch is available for preview at
[https://develop.nginxproxymanager.com](https://develop.nginxproxymanager.com)
### Contributors
Special thanks to [all of our contributors](https://github.com/NginxProxyManager/nginx-proxy-manager/graphs/contributors).
@ -107,5 +117,4 @@ Special thanks to [all of our contributors](https://github.com/NginxProxyManager
1. [Found a bug?](https://github.com/NginxProxyManager/nginx-proxy-manager/issues)
2. [Discussions](https://github.com/NginxProxyManager/nginx-proxy-manager/discussions)
3. [Development Gitter](https://gitter.im/nginx-proxy-manager/community)
4. [Reddit](https://reddit.com/r/nginxproxymanager)
3. [Reddit](https://reddit.com/r/nginxproxymanager)

@ -40,6 +40,210 @@
}
}
},
"/nginx/proxy-hosts": {
"get": {
"operationId": "getProxyHosts",
"summary": "Get all proxy hosts",
"tags": ["Proxy Hosts"],
"security": [
{
"BearerAuth": ["users"]
}
],
"parameters": [
{
"in": "query",
"name": "expand",
"description": "Expansions",
"schema": {
"type": "string",
"enum": ["access_list", "owner", "certificate"]
}
}
],
"responses": {
"200": {
"description": "200 response",
"content": {
"application/json": {
"examples": {
"default": {
"value": [
{
"id": 1,
"created_on": "2023-03-30T01:12:23.000Z",
"modified_on": "2023-03-30T02:15:40.000Z",
"owner_user_id": 1,
"domain_names": ["aasdasdad"],
"forward_host": "asdasd",
"forward_port": 80,
"access_list_id": 0,
"certificate_id": 0,
"ssl_forced": 0,
"caching_enabled": 0,
"block_exploits": 0,
"advanced_config": "sdfsdfsdf",
"meta": {
"letsencrypt_agree": false,
"dns_challenge": false,
"nginx_online": false,
"nginx_err": "Command failed: /usr/sbin/nginx -t -g \"error_log off;\"\nnginx: [emerg] unknown directive \"sdfsdfsdf\" in /data/nginx/proxy_host/1.conf:37\nnginx: configuration file /etc/nginx/nginx.conf test failed\n"
},
"allow_websocket_upgrade": 0,
"http2_support": 0,
"forward_scheme": "http",
"enabled": 1,
"locations": [],
"hsts_enabled": 0,
"hsts_subdomains": 0,
"owner": {
"id": 1,
"created_on": "2023-03-30T01:11:50.000Z",
"modified_on": "2023-03-30T01:11:50.000Z",
"is_deleted": 0,
"is_disabled": 0,
"email": "admin@example.com",
"name": "Administrator",
"nickname": "Admin",
"avatar": "",
"roles": ["admin"]
},
"access_list": null,
"certificate": null
},
{
"id": 2,
"created_on": "2023-03-30T02:11:49.000Z",
"modified_on": "2023-03-30T02:11:49.000Z",
"owner_user_id": 1,
"domain_names": ["test.example.com"],
"forward_host": "1.1.1.1",
"forward_port": 80,
"access_list_id": 0,
"certificate_id": 0,
"ssl_forced": 0,
"caching_enabled": 0,
"block_exploits": 0,
"advanced_config": "",
"meta": {
"letsencrypt_agree": false,
"dns_challenge": false,
"nginx_online": true,
"nginx_err": null
},
"allow_websocket_upgrade": 0,
"http2_support": 0,
"forward_scheme": "http",
"enabled": 1,
"locations": [],
"hsts_enabled": 0,
"hsts_subdomains": 0,
"owner": {
"id": 1,
"created_on": "2023-03-30T01:11:50.000Z",
"modified_on": "2023-03-30T01:11:50.000Z",
"is_deleted": 0,
"is_disabled": 0,
"email": "admin@example.com",
"name": "Administrator",
"nickname": "Admin",
"avatar": "",
"roles": ["admin"]
},
"access_list": null,
"certificate": null
}
]
}
},
"schema": {
"$ref": "#/components/schemas/ProxyHostsList"
}
}
}
}
}
},
"post": {
"operationId": "createProxyHost",
"summary": "Create a Proxy Host",
"tags": ["Proxy Hosts"],
"security": [
{
"BearerAuth": ["users"]
}
],
"parameters": [
{
"in": "body",
"name": "proxyhost",
"description": "Proxy Host Payload",
"required": true,
"schema": {
"$ref": "#/components/schemas/ProxyHostObject"
}
}
],
"responses": {
"201": {
"description": "201 response",
"content": {
"application/json": {
"examples": {
"default": {
"value": {
"id": 3,
"created_on": "2023-03-30T02:31:27.000Z",
"modified_on": "2023-03-30T02:31:27.000Z",
"owner_user_id": 1,
"domain_names": ["test2.example.com"],
"forward_host": "1.1.1.1",
"forward_port": 80,
"access_list_id": 0,
"certificate_id": 0,
"ssl_forced": 0,
"caching_enabled": 0,
"block_exploits": 0,
"advanced_config": "",
"meta": {
"letsencrypt_agree": false,
"dns_challenge": false
},
"allow_websocket_upgrade": 0,
"http2_support": 0,
"forward_scheme": "http",
"enabled": 1,
"locations": [],
"hsts_enabled": 0,
"hsts_subdomains": 0,
"certificate": null,
"owner": {
"id": 1,
"created_on": "2023-03-30T01:11:50.000Z",
"modified_on": "2023-03-30T01:11:50.000Z",
"is_deleted": 0,
"is_disabled": 0,
"email": "admin@example.com",
"name": "Administrator",
"nickname": "Admin",
"avatar": "",
"roles": ["admin"]
},
"access_list": null,
"use_default_location": true,
"ipv6": true
}
}
},
"schema": {
"$ref": "#/components/schemas/ProxyHostObject"
}
}
}
}
}
}
},
"/schema": {
"get": {
"operationId": "schema",
@ -55,14 +259,10 @@
"get": {
"operationId": "refreshToken",
"summary": "Refresh your access token",
"tags": [
"Tokens"
],
"tags": ["Tokens"],
"security": [
{
"BearerAuth": [
"tokens"
]
"BearerAuth": ["tokens"]
}
],
"responses": {
@ -104,19 +304,14 @@
"scope": {
"minLength": 1,
"type": "string",
"enum": [
"user"
]
"enum": ["user"]
},
"secret": {
"minLength": 1,
"type": "string"
}
},
"required": [
"identity",
"secret"
],
"required": ["identity", "secret"],
"type": "object"
}
}
@ -144,23 +339,17 @@
}
},
"summary": "Request a new access token from credentials",
"tags": [
"Tokens"
]
"tags": ["Tokens"]
}
},
"/settings": {
"get": {
"operationId": "getSettings",
"summary": "Get all settings",
"tags": [
"Settings"
],
"tags": ["Settings"],
"security": [
{
"BearerAuth": [
"settings"
]
"BearerAuth": ["settings"]
}
],
"responses": {
@ -194,14 +383,10 @@
"get": {
"operationId": "getSetting",
"summary": "Get a setting",
"tags": [
"Settings"
],
"tags": ["Settings"],
"security": [
{
"BearerAuth": [
"settings"
]
"BearerAuth": ["settings"]
}
],
"parameters": [
@ -244,14 +429,10 @@
"put": {
"operationId": "updateSetting",
"summary": "Update a setting",
"tags": [
"Settings"
],
"tags": ["Settings"],
"security": [
{
"BearerAuth": [
"settings"
]
"BearerAuth": ["settings"]
}
],
"parameters": [
@ -305,14 +486,10 @@
"get": {
"operationId": "getUsers",
"summary": "Get all users",
"tags": [
"Users"
],
"tags": ["Users"],
"security": [
{
"BearerAuth": [
"users"
]
"BearerAuth": ["users"]
}
],
"parameters": [
@ -322,9 +499,7 @@
"description": "Expansions",
"schema": {
"type": "string",
"enum": [
"permissions"
]
"enum": ["permissions"]
}
}
],
@ -345,9 +520,7 @@
"name": "Jamie Curnow",
"nickname": "James",
"avatar": "//www.gravatar.com/avatar/6193176330f8d38747f038c170ddb193?default=mm",
"roles": [
"admin"
]
"roles": ["admin"]
}
]
},
@ -362,9 +535,7 @@
"name": "Jamie Curnow",
"nickname": "James",
"avatar": "//www.gravatar.com/avatar/6193176330f8d38747f038c170ddb193?default=mm",
"roles": [
"admin"
],
"roles": ["admin"],
"permissions": {
"visibility": "all",
"proxy_hosts": "manage",
@ -389,14 +560,10 @@
"post": {
"operationId": "createUser",
"summary": "Create a User",
"tags": [
"Users"
],
"tags": ["Users"],
"security": [
{
"BearerAuth": [
"users"
]
"BearerAuth": ["users"]
}
],
"parameters": [
@ -426,9 +593,7 @@
"name": "Jamie Curnow",
"nickname": "James",
"avatar": "//www.gravatar.com/avatar/6193176330f8d38747f038c170ddb193?default=mm",
"roles": [
"admin"
],
"roles": ["admin"],
"permissions": {
"visibility": "all",
"proxy_hosts": "manage",
@ -454,14 +619,10 @@
"get": {
"operationId": "getUser",
"summary": "Get a user",
"tags": [
"Users"
],
"tags": ["Users"],
"security": [
{
"BearerAuth": [
"users"
]
"BearerAuth": ["users"]
}
],
"parameters": [
@ -501,9 +662,7 @@
"name": "Jamie Curnow",
"nickname": "James",
"avatar": "//www.gravatar.com/avatar/6193176330f8d38747f038c170ddb193?default=mm",
"roles": [
"admin"
]
"roles": ["admin"]
}
}
},
@ -518,14 +677,10 @@
"put": {
"operationId": "updateUser",
"summary": "Update a User",
"tags": [
"Users"
],
"tags": ["Users"],
"security": [
{
"BearerAuth": [
"users"
]
"BearerAuth": ["users"]
}
],
"parameters": [
@ -574,9 +729,7 @@
"name": "Jamie Curnow",
"nickname": "James",
"avatar": "//www.gravatar.com/avatar/6193176330f8d38747f038c170ddb193?default=mm",
"roles": [
"admin"
]
"roles": ["admin"]
}
}
},
@ -591,14 +744,10 @@
"delete": {
"operationId": "deleteUser",
"summary": "Delete a User",
"tags": [
"Users"
],
"tags": ["Users"],
"security": [
{
"BearerAuth": [
"users"
]
"BearerAuth": ["users"]
}
],
"parameters": [
@ -637,14 +786,10 @@
"put": {
"operationId": "updateUserAuth",
"summary": "Update a User's Authentication",
"tags": [
"Users"
],
"tags": ["Users"],
"security": [
{
"BearerAuth": [
"users"
]
"BearerAuth": ["users"]
}
],
"parameters": [
@ -700,14 +845,10 @@
"put": {
"operationId": "updateUserPermissions",
"summary": "Update a User's Permissions",
"tags": [
"Users"
],
"tags": ["Users"],
"security": [
{
"BearerAuth": [
"users"
]
"BearerAuth": ["users"]
}
],
"parameters": [
@ -755,14 +896,10 @@
"put": {
"operationId": "loginAsUser",
"summary": "Login as this user",
"tags": [
"Users"
],
"tags": ["Users"],
"security": [
{
"BearerAuth": [
"users"
]
"BearerAuth": ["users"]
}
],
"parameters": [
@ -797,9 +934,7 @@
"name": "Jamie Curnow",
"nickname": "James",
"avatar": "//www.gravatar.com/avatar/3c8d73f45fd8763f827b964c76e6032a?default=mm",
"roles": [
"admin"
]
"roles": ["admin"]
}
}
}
@ -807,11 +942,7 @@
"schema": {
"type": "object",
"description": "Login object",
"required": [
"expires",
"token",
"user"
],
"required": ["expires", "token", "user"],
"additionalProperties": false,
"properties": {
"expires": {
@ -840,14 +971,10 @@
"get": {
"operationId": "reportsHosts",
"summary": "Report on Host Statistics",
"tags": [
"Reports"
],
"tags": ["Reports"],
"security": [
{
"BearerAuth": [
"reports"
]
"BearerAuth": ["reports"]
}
],
"responses": {
@ -878,14 +1005,10 @@
"get": {
"operationId": "getAuditLog",
"summary": "Get Audit Log",
"tags": [
"Audit Log"
],
"tags": ["Audit Log"],
"security": [
{
"BearerAuth": [
"audit-log"
]
"BearerAuth": ["audit-log"]
}
],
"responses": {
@ -925,10 +1048,7 @@
"type": "object",
"description": "Health object",
"additionalProperties": false,
"required": [
"status",
"version"
],
"required": ["status", "version"],
"properties": {
"status": {
"type": "string",
@ -944,11 +1064,7 @@
"revision": 0
},
"additionalProperties": false,
"required": [
"major",
"minor",
"revision"
],
"required": ["major", "minor", "revision"],
"properties": {
"major": {
"type": "integer",
@ -969,10 +1085,7 @@
"TokenObject": {
"type": "object",
"description": "Token object",
"required": [
"expires",
"token"
],
"required": ["expires", "token"],
"additionalProperties": false,
"properties": {
"expires": {
@ -988,16 +1101,147 @@
}
}
},
"ProxyHostObject": {
"type": "object",
"description": "Proxy Host object",
"required": [
"id",
"created_on",
"modified_on",
"owner_user_id",
"domain_names",
"forward_host",
"forward_port",
"access_list_id",
"certificate_id",
"ssl_forced",
"caching_enabled",
"block_exploits",
"advanced_config",
"meta",
"allow_websocket_upgrade",
"http2_support",
"forward_scheme",
"enabled",
"locations",
"hsts_enabled",
"hsts_subdomains",
"certificate",
"use_default_location",
"ipv6"
],
"additionalProperties": false,
"properties": {
"id": {
"type": "integer",
"description": "Proxy Host ID",
"minimum": 1,
"example": 1
},
"created_on": {
"type": "string",
"description": "Created Date",
"example": "2020-01-30T09:36:08.000Z"
},
"modified_on": {
"type": "string",
"description": "Modified Date",
"example": "2020-01-30T09:41:04.000Z"
},
"owner_user_id": {
"type": "integer",
"minimum": 1,
"example": 1
},
"domain_names": {
"type": "array",
"minItems": 1,
"items": {
"type": "string",
"minLength": 1
}
},
"forward_host": {
"type": "string",
"minLength": 1
},
"forward_port": {
"type": "integer",
"minimum": 1
},
"access_list_id": {
"type": "integer"
},
"certificate_id": {
"type": "integer"
},
"ssl_forced": {
"type": "integer"
},
"caching_enabled": {
"type": "integer"
},
"block_exploits": {
"type": "integer"
},
"advanced_config": {
"type": "string"
},
"meta": {
"type": "object"
},
"allow_websocket_upgrade": {
"type": "integer"
},
"http2_support": {
"type": "integer"
},
"forward_scheme": {
"type": "string"
},
"enabled": {
"type": "integer"
},
"locations": {
"type": "array"
},
"hsts_enabled": {
"type": "integer"
},
"hsts_subdomains": {
"type": "integer"
},
"certificate": {
"type": "object",
"nullable": true
},
"owner": {
"type": "object",
"nullable": true
},
"access_list": {
"type": "object",
"nullable": true
},
"use_default_location": {
"type": "boolean"
},
"ipv6": {
"type": "boolean"
}
}
},
"ProxyHostsList": {
"type": "array",
"description": "Proxyn Hosts list",
"items": {
"$ref": "#/components/schemas/ProxyHostObject"
}
},
"SettingObject": {
"type": "object",
"description": "Setting object",
"required": [
"id",
"name",
"description",
"value",
"meta"
],
"required": ["id", "name", "description", "value", "meta"],
"additionalProperties": false,
"properties": {
"id": {
@ -1057,17 +1301,7 @@
"UserObject": {
"type": "object",
"description": "User object",
"required": [
"id",
"created_on",
"modified_on",
"is_disabled",
"email",
"name",
"nickname",
"avatar",
"roles"
],
"required": ["id", "created_on", "modified_on", "is_disabled", "email", "name", "nickname", "avatar", "roles"],
"additionalProperties": false,
"properties": {
"id": {
@ -1117,9 +1351,7 @@
},
"roles": {
"description": "Roles applied",
"example": [
"admin"
],
"example": ["admin"],
"type": "array",
"items": {
"type": "string"
@ -1137,10 +1369,7 @@
"AuthObject": {
"type": "object",
"description": "Authentication Object",
"required": [
"type",
"secret"
],
"required": ["type", "secret"],
"properties": {
"type": {
"type": "string",
@ -1167,64 +1396,37 @@
"visibility": {
"type": "string",
"description": "Visibility Type",
"enum": [
"all",
"user"
]
"enum": ["all", "user"]
},
"access_lists": {
"type": "string",
"description": "Access Lists Permissions",
"enum": [
"hidden",
"view",
"manage"
]
"enum": ["hidden", "view", "manage"]
},
"dead_hosts": {
"type": "string",
"description": "404 Hosts Permissions",
"enum": [
"hidden",
"view",
"manage"
]
"enum": ["hidden", "view", "manage"]
},
"proxy_hosts": {
"type": "string",
"description": "Proxy Hosts Permissions",
"enum": [
"hidden",
"view",
"manage"
]
"enum": ["hidden", "view", "manage"]
},
"redirection_hosts": {
"type": "string",
"description": "Redirection Permissions",
"enum": [
"hidden",
"view",
"manage"
]
"enum": ["hidden", "view", "manage"]
},
"streams": {
"type": "string",
"description": "Streams Permissions",
"enum": [
"hidden",
"view",
"manage"
]
"enum": ["hidden", "view", "manage"]
},
"certificates": {
"type": "string",
"description": "Certificates Permissions",
"enum": [
"hidden",
"view",
"manage"
]
"enum": ["hidden", "view", "manage"]
}
}
},
@ -1251,4 +1453,4 @@
}
}
}
}
}

@ -204,7 +204,6 @@ const internalAccessList = {
});
}
})
.then(internalNginx.reload)
.then(() => {
// Add to audit log
return internalAuditLog.add(access, {
@ -227,7 +226,7 @@ const internalAccessList = {
if (row.proxy_host_count) {
return internalNginx.bulkGenerateConfigs('proxy_host', row.proxy_hosts);
}
})
}).then(internalNginx.reload)
.then(() => {
return internalAccessList.maskItems(row);
});

@ -8,10 +8,12 @@ const config = require('../lib/config');
const error = require('../lib/error');
const utils = require('../lib/utils');
const certificateModel = require('../models/certificate');
const dnsPlugins = require('../global/certbot-dns-plugins');
const tokenModel = require('../models/token');
const dnsPlugins = require('../global/certbot-dns-plugins.json');
const internalAuditLog = require('./audit-log');
const internalNginx = require('./nginx');
const internalHost = require('./host');
const certbot = require('../lib/certbot');
const archiver = require('archiver');
const path = require('path');
const { isArray } = require('lodash');
@ -26,10 +28,11 @@ function omissions() {
const internalCertificate = {
allowedSslFiles: ['certificate', 'certificate_key', 'intermediate_certificate'],
intervalTimeout: 1000 * 60 * 60, // 1 hour
interval: null,
intervalProcessing: false,
allowedSslFiles: ['certificate', 'certificate_key', 'intermediate_certificate'],
intervalTimeout: 1000 * 60 * 60, // 1 hour
interval: null,
intervalProcessing: false,
renewBeforeExpirationBy: [30, 'days'],
initTimer: () => {
logger.info('Let\'s Encrypt Renewal Timer initialized');
@ -44,62 +47,51 @@ const internalCertificate = {
processExpiringHosts: () => {
if (!internalCertificate.intervalProcessing) {
internalCertificate.intervalProcessing = true;
logger.info('Renewing SSL certs close to expiry...');
logger.info('Renewing SSL certs expiring within ' + internalCertificate.renewBeforeExpirationBy[0] + ' ' + internalCertificate.renewBeforeExpirationBy[1] + ' ...');
const cmd = certbotCommand + ' renew --non-interactive --quiet ' +
'--config "' + letsencryptConfig + '" ' +
'--work-dir "/tmp/letsencrypt-lib" ' +
'--logs-dir "/tmp/letsencrypt-log" ' +
'--preferred-challenges "dns,http" ' +
'--disable-hook-validation ' +
(letsencryptStaging ? '--staging' : '');
const expirationThreshold = moment().add(internalCertificate.renewBeforeExpirationBy[0], internalCertificate.renewBeforeExpirationBy[1]).format('YYYY-MM-DD HH:mm:ss');
return utils.exec(cmd)
.then((result) => {
if (result) {
logger.info('Renew Result: ' + result);
// Fetch all the letsencrypt certs from the db that will expire within the configured threshold
certificateModel
.query()
.where('is_deleted', 0)
.andWhere('provider', 'letsencrypt')
.andWhere('expires_on', '<', expirationThreshold)
.then((certificates) => {
if (!certificates || !certificates.length) {
return null;
}
return internalNginx.reload()
.then(() => {
logger.info('Renew Complete');
return result;
});
})
.then(() => {
// Now go and fetch all the letsencrypt certs from the db and query the files and update expiry times
return certificateModel
.query()
.where('is_deleted', 0)
.andWhere('provider', 'letsencrypt')
.then((certificates) => {
if (certificates && certificates.length) {
let promises = [];
certificates.map(function (certificate) {
promises.push(
internalCertificate.getCertificateInfoFromFile('/etc/letsencrypt/live/npm-' + certificate.id + '/fullchain.pem')
.then((cert_info) => {
return certificateModel
.query()
.where('id', certificate.id)
.andWhere('provider', 'letsencrypt')
.patch({
expires_on: moment(cert_info.dates.to, 'X').format('YYYY-MM-DD HH:mm:ss')
});
})
.catch((err) => {
// Don't want to stop the train here, just log the error
logger.error(err.message);
})
);
});
return Promise.all(promises);
}
});
/**
* Renews must be run sequentially or we'll get an error 'Another
* instance of Certbot is already running.'
*/
let sequence = Promise.resolve();
certificates.forEach(function (certificate) {
sequence = sequence.then(() =>
internalCertificate
.renew(
{
can: () =>
Promise.resolve({
permission_visibility: 'all',
}),
token: new tokenModel(),
},
{ id: certificate.id },
)
.catch((err) => {
// Don't want to stop the train here, just log the error
logger.error(err.message);
}),
);
});
return sequence;
})
.then(() => {
logger.info('Completed SSL cert renew process');
internalCertificate.intervalProcessing = false;
})
.catch((err) => {
@ -858,26 +850,19 @@ const internalCertificate = {
/**
* @param {Object} certificate the certificate row
* @param {String} dns_provider the dns provider name (key used in `certbot-dns-plugins.js`)
* @param {String} dns_provider the dns provider name (key used in `certbot-dns-plugins.json`)
* @param {String | null} credentials the content of this providers credentials file
* @param {String} propagation_seconds the cloudflare api token
* @param {String} propagation_seconds
* @returns {Promise}
*/
requestLetsEncryptSslWithDnsChallenge: (certificate) => {
const dns_plugin = dnsPlugins[certificate.meta.dns_provider];
if (!dns_plugin) {
throw Error(`Unknown DNS provider '${certificate.meta.dns_provider}'`);
}
logger.info(`Requesting Let'sEncrypt certificates via ${dns_plugin.display_name} for Cert #${certificate.id}: ${certificate.domain_names.join(', ')}`);
requestLetsEncryptSslWithDnsChallenge: async (certificate) => {
await certbot.installPlugin(certificate.meta.dns_provider);
const dnsPlugin = dnsPlugins[certificate.meta.dns_provider];
logger.info(`Requesting Let'sEncrypt certificates via ${dnsPlugin.name} for Cert #${certificate.id}: ${certificate.domain_names.join(', ')}`);
const credentialsLocation = '/etc/letsencrypt/credentials/credentials-' + certificate.id;
// Escape single quotes and backslashes
const escapedCredentials = certificate.meta.dns_provider_credentials.replaceAll('\'', '\\\'').replaceAll('\\', '\\\\');
const credentialsCmd = 'mkdir -p /etc/letsencrypt/credentials 2> /dev/null; echo \'' + escapedCredentials + '\' > \'' + credentialsLocation + '\' && chmod 600 \'' + credentialsLocation + '\'';
// we call `. /opt/certbot/bin/activate` (`.` is alternative to `source` in dash) to access certbot venv
const prepareCmd = '. /opt/certbot/bin/activate && pip install --no-cache-dir --user ' + dns_plugin.package_name + (dns_plugin.version_requirement || '') + ' ' + dns_plugin.dependencies + ' && deactivate';
fs.mkdirSync('/etc/letsencrypt/credentials', { recursive: true });
fs.writeFileSync(credentialsLocation, certificate.meta.dns_provider_credentials, {mode: 0o600});
// Whether the plugin has a --<name>-credentials argument
const hasConfigArg = certificate.meta.dns_provider !== 'route53';
@ -890,15 +875,15 @@ const internalCertificate = {
'--agree-tos ' +
'--email "' + certificate.meta.letsencrypt_email + '" ' +
'--domains "' + certificate.domain_names.join(',') + '" ' +
'--authenticator ' + dns_plugin.full_plugin_name + ' ' +
'--authenticator ' + dnsPlugin.full_plugin_name + ' ' +
(
hasConfigArg
? '--' + dns_plugin.full_plugin_name + '-credentials "' + credentialsLocation + '"'
? '--' + dnsPlugin.full_plugin_name + '-credentials "' + credentialsLocation + '"'
: ''
) +
(
certificate.meta.propagation_seconds !== undefined
? ' --' + dns_plugin.full_plugin_name + '-propagation-seconds ' + certificate.meta.propagation_seconds
? ' --' + dnsPlugin.full_plugin_name + '-propagation-seconds ' + certificate.meta.propagation_seconds
: ''
) +
(letsencryptStaging ? ' --staging' : '');
@ -908,24 +893,21 @@ const internalCertificate = {
mainCmd = 'AWS_CONFIG_FILE=\'' + credentialsLocation + '\' ' + mainCmd;
}
logger.info('Command:', `${credentialsCmd} && ${prepareCmd} && ${mainCmd}`);
if (certificate.meta.dns_provider === 'duckdns') {
mainCmd = mainCmd + ' --dns-duckdns-no-txt-restore';
}
return utils.exec(credentialsCmd)
.then(() => {
return utils.exec(prepareCmd)
.then(() => {
return utils.exec(mainCmd)
.then(async (result) => {
logger.info(result);
return result;
});
});
}).catch(async (err) => {
// Don't fail if file does not exist
const delete_credentialsCmd = `rm -f '${credentialsLocation}' || true`;
await utils.exec(delete_credentialsCmd);
throw err;
});
logger.info('Command:', mainCmd);
try {
const result = await utils.exec(mainCmd);
logger.info(result);
return result;
} catch (err) {
// Don't fail if file does not exist, so no need for action in the callback
fs.unlink(credentialsLocation, () => {});
throw err;
}
},
@ -1004,15 +986,15 @@ const internalCertificate = {
* @returns {Promise}
*/
renewLetsEncryptSslWithDnsChallenge: (certificate) => {
const dns_plugin = dnsPlugins[certificate.meta.dns_provider];
const dnsPlugin = dnsPlugins[certificate.meta.dns_provider];
if (!dns_plugin) {
if (!dnsPlugin) {
throw Error(`Unknown DNS provider '${certificate.meta.dns_provider}'`);
}
logger.info(`Renewing Let'sEncrypt certificates via ${dns_plugin.display_name} for Cert #${certificate.id}: ${certificate.domain_names.join(', ')}`);
logger.info(`Renewing Let'sEncrypt certificates via ${dnsPlugin.name} for Cert #${certificate.id}: ${certificate.domain_names.join(', ')}`);
let mainCmd = certbotCommand + ' renew ' +
let mainCmd = certbotCommand + ' renew --force-renewal ' +
'--config "' + letsencryptConfig + '" ' +
'--work-dir "/tmp/letsencrypt-lib" ' +
'--logs-dir "/tmp/letsencrypt-log" ' +
@ -1046,6 +1028,8 @@ const internalCertificate = {
const mainCmd = certbotCommand + ' revoke ' +
'--config "' + letsencryptConfig + '" ' +
'--work-dir "/tmp/letsencrypt-lib" ' +
'--logs-dir "/tmp/letsencrypt-log" ' +
'--cert-path "/etc/letsencrypt/live/npm-' + certificate.id + '/fullchain.pem" ' +
'--delete-after-revoke ' +
(letsencryptStaging ? '--staging' : '');
@ -1163,6 +1147,7 @@ const internalCertificate = {
const options = {
method: 'POST',
headers: {
'User-Agent': 'Mozilla/5.0',
'Content-Type': 'application/x-www-form-urlencoded',
'Content-Length': Buffer.byteLength(formBody)
}
@ -1175,12 +1160,22 @@ const internalCertificate = {
res.on('data', (chunk) => responseBody = responseBody + chunk);
res.on('end', function () {
const parsedBody = JSON.parse(responseBody + '');
if (res.statusCode !== 200) {
logger.warn(`Failed to test HTTP challenge for domain ${domain}`, res);
try {
const parsedBody = JSON.parse(responseBody + '');
if (res.statusCode !== 200) {
logger.warn(`Failed to test HTTP challenge for domain ${domain} because HTTP status code ${res.statusCode} was returned: ${parsedBody.message}`);
resolve(undefined);
} else {
resolve(parsedBody);
}
} catch (err) {
if (res.statusCode !== 200) {
logger.warn(`Failed to test HTTP challenge for domain ${domain} because HTTP status code ${res.statusCode} was returned`);
} else {
logger.warn(`Failed to test HTTP challenge for domain ${domain} because response failed to be parsed: ${err.message}`);
}
resolve(undefined);
}
resolve(parsedBody);
});
});
@ -1194,6 +1189,9 @@ const internalCertificate = {
if (!result) {
// Some error occurred while trying to get the data
return 'failed';
} else if (result.error) {
logger.info(`HTTP challenge test failed for domain ${domain} because error was returned: ${result.error.msg}`);
return `other:${result.error.msg}`;
} else if (`${result.responsecode}` === '200' && result.htmlresponse === 'Success') {
// Server exists and has responded with the correct data
return 'ok';

@ -225,7 +225,7 @@ const internalProxyHost = {
.query()
.where('is_deleted', 0)
.andWhere('id', data.id)
.allowGraph('[owner,access_list,access_list.[clients,items],certificate]')
.allowGraph('[owner,access_list.[clients,items],certificate]')
.first();
if (access_data.permission_visibility !== 'all') {

78
backend/lib/certbot.js Normal file

@ -0,0 +1,78 @@
const dnsPlugins = require('../global/certbot-dns-plugins.json');
const utils = require('./utils');
const error = require('./error');
const logger = require('../logger').certbot;
const batchflow = require('batchflow');
const CERTBOT_VERSION_REPLACEMENT = '$(certbot --version | grep -Eo \'[0-9](\\.[0-9]+)+\')';
const certbot = {
/**
* @param {array} pluginKeys
*/
installPlugins: async function (pluginKeys) {
let hasErrors = false;
return new Promise((resolve, reject) => {
if (pluginKeys.length === 0) {
resolve();
return;
}
batchflow(pluginKeys).sequential()
.each((i, pluginKey, next) => {
certbot.installPlugin(pluginKey)
.then(() => {
next();
})
.catch((err) => {
hasErrors = true;
next(err);
});
})
.error((err) => {
logger.error(err.message);
})
.end(() => {
if (hasErrors) {
reject(new error.CommandError('Some plugins failed to install. Please check the logs above', 1));
} else {
resolve();
}
});
});
},
/**
* Installs a cerbot plugin given the key for the object from
* ../global/certbot-dns-plugins.json
*
* @param {string} pluginKey
* @returns {Object}
*/
installPlugin: async function (pluginKey) {
if (typeof dnsPlugins[pluginKey] === 'undefined') {
// throw Error(`Certbot plugin ${pluginKey} not found`);
throw new error.ItemNotFoundError(pluginKey);
}
const plugin = dnsPlugins[pluginKey];
logger.start(`Installing ${pluginKey}...`);
plugin.version = plugin.version.replace(/{{certbot-version}}/g, CERTBOT_VERSION_REPLACEMENT);
plugin.dependencies = plugin.dependencies.replace(/{{certbot-version}}/g, CERTBOT_VERSION_REPLACEMENT);
const cmd = '. /opt/certbot/bin/activate && pip install --no-cache-dir ' + plugin.dependencies + ' ' + plugin.package_name + plugin.version + ' ' + ' && deactivate';
return utils.exec(cmd)
.then((result) => {
logger.complete(`Installed ${pluginKey}`);
return result;
})
.catch((err) => {
throw err;
});
},
};
module.exports = certbot;

@ -93,7 +93,7 @@ const generateKeys = () => {
try {
fs.writeFileSync(keysFile, JSON.stringify(keys, null, 2));
} catch (err) {
logger.error('Could not write JWT key pair to config file: ' + keysFile + ': ' . err.message);
logger.error('Could not write JWT key pair to config file: ' + keysFile + ': ' + err.message);
process.exit(1);
}
logger.info('Wrote JWT key pair to config file: ' + keysFile);

@ -82,7 +82,16 @@ module.exports = {
this.message = message;
this.public = false;
this.status = 400;
}
},
CommandError: function (stdErr, code, previous) {
Error.captureStackTrace(this, this.constructor);
this.name = this.constructor.name;
this.previous = previous;
this.message = stdErr;
this.code = code;
this.public = false;
},
};
_.forEach(module.exports, function (error) {

@ -3,23 +3,27 @@ const exec = require('child_process').exec;
const execFile = require('child_process').execFile;
const { Liquid } = require('liquidjs');
const logger = require('../logger').global;
const error = require('./error');
module.exports = {
/**
* @param {String} cmd
* @returns {Promise}
*/
exec: function (cmd) {
return new Promise((resolve, reject) => {
exec(cmd, function (err, stdout, /*stderr*/) {
if (err && typeof err === 'object') {
reject(err);
exec: async function(cmd, options = {}) {
logger.debug('CMD:', cmd);
const { stdout, stderr } = await new Promise((resolve, reject) => {
const child = exec(cmd, options, (isError, stdout, stderr) => {
if (isError) {
reject(new error.CommandError(stderr, isError));
} else {
resolve(stdout.trim());
resolve({ stdout, stderr });
}
});
child.on('error', (e) => {
reject(new error.CommandError(stderr, 1, e));
});
});
return stdout;
},
/**
@ -28,7 +32,8 @@ module.exports = {
* @returns {Promise}
*/
execFile: function (cmd, args) {
logger.debug('CMD: ' + cmd + ' ' + (args ? args.join(' ') : ''));
// logger.debug('CMD: ' + cmd + ' ' + (args ? args.join(' ') : ''));
return new Promise((resolve, reject) => {
execFile(cmd, args, function (err, stdout, /*stderr*/) {
if (err && typeof err === 'object') {

@ -7,6 +7,7 @@ module.exports = {
access: new Signale({scope: 'Access '}),
nginx: new Signale({scope: 'Nginx '}),
ssl: new Signale({scope: 'SSL '}),
certbot: new Signale({scope: 'Certbot '}),
import: new Signale({scope: 'Importer '}),
setup: new Signale({scope: 'Setup '}),
ip_ranges: new Signale({scope: 'IP Ranges'})

@ -10,7 +10,7 @@
"bcrypt": "^5.0.0",
"body-parser": "^1.19.0",
"compression": "^1.7.4",
"express": "^4.17.3",
"express": "^4.19.2",
"express-fileupload": "^1.1.9",
"gravatar": "^1.8.0",
"json-schema-ref-parser": "^8.0.0",

@ -172,7 +172,7 @@
"description": "Domain Names separated by a comma",
"example": "*.jc21.com,blog.jc21.com",
"type": "array",
"maxItems": 15,
"maxItems": 100,
"uniqueItems": true,
"items": {
"type": "string",

@ -0,0 +1,49 @@
#!/usr/bin/node
// Usage:
// Install all plugins defined in `certbot-dns-plugins.json`:
// ./install-certbot-plugins
// Install one or more specific plugins:
// ./install-certbot-plugins route53 cloudflare
//
// Usage with a running docker container:
// docker exec npm_core /command/s6-setuidgid 1000:1000 bash -c "/app/scripts/install-certbot-plugins"
//
const dnsPlugins = require('../global/certbot-dns-plugins.json');
const certbot = require('../lib/certbot');
const logger = require('../logger').certbot;
const batchflow = require('batchflow');
let hasErrors = false;
let failingPlugins = [];
let pluginKeys = Object.keys(dnsPlugins);
if (process.argv.length > 2) {
pluginKeys = process.argv.slice(2);
}
batchflow(pluginKeys).sequential()
.each((i, pluginKey, next) => {
certbot.installPlugin(pluginKey)
.then(() => {
next();
})
.catch((err) => {
hasErrors = true;
failingPlugins.push(pluginKey);
next(err);
});
})
.error((err) => {
logger.error(err.message);
})
.end(() => {
if (hasErrors) {
logger.error('Some plugins failed to install. Please check the logs above. Failing plugins: ' + '\n - ' + failingPlugins.join('\n - '));
process.exit(1);
} else {
logger.complete('Plugins installed successfully');
process.exit(0);
}
});

@ -6,8 +6,7 @@ const userPermissionModel = require('./models/user_permission');
const utils = require('./lib/utils');
const authModel = require('./models/auth');
const settingModel = require('./models/setting');
const dns_plugins = require('./global/certbot-dns-plugins');
const certbot = require('./lib/certbot');
/**
* Creates a default admin users if one doesn't already exist in the database
*
@ -22,11 +21,14 @@ const setupDefaultUser = () => {
.then((row) => {
if (!row.count) {
// Create a new user and set password
logger.info('Creating a new user: admin@example.com with password: changeme');
let email = process.env.INITIAL_ADMIN_EMAIL || 'admin@example.com';
let password = process.env.INITIAL_ADMIN_PASSWORD || 'changeme';
logger.info('Creating a new user: ' + email + ' with password: ' + password);
let data = {
is_deleted: 0,
email: 'admin@example.com',
email: email,
name: 'Administrator',
nickname: 'Admin',
avatar: '',
@ -42,7 +44,7 @@ const setupDefaultUser = () => {
.insert({
user_id: user.id,
type: 'password',
secret: 'changeme',
secret: password,
meta: {},
})
.then(() => {
@ -116,10 +118,9 @@ const setupCertbotPlugins = () => {
certificates.map(function (certificate) {
if (certificate.meta && certificate.meta.dns_challenge === true) {
const dns_plugin = dns_plugins[certificate.meta.dns_provider];
const packages_to_install = `${dns_plugin.package_name}${dns_plugin.version_requirement || ''} ${dns_plugin.dependencies}`;
if (plugins.indexOf(packages_to_install) === -1) plugins.push(packages_to_install);
if (plugins.indexOf(certificate.meta.dns_provider) === -1) {
plugins.push(certificate.meta.dns_provider);
}
// Make sure credentials file exists
const credentials_loc = '/etc/letsencrypt/credentials/credentials-' + certificate.id;
@ -130,17 +131,15 @@ const setupCertbotPlugins = () => {
}
});
if (plugins.length) {
const install_cmd = '. /opt/certbot/bin/activate && pip install --no-cache-dir --user ' + plugins.join(' ') + ' && deactivate';
promises.push(utils.exec(install_cmd));
}
if (promises.length) {
return Promise.all(promises)
.then(() => {
logger.info('Added Certbot plugins ' + plugins.join(', '));
});
}
return certbot.installPlugins(plugins)
.then(() => {
if (promises.length) {
return Promise.all(promises)
.then(() => {
logger.info('Added Certbot plugins ' + plugins.join(', '));
});
}
});
}
});
};

@ -2,7 +2,7 @@
{% if ssl_forced == 1 or ssl_forced == true %}
{% if hsts_enabled == 1 or hsts_enabled == true %}
# HSTS (ngx_http_headers_module is required) (63072000 seconds = 2 years)
add_header Strict-Transport-Security "max-age=63072000;{% if hsts_subdomains == 1 or hsts_subdomains == true -%} includeSubDomains;{% endif %} preload" always;
add_header Strict-Transport-Security $hsts_header always;
{% endif %}
{% endif %}
{% endif %}

@ -0,0 +1,3 @@
map $scheme $hsts_header {
https "max-age=63072000;{% if hsts_subdomains == 1 or hsts_subdomains == true -%} includeSubDomains;{% endif %} preload";
}

@ -5,9 +5,9 @@
#listen [::]:80;
{% endif %}
{% if certificate -%}
listen 443 ssl{% if http2_support %} http2{% endif %};
listen 443 ssl{% if http2_support == 1 or http2_support == true %} http2{% endif %};
{% if ipv6 -%}
listen [::]:443 ssl{% if http2_support %} http2{% endif %};
listen [::]:443 ssl{% if http2_support == 1 or http2_support == true %} http2{% endif %};
{% else -%}
#listen [::]:443;
{% endif %}

@ -1,4 +1,6 @@
location {{ path }} {
{{ advanced_config }}
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Scheme $scheme;
proxy_set_header X-Forwarded-Proto $scheme;
@ -17,8 +19,5 @@
proxy_set_header Connection $http_connection;
proxy_http_version 1.1;
{% endif %}
{{ advanced_config }}
}

@ -1,6 +1,9 @@
{% include "_header_comment.conf" %}
{% if enabled %}
{% include "_hsts_map.conf" %}
server {
{% include "_listen.conf" %}
{% include "_certificates.conf" %}

@ -24,6 +24,12 @@ server {
}
{% endif %}
{%- if value == "444" %}
location / {
return 444;
}
{% endif %}
{%- if value == "redirect" %}
location / {
return 301 {{ meta.redirect }};

@ -1,6 +1,9 @@
{% include "_header_comment.conf" %}
{% if enabled %}
{% include "_hsts_map.conf" %}
server {
set $forward_scheme {{ forward_scheme }};
set $server "{{ forward_host }}";

@ -1,6 +1,9 @@
{% include "_header_comment.conf" %}
{% if enabled %}
{% include "_hsts_map.conf" %}
server {
{% include "_listen.conf" %}
{% include "_certificates.conf" %}

@ -407,21 +407,23 @@ blueimp-md5@^2.16.0:
resolved "https://registry.yarnpkg.com/blueimp-md5/-/blueimp-md5-2.17.0.tgz#f4fcac088b115f7b4045f19f5da59e9d01b1bb96"
integrity sha512-x5PKJHY5rHQYaADj6NwPUR2QRCUVSggPzrUKkeENpj871o9l9IefJbO2jkT5UvYykeOK9dx0VmkIo6dZ+vThYw==
body-parser@1.19.2, body-parser@^1.19.0:
version "1.19.2"
resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.19.2.tgz#4714ccd9c157d44797b8b5607d72c0b89952f26e"
integrity sha512-SAAwOxgoCKMGs9uUAUFHygfLAyaniaoun6I8mFY9pRAJL9+Kec34aU+oIjDhTycub1jozEfEwx1W1IuOYxVSFw==
body-parser@1.20.2, body-parser@^1.19.0:
version "1.20.2"
resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.2.tgz#6feb0e21c4724d06de7ff38da36dad4f57a747fd"
integrity sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==
dependencies:
bytes "3.1.2"
content-type "~1.0.4"
content-type "~1.0.5"
debug "2.6.9"
depd "~1.1.2"
http-errors "1.8.1"
depd "2.0.0"
destroy "1.2.0"
http-errors "2.0.0"
iconv-lite "0.4.24"
on-finished "~2.3.0"
qs "6.9.7"
raw-body "2.4.3"
on-finished "2.4.1"
qs "6.11.0"
raw-body "2.5.2"
type-is "~1.6.18"
unpipe "1.0.0"
boxen@^4.2.0:
version "4.2.0"
@ -446,11 +448,11 @@ brace-expansion@^1.1.7:
concat-map "0.0.1"
braces@~3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107"
integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==
version "3.0.3"
resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789"
integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==
dependencies:
fill-range "^7.0.1"
fill-range "^7.1.1"
buffer-crc32@^0.2.1, buffer-crc32@^0.2.13:
version "0.2.13"
@ -524,6 +526,17 @@ cacheable-request@^6.0.0:
normalize-url "^4.1.0"
responselike "^1.0.2"
call-bind@^1.0.7:
version "1.0.7"
resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.7.tgz#06016599c40c56498c18769d2730be242b6fa3b9"
integrity sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==
dependencies:
es-define-property "^1.0.0"
es-errors "^1.3.0"
function-bind "^1.1.2"
get-intrinsic "^1.2.4"
set-function-length "^1.2.1"
call-me-maybe@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/call-me-maybe/-/call-me-maybe-1.0.1.tgz#26d208ea89e37b5cbde60250a15f031c16a4d66b"
@ -728,20 +741,20 @@ content-disposition@0.5.4:
dependencies:
safe-buffer "5.2.1"
content-type@~1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b"
integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==
content-type@~1.0.4, content-type@~1.0.5:
version "1.0.5"
resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.5.tgz#8b773162656d1d1086784c8f23a54ce6d73d7918"
integrity sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==
cookie-signature@1.0.6:
version "1.0.6"
resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c"
integrity sha1-4wOogrNCzD7oylE6eZmXNNqzriw=
cookie@0.4.2:
version "0.4.2"
resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.2.tgz#0e41f24de5ecf317947c82fc789e06a884824432"
integrity sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==
cookie@0.6.0:
version "0.6.0"
resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.6.0.tgz#2798b04b071b0ecbff0dbb62a505a8efa4e19051"
integrity sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==
core-util-is@~1.0.0:
version "1.0.2"
@ -831,25 +844,29 @@ defer-to-connect@^1.0.1:
resolved "https://registry.yarnpkg.com/defer-to-connect/-/defer-to-connect-1.1.3.tgz#331ae050c08dcf789f8c83a7b81f0ed94f4ac591"
integrity sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==
define-data-property@^1.1.4:
version "1.1.4"
resolved "https://registry.yarnpkg.com/define-data-property/-/define-data-property-1.1.4.tgz#894dc141bb7d3060ae4366f6a0107e68fbe48c5e"
integrity sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==
dependencies:
es-define-property "^1.0.0"
es-errors "^1.3.0"
gopd "^1.0.1"
delegates@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a"
integrity sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=
depd@^2.0.0:
depd@2.0.0, depd@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df"
integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==
depd@~1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9"
integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=
destroy@~1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80"
integrity sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=
destroy@1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.2.0.tgz#4803735509ad8be552934c67df614f94e66fa015"
integrity sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==
detect-libc@^1.0.2:
version "1.0.3"
@ -950,6 +967,18 @@ error-ex@^1.3.1:
dependencies:
is-arrayish "^0.2.1"
es-define-property@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/es-define-property/-/es-define-property-1.0.0.tgz#c7faefbdff8b2696cf5f46921edfb77cc4ba3845"
integrity sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==
dependencies:
get-intrinsic "^1.2.4"
es-errors@^1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/es-errors/-/es-errors-1.3.0.tgz#05f75a25dab98e4fb1dcd5e1472c0546d5057c8f"
integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==
escalade@^3.1.1:
version "3.1.1"
resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40"
@ -1104,38 +1133,39 @@ express-fileupload@^1.1.9:
dependencies:
busboy "^0.3.1"
express@^4.17.3:
version "4.17.3"
resolved "https://registry.yarnpkg.com/express/-/express-4.17.3.tgz#f6c7302194a4fb54271b73a1fe7a06478c8f85a1"
integrity sha512-yuSQpz5I+Ch7gFrPCk4/c+dIBKlQUxtgwqzph132bsT6qhuzss6I8cLJQz7B3rFblzd6wtcI0ZbGltH/C4LjUg==
express@^4.19.2:
version "4.19.2"
resolved "https://registry.yarnpkg.com/express/-/express-4.19.2.tgz#e25437827a3aa7f2a827bc8171bbbb664a356465"
integrity sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==
dependencies:
accepts "~1.3.8"
array-flatten "1.1.1"
body-parser "1.19.2"
body-parser "1.20.2"
content-disposition "0.5.4"
content-type "~1.0.4"
cookie "0.4.2"
cookie "0.6.0"
cookie-signature "1.0.6"
debug "2.6.9"
depd "~1.1.2"
depd "2.0.0"
encodeurl "~1.0.2"
escape-html "~1.0.3"
etag "~1.8.1"
finalhandler "~1.1.2"
finalhandler "1.2.0"
fresh "0.5.2"
http-errors "2.0.0"
merge-descriptors "1.0.1"
methods "~1.1.2"
on-finished "~2.3.0"
on-finished "2.4.1"
parseurl "~1.3.3"
path-to-regexp "0.1.7"
proxy-addr "~2.0.7"
qs "6.9.7"
qs "6.11.0"
range-parser "~1.2.1"
safe-buffer "5.2.1"
send "0.17.2"
serve-static "1.14.2"
send "0.18.0"
serve-static "1.15.0"
setprototypeof "1.2.0"
statuses "~1.5.0"
statuses "2.0.1"
type-is "~1.6.18"
utils-merge "1.0.1"
vary "~1.1.2"
@ -1176,24 +1206,24 @@ file-entry-cache@^6.0.1:
dependencies:
flat-cache "^3.0.4"
fill-range@^7.0.1:
version "7.0.1"
resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40"
integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==
fill-range@^7.1.1:
version "7.1.1"
resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292"
integrity sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==
dependencies:
to-regex-range "^5.0.1"
finalhandler@~1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.2.tgz#b7e7d000ffd11938d0fdb053506f6ebabe9f587d"
integrity sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==
finalhandler@1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.2.0.tgz#7d23fe5731b207b4640e4fcd00aec1f9207a7b32"
integrity sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==
dependencies:
debug "2.6.9"
encodeurl "~1.0.2"
escape-html "~1.0.3"
on-finished "~2.3.0"
on-finished "2.4.1"
parseurl "~1.3.3"
statuses "~1.5.0"
statuses "2.0.1"
unpipe "~1.0.0"
find-up@^2.0.0:
@ -1276,6 +1306,11 @@ function-bind@^1.1.1:
resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d"
integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==
function-bind@^1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c"
integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==
gauge@^3.0.0:
version "3.0.2"
resolved "https://registry.yarnpkg.com/gauge/-/gauge-3.0.2.tgz#03bf4441c044383908bcfa0656ad91803259b395"
@ -1324,6 +1359,17 @@ get-caller-file@^2.0.1:
resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e"
integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==
get-intrinsic@^1.1.3, get-intrinsic@^1.2.4:
version "1.2.4"
resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.4.tgz#e385f5a4b5227d449c3eabbad05494ef0abbeadd"
integrity sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==
dependencies:
es-errors "^1.3.0"
function-bind "^1.1.2"
has-proto "^1.0.1"
has-symbols "^1.0.3"
hasown "^2.0.0"
get-package-type@^0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/get-package-type/-/get-package-type-0.1.0.tgz#8de2d803cff44df3bc6c456e6668b36c3926e11a"
@ -1356,9 +1402,9 @@ glob-parent@^6.0.2:
is-glob "^4.0.3"
glob-parent@~5.1.0:
version "5.1.1"
resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.1.tgz#b6c1ef417c4e5663ea498f1c45afac6916bbc229"
integrity sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==
version "5.1.2"
resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4"
integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==
dependencies:
is-glob "^4.0.1"
@ -1400,6 +1446,13 @@ globals@^13.19.0:
dependencies:
type-fest "^0.20.2"
gopd@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.0.1.tgz#29ff76de69dac7489b7c0918a5788e56477c332c"
integrity sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==
dependencies:
get-intrinsic "^1.1.3"
got@^9.6.0:
version "9.6.0"
resolved "https://registry.yarnpkg.com/got/-/got-9.6.0.tgz#edf45e7d67f99545705de1f7bbeeeb121765ed85"
@ -1457,6 +1510,23 @@ has-flag@^4.0.0:
resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b"
integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==
has-property-descriptors@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz#963ed7d071dc7bf5f084c5bfbe0d1b6222586854"
integrity sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==
dependencies:
es-define-property "^1.0.0"
has-proto@^1.0.1:
version "1.0.3"
resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.0.3.tgz#b31ddfe9b0e6e9914536a6ab286426d0214f77fd"
integrity sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==
has-symbols@^1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8"
integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==
has-unicode@^2.0.0, has-unicode@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9"
@ -1474,20 +1544,27 @@ has@^1.0.3:
dependencies:
function-bind "^1.1.1"
hasown@^2.0.0:
version "2.0.2"
resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003"
integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==
dependencies:
function-bind "^1.1.2"
http-cache-semantics@^4.0.0, http-cache-semantics@^4.1.0:
version "4.1.1"
resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz#abe02fcb2985460bf0323be664436ec3476a6d5a"
integrity sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==
http-errors@1.8.1:
version "1.8.1"
resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.8.1.tgz#7c3f28577cbc8a207388455dbd62295ed07bd68c"
integrity sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==
http-errors@2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-2.0.0.tgz#b7774a1486ef73cf7667ac9ae0858c012c57b9d3"
integrity sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==
dependencies:
depd "~1.1.2"
depd "2.0.0"
inherits "2.0.4"
setprototypeof "1.2.0"
statuses ">= 1.5.0 < 2"
statuses "2.0.1"
toidentifier "1.0.1"
http-proxy-agent@^4.0.1:
@ -1615,9 +1692,9 @@ interpret@^2.2.0:
integrity sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==
ip@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/ip/-/ip-2.0.0.tgz#4cf4ab182fee2314c75ede1276f8c80b479936da"
integrity sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==
version "2.0.1"
resolved "https://registry.yarnpkg.com/ip/-/ip-2.0.1.tgz#e8f3595d33a3ea66490204234b77636965307105"
integrity sha512-lJUL9imLTNi1ZfXT+DU6rBBdbiKGBuay9B6xGSPVjUeQwaH1RIGqef8RZkUtHioLmSNpPR5M4HVKJGm1j8FWVQ==
ipaddr.js@1.9.1:
version "1.9.1"
@ -2365,6 +2442,11 @@ object-assign@^4.1.0, object-assign@^4.1.1:
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=
object-inspect@^1.13.1:
version "1.13.1"
resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.1.tgz#b96c6109324ccfef6b12216a956ca4dc2ff94bc2"
integrity sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==
objection@3.0.1:
version "3.0.1"
resolved "https://registry.yarnpkg.com/objection/-/objection-3.0.1.tgz#f67dc698187d10524e5d1b5d37a54e5bba49a42a"
@ -2373,10 +2455,10 @@ objection@3.0.1:
ajv "^8.6.2"
db-errors "^0.2.3"
on-finished@~2.3.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947"
integrity sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=
on-finished@2.4.1:
version "2.4.1"
resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.4.1.tgz#58c8c44116e54845ad57f14ab10b03533184ac3f"
integrity sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==
dependencies:
ee-first "1.1.1"
@ -2653,10 +2735,12 @@ pupa@^2.0.1:
dependencies:
escape-goat "^2.0.0"
qs@6.9.7:
version "6.9.7"
resolved "https://registry.yarnpkg.com/qs/-/qs-6.9.7.tgz#4610846871485e1e048f44ae3b94033f0e675afe"
integrity sha512-IhMFgUmuNpyRfxA90umL7ByLlgRXu6tIfKPpF5TmcfRLlLCckfP/g3IQmju6jjpu+Hh8rA+2p6A27ZSPOOHdKw==
qs@6.11.0:
version "6.11.0"
resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.0.tgz#fd0d963446f7a65e1367e01abd85429453f0c37a"
integrity sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==
dependencies:
side-channel "^1.0.4"
querystring@0.2.0:
version "0.2.0"
@ -2673,13 +2757,13 @@ range-parser@~1.2.1:
resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031"
integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==
raw-body@2.4.3:
version "2.4.3"
resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.4.3.tgz#8f80305d11c2a0a545c2d9d89d7a0286fcead43c"
integrity sha512-UlTNLIcu0uzb4D2f4WltY6cVjLi+/jEN4lgEUj3E04tpMDpUlkBo/eSn6zou9hum2VMNpCCUone0O0WeJim07g==
raw-body@2.5.2:
version "2.5.2"
resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.5.2.tgz#99febd83b90e08975087e8f1f9419a149366b68a"
integrity sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==
dependencies:
bytes "3.1.2"
http-errors "1.8.1"
http-errors "2.0.0"
iconv-lite "0.4.24"
unpipe "1.0.0"
@ -2850,56 +2934,68 @@ semver-diff@^3.1.1:
semver "^6.3.0"
semver@^5.3.0, semver@^5.7.1:
version "5.7.1"
resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7"
integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==
version "5.7.2"
resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.2.tgz#48d55db737c3287cd4835e17fa13feace1c41ef8"
integrity sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==
semver@^6.0.0, semver@^6.2.0, semver@^6.3.0:
version "6.3.0"
resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d"
integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==
version "6.3.1"
resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4"
integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==
semver@^7.3.5, semver@^7.3.8:
version "7.3.8"
resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.8.tgz#07a78feafb3f7b32347d725e33de7e2a2df67798"
integrity sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==
version "7.5.4"
resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.4.tgz#483986ec4ed38e1c6c48c34894a9182dbff68a6e"
integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==
dependencies:
lru-cache "^6.0.0"
send@0.17.2:
version "0.17.2"
resolved "https://registry.yarnpkg.com/send/-/send-0.17.2.tgz#926622f76601c41808012c8bf1688fe3906f7820"
integrity sha512-UJYB6wFSJE3G00nEivR5rgWp8c2xXvJ3OPWPhmuteU0IKj8nKbG3DrjiOmLwpnHGYWAVwA69zmTm++YG0Hmwww==
send@0.18.0:
version "0.18.0"
resolved "https://registry.yarnpkg.com/send/-/send-0.18.0.tgz#670167cc654b05f5aa4a767f9113bb371bc706be"
integrity sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==
dependencies:
debug "2.6.9"
depd "~1.1.2"
destroy "~1.0.4"
depd "2.0.0"
destroy "1.2.0"
encodeurl "~1.0.2"
escape-html "~1.0.3"
etag "~1.8.1"
fresh "0.5.2"
http-errors "1.8.1"
http-errors "2.0.0"
mime "1.6.0"
ms "2.1.3"
on-finished "~2.3.0"
on-finished "2.4.1"
range-parser "~1.2.1"
statuses "~1.5.0"
statuses "2.0.1"
serve-static@1.14.2:
version "1.14.2"
resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.14.2.tgz#722d6294b1d62626d41b43a013ece4598d292bfa"
integrity sha512-+TMNA9AFxUEGuC0z2mevogSnn9MXKb4fa7ngeRMJaaGv8vTwnIEkKi+QGvPt33HSnf8pRS+WGM0EbMtCJLKMBQ==
serve-static@1.15.0:
version "1.15.0"
resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.15.0.tgz#faaef08cffe0a1a62f60cad0c4e513cff0ac9540"
integrity sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==
dependencies:
encodeurl "~1.0.2"
escape-html "~1.0.3"
parseurl "~1.3.3"
send "0.17.2"
send "0.18.0"
set-blocking@^2.0.0, set-blocking@~2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7"
integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc=
set-function-length@^1.2.1:
version "1.2.2"
resolved "https://registry.yarnpkg.com/set-function-length/-/set-function-length-1.2.2.tgz#aac72314198eaed975cf77b2c3b6b880695e5449"
integrity sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==
dependencies:
define-data-property "^1.1.4"
es-errors "^1.3.0"
function-bind "^1.1.2"
get-intrinsic "^1.2.4"
gopd "^1.0.1"
has-property-descriptors "^1.0.2"
setprototypeof@1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424"
@ -2917,6 +3013,16 @@ shebang-regex@^3.0.0:
resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172"
integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==
side-channel@^1.0.4:
version "1.0.6"
resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.6.tgz#abd25fb7cd24baf45466406b1096b7831c9215f2"
integrity sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==
dependencies:
call-bind "^1.0.7"
es-errors "^1.3.0"
get-intrinsic "^1.2.4"
object-inspect "^1.13.1"
signal-exit@^3.0.0, signal-exit@^3.0.2:
version "3.0.3"
resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c"
@ -2986,10 +3092,10 @@ ssri@^8.0.0, ssri@^8.0.1:
dependencies:
minipass "^3.1.1"
"statuses@>= 1.5.0 < 2", statuses@~1.5.0:
version "1.5.0"
resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c"
integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=
statuses@2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.1.tgz#55cb000ccf1d48728bd23c685a063998cf1a1b63"
integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==
streamsearch@0.1.2:
version "0.1.2"
@ -3396,9 +3502,9 @@ widest-line@^3.1.0:
string-width "^4.0.0"
word-wrap@^1.2.3:
version "1.2.3"
resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c"
integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==
version "1.2.4"
resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.4.tgz#cb4b50ec9aca570abd1f52f33cd45b6c61739a9f"
integrity sha512-2V81OA4ugVo5pRo46hAoD2ivUJx8jXmWXfUkY4KFNw0hEptvN0QfH3K4nHiwzGeKl5rFKedV48QVoqYavy4YpA==
wrap-ansi@^6.2.0:
version "6.2.0"

@ -3,20 +3,25 @@
# This file assumes that the frontend has been built using ./scripts/frontend-build
FROM jc21/nginx-full:certbot-node
FROM nginxproxymanager/nginx-full:certbot-node
ARG TARGETPLATFORM
ARG BUILD_VERSION
ARG BUILD_COMMIT
ARG BUILD_DATE
# See: https://github.com/just-containers/s6-overlay/blob/master/README.md
ENV SUPPRESS_NO_CONFIG_WARNING=1 \
S6_FIX_ATTRS_HIDDEN=1 \
S6_BEHAVIOUR_IF_STAGE2_FAILS=1 \
S6_CMD_WAIT_FOR_SERVICES_MAXTIME=0 \
S6_FIX_ATTRS_HIDDEN=1 \
S6_KILL_FINISH_MAXTIME=10000 \
S6_VERBOSITY=1 \
NODE_ENV=production \
NPM_BUILD_VERSION="${BUILD_VERSION}" \
NPM_BUILD_COMMIT="${BUILD_COMMIT}" \
NPM_BUILD_DATE="${BUILD_DATE}"
NPM_BUILD_DATE="${BUILD_DATE}" \
NODE_OPTIONS="--openssl-legacy-provider"
RUN echo "fs.file-max = 65535" > /etc/sysctl.conf \
&& apt-get update \
@ -42,12 +47,10 @@ RUN yarn install \
COPY docker/rootfs /
# Remove frontend service not required for prod, dev nginx config as well
RUN rm -rf /etc/services.d/frontend /etc/nginx/conf.d/dev.conf \
&& chmod 644 /etc/logrotate.d/nginx-proxy-manager \
&& pip uninstall --yes setuptools \
&& pip install --no-cache-dir "setuptools==58.0.0"
RUN rm -rf /etc/s6-overlay/s6-rc.d/user/contents.d/frontend /etc/nginx/conf.d/dev.conf \
&& chmod 644 /etc/logrotate.d/nginx-proxy-manager
VOLUME [ "/data", "/etc/letsencrypt" ]
VOLUME [ "/data" ]
ENTRYPOINT [ "/init" ]
LABEL org.label-schema.schema-version="1.0" \

@ -1,9 +1,14 @@
FROM jc21/nginx-full:certbot-node
FROM nginxproxymanager/nginx-full:certbot-node
LABEL maintainer="Jamie Curnow <jc@jc21.com>"
ENV S6_LOGGING=0 \
SUPPRESS_NO_CONFIG_WARNING=1 \
S6_FIX_ATTRS_HIDDEN=1
# See: https://github.com/just-containers/s6-overlay/blob/master/README.md
ENV SUPPRESS_NO_CONFIG_WARNING=1 \
S6_BEHAVIOUR_IF_STAGE2_FAILS=1 \
S6_CMD_WAIT_FOR_SERVICES_MAXTIME=0 \
S6_FIX_ATTRS_HIDDEN=1 \
S6_KILL_FINISH_MAXTIME=10000 \
S6_VERBOSITY=2 \
NODE_OPTIONS="--openssl-legacy-provider"
RUN echo "fs.file-max = 65535" > /etc/sysctl.conf \
&& apt-get update \

@ -0,0 +1,28 @@
{
"log": {
"format": "nice",
"level": "debug"
},
"servers": [
{
"host": "0.0.0.0",
"port": 53,
"upstreams": [
{
"regex": "website[0-9]+.example\\.com",
"upstream": "127.0.0.11"
},
{
"regex": ".*\\.example\\.com",
"upstream": "1.1.1.1"
},
{
"regex": "local",
"nxdomain": true
}
],
"internal": null,
"default_upstream": "127.0.0.11"
}
]
}

@ -0,0 +1,7 @@
text = True
non-interactive = True
webroot-path = /data/letsencrypt-acme-challenge
key-type = ecdsa
elliptic-curve = secp384r1
preferred-chain = ISRG Root X1
server =

255
docker/dev/pdns-db.sql Normal file

@ -0,0 +1,255 @@
/*
How this was generated:
1. bring up an empty pdns stack
2. use api to create a zone ...
curl -X POST \
'http://npm.dev:8081/api/v1/servers/localhost/zones' \
--header 'X-API-Key: npm' \
--header 'Content-Type: application/json' \
--data-raw '{
"name": "example.com.",
"kind": "Native",
"masters": [],
"nameservers": [
"ns1.pdns.",
"ns2.pdns."
]
}'
3. Dump sql:
docker exec -ti npm.pdns.db mysqldump -u pdns -p pdns
*/
----------------------------------------------------------------------
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!40101 SET NAMES utf8mb4 */;
/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
/*!40103 SET TIME_ZONE='+00:00' */;
/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
--
-- Table structure for table `comments`
--
DROP TABLE IF EXISTS `comments`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `comments` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`domain_id` int(11) NOT NULL,
`name` varchar(255) NOT NULL,
`type` varchar(10) NOT NULL,
`modified_at` int(11) NOT NULL,
`account` varchar(40) CHARACTER SET utf8mb3 DEFAULT NULL,
`comment` text CHARACTER SET utf8mb3 NOT NULL,
PRIMARY KEY (`id`),
KEY `comments_name_type_idx` (`name`,`type`),
KEY `comments_order_idx` (`domain_id`,`modified_at`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Dumping data for table `comments`
--
LOCK TABLES `comments` WRITE;
/*!40000 ALTER TABLE `comments` DISABLE KEYS */;
/*!40000 ALTER TABLE `comments` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Table structure for table `cryptokeys`
--
DROP TABLE IF EXISTS `cryptokeys`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `cryptokeys` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`domain_id` int(11) NOT NULL,
`flags` int(11) NOT NULL,
`active` tinyint(1) DEFAULT NULL,
`published` tinyint(1) DEFAULT 1,
`content` text DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `domainidindex` (`domain_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Dumping data for table `cryptokeys`
--
LOCK TABLES `cryptokeys` WRITE;
/*!40000 ALTER TABLE `cryptokeys` DISABLE KEYS */;
/*!40000 ALTER TABLE `cryptokeys` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Table structure for table `domainmetadata`
--
DROP TABLE IF EXISTS `domainmetadata`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `domainmetadata` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`domain_id` int(11) NOT NULL,
`kind` varchar(32) DEFAULT NULL,
`content` text DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `domainmetadata_idx` (`domain_id`,`kind`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=latin1;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Dumping data for table `domainmetadata`
--
LOCK TABLES `domainmetadata` WRITE;
/*!40000 ALTER TABLE `domainmetadata` DISABLE KEYS */;
INSERT INTO `domainmetadata` VALUES
(1,1,'SOA-EDIT-API','DEFAULT');
/*!40000 ALTER TABLE `domainmetadata` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Table structure for table `domains`
--
DROP TABLE IF EXISTS `domains`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `domains` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL,
`master` varchar(128) DEFAULT NULL,
`last_check` int(11) DEFAULT NULL,
`type` varchar(8) NOT NULL,
`notified_serial` int(10) unsigned DEFAULT NULL,
`account` varchar(40) CHARACTER SET utf8mb3 DEFAULT NULL,
`options` varchar(64000) DEFAULT NULL,
`catalog` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `name_index` (`name`),
KEY `catalog_idx` (`catalog`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=latin1;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Dumping data for table `domains`
--
LOCK TABLES `domains` WRITE;
/*!40000 ALTER TABLE `domains` DISABLE KEYS */;
INSERT INTO `domains` VALUES
(1,'example.com','',NULL,'NATIVE',NULL,'',NULL,NULL);
/*!40000 ALTER TABLE `domains` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Table structure for table `records`
--
DROP TABLE IF EXISTS `records`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `records` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`domain_id` int(11) DEFAULT NULL,
`name` varchar(255) DEFAULT NULL,
`type` varchar(10) DEFAULT NULL,
`content` varchar(64000) DEFAULT NULL,
`ttl` int(11) DEFAULT NULL,
`prio` int(11) DEFAULT NULL,
`disabled` tinyint(1) DEFAULT 0,
`ordername` varchar(255) CHARACTER SET latin1 COLLATE latin1_bin DEFAULT NULL,
`auth` tinyint(1) DEFAULT 1,
PRIMARY KEY (`id`),
KEY `nametype_index` (`name`,`type`),
KEY `domain_id` (`domain_id`),
KEY `ordername` (`ordername`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=latin1;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Dumping data for table `records`
--
LOCK TABLES `records` WRITE;
/*!40000 ALTER TABLE `records` DISABLE KEYS */;
INSERT INTO `records` VALUES
(1,1,'example.com','NS','ns1.pdns',1500,0,0,NULL,1),
(2,1,'example.com','NS','ns2.pdns',1500,0,0,NULL,1),
(3,1,'example.com','SOA','a.misconfigured.dns.server.invalid hostmaster.example.com 2023030501 10800 3600 604800 3600',1500,0,0,NULL,1);
/*!40000 ALTER TABLE `records` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Table structure for table `supermasters`
--
DROP TABLE IF EXISTS `supermasters`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `supermasters` (
`ip` varchar(64) NOT NULL,
`nameserver` varchar(255) NOT NULL,
`account` varchar(40) CHARACTER SET utf8mb3 NOT NULL,
PRIMARY KEY (`ip`,`nameserver`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Dumping data for table `supermasters`
--
LOCK TABLES `supermasters` WRITE;
/*!40000 ALTER TABLE `supermasters` DISABLE KEYS */;
/*!40000 ALTER TABLE `supermasters` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Table structure for table `tsigkeys`
--
DROP TABLE IF EXISTS `tsigkeys`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `tsigkeys` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) DEFAULT NULL,
`algorithm` varchar(50) DEFAULT NULL,
`secret` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `namealgoindex` (`name`,`algorithm`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Dumping data for table `tsigkeys`
--
LOCK TABLES `tsigkeys` WRITE;
/*!40000 ALTER TABLE `tsigkeys` DISABLE KEYS */;
/*!40000 ALTER TABLE `tsigkeys` ENABLE KEYS */;
UNLOCK TABLES;
/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;

@ -0,0 +1,12 @@
{
"pebble": {
"listenAddress": "0.0.0.0:443",
"managementListenAddress": "0.0.0.0:15000",
"certificate": "test/certs/localhost/cert.pem",
"privateKey": "test/certs/localhost/key.pem",
"httpPort": 80,
"tlsPort": 443,
"ocspResponderURL": "",
"externalAccountBindingRequired": false
}
}

@ -0,0 +1,27 @@
# WARNING: This is a CI docker-compose file used for building and testing of the entire app, it should not be used for production.
services:
fullstack:
environment:
DB_MYSQL_HOST: 'db-mysql'
DB_MYSQL_PORT: '3306'
DB_MYSQL_USER: 'npm'
DB_MYSQL_PASSWORD: 'npmpass'
DB_MYSQL_NAME: 'npm'
depends_on:
- db-mysql
db-mysql:
image: jc21/mariadb-aria
environment:
MYSQL_ROOT_PASSWORD: 'npm'
MYSQL_DATABASE: 'npm'
MYSQL_USER: 'npm'
MYSQL_PASSWORD: 'npmpass'
volumes:
- mysql_vol:/var/lib/mysql
networks:
- fulltest
volumes:
mysql_vol:

@ -0,0 +1,9 @@
# WARNING: This is a CI docker-compose file used for building and testing of the entire app, it should not be used for production.
services:
fullstack:
environment:
DB_SQLITE_FILE: '/data/mydb.sqlite'
PUID: 1000
PGID: 1000
DISABLE_IPV6: 'true'

@ -1,82 +1,110 @@
# WARNING: This is a CI docker-compose file used for building and testing of the entire app, it should not be used for production.
version: '3.8'
# WARNING: This is a CI docker-compose file used for building
# and testing of the entire app, it should not be used for production.
# This is a base compose file, it should be extended with a
# docker-compose.ci.*.yml file
services:
fullstack-mysql:
image: "${IMAGE}:ci-${BUILD_NUMBER}"
fullstack:
image: "${IMAGE}:${BRANCH_LOWER}-ci-${BUILD_NUMBER}"
environment:
DEBUG: 'true'
LE_STAGING: 'true'
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
expose:
- 81
- 80
- 443
- 'npm_data_ci:/data'
- 'npm_le_ci:/etc/letsencrypt'
- './dev/letsencrypt.ini:/etc/letsencrypt.ini:ro'
- './dev/resolv.conf:/etc/resolv.conf:ro'
- '/etc/localtime:/etc/localtime:ro'
healthcheck:
test: ["CMD", "/usr/bin/check-health"]
interval: 10s
timeout: 3s
networks:
fulltest:
aliases:
- website1.example.com
- website2.example.com
- website3.example.com
stepca:
image: jc21/testca
volumes:
- './dev/resolv.conf:/etc/resolv.conf:ro'
- '/etc/localtime:/etc/localtime:ro'
networks:
fulltest:
aliases:
- ca.internal
pdns:
image: pschiffe/pdns-mysql
volumes:
- '/etc/localtime:/etc/localtime:ro'
environment:
PDNS_master: 'yes'
PDNS_api: 'yes'
PDNS_api_key: 'npm'
PDNS_webserver: 'yes'
PDNS_webserver_address: '0.0.0.0'
PDNS_webserver_password: 'npm'
PDNS_webserver-allow-from: '127.0.0.0/8,192.0.0.0/8,10.0.0.0/8,172.0.0.0/8'
PDNS_version_string: 'anonymous'
PDNS_default_ttl: 1500
PDNS_allow_axfr_ips: '127.0.0.0/8,192.0.0.0/8,10.0.0.0/8,172.0.0.0/8'
PDNS_gmysql_host: pdns-db
PDNS_gmysql_port: 3306
PDNS_gmysql_user: pdns
PDNS_gmysql_password: pdns
PDNS_gmysql_dbname: pdns
depends_on:
- db
healthcheck:
test: ["CMD", "/bin/check-health"]
interval: 10s
timeout: 3s
- pdns-db
networks:
fulltest:
aliases:
- ns1.pdns
- ns2.pdns
fullstack-sqlite:
image: "${IMAGE}:ci-${BUILD_NUMBER}"
pdns-db:
image: mariadb
environment:
DEBUG: 'true'
LE_STAGING: 'true'
FORCE_COLOR: 1
DB_SQLITE_FILE: '/data/mydb.sqlite'
MYSQL_ROOT_PASSWORD: 'pdns'
MYSQL_DATABASE: 'pdns'
MYSQL_USER: 'pdns'
MYSQL_PASSWORD: 'pdns'
volumes:
- npm_data:/data
expose:
- 81
- 80
- 443
healthcheck:
test: ["CMD", "/bin/check-health"]
interval: 10s
timeout: 3s
- 'pdns_mysql_vol:/var/lib/mysql'
- '/etc/localtime:/etc/localtime:ro'
- './dev/pdns-db.sql:/docker-entrypoint-initdb.d/01_init.sql:ro'
networks:
- fulltest
db:
image: jc21/mariadb-aria
environment:
MYSQL_ROOT_PASSWORD: 'npm'
MYSQL_DATABASE: 'npm'
MYSQL_USER: 'npm'
MYSQL_PASSWORD: 'npm'
dnsrouter:
image: jc21/dnsrouter
volumes:
- db_data:/var/lib/mysql
- ./dev/dnsrouter-config.json.tmp:/dnsrouter-config.json:ro
networks:
- fulltest
cypress-mysql:
cypress:
image: "${IMAGE}-cypress:ci-${BUILD_NUMBER}"
build:
context: ../test/
dockerfile: cypress/Dockerfile
context: ../
dockerfile: test/cypress/Dockerfile
environment:
CYPRESS_baseUrl: 'http://fullstack-mysql:81'
CYPRESS_baseUrl: 'http://fullstack:81'
volumes:
- cypress-logs:/results
command: cypress run --browser chrome --config-file=${CYPRESS_CONFIG:-cypress/config/ci.json}
cypress-sqlite:
image: "${IMAGE}-cypress:ci-${BUILD_NUMBER}"
build:
context: ../test/
dockerfile: cypress/Dockerfile
environment:
CYPRESS_baseUrl: "http://fullstack-sqlite:81"
volumes:
- cypress-logs:/results
command: cypress run --browser chrome --config-file=${CYPRESS_CONFIG:-cypress/config/ci.json}
- 'cypress_logs:/results'
- './dev/resolv.conf:/etc/resolv.conf:ro'
command: cypress run --browser chrome --config-file=cypress/config/ci.js
networks:
- fulltest
volumes:
cypress-logs:
npm_data:
db_data:
cypress_logs:
npm_data_ci:
npm_le_ci:
pdns_mysql_vol:
networks:
fulltest:
name: "npm-${BRANCH_LOWER}-ci-${BUILD_NUMBER}"

@ -1,5 +1,4 @@
# WARNING: This is a DEVELOPMENT docker-compose file, it should not be used for production.
version: '3.8'
services:
npm:

@ -1,29 +0,0 @@
#!/bin/bash
set -e
CYAN='\E[1;36m'
BLUE='\E[1;34m'
YELLOW='\E[1;33m'
RED='\E[1;31m'
RESET='\E[0m'
export CYAN BLUE YELLOW RED RESET
log_info () {
echo -e "${BLUE} ${CYAN}$1${RESET}"
}
log_error () {
echo -e "${RED} $1${RESET}"
}
# The `run` file will only execute 1 line so this helps keep things
# logically separated
log_fatal () {
echo -e "${RED}--------------------------------------${RESET}"
echo -e "${RED}ERROR: $1${RESET}"
echo -e "${RED}--------------------------------------${RESET}"
/run/s6/basedir/bin/halt
exit 1
}

@ -1,5 +1,6 @@
/data/logs/*_access.log /data/logs/*/access.log {
create 0644 root root
su npm npm
create 0644
weekly
rotate 4
missingok
@ -12,7 +13,8 @@
}
/data/logs/*_error.log /data/logs/*/error.log {
create 0644 root root
su npm npm
create 0644
weekly
rotate 10
missingok

@ -32,6 +32,7 @@ server {
server_name localhost;
access_log /data/logs/fallback_access.log standard;
error_log /dev/null crit;
include conf.d/include/ssl-ciphers.conf;
ssl_reject_handshake on;
return 444;

@ -1,3 +1,10 @@
set $test "";
if ($scheme = "http") {
set $test "H";
}
if ($request_uri = /.well-known/acme-challenge/test-challenge) {
set $test "${test}T";
}
if ($test = H) {
return 301 https://$host$request_uri;
}

@ -0,0 +1,4 @@
log_format proxy '[$time_local] $upstream_cache_status $upstream_status $status - $request_method $scheme $host "$request_uri" [Client $remote_addr] [Length $body_bytes_sent] [Gzip $gzip_ratio] [Sent-to $server] "$http_user_agent" "$http_referer"';
log_format standard '[$time_local] $status - $request_method $scheme $host "$request_uri" [Client $remote_addr] [Length $body_bytes_sent] [Gzip $gzip_ratio] "$http_user_agent" "$http_referer"';
access_log /data/logs/fallback_access.log proxy;

@ -1,6 +1,7 @@
# run nginx in foreground
daemon off;
pid /run/nginx/nginx.pid;
user npm;
# Set number of worker processes automatically based on number of CPU cores.
worker_processes auto;
@ -13,6 +14,9 @@ error_log /data/logs/fallback_error.log warn;
# Includes files with directives to load dynamic modules.
include /etc/nginx/modules/*.conf;
# Custom
include /data/nginx/custom/root_top[.]conf;
events {
include /data/nginx/custom/events[.]conf;
}
@ -42,10 +46,8 @@ http {
proxy_cache_path /var/lib/nginx/cache/public levels=1:2 keys_zone=public-cache:30m max_size=192m;
proxy_cache_path /var/lib/nginx/cache/private levels=1:2 keys_zone=private-cache:5m max_size=1024m;
log_format proxy '[$time_local] $upstream_cache_status $upstream_status $status - $request_method $scheme $host "$request_uri" [Client $remote_addr] [Length $body_bytes_sent] [Gzip $gzip_ratio] [Sent-to $server] "$http_user_agent" "$http_referer"';
log_format standard '[$time_local] $status - $request_method $scheme $host "$request_uri" [Client $remote_addr] [Length $body_bytes_sent] [Gzip $gzip_ratio] "$http_user_agent" "$http_referer"';
access_log /data/logs/fallback_access.log proxy;
# Log format and fallback log file
include /etc/nginx/conf.d/include/log.conf;
# Dynamically generated resolvers file
include /etc/nginx/conf.d/include/resolvers.conf;

@ -3,20 +3,19 @@
set -e
. /bin/common.sh
. /usr/bin/common.sh
cd /app || exit 1
log_info 'Starting backend ...'
if [ "$DEVELOPMENT" == "true" ]; then
cd /app || exit 1
# If yarn install fails: add --verbose --network-concurrency 1
s6-setuidgid npmuser yarn install
exec s6-setuidgid npmuser bash -c 'export HOME=/tmp/npmuserhome;node --max_old_space_size=250 --abort_on_uncaught_exception node_modules/nodemon/bin/nodemon.js'
if [ "${DEVELOPMENT:-}" = 'true' ]; then
s6-setuidgid "$PUID:$PGID" yarn install
exec s6-setuidgid "$PUID:$PGID" bash -c "export HOME=$NPMHOME;node --max_old_space_size=250 --abort_on_uncaught_exception node_modules/nodemon/bin/nodemon.js"
else
cd /app || exit 1
while :
do
s6-setuidgid npmuser bash -c 'export HOME=/tmp/npmuserhome;node --abort_on_uncaught_exception --max_old_space_size=250 index.js'
s6-setuidgid "$PUID:$PGID" bash -c "export HOME=$NPMHOME;node --abort_on_uncaught_exception --max_old_space_size=250 index.js"
sleep 1
done
fi

@ -5,17 +5,17 @@ set -e
# This service is DEVELOPMENT only.
if [ "$DEVELOPMENT" == "true" ]; then
. /bin/common.sh
if [ "$DEVELOPMENT" = 'true' ]; then
. /usr/bin/common.sh
cd /app/frontend || exit 1
log_info 'Starting frontend ...'
HOME=/tmp/npmuserhome
HOME=$NPMHOME
export HOME
mkdir -p /app/frontend/dist
chown -R npmuser:npmuser /app/frontend/dist
# If yarn install fails: add --verbose --network-concurrency 1
s6-setuidgid npmuser yarn install
exec s6-setuidgid npmuser yarn watch
chown -R "$PUID:$PGID" /app/frontend/dist
log_info 'Starting frontend ...'
s6-setuidgid "$PUID:$PGID" yarn install
exec s6-setuidgid "$PUID:$PGID" yarn watch
else
exit 0
fi

@ -3,8 +3,7 @@
set -e
. /bin/common.sh
. /usr/bin/common.sh
log_info 'Starting nginx ...'
exec s6-setuidgid npmuser nginx
exec s6-setuidgid "$PUID:$PGID" nginx

@ -3,13 +3,17 @@
set -e
. /bin/common.sh
. /usr/bin/common.sh
if [ "$(id -u)" != "0" ]; then
log_fatal "This docker container must be run as root, do not specify a user.\nYou can specify PUID and PGID env vars to run processes as that user and group after initialization."
fi
. /etc/s6-overlay/s6-rc.d/prepare/10-npmuser.sh
if [ "$DEBUG" = "true" ]; then
set -x
fi
. /etc/s6-overlay/s6-rc.d/prepare/10-usergroup.sh
. /etc/s6-overlay/s6-rc.d/prepare/20-paths.sh
. /etc/s6-overlay/s6-rc.d/prepare/30-ownership.sh
. /etc/s6-overlay/s6-rc.d/prepare/40-dynamic.sh

@ -1,25 +0,0 @@
#!/command/with-contenv bash
# shellcheck shell=bash
set -e
PUID=${PUID:-911}
PGID=${PGID:-911}
log_info 'Configuring npmuser ...'
groupmod -g 1000 users || exit 1
if id -u npmuser; then
# user already exists
usermod -u "${PUID}" npmuser || exit 1
else
# Add npmuser user
useradd -u "${PUID}" -U -d /tmp/npmuserhome -s /bin/false npmuser || exit 1
fi
usermod -G users npmuser || exit 1
groupmod -o -g "${PGID}" npmuser || exit 1
# Home for npmuser
mkdir -p /tmp/npmuserhome
chown -R npmuser:npmuser /tmp/npmuserhome

@ -0,0 +1,40 @@
#!/command/with-contenv bash
# shellcheck shell=bash
set -e
log_info "Configuring $NPMUSER user ..."
if id -u "$NPMUSER" 2>/dev/null; then
# user already exists
usermod -u "$PUID" "$NPMUSER"
else
# Add user
useradd -o -u "$PUID" -U -d "$NPMHOME" -s /bin/false "$NPMUSER"
fi
log_info "Configuring $NPMGROUP group ..."
if [ "$(get_group_id "$NPMGROUP")" = '' ]; then
# Add group. This will not set the id properly if it's already taken
groupadd -f -g "$PGID" "$NPMGROUP"
else
groupmod -o -g "$PGID" "$NPMGROUP"
fi
# Set the group ID and check it
groupmod -o -g "$PGID" "$NPMGROUP"
if [ "$(get_group_id "$NPMGROUP")" != "$PGID" ]; then
echo "ERROR: Unable to set group id properly"
exit 1
fi
# Set the group against the user and check it
usermod -G "$PGID" "$NPMGROUP"
if [ "$(id -g "$NPMUSER")" != "$PGID" ] ; then
echo "ERROR: Unable to set group against the user properly"
exit 1
fi
# Home for user
mkdir -p "$NPMHOME"
chown -R "$PUID:$PGID" "$NPMHOME"

@ -8,14 +8,21 @@ log_info 'Setting ownership ...'
# root
chown root /tmp/nginx
# npmuser
chown -R npmuser:npmuser \
/data \
/etc/letsencrypt \
/etc/nginx \
/run/nginx \
/tmp/nginx \
/var/cache/nginx \
/var/lib/logrotate \
/var/lib/nginx \
/var/log/nginx
# npm user and group
chown -R "$PUID:$PGID" /data
chown -R "$PUID:$PGID" /etc/letsencrypt
chown -R "$PUID:$PGID" /run/nginx
chown -R "$PUID:$PGID" /tmp/nginx
chown -R "$PUID:$PGID" /var/cache/nginx
chown -R "$PUID:$PGID" /var/lib/logrotate
chown -R "$PUID:$PGID" /var/lib/nginx
chown -R "$PUID:$PGID" /var/log/nginx
# Don't chown entire /etc/nginx folder as this causes crashes on some systems
chown -R "$PUID:$PGID" /etc/nginx/nginx
chown -R "$PUID:$PGID" /etc/nginx/nginx.conf
chown -R "$PUID:$PGID" /etc/nginx/conf.d
# Prevents errors when installing python certbot plugins when non-root
chown "$PUID:$PGID" /opt/certbot /opt/certbot/bin
find /opt/certbot/lib/python*/site-packages -not -user "$PUID" -execdir chown "$PUID:$PGID" {} \+

11
docker/rootfs/etc/s6-overlay/s6-rc.d/prepare/50-ipv6.sh Normal file → Executable file

@ -1,8 +1,11 @@
#!/bin/bash
#!/command/with-contenv bash
# shellcheck shell=bash
# This command reads the `DISABLE_IPV6` env var and will either enable
# or disable ipv6 in all nginx configs based on this setting.
set -e
log_info 'IPv6 ...'
# Lowercase
@ -25,11 +28,11 @@ process_folder () {
for FILE in $FILES
do
echo "- ${FILE}"
sed -E -i "$SED_REGEX" "$FILE"
echo "$(sed -E "$SED_REGEX" "$FILE")" > $FILE
done
# ensure the files are still owned by the npmuser
chown -R npmuser:npmuser "$1"
# ensure the files are still owned by the npm user
chown -R "$PUID:$PGID" "$1"
}
process_folder /etc/nginx/conf.d

@ -2,16 +2,17 @@
# shellcheck shell=bash
set -e
set +x
echo
echo "-------------------------------------
echo "
-------------------------------------
_ _ ____ __ __
| \ | | _ \| \/ |
| \| | |_) | |\/| |
| |\ | __/| | | |
|_| \_|_| |_| |_|
-------------------------------------
User UID: $(id -u npmuser)
User GID: $(id -g npmuser)
User: $NPMUSER PUID:$PUID ID:$(id -u "$NPMUSER") GROUP:$(id -g "$NPMUSER")
Group: $NPMGROUP PGID:$PGID ID:$(get_group_id "$NPMGROUP")
-------------------------------------
"

@ -0,0 +1,58 @@
#!/bin/bash
set -e
CYAN='\E[1;36m'
BLUE='\E[1;34m'
YELLOW='\E[1;33m'
RED='\E[1;31m'
RESET='\E[0m'
export CYAN BLUE YELLOW RED RESET
PUID=${PUID:-0}
PGID=${PGID:-0}
# If changing the username and group name below,
# ensure all references to this user is also changed.
# See docker/rootfs/etc/logrotate.d/nginx-proxy-manager
# and docker/rootfs/etc/nginx/nginx.conf
NPMUSER=npm
NPMGROUP=npm
NPMHOME=/tmp/npmuserhome
export NPMUSER NPMGROUP NPMHOME
if [[ "$PUID" -ne '0' ]] && [ "$PGID" = '0' ]; then
# set group id to same as user id,
# the user probably forgot to specify the group id and
# it would be rediculous to intentionally use the root group
# for a non-root user
PGID=$PUID
fi
export PUID PGID
log_info () {
echo -e "${BLUE} ${CYAN}$1${RESET}"
}
log_error () {
echo -e "${RED} $1${RESET}"
}
# The `run` file will only execute 1 line so this helps keep things
# logically separated
log_fatal () {
echo -e "${RED}--------------------------------------${RESET}"
echo -e "${RED}ERROR: $1${RESET}"
echo -e "${RED}--------------------------------------${RESET}"
/run/s6/basedir/bin/halt
exit 1
}
# param $1: group_name
get_group_id () {
if [ "${1:-}" != '' ]; then
getent group "$1" | cut -d: -f3
fi
}

@ -8,8 +8,8 @@ BLUE='\E[1;34m'
GREEN='\E[1;32m'
RESET='\E[0m'
S6_OVERLAY_VERSION=3.1.4.1
TARGETPLATFORM=${1:unspecified}
S6_OVERLAY_VERSION=3.1.5.0
TARGETPLATFORM=${1:-linux/amd64}
# Determine the correct binary file for the architecture given
case $TARGETPLATFORM in

13
docs/.gitignore vendored

@ -1,3 +1,14 @@
.vuepress/dist
dist
node_modules
ts
.temp
.cache
.vitepress/cache
.yarn/*
!.yarn/releases
!.yarn/plugins
!.yarn/sdks
!.yarn/versions
*.gz
*.tgz

@ -0,0 +1,61 @@
import { defineConfig, type DefaultTheme } from 'vitepress';
// https://vitepress.dev/reference/site-config
export default defineConfig({
title: "Nginx Proxy Manager",
description: "Expose your services easily and securely",
head: [
["link", { rel: "icon", href: "/icon.png" }],
["meta", { name: "description", content: "Docker container and built in Web Application for managing Nginx proxy hosts with a simple, powerful interface, providing free SSL support via Let's Encrypt" }],
["meta", { property: "og:title", content: "Nginx Proxy Manager" }],
["meta", { property: "og:description", content: "Docker container and built in Web Application for managing Nginx proxy hosts with a simple, powerful interface, providing free SSL support via Let's Encrypt"}],
["meta", { property: "og:type", content: "website" }],
["meta", { property: "og:url", content: "https://nginxproxymanager.com/" }],
["meta", { property: "og:image", content: "https://nginxproxymanager.com/icon.png" }],
["meta", { name: "twitter:card", content: "summary"}],
["meta", { name: "twitter:title", content: "Nginx Proxy Manager"}],
["meta", { name: "twitter:description", content: "Docker container and built in Web Application for managing Nginx proxy hosts with a simple, powerful interface, providing free SSL support via Let's Encrypt"}],
["meta", { name: "twitter:image", content: "https://nginxproxymanager.com/icon.png"}],
["meta", { name: "twitter:alt", content: "Nginx Proxy Manager"}],
// GA
['script', { async: 'true', src: 'https://www.googletagmanager.com/gtag/js?id=G-TXT8F5WY5B'}],
['script', {}, "window.dataLayer = window.dataLayer || [];\nfunction gtag(){dataLayer.push(arguments);}\ngtag('js', new Date());\ngtag('config', 'G-TXT8F5WY5B');"],
],
sitemap: {
hostname: 'https://nginxproxymanager.com'
},
metaChunk: true,
srcDir: './src',
outDir: './dist',
themeConfig: {
// https://vitepress.dev/reference/default-theme-config
logo: { src: '/logo.svg', width: 24, height: 24 },
nav: [
{ text: 'Setup', link: '/setup/' },
],
sidebar: [
{
items: [
// { text: 'Home', link: '/' },
{ text: 'Guide', link: '/guide/' },
{ text: 'Screenshots', link: '/screenshots/' },
{ text: 'Setup Instructions', link: '/setup/' },
{ text: 'Advanced Configuration', link: '/advanced-config/' },
{ text: 'Upgrading', link: '/upgrading/' },
{ text: 'Frequently Asked Questions', link: '/faq/' },
{ text: 'Third Party', link: '/third-party/' },
]
}
],
socialLinks: [
{ icon: 'github', link: 'https://github.com/NginxProxyManager/nginx-proxy-manager' }
],
search: {
provider: 'local'
},
footer: {
message: 'Released under the MIT License.',
copyright: 'Copyright © 2016-present jc21.com'
}
}
});

@ -0,0 +1,27 @@
:root {
--vp-home-hero-name-color: transparent;
--vp-home-hero-name-background: -webkit-linear-gradient(120deg, #f15833 30%, #FAA42F);
--vp-home-hero-image-background-image: linear-gradient(-45deg, #aaaaaa 50%, #777777 50%);
--vp-home-hero-image-filter: blur(44px);
--vp-c-brand-1: #f15833;
--vp-c-brand-2: #FAA42F;
--vp-c-brand-3: #f15833;
}
@media (min-width: 640px) {
:root {
--vp-home-hero-image-filter: blur(56px);
}
}
@media (min-width: 960px) {
:root {
--vp-home-hero-image-filter: blur(68px);
}
}
.inline-img img {
display: inline;
}

@ -0,0 +1,4 @@
import DefaultTheme from 'vitepress/theme'
import './custom.css'
export default DefaultTheme

@ -1,82 +0,0 @@
module.exports = {
locales: {
"/": {
lang: "en-US",
title: "Nginx Proxy Manager",
description: "Expose your services easily and securely"
}
},
head: [
["link", { rel: "icon", href: "/icon.png" }],
["meta", { name: "description", content: "Docker container and built in Web Application for managing Nginx proxy hosts with a simple, powerful interface, providing free SSL support via Let's Encrypt" }],
["meta", { property: "og:title", content: "Nginx Proxy Manager" }],
["meta", { property: "og:description", content: "Docker container and built in Web Application for managing Nginx proxy hosts with a simple, powerful interface, providing free SSL support via Let's Encrypt"}],
["meta", { property: "og:type", content: "website" }],
["meta", { property: "og:url", content: "https://nginxproxymanager.com/" }],
["meta", { property: "og:image", content: "https://nginxproxymanager.com/icon.png" }],
["meta", { name: "twitter:card", content: "summary"}],
["meta", { name: "twitter:title", content: "Nginx Proxy Manager"}],
["meta", { name: "twitter:description", content: "Docker container and built in Web Application for managing Nginx proxy hosts with a simple, powerful interface, providing free SSL support via Let's Encrypt"}],
["meta", { name: "twitter:image", content: "https://nginxproxymanager.com/icon.png"}],
["meta", { name: "twitter:alt", content: "Nginx Proxy Manager"}],
],
themeConfig: {
logo: "/icon.png",
// the GitHub repo path
repo: "jc21/nginx-proxy-manager",
// the label linking to the repo
repoLabel: "GitHub",
// if your docs are not at the root of the repo:
docsDir: "docs",
// defaults to false, set to true to enable
editLinks: true,
locales: {
"/": {
// text for the language dropdown
selectText: "Languages",
// label for this locale in the language dropdown
label: "English",
// Custom text for edit link. Defaults to "Edit this page"
editLinkText: "Edit this page on GitHub",
// Custom navbar values
nav: [{ text: "Setup", link: "/setup/" }],
// Custom sidebar values
sidebar: [
"/",
["/guide/", "Guide"],
["/screenshots/", "Screenshots"],
["/setup/", "Setup Instructions"],
["/advanced-config/", "Advanced Configuration"],
["/upgrading/", "Upgrading"],
["/faq/", "Frequently Asked Questions"],
["/third-party/", "Third Party"]
]
}
}
},
plugins: [
[
"@vuepress/google-analytics",
{
ga: "UA-99675467-4"
}
],
[
"sitemap",
{
hostname: "https://nginxproxymanager.com"
}
],
[
'vuepress-plugin-zooming',
{
selector: '.zooming',
delay: 1000,
options: {
bgColor: 'black',
zIndex: 10000,
},
},
],
]
};

Binary file not shown.

Before

(image error) Size: 57 KiB

Binary file not shown.

@ -1,23 +0,0 @@
.home .hero img
max-width: 500px !important
min-width: 300px
width: 100%
.center
margin 0 auto;
width: 80%
#main-title
display: none
.hero
margin: 150px 25px 70px
@font-face
font-family: 'Nerd Font';
src: url("/nerd-font.woff2") format("woff2");
font-weight: 400;
font-style: normal
code
font-family: 'Nerd Font', source-code-pro, Menlo, Monaco, Consolas, "Courier New", monospace;

@ -1,4 +0,0 @@
$accentColor = #f15833
$textColor = #663015
$borderColor = #eaecef
$codeBgColor = #282c34

@ -1,39 +0,0 @@
---
home: true
heroImage: /logo.png
actionText: Get Started →
actionLink: /guide/
footer: MIT Licensed | Copyright © 2016-present jc21.com
---
<div class="features">
<div class="feature">
<h2>Get Connected</h2>
<p>
Expose web services on your network &middot;
Free SSL with Let's Encrypt &middot;
Designed with security in mind &middot;
Perfect for home networks
</p>
</div>
<div class="feature">
<h2>Proxy Hosts</h2>
<p>Expose your private network Web services and get connected anywhere.</p>
</div>
<div class="feature">
<h2>Beautiful UI</h2>
<p>Based on Tabler, the interface is a pleasure to use. Configuring a server has never been so fun.</p>
</div>
<div class="feature">
<h2>Free SSL</h2>
<p>Built in Lets Encrypt support allows you to secure your Web services at no cost to you. The certificates even renew themselves!</p>
</div>
<div class="feature">
<h2>Docker FTW</h2>
<p>Built as a Docker Image, Nginx Proxy Manager only requires a database.</p>
</div>
<div class="feature">
<h2>Multiple Users</h2>
<p>Configure other users to either view or manage their own hosts. Full access permissions are available.</p>
</div>
</div>

@ -1 +0,0 @@
../../README.md

@ -1,777 +1,11 @@
{
"name": "docs",
"version": "1.0.0",
"description": "",
"main": "index.js",
"dependencies": {
"@vuepress/plugin-google-analytics": "^1.5.3",
"abbrev": "^1.1.1",
"accepts": "^1.3.7",
"acorn": "^7.4.0",
"agentkeepalive": "^4.1.3",
"ajv": "^6.12.3",
"ajv-errors": "^1.0.1",
"ajv-keywords": "^3.5.2",
"algoliasearch": "^4.3.1",
"alphanum-sort": "^1.0.2",
"ansi-colors": "^4.1.1",
"ansi-escapes": "^4.3.1",
"ansi-html": "^0.0.8",
"ansi-regex": "^5.0.0",
"ansi-styles": "^4.2.1",
"anymatch": "^3.1.1",
"aproba": "^2.0.0",
"argparse": "^1.0.10",
"arr-diff": "^4.0.0",
"arr-flatten": "^1.1.0",
"arr-union": "^3.1.0",
"array-flatten": "^3.0.0",
"array-union": "^2.1.0",
"array-uniq": "^2.1.0",
"array-unique": "^0.3.2",
"asn1": "^0.2.4",
"asn1.js": "^5.4.1",
"assert": "^2.0.0",
"assert-plus": "^1.0.0",
"assign-symbols": "^2.0.2",
"async": "^3.2.0",
"async-each": "^1.0.3",
"async-limiter": "^2.0.0",
"asynckit": "^0.4.0",
"atob": "^2.1.2",
"autocomplete.js": "^0.37.1",
"autoprefixer": "^9.8.6",
"aws-sign2": "^0.7.0",
"aws4": "^1.10.0",
"babel-loader": "^8.1.0",
"babel-plugin-dynamic-import-node": "^2.3.3",
"babel-plugin-module-resolver": "^4.0.0",
"balanced-match": "^1.0.0",
"base": "^3.0.0",
"base64-js": "^1.3.1",
"batch": "^0.6.1",
"bcrypt-pbkdf": "^1.0.2",
"big.js": "^5.2.2",
"binary-extensions": "^2.1.0",
"bluebird": "^3.7.2",
"bn.js": "^5.1.2",
"body-parser": "^1.19.0",
"bonjour": "^3.5.0",
"boolbase": "^1.0.0",
"brace-expansion": "^1.1.11",
"braces": "^3.0.2",
"brorand": "^1.1.0",
"browserify-aes": "^1.2.0",
"browserify-cipher": "^1.0.1",
"browserify-des": "^1.0.2",
"browserify-rsa": "^4.0.1",
"browserify-sign": "^4.2.1",
"browserify-zlib": "^0.2.0",
"browserslist": "^4.13.0",
"buffer": "^5.6.0",
"buffer-from": "^1.1.1",
"buffer-indexof": "^1.1.1",
"buffer-json": "^2.0.0",
"buffer-xor": "^2.0.2",
"builtin-status-codes": "^3.0.0",
"bytes": "^3.1.0",
"cac": "^6.6.1",
"cacache": "^15.0.5",
"cache-base": "^4.0.0",
"cache-loader": "^4.1.0",
"call-me-maybe": "^1.0.1",
"caller-callsite": "^4.1.0",
"caller-path": "^3.0.0",
"callsites": "^3.1.0",
"camel-case": "^4.1.1",
"camelcase": "^6.0.0",
"caniuse-api": "^3.0.0",
"caniuse-lite": "^1.0.30001111",
"caseless": "^0.12.0",
"chalk": "^4.1.0",
"chokidar": "^3.4.1",
"chownr": "^2.0.0",
"chrome-trace-event": "^1.0.2",
"ci-info": "^2.0.0",
"cipher-base": "^1.0.4",
"class-utils": "^0.3.6",
"clean-css": "^4.2.3",
"clipboard": "^2.0.6",
"cliui": "^6.0.0",
"coa": "^2.0.2",
"code-point-at": "^1.1.0",
"collection-visit": "^1.0.0",
"color": "^3.1.2",
"color-convert": "^2.0.1",
"color-name": "^1.1.4",
"color-string": "^1.5.3",
"combined-stream": "^1.0.8",
"commander": "^6.0.0",
"commondir": "^1.0.1",
"component-emitter": "^1.3.0",
"compressible": "^2.0.18",
"compression": "^1.7.4",
"concat-map": "^0.0.1",
"concat-stream": "^2.0.0",
"connect-history-api-fallback": "^1.6.0",
"consola": "^2.15.0",
"console-browserify": "^1.2.0",
"consolidate": "^0.15.1",
"constants-browserify": "^1.0.0",
"content-disposition": "^0.5.3",
"content-type": "^1.0.4",
"convert-source-map": "^1.7.0",
"cookie": "^0.4.1",
"cookie-signature": "^1.1.0",
"copy-concurrently": "^1.0.5",
"copy-descriptor": "^0.1.1",
"copy-webpack-plugin": "^6.0.3",
"core-js": "^3.6.5",
"core-util-is": "^1.0.2",
"cosmiconfig": "^7.0.0",
"create-ecdh": "^4.0.4",
"create-hash": "^1.2.0",
"create-hmac": "^1.1.7",
"cross-spawn": "^7.0.3",
"crypto-browserify": "^3.12.0",
"css": "^3.0.0",
"css-color-names": "^1.0.1",
"css-declaration-sorter": "^5.1.2",
"css-loader": "^4.2.0",
"css-parse": "^2.0.0",
"css-select": "^2.1.0",
"css-select-base-adapter": "^0.1.1",
"css-tree": "^1.0.0-alpha.39",
"css-unit-converter": "^1.1.2",
"css-what": "^5.0.1",
"cssesc": "^3.0.0",
"cssnano": "^4.1.10",
"cssnano-preset-default": "^4.0.7",
"cssnano-util-get-arguments": "^4.0.0",
"cssnano-util-get-match": "^4.0.0",
"cssnano-util-raw-cache": "^4.0.1",
"cssnano-util-same-parent": "^4.0.1",
"csso": "^4.0.3",
"cyclist": "^1.0.1",
"dashdash": "^1.14.1",
"de-indent": "^1.0.2",
"debug": "^4.1.1",
"decamelize": "^4.0.0",
"decode-uri-component": "^0.2.0",
"deep-equal": "^2.0.3",
"deepmerge": "^4.2.2",
"default-gateway": "^6.0.1",
"define-properties": "^1.1.3",
"define-property": "^2.0.2",
"del": "^5.1.0",
"delayed-stream": "^1.0.0",
"delegate": "^3.2.0",
"depd": "^2.0.0",
"des.js": "^1.0.1",
"destroy": "^1.0.4",
"detect-node": "^2.0.4",
"diacritics": "^1.3.0",
"diffie-hellman": "^5.0.3",
"dir-glob": "^3.0.1",
"dns-equal": "^1.0.0",
"dns-packet": "^5.2.1",
"dns-txt": "^2.0.2",
"docsearch.js": "^2.6.3",
"dom-converter": "^0.2.0",
"dom-serializer": "^1.0.1",
"dom-walk": "^0.1.2",
"domain-browser": "^4.16.0",
"domelementtype": "^2.0.1",
"domhandler": "^3.0.0",
"domutils": "^2.1.0",
"dot-prop": "^5.2.0",
"duplexify": "^4.1.1",
"ecc-jsbn": "^0.2.0",
"ee-first": "^1.1.1",
"electron-to-chromium": "^1.3.522",
"elliptic": "^6.5.3",
"emoji-regex": "^9.0.0",
"emojis-list": "^3.0.0",
"encodeurl": "^1.0.2",
"end-of-stream": "^1.4.4",
"enhanced-resolve": "^4.3.0",
"entities": "^2.0.3",
"envify": "^4.1.0",
"envinfo": "^7.7.2",
"errno": "^0.1.7",
"error-ex": "^1.3.2",
"es-abstract": "^1.17.6",
"es-to-primitive": "^1.2.1",
"es6-promise": "^4.2.8",
"escape-html": "^1.0.3",
"escape-string-regexp": "^4.0.0",
"eslint-scope": "^5.1.0",
"esprima": "^4.0.1",
"esrecurse": "^4.2.1",
"estraverse": "^5.2.0",
"esutils": "^2.0.3",
"etag": "^1.8.1",
"eventemitter3": "^4.0.4",
"events": "^3.2.0",
"eventsource": "^2.0.2",
"evp_bytestokey": "^1.0.3",
"execa": "^4.0.3",
"expand-brackets": "^4.0.0",
"express": "^4.17.1",
"extend": "^3.0.2",
"extend-shallow": "^3.0.2",
"extglob": "^3.0.0",
"extsprintf": "^1.4.0",
"fast-deep-equal": "^3.1.3",
"fast-glob": "^3.2.4",
"fast-json-stable-stringify": "^2.1.0",
"faye-websocket": "^0.11.3",
"figgy-pudding": "^3.5.2",
"figures": "^3.2.0",
"file-loader": "^6.0.0",
"fill-range": "^7.0.1",
"finalhandler": "^1.1.2",
"find-babel-config": "^1.2.0",
"find-cache-dir": "^3.3.1",
"find-up": "^4.1.0",
"flush-write-stream": "^2.0.0",
"follow-redirects": "^1.12.1",
"for-in": "^1.0.2",
"foreach": "^2.0.5",
"forever-agent": "^0.6.1",
"form-data": "^3.0.0",
"forwarded": "^0.1.2",
"fragment-cache": "^0.2.1",
"fresh": "^0.5.2",
"from2": "^2.3.0",
"fs-extra": "^9.0.1",
"fs-write-stream-atomic": "^1.0.10",
"fs.realpath": "^1.0.0",
"function-bind": "^1.1.1",
"gensync": "^1.0.0-beta.1",
"get-caller-file": "^2.0.5",
"get-stream": "^5.1.0",
"get-value": "^3.0.1",
"getpass": "^0.1.7",
"glob": "^7.1.6",
"glob-parent": "^5.1.1",
"glob-to-regexp": "^0.4.1",
"global": "^4.4.0",
"globals": "^13.1.0",
"globby": "^11.0.1",
"good-listener": "^1.2.2",
"graceful-fs": "^4.2.4",
"gray-matter": "^4.0.2",
"handle-thing": "^2.0.1",
"har-schema": "^2.0.0",
"har-validator": "^5.1.5",
"has": "^1.0.3",
"has-ansi": "^4.0.0",
"has-flag": "^4.0.0",
"has-symbols": "^1.0.1",
"has-value": "^2.0.2",
"has-values": "^2.0.1",
"hash-base": "^3.1.0",
"hash-sum": "^2.0.0",
"hash.js": "^1.1.7",
"he": "^1.2.0",
"hex-color-regex": "^1.1.0",
"hmac-drbg": "^1.0.1",
"hogan.js": "^3.0.2",
"hpack.js": "^2.1.6",
"hsl-regex": "^1.0.0",
"hsla-regex": "^1.0.0",
"html-comment-regex": "^1.1.2",
"html-entities": "^1.3.1",
"html-minifier": "^4.0.0",
"html-tags": "^3.1.0",
"htmlparser2": "^4.1.0",
"http-deceiver": "^1.2.7",
"http-errors": "^1.8.0",
"http-parser-js": "^0.5.2",
"http-proxy": "^1.18.1",
"http-proxy-middleware": "^1.0.5",
"http-signature": "^1.3.4",
"https-browserify": "^1.0.0",
"iconv-lite": "^0.6.2",
"icss-replace-symbols": "^1.1.0",
"icss-utils": "^4.1.1",
"ieee754": "^1.1.13",
"iferr": "^1.0.2",
"ignore": "^5.1.8",
"immediate": "^3.3.0",
"import-cwd": "^3.0.0",
"import-fresh": "^3.2.1",
"import-from": "^3.0.0",
"import-local": "^3.0.2",
"imurmurhash": "^0.1.4",
"indexes-of": "^1.0.1",
"infer-owner": "^1.0.4",
"inflight": "^1.0.6",
"inherits": "^2.0.4",
"internal-ip": "^6.1.0",
"invariant": "^2.2.4",
"invert-kv": "^3.0.1",
"ip": "^1.1.5",
"ip-regex": "^4.1.0",
"ipaddr.js": "^1.9.1",
"is-absolute-url": "^3.0.3",
"is-accessor-descriptor": "^3.0.1",
"is-arguments": "^1.0.4",
"is-arrayish": "^0.3.2",
"is-binary-path": "^2.1.0",
"is-buffer": "^2.0.4",
"is-callable": "^1.2.0",
"is-color-stop": "^1.1.0",
"is-data-descriptor": "^2.0.0",
"is-date-object": "^1.0.2",
"is-descriptor": "^3.0.0",
"is-directory": "^0.3.1",
"is-extendable": "^1.0.1",
"is-extglob": "^2.1.1",
"is-fullwidth-code-point": "^3.0.0",
"is-glob": "^4.0.1",
"is-number": "^7.0.0",
"is-obj": "^2.0.0",
"is-path-cwd": "^2.2.0",
"is-path-in-cwd": "^3.0.0",
"is-path-inside": "^3.0.2",
"is-plain-obj": "^2.1.0",
"is-plain-object": "^4.1.1",
"is-regex": "^1.1.1",
"is-resolvable": "^1.1.0",
"is-stream": "^2.0.0",
"is-svg": "^4.2.1",
"is-symbol": "^1.0.3",
"is-typedarray": "^1.0.0",
"is-windows": "^1.0.2",
"is-wsl": "^2.2.0",
"isarray": "^2.0.5",
"isexe": "^2.0.0",
"isobject": "^4.0.0",
"isstream": "^0.1.2",
"javascript-stringify": "^2.0.1",
"js-levenshtein": "^1.1.6",
"js-tokens": "^6.0.0",
"js-yaml": "^3.14.0",
"jsbn": "^1.1.0",
"jsesc": "^3.0.1",
"json-parse-better-errors": "^1.0.2",
"json-schema": "^0.4.0",
"json-schema-traverse": "^0.4.1",
"json-stringify-safe": "^5.0.1",
"json3": "^3.3.3",
"json5": "^2.1.3",
"jsonfile": "^6.0.1",
"jsprim": "^2.0.0",
"killable": "^1.0.1",
"kind-of": "^6.0.3",
"last-call-webpack-plugin": "^3.0.0",
"lcid": "^3.1.1",
"linkify-it": "^3.0.2",
"load-script": "^1.0.0",
"loader-runner": "^4.0.0",
"loader-utils": "^2.0.0",
"locate-path": "^5.0.0",
"lodash": "^4.17.19",
"lodash._reinterpolate": "^3.0.0",
"lodash.chunk": "^4.2.0",
"lodash.clonedeep": "^4.5.0",
"lodash.debounce": "^4.0.8",
"lodash.kebabcase": "^4.1.1",
"lodash.memoize": "^4.1.2",
"lodash.padstart": "^4.6.1",
"lodash.sortby": "^4.7.0",
"lodash.template": "^4.5.0",
"lodash.templatesettings": "^4.2.0",
"lodash.uniq": "^4.5.0",
"loglevel": "^1.6.8",
"loose-envify": "^1.4.0",
"lower-case": "^2.0.1",
"lru-cache": "^6.0.0",
"make-dir": "^3.1.0",
"mamacro": "^0.0.7",
"map-age-cleaner": "^0.1.3",
"map-cache": "^0.2.2",
"map-visit": "^1.0.0",
"markdown-it": "^12.3.2",
"markdown-it-anchor": "^5.3.0",
"markdown-it-chain": "^1.3.0",
"markdown-it-container": "^3.0.0",
"markdown-it-emoji": "^1.4.0",
"markdown-it-table-of-contents": "^0.4.4",
"md5.js": "^1.3.5",
"mdn-data": "^2.0.11",
"mdurl": "^1.0.1",
"media-typer": "^1.1.0",
"mem": "^6.1.0",
"memory-fs": "^0.5.0",
"merge-descriptors": "^1.0.1",
"merge-source-map": "^1.1.0",
"merge2": "^1.4.1",
"methods": "^1.1.2",
"micromatch": "^4.0.2",
"miller-rabin": "^4.0.1",
"mime": "^2.4.6",
"mime-db": "^1.44.0",
"mime-types": "^2.1.27",
"mimic-fn": "^3.1.0",
"min-document": "^2.19.0",
"mini-css-extract-plugin": "^0.9.0",
"minimalistic-assert": "^1.0.1",
"minimalistic-crypto-utils": "^1.0.1",
"minimatch": "^3.0.4",
"minimist": "^1.2.5",
"mississippi": "^4.0.0",
"mixin-deep": "^2.0.1",
"mkdirp": "^1.0.4",
"move-concurrently": "^1.0.1",
"ms": "^2.1.2",
"multicast-dns": "^7.2.2",
"multicast-dns-service-types": "^1.1.0",
"nanomatch": "^1.2.13",
"negotiator": "^0.6.2",
"neo-async": "^2.6.2",
"nice-try": "^2.0.1",
"no-case": "^3.0.3",
"node-forge": "^1.0.0",
"node-libs-browser": "^2.2.1",
"node-releases": "^1.1.60",
"nopt": "^4.0.3",
"normalize-path": "^3.0.0",
"normalize-range": "^0.1.2",
"normalize-url": "^5.1.0",
"npm-run-path": "^4.0.1",
"nprogress": "^0.2.0",
"nth-check": "^2.0.1",
"num2fraction": "^1.2.2",
"number-is-nan": "^2.0.0",
"oauth-sign": "^0.9.0",
"object-assign": "^4.1.1",
"object-copy": "^1.0.0",
"object-inspect": "^1.8.0",
"object-is": "^1.1.2",
"object-keys": "^1.1.1",
"object-visit": "^1.0.1",
"object.assign": "^4.1.0",
"object.getownpropertydescriptors": "^2.1.0",
"object.pick": "^1.3.0",
"object.values": "^1.1.1",
"obuf": "^1.1.2",
"on-finished": "^2.3.0",
"on-headers": "^1.0.2",
"once": "^1.4.0",
"opencollective-postinstall": "^2.0.3",
"opn": "^6.0.0",
"optimize-css-assets-webpack-plugin": "^5.0.3",
"original": "^1.0.2",
"os-browserify": "^0.3.0",
"os-locale": "^5.0.0",
"p-defer": "^3.0.0",
"p-finally": "^2.0.1",
"p-is-promise": "^3.0.0",
"p-limit": "^3.0.2",
"p-locate": "^4.1.0",
"p-map": "^4.0.0",
"p-retry": "^4.2.0",
"p-try": "^2.2.0",
"pako": "^1.0.11",
"parallel-transform": "^1.2.0",
"param-case": "^3.0.3",
"parse-asn1": "^5.1.5",
"parse-json": "^5.0.1",
"parseurl": "^1.3.3",
"pascalcase": "^1.0.0",
"path-browserify": "^1.0.1",
"path-dirname": "^1.0.2",
"path-exists": "^4.0.0",
"path-is-absolute": "^2.0.0",
"path-is-inside": "^1.0.2",
"path-key": "^3.1.1",
"path-parse": "^1.0.6",
"path-to-regexp": "^6.1.0",
"path-type": "^4.0.0",
"pbkdf2": "^3.1.1",
"performance-now": "^2.1.0",
"pify": "^5.0.0",
"pinkie": "^2.0.4",
"pinkie-promise": "^2.0.1",
"pkg-dir": "^4.2.0",
"pkg-up": "^3.1.0",
"portfinder": "^1.0.28",
"posix-character-classes": "^1.0.0",
"postcss": "^8.2.10",
"postcss-calc": "^7.0.2",
"postcss-colormin": "^4.0.3",
"postcss-convert-values": "^4.0.1",
"postcss-discard-comments": "^4.0.2",
"postcss-discard-duplicates": "^4.0.2",
"postcss-discard-empty": "^4.0.1",
"postcss-discard-overridden": "^4.0.1",
"postcss-load-config": "^2.1.0",
"postcss-loader": "^3.0.0",
"postcss-merge-longhand": "^4.0.11",
"postcss-merge-rules": "^4.0.3",
"postcss-minify-font-values": "^4.0.2",
"postcss-minify-gradients": "^4.0.2",
"postcss-minify-params": "^4.0.2",
"postcss-minify-selectors": "^4.0.2",
"postcss-modules-extract-imports": "^2.0.0",
"postcss-modules-local-by-default": "^3.0.3",
"postcss-modules-scope": "^2.2.0",
"postcss-modules-values": "^3.0.0",
"postcss-normalize-charset": "^4.0.1",
"postcss-normalize-display-values": "^4.0.2",
"postcss-normalize-positions": "^4.0.2",
"postcss-normalize-repeat-style": "^4.0.2",
"postcss-normalize-string": "^4.0.2",
"postcss-normalize-timing-functions": "^4.0.2",
"postcss-normalize-unicode": "^4.0.1",
"postcss-normalize-url": "^4.0.1",
"postcss-normalize-whitespace": "^4.0.2",
"postcss-ordered-values": "^4.1.2",
"postcss-reduce-initial": "^4.0.3",
"postcss-reduce-transforms": "^4.0.2",
"postcss-safe-parser": "^4.0.2",
"postcss-selector-parser": "^6.0.2",
"postcss-svgo": "^4.0.2",
"postcss-unique-selectors": "^4.0.1",
"postcss-value-parser": "^4.1.0",
"prepend-http": "^3.0.1",
"prettier": "^2.0.5",
"pretty-error": "^2.1.1",
"pretty-time": "^1.1.0",
"prismjs": "^1.20.0",
"private": "^0.1.8",
"process": "^0.11.10",
"process-nextick-args": "^2.0.1",
"promise-inflight": "^1.0.1",
"proxy-addr": "^2.0.6",
"prr": "^1.0.1",
"pseudomap": "^1.0.2",
"psl": "^1.8.0",
"public-encrypt": "^4.0.3",
"pump": "^3.0.0",
"pumpify": "^2.0.1",
"punycode": "^2.1.1",
"q": "^1.5.1",
"qs": "^6.9.4",
"query-string": "^6.13.1",
"querystring": "^0.2.0",
"querystring-es3": "^0.2.1",
"querystringify": "^2.1.1",
"randombytes": "^2.1.0",
"randomfill": "^1.0.4",
"range-parser": "^1.2.1",
"raw-body": "^2.4.1",
"readable-stream": "^3.6.0",
"readdirp": "^3.4.0",
"reduce": "^1.0.2",
"regenerate": "^1.4.1",
"regenerate-unicode-properties": "^8.2.0",
"regenerator-runtime": "^0.13.7",
"regenerator-transform": "^0.14.5",
"regex-not": "^1.0.2",
"regexp.prototype.flags": "^1.3.0",
"regexpu-core": "^4.7.0",
"regjsgen": "^0.5.2",
"regjsparser": "^0.6.4",
"relateurl": "^0.2.7",
"remove-trailing-separator": "^1.1.0",
"renderkid": "^2.0.3",
"repeat-element": "^1.1.3",
"repeat-string": "^1.6.1",
"request": "^2.88.2",
"require-directory": "^2.1.1",
"require-main-filename": "^2.0.0",
"requires-port": "^1.0.0",
"reselect": "^4.0.0",
"resolve": "^1.17.0",
"resolve-cwd": "^3.0.0",
"resolve-from": "^5.0.0",
"resolve-url": "^0.2.1",
"ret": "^0.3.1",
"retry": "^0.12.0",
"rgb-regex": "^1.0.1",
"rgba-regex": "^1.0.0",
"rimraf": "^3.0.2",
"ripemd160": "^2.0.2",
"run-queue": "^2.0.1",
"safe-buffer": "^5.2.1",
"safe-regex": "^2.1.1",
"safer-buffer": "^2.1.2",
"sax": "^1.2.4",
"schema-utils": "^2.7.0",
"section-matter": "^1.0.0",
"select": "^1.1.2",
"select-hose": "^2.0.0",
"selfsigned": "^1.10.7",
"semver": "^7.3.2",
"send": "^0.17.1",
"serialize-javascript": "^4.0.0",
"serve-index": "^1.9.1",
"serve-static": "^1.14.1",
"set-blocking": "^2.0.0",
"set-value": "^4.0.1",
"setimmediate": "^1.0.5",
"setprototypeof": "^1.2.0",
"sha.js": "^2.4.11",
"shebang-command": "^2.0.0",
"shebang-regex": "^3.0.0",
"signal-exit": "^3.0.3",
"simple-swizzle": "^0.2.2",
"sitemap": "^6.2.0",
"slash": "^3.0.0",
"smoothscroll-polyfill": "^0.4.4",
"snapdragon": "^0.12.0",
"snapdragon-node": "^3.0.0",
"snapdragon-util": "^5.0.1",
"sockjs": "^0.3.21",
"sockjs-client": "^1.5.0",
"sort-keys": "^4.0.0",
"source-list-map": "^2.0.1",
"source-map": "^0.7.3",
"source-map-resolve": "^0.6.0",
"source-map-support": "^0.5.19",
"source-map-url": "^0.4.0",
"spdy": "^4.0.2",
"spdy-transport": "^3.0.0",
"split-string": "^6.1.0",
"sprintf-js": "^1.1.2",
"sshpk": "^1.16.1",
"ssri": "^8.0.0",
"stable": "^0.1.8",
"stack-utils": "^2.0.2",
"static-extend": "^0.1.2",
"statuses": "^2.0.0",
"std-env": "^2.2.1",
"stream-browserify": "^3.0.0",
"stream-each": "^1.2.3",
"stream-http": "^3.1.1",
"stream-shift": "^1.0.1",
"strict-uri-encode": "^2.0.0",
"string-width": "^4.2.0",
"string.prototype.trimleft": "^2.1.2",
"string.prototype.trimright": "^2.1.2",
"string_decoder": "^1.3.0",
"strip-ansi": "^6.0.0",
"strip-bom-string": "^1.0.0",
"strip-eof": "^2.0.0",
"stylehacks": "^4.0.3",
"stylus": "^0.54.8",
"stylus-loader": "^3.0.2",
"supports-color": "^7.1.0",
"svg-tags": "^1.0.0",
"svgo": "^1.3.2",
"tapable": "^1.1.3",
"terser": "^5.0.0",
"terser-webpack-plugin": "^4.0.0",
"text-table": "^0.2.0",
"through": "^2.3.8",
"through2": "^4.0.2",
"thunky": "^1.1.0",
"timers-browserify": "^2.0.11",
"timsort": "^0.3.0",
"tiny-emitter": "^2.1.0",
"to-arraybuffer": "^1.0.1",
"to-factory": "^1.0.0",
"to-fast-properties": "^3.0.1",
"to-object-path": "^0.3.0",
"to-regex": "^3.0.2",
"to-regex-range": "^5.0.1",
"toidentifier": "^1.0.0",
"toml": "^3.0.0",
"toposort": "^2.0.2",
"tough-cookie": "^4.0.0",
"tr46": "^2.0.2",
"tslib": "^2.0.0",
"tty-browserify": "^0.0.1",
"tunnel-agent": "^0.6.0",
"tweetnacl": "^1.0.3",
"type-fest": "^0.16.0",
"type-is": "^1.6.18",
"typedarray": "^0.0.6",
"uc.micro": "^1.0.6",
"uglify-js": "^3.10.1",
"unicode-canonical-property-names-ecmascript": "^1.0.4",
"unicode-match-property-ecmascript": "^1.0.4",
"unicode-match-property-value-ecmascript": "^1.2.0",
"unicode-property-aliases-ecmascript": "^1.1.0",
"union-value": "^2.0.1",
"uniq": "^1.0.1",
"uniqs": "^2.0.0",
"unique-filename": "^1.1.1",
"unique-slug": "^2.0.2",
"universalify": "^2.0.0",
"unpipe": "^1.0.0",
"unquote": "^1.1.1",
"unset-value": "^1.0.0",
"upath": "^1.2.0",
"upper-case": "^2.0.1",
"uri-js": "^4.2.2",
"urix": "^0.1.0",
"url": "^0.11.0",
"url-loader": "^4.1.0",
"url-parse": "^1.4.7",
"use": "^3.1.1",
"util": "^0.12.3",
"util-deprecate": "^1.0.2",
"util.promisify": "^1.0.1",
"utila": "^0.4.0",
"utils-merge": "^1.0.1",
"uuid": "^8.3.0",
"vary": "^1.1.2",
"vendors": "^1.0.4",
"verror": "^1.10.0",
"vm-browserify": "^1.1.2",
"vue": "^2.6.11",
"vue-hot-reload-api": "^2.3.4",
"vue-loader": "^15.9.3",
"vue-router": "^3.4.0",
"vue-server-renderer": "^2.6.11",
"vue-style-loader": "^4.1.2",
"vue-template-compiler": "^2.6.11",
"vue-template-es2015-compiler": "^1.9.1",
"vuepress": "^1.5.3",
"vuepress-html-webpack-plugin": "^3.2.0",
"vuepress-plugin-container": "^2.1.4",
"vuepress-plugin-sitemap": "^2.3.1",
"vuepress-plugin-smooth-scroll": "^0.0.9",
"vuepress-plugin-zooming": "^1.1.7",
"watchpack": "^1.7.4",
"wbuf": "^1.7.3",
"webidl-conversions": "^6.1.0",
"webpack": "^4.44.1",
"webpack-chain": "^6.5.1",
"webpack-dev-middleware": "^3.7.2",
"webpack-dev-server": "^3.11.0",
"webpack-log": "^3.0.1",
"webpack-merge": "^5.1.1",
"webpack-sources": "^1.4.3",
"webpackbar": "^4.0.0",
"websocket-driver": "^0.7.4",
"websocket-extensions": "^0.1.4",
"whatwg-url": "^8.1.0",
"when": "^3.7.8",
"which": "^2.0.2",
"which-module": "^2.0.0",
"worker-farm": "^1.7.0",
"wrap-ansi": "^7.0.0",
"wrappy": "^1.0.2",
"ws": "^7.3.1",
"xmlbuilder": "^15.1.1",
"xtend": "^4.0.2",
"y18n": "^4.0.0",
"yallist": "^4.0.0",
"yargs": "^15.4.1",
"yargs-parser": "^18.1.3",
"zepto": "^1.2.0"
},
"devDependencies": {},
"scripts": {
"dev": "vuepress dev",
"build": "vuepress build"
"dev": "vitepress dev --host",
"build": "vitepress build",
"preview": "vitepress preview"
},
"author": "",
"license": "ISC"
"devDependencies": {
"vitepress": "^1.1.4"
},
"dependencies": {}
}

@ -1,12 +0,0 @@
# Screenshots
<img class="no-medium-zoom zooming" src="/screenshots/login.png" alt="Login" title="Login" width="200"/>
<img class="no-medium-zoom zooming" src="/screenshots/dashboard.png" alt="Dashboard" title="Dashboard" width="200"/>
<img class="no-medium-zoom zooming" src="/screenshots/proxy-hosts.png" alt="Proxy Hosts" title="Proxy Hosts" width="200"/>
<img class="no-medium-zoom zooming" src="/screenshots/proxy-hosts-add.png" alt="Add Proxy Host" title="Add Proxy Host" width="200"/>
<img class="no-medium-zoom zooming" src="/screenshots/redirection-hosts.png" alt="Redirection Hosts" title="Redirection Hosts" width="200"/>
<img class="no-medium-zoom zooming" src="/screenshots/dead-hosts.png" alt="404 Hosts" title="404 Hosts" width="200"/>
<img class="no-medium-zoom zooming" src="/screenshots/permissions.png" alt="User Permissions" title="User Permissions" width="200"/>
<img class="no-medium-zoom zooming" src="/screenshots/certificates.png" alt="Certificates" title="Certificates" width="200"/>
<img class="no-medium-zoom zooming" src="/screenshots/audit-log.png" alt="Audit Log" title="Audit Log" width="200"/>
<img class="no-medium-zoom zooming" src="/screenshots/custom-settings.png" alt="Custom Settings" title="Custom Settings" width="200"/>

@ -1,5 +1,30 @@
---
outline: deep
---
# Advanced Configuration
## Running processes as a user/group
By default, the services (nginx etc) will run as `root` user inside the docker container.
You can change this behaviour by setting the following environment variables.
Not only will they run the services as this user/group, they will change the ownership
on the `data` and `letsencrypt` folders at startup.
```yml
services:
app:
image: 'jc21/nginx-proxy-manager:latest'
environment:
PUID: 1000
PGID: 1000
# ...
```
This may have the side effect of a failed container start due to permission denied trying
to open port 80 on some systems. The only course to fix that is to remove the variables
and run as the default root user.
## Best Practice: Use a Docker network
For those who have a few of their upstream services running in Docker on the same Docker
@ -55,7 +80,7 @@ feature by adding the following to the service in your `docker-compose.yml` file
```yml
healthcheck:
test: ["CMD", "/bin/check-health"]
test: ["CMD", "/usr/bin/check-health"]
interval: 10s
timeout: 3s
```
@ -117,8 +142,9 @@ services:
MYSQL_USER: "npm"
# MYSQL_PASSWORD: "npm" # use secret instead
MYSQL_PASSWORD__FILE: /run/secrets/MYSQL_PWD
MARIADB_AUTO_UPGRADE: '1'
volumes:
- ./data/mysql:/var/lib/mysql
- ./mysql:/var/lib/mysql
secrets:
- DB_ROOT_PWD
- MYSQL_PWD
@ -147,6 +173,7 @@ NPM has the ability to include different custom configuration snippets in differ
You can add your custom configuration snippet files at `/data/nginx/custom` as follow:
- `/data/nginx/custom/root_top.conf`: Included at the top of nginx.conf
- `/data/nginx/custom/root.conf`: Included at the very end of nginx.conf
- `/data/nginx/custom/http_top.conf`: Included at the top of the main http block
- `/data/nginx/custom/http.conf`: Included at the end of the main http block
@ -172,3 +199,26 @@ value by specifying it as a Docker environment variable. The default if not spec
X_FRAME_OPTIONS: "sameorigin"
...
```
## Customising logrotate settings
By default, NPM rotates the access- and error logs weekly and keeps 4 and 10 log files respectively.
Depending on the usage, this can lead to large log files, especially access logs.
You can customise the logrotate configuration through a mount (if your custom config is `logrotate.custom`):
```yml
volumes:
...
- ./logrotate.custom:/etc/logrotate.d/nginx-proxy-manager
```
For reference, the default configuration can be found [here](https://github.com/NginxProxyManager/nginx-proxy-manager/blob/develop/docker/rootfs/etc/logrotate.d/nginx-proxy-manager).
## Enabling the geoip2 module
To enable the geoip2 module, you can create the custom configuration file `/data/nginx/custom/root_top.conf` and include the following snippet:
```
load_module /usr/lib/nginx/modules/ngx_http_geoip2_module.so;
load_module /usr/lib/nginx/modules/ngx_stream_geoip2_module.so;
```

@ -1,26 +1,26 @@
---
outline: deep
---
# FAQ
## Do I have to use Docker?
Yes, that's how this project is packaged.
This makes it easier to support the project when I have control over the version of Nginx and NodeJS
being used. In future this could change if the backend was no longer using NodeJS and it's long list
of dependencies.
This makes it easier to support the project when we have control over the version of Nginx other packages
use by the project.
## Can I run it on a Raspberry Pi?
Yes! The docker image is multi-arch and is built for a variety of architectures. If yours is
[not listed](https://hub.docker.com/r/jc21/nginx-proxy-manager/tags) please open a
[GitHub issue](https://github.com/jc21/nginx-proxy-manager/issues/new?assignees=&labels=enhancement&template=feature_request.md&title=).
[GitHub issue](https://github.com/NginxProxyManager/nginx-proxy-manager/issues/new?assignees=&labels=enhancement&template=feature_request.md&title=).
## I can't get my service to proxy properly?
Your best bet is to ask the [Reddit community for support](https://www.reddit.com/r/nginxproxymanager/). There's safety in numbers.
Gitter is best left for anyone contributing to the project to ask for help about internals, code reviews etc.
## When adding username and password access control to a proxy host, I can no longer login into the app.
Having an Access Control List (ACL) with username and password requires the browser to always send this username and password in the `Authorization` header on each request. If your proxied app also requires authentication (like Nginx Proxy Manager itself), most likely the app will also use the `Authorization` header to transmit this information, as this is the standardized header meant for this kind of information. However having multiples of the same headers is not allowed in the [internet standard](https://www.rfc-editor.org/rfc/rfc7230#section-3.2.2) and almost all apps do not support multiple values in the `Authorization` header. Hence one of the two logins will be broken. This can only be fixed by either removing one of the logins or by changing the app to use other non-standard headers for authorization.
Having an Access Control List (ACL) with username and password requires the browser to always send this username and password in the `Authorization` header on each request. If your proxied app also requires authentication (like Nginx Proxy Manager itself), most likely the app will also use the `Authorization` header to transmit this information, as this is the standardized header meant for this kind of information. However having multiples of the same headers is not allowed in the [internet standard](https://www.rfc-editor.org/rfc/rfc7230#section-3.2.2) and almost all apps do not support multiple values in the `Authorization` header. Hence one of the two logins will be broken. This can only be fixed by either removing one of the logins or by changing the app to use other non-standard headers for authorization.

126
docs/src/guide/index.md Normal file

@ -0,0 +1,126 @@
---
outline: deep
---
# Guide
::: raw
<p align="center">
<a href="https://hub.docker.com/repository/docker/jc21/nginx-proxy-manager" style="display:inline;margin-right:5px;">
<img src="https://img.shields.io/docker/stars/jc21/nginx-proxy-manager.svg?style=for-the-badge" style="display:inline;">
</a>
<a href="https://hub.docker.com/repository/docker/jc21/nginx-proxy-manager" style="display:inline;margin-right:5px;">
<img src="https://img.shields.io/docker/pulls/jc21/nginx-proxy-manager.svg?style=for-the-badge" style="display:inline;">
</a>
</p>
:::
This project comes as a pre-built docker image that enables you to easily forward to your websites
running at home or otherwise, including free SSL, without having to know too much about Nginx or Letsencrypt.
- [Quick Setup](#quick-setup)
- [Full Setup](/setup/)
- [Screenshots](/screenshots/)
## Project Goal
I created this project to fill a personal need to provide users with an easy way to accomplish reverse
proxying hosts with SSL termination and it had to be so easy that a monkey could do it. This goal hasn't changed.
While there might be advanced options they are optional and the project should be as simple as possible
so that the barrier for entry here is low.
::: raw
<a href="https://www.buymeacoffee.com/jc21" target="_blank"><img src="http://public.jc21.com/github/by-me-a-coffee.png" alt="Buy Me A Coffee" style="height: 51px !important;width: 217px !important;" ></a>
:::
## Features
- Beautiful and Secure Admin Interface based on [Tabler](https://tabler.github.io/)
- Easily create forwarding domains, redirections, streams and 404 hosts without knowing anything about Nginx
- Free SSL using Let's Encrypt or provide your own custom SSL certificates
- Access Lists and basic HTTP Authentication for your hosts
- Advanced Nginx configuration available for super users
- User management, permissions and audit log
## Hosting your home network
I won't go in to too much detail here but here are the basics for someone new to this self-hosted world.
1. Your home router will have a Port Forwarding section somewhere. Log in and find it
2. Add port forwarding for port 80 and 443 to the server hosting this project
3. Configure your domain name details to point to your home, either with a static ip or a service like DuckDNS or [Amazon Route53](https://github.com/jc21/route53-ddns)
4. Use the Nginx Proxy Manager as your gateway to forward to your other web based services
## Quick Setup
1. Install Docker and Docker-Compose
- [Docker Install documentation](https://docs.docker.com/get-docker/)
- [Docker-Compose Install documentation](https://docs.docker.com/compose/install/)
2. Create a docker-compose.yml file similar to this:
```yml
version: '3.8'
services:
app:
image: 'jc21/nginx-proxy-manager:latest'
restart: unless-stopped
ports:
- '80:80'
- '81:81'
- '443:443'
volumes:
- ./data:/data
- ./letsencrypt:/etc/letsencrypt
```
This is the bare minimum configuration required. See the [documentation](https://nginxproxymanager.com/setup/) for more.
3. Bring up your stack by running
```bash
docker-compose up -d
# If using docker-compose-plugin
docker compose up -d
```
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.
[http://127.0.0.1:81](http://127.0.0.1:81)
Default Admin User:
```
Email: admin@example.com
Password: changeme
```
Immediately after logging in with this default user you will be asked to modify your details and change your password.
## Contributing
All are welcome to create pull requests for this project, against the `develop` branch. Official releases are created from the `master` branch.
CI is used in this project. All PR's must pass before being considered. After passing,
docker builds for PR's are available on dockerhub for manual verifications.
Documentation within the `develop` branch is available for preview at
[https://develop.nginxproxymanager.com](https://develop.nginxproxymanager.com)
### Contributors
Special thanks to [all of our contributors](https://github.com/NginxProxyManager/nginx-proxy-manager/graphs/contributors).
## Getting Support
1. [Found a bug?](https://github.com/NginxProxyManager/nginx-proxy-manager/issues)
2. [Discussions](https://github.com/NginxProxyManager/nginx-proxy-manager/discussions)
3. [Reddit](https://reddit.com/r/nginxproxymanager)

32
docs/src/index.md Normal file

@ -0,0 +1,32 @@
---
# https://vitepress.dev/reference/default-theme-home-page
layout: home
hero:
name: "Nginx Proxy Manager"
tagline: Expose your services easily and securely
image:
src: /logo.svg
alt: NPM Logo
actions:
- theme: brand
text: Get Started
link: /guide/
- theme: alt
text: GitHub
link: https://github.com/NginxProxyManager/nginx-proxy-manager
features:
- title: Get Connected
details: Expose web services on your network &middot; Free SSL with Let's Encrypt &middot; Designed with security in mind &middot; Perfect for home networks
- title: Proxy Hosts
details: Expose your private network Web services and get connected anywhere.
- title: Beautiful UI
details: Based on Tabler, the interface is a pleasure to use. Configuring a server has never been so fun.
- title: Free SSL
details: Built in Lets Encrypt support allows you to secure your Web services at no cost to you. The certificates even renew themselves!
- title: Docker FTW
details: Built as a Docker Image, Nginx Proxy Manager only requires a database.
- title: Multiple Users
details: Configure other users to either view or manage their own hosts. Full access permissions are available.
---

Before

(image error) Size: 13 KiB

After

(image error) Size: 13 KiB

Before

(image error) Size: 18 KiB

After

(image error) Size: 18 KiB

Before

(image error) Size: 13 KiB

After

(image error) Size: 13 KiB

Before

(image error) Size: 92 KiB

After

(image error) Size: 92 KiB

@ -0,0 +1,20 @@
---
outline: deep
---
# Screenshots
::: raw
<div class="inline-img">
<a href="/screenshots/login.png" target="_blank"><img class="no-medium-zoom zooming" src="/screenshots/login.png" alt="Login" title="Login" width="200"/></a>
<a href="/screenshots/dashboard.png" target="_blank"><img class="no-medium-zoom zooming" src="/screenshots/dashboard.png" alt="Dashboard" title="Dashboard" width="200"/></a>
<a href="/screenshots/proxy-hosts.png" target="_blank"><img class="no-medium-zoom zooming" src="/screenshots/proxy-hosts.png" alt="Proxy Hosts" title="Proxy Hosts" width="200"/></a>
<a href="/screenshots/proxy-hosts-add.png" target="_blank"><img class="no-medium-zoom zooming" src="/screenshots/proxy-hosts-add.png" alt="Add Proxy Host" title="Add Proxy Host" width="200"/></a>
<a href="/screenshots/redirection-hosts.png" target="_blank"><img class="no-medium-zoom zooming" src="/screenshots/redirection-hosts.png" alt="Redirection Hosts" title="Redirection Hosts" width="200"/></a>
<a href="/screenshots/dead-hosts.png" target="_blank"><img class="no-medium-zoom zooming" src="/screenshots/dead-hosts.png" alt="404 Hosts" title="404 Hosts" width="200"/></a>
<a href="/screenshots/permissions.png" target="_blank"><img class="no-medium-zoom zooming" src="/screenshots/permissions.png" alt="User Permissions" title="User Permissions" width="200"/></a>
<a href="/screenshots/certificates.png" target="_blank"><img class="no-medium-zoom zooming" src="/screenshots/certificates.png" alt="Certificates" title="Certificates" width="200"/></a>
<a href="/screenshots/audit-log.png" target="_blank"><img class="no-medium-zoom zooming" src="/screenshots/audit-log.png" alt="Audit Log" title="Audit Log" width="200"/></a>
<a href="/screenshots/custom-settings.png" target="_blank"><img class="no-medium-zoom zooming" src="/screenshots/custom-settings.png" alt="Custom Settings" title="Custom Settings" width="200"/></a>
</div>
:::

@ -1,3 +1,7 @@
---
outline: deep
---
# Full Setup Instructions
## Running the App
@ -35,7 +39,7 @@ services:
Then:
```bash
docker-compose up -d
docker compose up -d
```
## Using MySQL / MariaDB Database
@ -64,9 +68,6 @@ services:
# Add any other Stream port you want to expose
# - '21:21' # FTP
environment:
# Unix user and group IDs, optional
PUID: 1000
PGID: 1000
# Mysql/Maria connection parameters:
DB_MYSQL_HOST: "db"
DB_MYSQL_PORT: 3306
@ -89,8 +90,9 @@ services:
MYSQL_DATABASE: 'npm'
MYSQL_USER: 'npm'
MYSQL_PASSWORD: 'npm'
MARIADB_AUTO_UPGRADE: '1'
volumes:
- ./data/mysql:/var/lib/mysql
- ./mysql:/var/lib/mysql
```
::: warning
@ -122,7 +124,7 @@ Please note that the `jc21/mariadb-aria:latest` image might have some problems o
After the app is running for the first time, the following will happen:
1. GPG keys will be generated and saved in the data folder
1. JWT keys will be generated and saved in the data folder
2. The database will initialize with table structures
3. A default admin user will be created

@ -1,3 +1,7 @@
---
outline: deep
---
# Third Party
As this software gains popularity it's common to see it integrated with other platforms. Please be aware that unless specifically mentioned in the documentation of those
@ -7,10 +11,9 @@ Known integrations:
- [HomeAssistant Hass.io plugin](https://github.com/hassio-addons/addon-nginx-proxy-manager)
- [UnRaid / Synology](https://github.com/jlesage/docker-nginx-proxy-manager)
- [Proxmox Scripts](https://github.com/ej52/proxmox-scripts/tree/main/lxc/nginx-proxy-manager)
- [Proxmox Scripts](https://github.com/ej52/proxmox-scripts/tree/main/apps/nginx-proxy-manager)
- [nginxproxymanagerGraf](https://github.com/ma-karai/nginxproxymanagerGraf)
If you would like your integration of NPM listed, please open a
[Github issue](https://github.com/jc21/nginx-proxy-manager/issues/new?assignees=&labels=enhancement&template=feature_request.md&title=)
[Github issue](https://github.com/NginxProxyManager/nginx-proxy-manager/issues/new?assignees=&labels=enhancement&template=feature_request.md&title=)

@ -1,8 +1,12 @@
---
outline: deep
---
# Upgrading
```bash
docker-compose pull
docker-compose up -d
docker compose pull
docker compose up -d
```
This project will automatically update any databases or other requirements so you don't have to follow

File diff suppressed because it is too large Load Diff

@ -10,6 +10,7 @@
<meta name="mobile-web-app-capable" content="yes">
<meta name="HandheldFriendly" content="True">
<meta name="MobileOptimized" content="320">
<meta name="robots" content="noindex">
<title><%- title %></title>
<link rel="apple-touch-icon" sizes="180x180" href="/images/favicons/apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32" href="/images/favicons/favicon-32x32.png">

@ -22,7 +22,7 @@
<div class="mb-3 test-domains-container">
<button type="button" class="btn btn-secondary test-domains col-sm-12"><%- i18n('certificates', 'test-reachability') %></button>
<div class="text-secondary small">
<i class="fe fe-info"></i>
<i class="fe fe-info"></i>
<%- i18n('certificates', 'reachability-info') %>
</div>
</div>
@ -38,11 +38,11 @@
<div class="col-sm-12 col-md-12">
<div class="form-group">
<label class="custom-switch">
<input
type="checkbox"
class="custom-switch-input"
name="meta[dns_challenge]"
value="1"
<input
type="checkbox"
class="custom-switch-input"
name="meta[dns_challenge]"
value="1"
<%- getUseDnsChallenge() ? 'checked' : '' %>
>
<span class="custom-switch-indicator"></span>
@ -59,22 +59,22 @@
<div class="col-sm-12 col-md-12">
<div class="form-group">
<label class="form-label"><%- i18n('ssl', 'dns-provider') %> <span class="form-required">*</span></label>
<select
name="meta[dns_provider]"
<select
name="meta[dns_provider]"
id="dns_provider"
class="form-control custom-select"
>
<option
value=""
disabled
<option
value=""
disabled
hidden
<%- getDnsProvider() === null ? 'selected' : '' %>
>Please Choose...</option>
<% _.each(dns_plugins, function(plugin_info, plugin_name){ %>
<option
<option
value="<%- plugin_name %>"
<%- getDnsProvider() === plugin_name ? 'selected' : '' %>
><%- plugin_info.display_name %></option>
><%- plugin_info.name %></option>
<% }); %>
</select>
</div>
@ -86,17 +86,17 @@
<div class="col-sm-12 col-md-12">
<div class="form-group">
<label class="form-label"><%- i18n('ssl', 'credentials-file-content') %> <span class="form-required">*</span></label>
<textarea
name="meta[dns_provider_credentials]"
class="form-control text-monospace"
id="dns_provider_credentials"
<textarea
name="meta[dns_provider_credentials]"
class="form-control text-monospace"
id="dns_provider_credentials"
><%- getDnsProviderCredentials() %></textarea>
<div class="text-secondary small">
<i class="fe fe-info"></i>
<i class="fe fe-info"></i>
<%= i18n('ssl', 'credentials-file-content-info') %>
</div>
<div class="text-red small">
<i class="fe fe-alert-triangle"></i>
<i class="fe fe-alert-triangle"></i>
<%= i18n('ssl', 'stored-as-plaintext-info') %>
</div>
</div>
@ -108,16 +108,16 @@
<div class="col-sm-12 col-md-12">
<div class="form-group mb-0">
<label class="form-label"><%- i18n('ssl', 'propagation-seconds') %></label>
<input
<input
type="number"
min="0"
name="meta[propagation_seconds]"
class="form-control"
id="propagation_seconds"
name="meta[propagation_seconds]"
class="form-control"
id="propagation_seconds"
value="<%- getPropagationSeconds() %>"
>
<div class="text-secondary small">
<i class="fe fe-info"></i>
<i class="fe fe-info"></i>
<%= i18n('ssl', 'propagation-seconds-info') %>
</div>
</div>

@ -11,7 +11,7 @@ require('selectize');
function sortProvidersAlphabetically(obj) {
return Object.entries(obj)
.sort((a,b) => a[1].display_name.toLowerCase() > b[1].display_name.toLowerCase())
.sort((a,b) => a[1].name.toLowerCase() > b[1].name.toLowerCase())
.reduce((result, entry) => {
result[entry[0]] = entry[1];
return result;
@ -47,7 +47,7 @@ module.exports = Mn.View.extend({
other_intermediate_certificate: '#other_intermediate_certificate',
other_intermediate_certificate_label: '#other_intermediate_certificate_label'
},
events: {
'change @ui.dns_challenge_switch': function () {
const checked = this.ui.dns_challenge_switch.prop('checked');
@ -63,7 +63,7 @@ module.exports = Mn.View.extend({
this.ui.dns_provider.prop('required', false);
this.ui.dns_provider_credentials.prop('required', false);
this.ui.dns_challenge_content.hide();
this.ui.test_domains_container.show();
this.ui.test_domains_container.show();
}
},
@ -75,10 +75,10 @@ module.exports = Mn.View.extend({
this.ui.credentials_file_content.show();
} else {
this.ui.dns_provider_credentials.prop('required', false);
this.ui.credentials_file_content.hide();
this.ui.credentials_file_content.hide();
}
},
'click @ui.save': function (e) {
e.preventDefault();
this.ui.le_error_info.hide();
@ -97,7 +97,7 @@ module.exports = Mn.View.extend({
if (typeof data.meta === 'undefined') data.meta = {};
let domain_err = false;
if (!data.meta.dns_challenge) {
if (!data.meta.dns_challenge) {
data.domain_names.split(',').map(function (name) {
if (name.match(/\*/im)) {
domain_err = true;
@ -119,7 +119,7 @@ module.exports = Mn.View.extend({
data.meta.dns_provider_credentials = undefined;
data.meta.propagation_seconds = undefined;
} else {
if(data.meta.propagation_seconds === '') data.meta.propagation_seconds = undefined;
if(data.meta.propagation_seconds === '') data.meta.propagation_seconds = undefined;
}
if (typeof data.domain_names === 'string' && data.domain_names) {
@ -265,7 +265,7 @@ module.exports = Mn.View.extend({
this.ui.domain_names.selectize({
delimiter: ',',
persist: false,
maxOptions: 15,
maxOptions: 100,
create: function (input) {
return {
value: input,
@ -275,7 +275,7 @@ module.exports = Mn.View.extend({
createFilter: /^(?:\*\.)?(?:[^.*]+\.?)+[^.]$/
});
this.ui.dns_challenge_content.hide();
this.ui.credentials_file_content.hide();
this.ui.credentials_file_content.hide();
this.ui.loader_content.hide();
this.ui.le_error_info.hide();
if (this.ui.domain_names[0]) {

@ -28,7 +28,7 @@
</div>
</td>
<td>
<%- i18n('ssl', provider) %><% if (meta.dns_provider) { %> - <%- dns_providers[meta.dns_provider].display_name %><% } %>
<%- i18n('ssl', provider) %><% if (meta.dns_provider) { %> - <%- dns_providers[meta.dns_provider].name %><% } %>
</td>
<td class="<%- isExpired() ? 'text-danger' : '' %>">
<%- formatDbDate(expires_on, 'Do MMMM YYYY, h:mm a') %>
@ -51,4 +51,4 @@
</div>
</div>
</td>
<% } %>
<% } %>

@ -78,11 +78,11 @@
<div class="col-sm-12 col-md-12 letsencrypt">
<div class="form-group">
<label class="custom-switch">
<input
type="checkbox"
class="custom-switch-input"
name="meta[dns_challenge]"
value="1"
<input
type="checkbox"
class="custom-switch-input"
name="meta[dns_challenge]"
value="1"
<%- getUseDnsChallenge() ? 'checked' : '' %>
>
<span class="custom-switch-indicator"></span>
@ -99,22 +99,22 @@
<div class="col-sm-12 col-md-12">
<div class="form-group">
<label class="form-label"><%- i18n('ssl', 'dns-provider') %> <span class="form-required">*</span></label>
<select
name="meta[dns_provider]"
<select
name="meta[dns_provider]"
id="dns_provider"
class="form-control custom-select"
>
<option
value=""
disabled
<option
value=""
disabled
hidden
<%- getDnsProvider() === null ? 'selected' : '' %>
>Please Choose...</option>
<% _.each(dns_plugins, function(plugin_info, plugin_name){ %>
<option
<option
value="<%- plugin_name %>"
<%- getDnsProvider() === plugin_name ? 'selected' : '' %>
><%- plugin_info.display_name %></option>
><%- plugin_info.name %></option>
<% }); %>
</select>
</div>
@ -126,17 +126,17 @@
<div class="col-sm-12 col-md-12">
<div class="form-group">
<label class="form-label"><%- i18n('ssl', 'credentials-file-content') %> <span class="form-required">*</span></label>
<textarea
name="meta[dns_provider_credentials]"
class="form-control text-monospace"
id="dns_provider_credentials"
<textarea
name="meta[dns_provider_credentials]"
class="form-control text-monospace"
id="dns_provider_credentials"
><%- getDnsProviderCredentials() %></textarea>
<div class="text-secondary small">
<i class="fe fe-info"></i>
<i class="fe fe-info"></i>
<%= i18n('ssl', 'credentials-file-content-info') %>
</div>
<div class="text-red small">
<i class="fe fe-alert-triangle"></i>
<i class="fe fe-alert-triangle"></i>
<%= i18n('ssl', 'stored-as-plaintext-info') %>
</div>
</div>
@ -148,16 +148,16 @@
<div class="col-sm-12 col-md-12">
<div class="form-group mb-0">
<label class="form-label"><%- i18n('ssl', 'propagation-seconds') %></label>
<input
<input
type="number"
min="0"
name="meta[propagation_seconds]"
class="form-control"
id="propagation_seconds"
name="meta[propagation_seconds]"
class="form-control"
id="propagation_seconds"
value="<%- getPropagationSeconds() %>"
>
<div class="text-secondary small">
<i class="fe fe-info"></i>
<i class="fe fe-info"></i>
<%= i18n('ssl', 'propagation-seconds-info') %>
</div>
</div>

@ -233,7 +233,7 @@ module.exports = Mn.View.extend({
this.ui.domain_names.selectize({
delimiter: ',',
persist: false,
maxOptions: 15,
maxOptions: 100,
create: function (input) {
return {
value: input,

@ -146,11 +146,11 @@
<div class="col-sm-12 col-md-12 letsencrypt">
<div class="form-group">
<label class="custom-switch">
<input
type="checkbox"
class="custom-switch-input"
name="meta[dns_challenge]"
value="1"
<input
type="checkbox"
class="custom-switch-input"
name="meta[dns_challenge]"
value="1"
<%- getUseDnsChallenge() ? 'checked' : '' %>
>
<span class="custom-switch-indicator"></span>
@ -167,22 +167,22 @@
<div class="col-sm-12 col-md-12">
<div class="form-group">
<label class="form-label"><%- i18n('ssl', 'dns-provider') %> <span class="form-required">*</span></label>
<select
name="meta[dns_provider]"
<select
name="meta[dns_provider]"
id="dns_provider"
class="form-control custom-select"
>
<option
value=""
disabled
<option
value=""
disabled
hidden
<%- getDnsProvider() === null ? 'selected' : '' %>
>Please Choose...</option>
<% _.each(dns_plugins, function(plugin_info, plugin_name){ %>
<option
<option
value="<%- plugin_name %>"
<%- getDnsProvider() === plugin_name ? 'selected' : '' %>
><%- plugin_info.display_name %></option>
><%- plugin_info.name %></option>
<% }); %>
</select>
</div>
@ -194,17 +194,17 @@
<div class="col-sm-12 col-md-12">
<div class="form-group">
<label class="form-label"><%- i18n('ssl', 'credentials-file-content') %> <span class="form-required">*</span></label>
<textarea
name="meta[dns_provider_credentials]"
class="form-control text-monospace"
id="dns_provider_credentials"
<textarea
name="meta[dns_provider_credentials]"
class="form-control text-monospace"
id="dns_provider_credentials"
><%- getDnsProviderCredentials() %></textarea>
<div class="text-secondary small">
<i class="fe fe-info"></i>
<i class="fe fe-info"></i>
<%= i18n('ssl', 'credentials-file-content-info') %>
</div>
<div class="text-red small">
<i class="fe fe-alert-triangle"></i>
<i class="fe fe-alert-triangle"></i>
<%= i18n('ssl', 'stored-as-plaintext-info') %>
</div>
</div>
@ -216,16 +216,16 @@
<div class="col-sm-12 col-md-12">
<div class="form-group mb-0">
<label class="form-label"><%- i18n('ssl', 'propagation-seconds') %></label>
<input
<input
type="number"
min="0"
name="meta[propagation_seconds]"
class="form-control"
id="propagation_seconds"
name="meta[propagation_seconds]"
class="form-control"
id="propagation_seconds"
value="<%- getPropagationSeconds() %>"
>
<div class="text-secondary small">
<i class="fe fe-info"></i>
<i class="fe fe-info"></i>
<%= i18n('ssl', 'propagation-seconds-info') %>
</div>
</div>

@ -271,7 +271,7 @@ module.exports = Mn.View.extend({
this.ui.domain_names.selectize({
delimiter: ',',
persist: false,
maxOptions: 15,
maxOptions: 100,
create: function (input) {
return {
value: input,

Some files were not shown because too many files have changed in this diff Show More