Compare commits

...

181 Commits

Author SHA1 Message Date
aec30207da Merge pull request #3483 from NginxProxyManager/develop
v2.11.1
2024-01-21 21:17:30 +10:00
209c1b3334 Merge branch 'master' into develop 2024-01-21 21:16:30 +10:00
58138fbac4 Bump version 2024-01-21 21:13:03 +10:00
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
89a405f60c Merge pull request #3466 from NginxProxyManager/develop
v2.11.0
2024-01-19 10:52:34 +10:00
0353051436 Prevent installing same plugin over and over 2024-01-18 16:06:09 +10:00
a3630a6286 Fix unused var 2024-01-18 15:17:27 +10:00
10d9760242 Refactor certbot plugin install for setup 2024-01-18 15:13:16 +10:00
c722eb1cea Merge branch 'master' into develop 2024-01-18 13:21:39 +10:00
0472abacd2 Remove test file 2024-01-18 13:20:03 +10:00
a2e85ceed8 Use certbot version for godaddy plugin, relates to #3165 2024-01-18 13:08:16 +10:00
cddd6fb985 certbot-dns-cloudns update 0.6.0 from PR #3459 by @existful 2024-01-18 13:01:05 +10:00
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
8646cb5a19 Allow stale action to run manually 2024-01-16 07:57:38 +10:00
fe0c04610f Add stale github action and set a wide limit 2024-01-16 07:53:02 +10:00
9f16dae2ff Merge pull request #3258 from iBobik/patch-1
Removed /etc/letsencrypt from explicit volumes
2024-01-15 09:12:44 +10:00
00264bcfb2 Mount letsencrypt folder in CI 2024-01-15 08:18:48 +10:00
834fb1a361 Add missing args to certbot command, was causing failures in rovokation 2024-01-12 17:04:55 +10:00
1be87f48c1 Merge pull request #3392 from stevecrozz/auto-renew-uses-bulitin-renew
Make auto-renew use built-in renew function
2024-01-12 12:15:37 +10:00
9c54d1b718 Provide the token model for certificate renewal 2024-01-10 20:08:36 -08:00
f7d1c490b3 Run renews sequentially 2024-01-10 20:08:36 -08:00
fe4bd9fed6 Make auto-renew use built-in renew function 2024-01-10 20:08:29 -08:00
58ef9a688e Merge pull request #3445 from tilalx/develop
Update the vuepress config.js to fix pr/3395
2024-01-10 20:43:33 +10:00
d19ebf5925 Update the config.js to fix pr/3395 2024-01-10 11:06:40 +01:00
96fc6a20bb Merge pull request #3444 from NginxProxyManager/bookworm-base
Use nginxproxymanager/nginx-full image base
2024-01-10 13:18:10 +10:00
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
be39253a6f No need to use berry yarn for docs
as the ci image uses latest yarn
2024-01-10 09:39:25 +10:00
30772a48bd Fix jenkinsfile after messy merge - again 2024-01-10 09:29:05 +10:00
33c867895c Fix jenkinsfile after messy merge 2024-01-10 09:24:45 +10:00
a7fe687bae Fix permission recursiveness 2024-01-10 09:22:34 +10:00
4028120f55 Merge pull request #3395 from tilalx/develop
upgrade docs to vuepress v2.0.0-rc and implement dark mode
2024-01-10 09:21:10 +10:00
d1119ec63f revert change 2024-01-09 09:35:16 +01:00
4c906283df try to set the yarn version in jenkins 2024-01-09 09:35:15 +01:00
8ec0c76f51 update docs-build and add yarn.lock 2024-01-09 09:31:39 +01:00
c70f65d349 upgrade to v2.0.0-rc and implement dark mode 2024-01-09 09:27:34 +01:00
883a272b0a Bump version 2024-01-09 11:30:50 +10:00
6aee2bbcba Fix race condition with integration network 2024-01-09 10:57:47 +10:00
025fc9776b Pre-build cypress images before runnings integration tests 2024-01-09 10:32:58 +10:00
b699f05f47 Run integration tests in parallel 2024-01-09 10:25:10 +10:00
f7c87f63bd Updated CI to run some things in parallel 2024-01-09 10:05:19 +10:00
e4ef095254 Deploy develop docs in CI, updated readme 2024-01-09 08:36:32 +10:00
09d5e2c94f Merge pull request #3360 from DarioViva42/hsts-only-with-https
only add hsts header with https.
2024-01-09 08:16:01 +10:00
459b7a2223 Merge pull request #3361 from timob/improve-container-start
Improve container startup time
2024-01-09 08:15:33 +10:00
9c813bcce3 Merge pull request #3437 from Encephala/fix-logrotate-docs
Fix typo in logrotate config path
2024-01-09 07:41:36 +10:00
b8596ac01c Merge pull request #3367 from ej52/develop
chore: update Proxmox Scripts link
2024-01-09 07:40:50 +10:00
082c4e1008 Fix typo in logrotate config path 2024-01-08 16:14:27 +01:00
2273eae6ee Merge pull request #3436 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
997e9d431b Merge pull request #2924 from benhubert/2153_add-support-for-dns-hurricane-electric
added support for dns.he.net certbot plugin #2153
2024-01-08 10:49:27 +10:00
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
4e27cdabc4 Merge pull request #3263 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
965873adc5 Merge pull request #3377 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
5de95a8c90 Merge pull request #3382 from r3na/patch-1
fix: increasing maxOptions (amount of domains) to 30
2024-01-08 10:26:01 +10:00
fa557d8159 Merge pull request #3387 from clord/clord/update-vultr
chore: bump version of vultr certbot
2024-01-08 10:19:58 +10:00
bc8211a6a9 Merge pull request #3388 from jlesage/reachability-test-fix
Fixes for the server reachability test.
2024-01-08 10:19:27 +10:00
1c498f84ad Merge pull request #3399 from hywax/patch-1
Fix proxmox scripts link
2024-01-08 10:13:06 +10:00
ea6e9757e3 Merge pull request #3401 from JeremieA/certbot-dns-gandi-1.5.0
Update certbot-dns-plugins.js for gandi
2024-01-08 10:12:50 +10:00
1308ae42c2 Merge pull request #3408 from arussell/certbot-dns-plesk
Add support for certbot-dns-plesk
2024-01-08 10:12:24 +10:00
7be548575b Merge pull request #3422 from Encephala/logrotate-docs
Add documentation on customising logrotate config
2024-01-08 10:12:03 +10:00
c6aab8d4e6 Merge pull request #3427 from Encephala/bump-year
Update year to 2024 in footer
2024-01-08 10:10:44 +10:00
da55e93183 Update year to 2024 in footer 2024-01-03 16:48:58 +01:00
af475ab5d4 Add documentation on customising logrotate config 2023-12-30 15:23:17 +01:00
7d85463dae Add support for certbot-dns-plesk 2023-12-21 16:07:34 +00:00
13d4f98fdb Update certbot-dns-plugins.js for gandi (deprecation of Apikey in favor of personal tokens) 2023-12-20 12:19:17 +01:00
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
49a765516c Fix proxmox scripts link 2023-12-19 18:37:50 +05:00
27bc8c4e33 use same formatting 2023-12-13 15:15:02 -07:00
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
1975e4a151 fix: updating maxItems (schema/definitions) to 30 2023-12-12 12:45:35 +01:00
4704bd6a38 Merge branch 'develop' into patch-1 2023-12-12 12:38:42 +01:00
ca56e0483f fix: updating default maxOptions to 30 (dead) 2023-12-12 12:37:06 +01:00
3b8cb86d72 fix: updating default maxOptions to 30 (redirection) 2023-12-12 12:36:32 +01:00
5165de4a91 fix: updating default maxOptions to 30 (proxy) 2023-12-12 12:36:05 +01:00
1ab3575c68 fix: increasing maxOptions (amount of domains) to 30 2023-12-12 09:39:28 +01:00
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
3ad2188f78 chore: upddate Proxmox Scripts link 2023-12-04 10:31:26 +00:00
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
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
e08a4d4490 Update mariadb example to auto upgrade from latest image 2023-11-28 08:27:11 +10:00
d1d1819677 Merge pull request #3281 from nmatton/patch-1
update docker-compose execution
2023-11-22 10:06:55 +10:00
4e0768d56c Merge pull request #3289 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
3666364418 Merge pull request #3290 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
9052502a17 Merge pull request #3293 from xiaoxinpro/develop
Replace the description string on the default-site page with i18n
2023-11-09 07:37:13 +10:00
b608d3392d Merge pull request #3312 from AngusC222/develop
min/max ports added for Streams
2023-11-09 07:36:05 +10:00
edb81ecce0 Fix CI branch names being incorrectly replaced 2023-11-09 07:35:24 +10:00
e24181936f min/max ports added 2023-11-08 12:09:36 +00:00
940d06cac9 Replace the 'default-site' variable 'description' with the 'i18n' configuration 2023-10-29 10:50:45 +08:00
134902d127 Add a default-site-description string 2023-10-29 10:43:57 +08:00
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
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
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
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
53dbe258a5 Fix CI compose project name not allowing dots 2023-10-17 11:57:14 +10:00
e4ba22f0f8 Removed /etc/letsencrypt from explicit volumes
So it can be moved in other images using this as a base.

Fixes #3170
2023-10-15 08:55:36 +02:00
3197de41de Merge pull request #3155 from devedse/develop
Added force renewal + --dns-duckdns-no-txt-restore
2023-10-03 18:54:02 +10:00
0f7be7987b Merge pull request #3188 from AngusC222/develop
minimum/maximum ports added on frontend
2023-10-03 18:50:37 +10:00
853c48dff6 Merge pull request #3190 from OpenSourceSimon/patch-1
Add robots noindex meta tag to prevent indexing
2023-10-03 18:49:56 +10:00
410c3484ab Merge pull request #3194 from zhzy0077/patch-1
certbot-dns-tencentcloud should be 2.0.2 or above.
2023-10-03 18:49:13 +10:00
44e9f377f9 Merge pull request #3212 from FlixMa/develop
Strato Certbot Plugin: 2FA and International Site Support
2023-10-03 18:48:42 +10:00
0f3b76f607 Merge pull request #3219 from FibreTTP/logrotate-perms
Make logrotate use the proper user and group.
2023-10-03 18:48:01 +10:00
f426e64569 Add warning comment about changing the default user name and group name 2023-09-27 16:12:33 +10:00
4867db078c Remove explicit user and group - add su directive for default user (npm). 2023-09-27 14:58:19 +10:00
6b565e628f Change perms on logrotated logs to npm user 2023-09-27 14:25:04 +10:00
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
62e4edddf0 Update certbot-dns-plugins.js 2023-09-13 12:01:15 +08:00
4b9c02cc0c Add robots noindex meta tag to prevent indexing 2023-09-10 12:08:28 +02:00
5af834e40b mix/max ports 2023-09-09 13:44:16 +01:00
6f8db95249 Added force renewal + --dns-duckdns-no-txt-restore 2023-08-24 13:21:01 +02:00
fe93cb3474 Merge pull request #3089 from NginxProxyManager/develop
v2.10.4
2023-08-02 11:44:02 +10:00
fa851b61da Bump version 2023-07-31 07:25:09 +10:00
3333a32612 Merge pull request #2971 from wolviex/certbot-dnsplugin-user-site-fix
drop --user on pip install dns plugin
2023-07-31 07:21:18 +10:00
9a79fce498 Merge pull request #3078 from andycandy-de/patch-1
Corrected docker-compose.yml
2023-07-26 10:27:30 +10:00
b1180f5077 Corrected docker-compose.yml
The mysql folder should not be mounted to the npm container!
2023-07-25 18:00:48 +02:00
5454352fe5 Merge pull request #2929 from FlixMa/develop
Add strato.de to certbot dns plugins
2023-07-20 12:25:37 +10:00
aee93a2f6f Merge pull request #2932 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
f38cb5b500 Merge pull request #2942 from wrouesnel/444_default_support
Add support for nginx 444 default response
2023-07-20 12:23:57 +10:00
f1b7156c89 Merge pull request #3000 from xrh0905/xrh0905-patch-sed
Fix device or resource busy when patching IPv6 settings
2023-07-20 12:17:34 +10:00
98465cf1b0 Merge pull request #3018 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
137e865b66 Merge pull request #3069 from lug-gh/develop
update year 2022 -> 2023 in footer
2023-07-20 12:16:01 +10:00
e740fb4064 update year 2022 -> 2023 2023-07-19 13:27:17 +02:00
f91f0ee8db Merge pull request #3044 from 6twenty/2741-suppress-s6-supervise-disk-writes
Fix #2741 - Prevent excessive disk writes by only adding frontend service when in development
2023-07-19 13:09:12 +10:00
1c9f751512 Fix path to frontend service 2023-07-19 14:05:57 +12:00
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
f7b2be68cc Merge pull request #3048 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
ab4586fc6b Merge pull request #3049 from deftdawg/patch-1
Add bunny.net DNS to DNS challenges
2023-07-19 10:02:29 +10:00
a984a68065 Merge pull request #3051 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
52875fca6e Merge pull request #3053 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
63b50fcd95 Merge pull request #3054 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
5ab4aea03f Merge pull request #3065 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
d73135378e Merge pull request #3066 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
e19d685cb6 Merge pull request #3067 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
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
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
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
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
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
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
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
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
63ee69f432 Fix device or resource busy when patching IPv6 settings 2023-06-15 11:17:02 +08:00
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
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
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
53d61bd626 Try to fix linter error in certbot plugin definitions. 2023-05-18 14:14:38 +02:00
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
4c59400731 added support for dns.he.net certbot plugin #2153 2023-05-16 22:38:43 +02:00
824c837a38 Merge pull request #2906 from NginxProxyManager/develop
Fix certbot plugins install when using PUID/PGID
2023-05-10 14:40:15 +10:00
2a06384a4a Merge branch 'master' into develop 2023-05-10 14:40:06 +10:00
05307aa253 Fix certbot plugins install when using PUID/PGID 2023-05-10 14:39:08 +10:00
3d2406ac3d Merge pull request #2905 from NginxProxyManager/develop
v2.10.3
2023-05-10 14:09:04 +10:00
0127dc7f03 Bump version 2023-05-10 11:32:22 +10:00
4349d42636 Merge pull request #2904 from NginxProxyManager/s6-verbose
Fixes for s6 timeout at startup
2023-05-10 11:31:17 +10:00
4b6f9d9419 Remove s6 service timeout 2023-05-10 09:57:24 +10:00
c3f019c911 Test ipv6 disabled in ci 2023-05-09 08:19:09 +10:00
ecf0290203 Update s6-overlay 2023-05-09 08:15:44 +10:00
4f41fe0c95 Update s6-overlay 2023-05-05 08:46:54 +10:00
c3735fdbbb Missed a file that was explicit verbose 2023-05-04 12:30:27 +10:00
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
a1245bc161 Split up ownership to indentify point of failure 2023-05-04 08:27:38 +10:00
db4ab1d548 Verbose debugging of s6 scripts 2023-05-03 16:01:27 +10:00
86ddd9c83c Merge pull request #2784 from NginxProxyManager/develop
v2.10.2
2023-03-31 09:37:08 +10:00
67208e43cc Merge branch 'master' into develop 2023-03-31 08:27:00 +10:00
ddf80302c6 Bump version 2023-03-31 08:25:45 +10:00
5f2576946d Merge pull request #2783 from NginxProxyManager/uidgid
Make PUID and PGID optional
2023-03-31 08:25:07 +10:00
9fe07fa6c3 Update documentation 2023-03-30 15:37:59 +10:00
d9b9af543e Fix text replacement whoops 2023-03-30 15:03:57 +10:00
eb2e2e0478 Throw in a docker restart during testing phase 2023-03-30 14:44:15 +10:00
9225d5d442 Tweak test 2023-03-30 13:00:22 +10:00
308a7149ed Tweak test 2023-03-30 12:55:20 +10:00
8a4a7d0caf Allow 201 as success in test result 2023-03-30 12:51:26 +10:00
5d03ede100 Add test for creating a host 2023-03-30 12:44:28 +10:00
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
dad8561ea1 Use numbers for permissions in case npmuser doesn't exist 2023-03-30 10:20:20 +10:00
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
9d672f5813 Own this nginx folder too 2023-03-29 14:04:48 +10:00
d5ed70dbb6 Own this nginx folder too 2023-03-29 14:03:58 +10:00
c197e66d62 Merge pull request #2764 from NginxProxyManager/develop
v2.10.1
2023-03-29 08:54:30 +10:00
91cf3c8873 Tweaks to docker compose ci after updates 2023-03-29 08:24:28 +10:00
7f5e0414ac Bump version 2023-03-29 07:22:15 +10:00
d179887c15 Another fix for #2734, only chown parts of /etc/nginx 2023-03-28 10:39:26 +10:00
35abb4d7ae Execute permissions missing on script 2023-03-28 09:33:30 +10:00
61b290e220 Chown each folder on separately
Really not sure why this fixes #2734 however it does actually
help the ownership script succeed specifically on arm7/raspbian
2023-03-28 08:50:10 +10:00
82 changed files with 7212 additions and 13121 deletions

21
.github/workflows/stale.yml vendored Normal file
View 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

View File

@ -1 +1 @@
2.10.0 2.11.1

248
Jenkinsfile vendored
View File

@ -17,13 +17,11 @@ pipeline {
IMAGE = 'nginx-proxy-manager' IMAGE = 'nginx-proxy-manager'
BUILD_VERSION = getVersion() BUILD_VERSION = getVersion()
MAJOR_VERSION = '2' MAJOR_VERSION = '2'
BRANCH_LOWER = "${BRANCH_NAME.toLowerCase().replaceAll('/', '-')}" BRANCH_LOWER = "${BRANCH_NAME.toLowerCase().replaceAll('\\\\', '-').replaceAll('/', '-').replaceAll('\\.', '-')}"
COMPOSE_PROJECT_NAME = "npm_${BRANCH_LOWER}_${BUILD_NUMBER}" COMPOSE_PROJECT_NAME = "npm_${BRANCH_LOWER}_${BUILD_NUMBER}"
COMPOSE_FILE = 'docker/docker-compose.ci.yml' COMPOSE_FILE = 'docker/docker-compose.ci.yml'
COMPOSE_INTERACTIVE_NO_CLI = 1 COMPOSE_INTERACTIVE_NO_CLI = 1
BUILDX_NAME = "${COMPOSE_PROJECT_NAME}" BUILDX_NAME = "${COMPOSE_PROJECT_NAME}"
DOCS_BUCKET = 'jc21-npm-site'
DOCS_CDN = 'EN1G6DEWZUTDT'
} }
stages { stages {
stage('Environment') { stage('Environment') {
@ -62,99 +60,114 @@ pipeline {
} }
} }
} }
stage('Build and Test') { stage('Builds') {
steps { parallel {
script { stage('Project') {
// Frontend and Backend steps {
def shStatusCode = sh(label: 'Checking and Building', returnStatus: true, script: ''' script {
set -e // Frontend and Backend
./scripts/ci/frontend-build > ${WORKSPACE}/tmp-sh-build 2>&1 def shStatusCode = sh(label: 'Checking and Building', returnStatus: true, script: '''
./scripts/ci/test-and-build > ${WORKSPACE}/tmp-sh-build 2>&1 set -e
''') ./scripts/ci/frontend-build > ${WORKSPACE}/tmp-sh-build 2>&1
shOutput = readFile "${env.WORKSPACE}/tmp-sh-build" ./scripts/ci/test-and-build > ${WORKSPACE}/tmp-sh-build 2>&1
if (shStatusCode != 0) { ''')
error "${shOutput}" 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'
}
dir(path: 'docs/.vuepress/dist') {
sh 'tar -czf ../../docs.tgz *'
}
archiveArtifacts(artifacts: 'docs/docs.tgz', allowEmptyArchive: false)
}
}
stage('Cypress') {
steps {
// Creating will also create the network prior to
// using it in parallel stages below and mitigating
// a race condition.
sh 'docker-compose build cypress-sqlite'
sh 'docker-compose build cypress-mysql'
sh 'docker-compose create cypress-sqlite'
sh 'docker-compose create cypress-mysql'
} }
} }
} }
post {
always {
sh 'rm -f ${WORKSPACE}/tmp-sh-build'
}
failure {
npmGithubPrComment("CI Error:\n\n```\n${shOutput}\n```", true)
}
}
} }
stage('Integration Tests Sqlite') { stage('Integration Tests') {
steps { parallel {
// Bring up a stack stage('Sqlite') {
sh 'docker-compose up -d fullstack-sqlite' steps {
sh './scripts/wait-healthy $(docker-compose ps -q fullstack-sqlite) 120' // Bring up a stack
sh 'docker-compose up -d fullstack-sqlite'
sh './scripts/wait-healthy $(docker-compose ps --all -q fullstack-sqlite) 120'
// Stop and Start it, as this will test it's ability to restart with existing data
sh 'docker-compose stop fullstack-sqlite'
sh 'docker-compose start fullstack-sqlite'
sh './scripts/wait-healthy $(docker-compose ps --all -q fullstack-sqlite) 120'
// Run tests // Run tests
sh 'rm -rf test/results' sh 'rm -rf test/results-sqlite'
sh 'docker-compose up cypress-sqlite' sh 'docker-compose up cypress-sqlite'
// Get results // Get results
sh 'docker cp -L "$(docker-compose ps -q cypress-sqlite):/test/results" test/' sh 'docker cp -L "$(docker-compose ps --all -q cypress-sqlite):/test/results" test/results-sqlite'
}
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/*' post {
} always {
} // Dumps to analyze later
} sh 'mkdir -p debug/sqlite'
stage('Integration Tests Mysql') { sh 'docker-compose logs fullstack-sqlite > debug/sqlite/docker_fullstack_sqlite.log'
steps { // Cypress videos and screenshot artifacts
// Bring up a stack dir(path: 'test/results-sqlite') {
sh 'docker-compose up -d fullstack-mysql' archiveArtifacts allowEmptyArchive: true, artifacts: '**/*', excludes: '**/*.xml'
sh './scripts/wait-healthy $(docker-compose ps -q fullstack-mysql) 120' }
junit 'test/results-sqlite/junit/*'
// 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'
} }
stage('Mysql') {
steps {
// Bring up a stack
sh 'docker-compose up -d fullstack-mysql'
sh './scripts/wait-healthy $(docker-compose ps --all -q fullstack-mysql) 120'
dir(path: 'docs/.vuepress/dist') { // Run tests
sh 'tar -czf ../../docs.tgz *' sh 'rm -rf test/results-mysql'
sh 'docker-compose up cypress-mysql'
// Get results
sh 'docker cp -L "$(docker-compose ps --all -q cypress-mysql):/test/results" test/results-mysql'
}
post {
always {
// Dumps to analyze later
sh 'mkdir -p debug/mysql'
sh 'docker-compose logs fullstack-mysql > debug/mysql/docker_fullstack_mysql.log'
sh 'docker-compose logs db > debug/mysql/docker_db.log'
// Cypress videos and screenshot artifacts
dir(path: 'test/results-mysql') {
archiveArtifacts allowEmptyArchive: true, artifacts: '**/*', excludes: '**/*.xml'
}
junit 'test/results-mysql/junit/*'
}
}
} }
archiveArtifacts(artifacts: 'docs/docs.tgz', allowEmptyArchive: false)
} }
} }
stage('MultiArch Build') { stage('MultiArch Build') {
@ -170,31 +183,48 @@ pipeline {
} }
} }
} }
stage('Docs Deploy') { stage('Docs / Comment') {
when { parallel {
allOf { stage('Master Docs') {
branch 'master' when {
not { allOf {
equals expected: 'UNSTABLE', actual: currentBuild.result branch 'master'
not {
equals expected: 'UNSTABLE', actual: currentBuild.result
}
}
}
steps {
npmDocsReleaseMaster()
} }
} }
} stage('Develop Docs') {
steps { when {
npmDocsRelease("$DOCS_BUCKET", "$DOCS_CDN") allOf {
} branch 'develop'
} not {
stage('PR Comment') { equals expected: 'UNSTABLE', actual: currentBuild.result
when { }
allOf { }
changeRequest() }
not { steps {
equals expected: 'UNSTABLE', actual: currentBuild.result npmDocsReleaseDevelop()
} }
} }
} stage('PR Comment') {
steps { when {
script { allOf {
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) 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)
}
}
} }
} }
} }
@ -210,12 +240,12 @@ pipeline {
sh 'figlet "SUCCESS"' sh 'figlet "SUCCESS"'
} }
failure { failure {
archiveArtifacts(artifacts: 'debug/**.*', allowEmptyArchive: true) archiveArtifacts(artifacts: 'debug/**/*.*', allowEmptyArchive: true)
juxtapose event: 'failure' juxtapose event: 'failure'
sh 'figlet "FAILURE"' sh 'figlet "FAILURE"'
} }
unstable { unstable {
archiveArtifacts(artifacts: 'debug/**.*', allowEmptyArchive: true) archiveArtifacts(artifacts: 'debug/**/*.*', allowEmptyArchive: true)
juxtapose event: 'unstable' juxtapose event: 'unstable'
sh 'figlet "UNSTABLE"' sh 'figlet "UNSTABLE"'
} }

View File

@ -1,7 +1,7 @@
<p align="center"> <p align="center">
<img src="https://nginxproxymanager.com/github.png"> <img src="https://nginxproxymanager.com/github.png">
<br><br> <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.1-green.svg?style=for-the-badge">
<a href="https://hub.docker.com/repository/docker/jc21/nginx-proxy-manager"> <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"> <img src="https://img.shields.io/docker/stars/jc21/nginx-proxy-manager.svg?style=for-the-badge">
</a> </a>
@ -98,7 +98,18 @@ Password: changeme
Immediately after logging in with this default user you will be asked to modify your details and change your password. 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). Special thanks to [all of our contributors](https://github.com/NginxProxyManager/nginx-proxy-manager/graphs/contributors).
@ -107,5 +118,4 @@ Special thanks to [all of our contributors](https://github.com/NginxProxyManager
1. [Found a bug?](https://github.com/NginxProxyManager/nginx-proxy-manager/issues) 1. [Found a bug?](https://github.com/NginxProxyManager/nginx-proxy-manager/issues)
2. [Discussions](https://github.com/NginxProxyManager/nginx-proxy-manager/discussions) 2. [Discussions](https://github.com/NginxProxyManager/nginx-proxy-manager/discussions)
3. [Development Gitter](https://gitter.im/nginx-proxy-manager/community) 3. [Reddit](https://reddit.com/r/nginxproxymanager)
4. [Reddit](https://reddit.com/r/nginxproxymanager)

View File

@ -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": { "/schema": {
"get": { "get": {
"operationId": "schema", "operationId": "schema",
@ -55,14 +259,10 @@
"get": { "get": {
"operationId": "refreshToken", "operationId": "refreshToken",
"summary": "Refresh your access token", "summary": "Refresh your access token",
"tags": [ "tags": ["Tokens"],
"Tokens"
],
"security": [ "security": [
{ {
"BearerAuth": [ "BearerAuth": ["tokens"]
"tokens"
]
} }
], ],
"responses": { "responses": {
@ -104,19 +304,14 @@
"scope": { "scope": {
"minLength": 1, "minLength": 1,
"type": "string", "type": "string",
"enum": [ "enum": ["user"]
"user"
]
}, },
"secret": { "secret": {
"minLength": 1, "minLength": 1,
"type": "string" "type": "string"
} }
}, },
"required": [ "required": ["identity", "secret"],
"identity",
"secret"
],
"type": "object" "type": "object"
} }
} }
@ -144,23 +339,17 @@
} }
}, },
"summary": "Request a new access token from credentials", "summary": "Request a new access token from credentials",
"tags": [ "tags": ["Tokens"]
"Tokens"
]
} }
}, },
"/settings": { "/settings": {
"get": { "get": {
"operationId": "getSettings", "operationId": "getSettings",
"summary": "Get all settings", "summary": "Get all settings",
"tags": [ "tags": ["Settings"],
"Settings"
],
"security": [ "security": [
{ {
"BearerAuth": [ "BearerAuth": ["settings"]
"settings"
]
} }
], ],
"responses": { "responses": {
@ -194,14 +383,10 @@
"get": { "get": {
"operationId": "getSetting", "operationId": "getSetting",
"summary": "Get a setting", "summary": "Get a setting",
"tags": [ "tags": ["Settings"],
"Settings"
],
"security": [ "security": [
{ {
"BearerAuth": [ "BearerAuth": ["settings"]
"settings"
]
} }
], ],
"parameters": [ "parameters": [
@ -244,14 +429,10 @@
"put": { "put": {
"operationId": "updateSetting", "operationId": "updateSetting",
"summary": "Update a setting", "summary": "Update a setting",
"tags": [ "tags": ["Settings"],
"Settings"
],
"security": [ "security": [
{ {
"BearerAuth": [ "BearerAuth": ["settings"]
"settings"
]
} }
], ],
"parameters": [ "parameters": [
@ -305,14 +486,10 @@
"get": { "get": {
"operationId": "getUsers", "operationId": "getUsers",
"summary": "Get all users", "summary": "Get all users",
"tags": [ "tags": ["Users"],
"Users"
],
"security": [ "security": [
{ {
"BearerAuth": [ "BearerAuth": ["users"]
"users"
]
} }
], ],
"parameters": [ "parameters": [
@ -322,9 +499,7 @@
"description": "Expansions", "description": "Expansions",
"schema": { "schema": {
"type": "string", "type": "string",
"enum": [ "enum": ["permissions"]
"permissions"
]
} }
} }
], ],
@ -345,9 +520,7 @@
"name": "Jamie Curnow", "name": "Jamie Curnow",
"nickname": "James", "nickname": "James",
"avatar": "//www.gravatar.com/avatar/6193176330f8d38747f038c170ddb193?default=mm", "avatar": "//www.gravatar.com/avatar/6193176330f8d38747f038c170ddb193?default=mm",
"roles": [ "roles": ["admin"]
"admin"
]
} }
] ]
}, },
@ -362,9 +535,7 @@
"name": "Jamie Curnow", "name": "Jamie Curnow",
"nickname": "James", "nickname": "James",
"avatar": "//www.gravatar.com/avatar/6193176330f8d38747f038c170ddb193?default=mm", "avatar": "//www.gravatar.com/avatar/6193176330f8d38747f038c170ddb193?default=mm",
"roles": [ "roles": ["admin"],
"admin"
],
"permissions": { "permissions": {
"visibility": "all", "visibility": "all",
"proxy_hosts": "manage", "proxy_hosts": "manage",
@ -389,14 +560,10 @@
"post": { "post": {
"operationId": "createUser", "operationId": "createUser",
"summary": "Create a User", "summary": "Create a User",
"tags": [ "tags": ["Users"],
"Users"
],
"security": [ "security": [
{ {
"BearerAuth": [ "BearerAuth": ["users"]
"users"
]
} }
], ],
"parameters": [ "parameters": [
@ -426,9 +593,7 @@
"name": "Jamie Curnow", "name": "Jamie Curnow",
"nickname": "James", "nickname": "James",
"avatar": "//www.gravatar.com/avatar/6193176330f8d38747f038c170ddb193?default=mm", "avatar": "//www.gravatar.com/avatar/6193176330f8d38747f038c170ddb193?default=mm",
"roles": [ "roles": ["admin"],
"admin"
],
"permissions": { "permissions": {
"visibility": "all", "visibility": "all",
"proxy_hosts": "manage", "proxy_hosts": "manage",
@ -454,14 +619,10 @@
"get": { "get": {
"operationId": "getUser", "operationId": "getUser",
"summary": "Get a user", "summary": "Get a user",
"tags": [ "tags": ["Users"],
"Users"
],
"security": [ "security": [
{ {
"BearerAuth": [ "BearerAuth": ["users"]
"users"
]
} }
], ],
"parameters": [ "parameters": [
@ -501,9 +662,7 @@
"name": "Jamie Curnow", "name": "Jamie Curnow",
"nickname": "James", "nickname": "James",
"avatar": "//www.gravatar.com/avatar/6193176330f8d38747f038c170ddb193?default=mm", "avatar": "//www.gravatar.com/avatar/6193176330f8d38747f038c170ddb193?default=mm",
"roles": [ "roles": ["admin"]
"admin"
]
} }
} }
}, },
@ -518,14 +677,10 @@
"put": { "put": {
"operationId": "updateUser", "operationId": "updateUser",
"summary": "Update a User", "summary": "Update a User",
"tags": [ "tags": ["Users"],
"Users"
],
"security": [ "security": [
{ {
"BearerAuth": [ "BearerAuth": ["users"]
"users"
]
} }
], ],
"parameters": [ "parameters": [
@ -574,9 +729,7 @@
"name": "Jamie Curnow", "name": "Jamie Curnow",
"nickname": "James", "nickname": "James",
"avatar": "//www.gravatar.com/avatar/6193176330f8d38747f038c170ddb193?default=mm", "avatar": "//www.gravatar.com/avatar/6193176330f8d38747f038c170ddb193?default=mm",
"roles": [ "roles": ["admin"]
"admin"
]
} }
} }
}, },
@ -591,14 +744,10 @@
"delete": { "delete": {
"operationId": "deleteUser", "operationId": "deleteUser",
"summary": "Delete a User", "summary": "Delete a User",
"tags": [ "tags": ["Users"],
"Users"
],
"security": [ "security": [
{ {
"BearerAuth": [ "BearerAuth": ["users"]
"users"
]
} }
], ],
"parameters": [ "parameters": [
@ -637,14 +786,10 @@
"put": { "put": {
"operationId": "updateUserAuth", "operationId": "updateUserAuth",
"summary": "Update a User's Authentication", "summary": "Update a User's Authentication",
"tags": [ "tags": ["Users"],
"Users"
],
"security": [ "security": [
{ {
"BearerAuth": [ "BearerAuth": ["users"]
"users"
]
} }
], ],
"parameters": [ "parameters": [
@ -700,14 +845,10 @@
"put": { "put": {
"operationId": "updateUserPermissions", "operationId": "updateUserPermissions",
"summary": "Update a User's Permissions", "summary": "Update a User's Permissions",
"tags": [ "tags": ["Users"],
"Users"
],
"security": [ "security": [
{ {
"BearerAuth": [ "BearerAuth": ["users"]
"users"
]
} }
], ],
"parameters": [ "parameters": [
@ -755,14 +896,10 @@
"put": { "put": {
"operationId": "loginAsUser", "operationId": "loginAsUser",
"summary": "Login as this user", "summary": "Login as this user",
"tags": [ "tags": ["Users"],
"Users"
],
"security": [ "security": [
{ {
"BearerAuth": [ "BearerAuth": ["users"]
"users"
]
} }
], ],
"parameters": [ "parameters": [
@ -797,9 +934,7 @@
"name": "Jamie Curnow", "name": "Jamie Curnow",
"nickname": "James", "nickname": "James",
"avatar": "//www.gravatar.com/avatar/3c8d73f45fd8763f827b964c76e6032a?default=mm", "avatar": "//www.gravatar.com/avatar/3c8d73f45fd8763f827b964c76e6032a?default=mm",
"roles": [ "roles": ["admin"]
"admin"
]
} }
} }
} }
@ -807,11 +942,7 @@
"schema": { "schema": {
"type": "object", "type": "object",
"description": "Login object", "description": "Login object",
"required": [ "required": ["expires", "token", "user"],
"expires",
"token",
"user"
],
"additionalProperties": false, "additionalProperties": false,
"properties": { "properties": {
"expires": { "expires": {
@ -840,14 +971,10 @@
"get": { "get": {
"operationId": "reportsHosts", "operationId": "reportsHosts",
"summary": "Report on Host Statistics", "summary": "Report on Host Statistics",
"tags": [ "tags": ["Reports"],
"Reports"
],
"security": [ "security": [
{ {
"BearerAuth": [ "BearerAuth": ["reports"]
"reports"
]
} }
], ],
"responses": { "responses": {
@ -878,14 +1005,10 @@
"get": { "get": {
"operationId": "getAuditLog", "operationId": "getAuditLog",
"summary": "Get Audit Log", "summary": "Get Audit Log",
"tags": [ "tags": ["Audit Log"],
"Audit Log"
],
"security": [ "security": [
{ {
"BearerAuth": [ "BearerAuth": ["audit-log"]
"audit-log"
]
} }
], ],
"responses": { "responses": {
@ -925,10 +1048,7 @@
"type": "object", "type": "object",
"description": "Health object", "description": "Health object",
"additionalProperties": false, "additionalProperties": false,
"required": [ "required": ["status", "version"],
"status",
"version"
],
"properties": { "properties": {
"status": { "status": {
"type": "string", "type": "string",
@ -944,11 +1064,7 @@
"revision": 0 "revision": 0
}, },
"additionalProperties": false, "additionalProperties": false,
"required": [ "required": ["major", "minor", "revision"],
"major",
"minor",
"revision"
],
"properties": { "properties": {
"major": { "major": {
"type": "integer", "type": "integer",
@ -969,10 +1085,7 @@
"TokenObject": { "TokenObject": {
"type": "object", "type": "object",
"description": "Token object", "description": "Token object",
"required": [ "required": ["expires", "token"],
"expires",
"token"
],
"additionalProperties": false, "additionalProperties": false,
"properties": { "properties": {
"expires": { "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": { "SettingObject": {
"type": "object", "type": "object",
"description": "Setting object", "description": "Setting object",
"required": [ "required": ["id", "name", "description", "value", "meta"],
"id",
"name",
"description",
"value",
"meta"
],
"additionalProperties": false, "additionalProperties": false,
"properties": { "properties": {
"id": { "id": {
@ -1057,17 +1301,7 @@
"UserObject": { "UserObject": {
"type": "object", "type": "object",
"description": "User object", "description": "User object",
"required": [ "required": ["id", "created_on", "modified_on", "is_disabled", "email", "name", "nickname", "avatar", "roles"],
"id",
"created_on",
"modified_on",
"is_disabled",
"email",
"name",
"nickname",
"avatar",
"roles"
],
"additionalProperties": false, "additionalProperties": false,
"properties": { "properties": {
"id": { "id": {
@ -1117,9 +1351,7 @@
}, },
"roles": { "roles": {
"description": "Roles applied", "description": "Roles applied",
"example": [ "example": ["admin"],
"admin"
],
"type": "array", "type": "array",
"items": { "items": {
"type": "string" "type": "string"
@ -1137,10 +1369,7 @@
"AuthObject": { "AuthObject": {
"type": "object", "type": "object",
"description": "Authentication Object", "description": "Authentication Object",
"required": [ "required": ["type", "secret"],
"type",
"secret"
],
"properties": { "properties": {
"type": { "type": {
"type": "string", "type": "string",
@ -1167,64 +1396,37 @@
"visibility": { "visibility": {
"type": "string", "type": "string",
"description": "Visibility Type", "description": "Visibility Type",
"enum": [ "enum": ["all", "user"]
"all",
"user"
]
}, },
"access_lists": { "access_lists": {
"type": "string", "type": "string",
"description": "Access Lists Permissions", "description": "Access Lists Permissions",
"enum": [ "enum": ["hidden", "view", "manage"]
"hidden",
"view",
"manage"
]
}, },
"dead_hosts": { "dead_hosts": {
"type": "string", "type": "string",
"description": "404 Hosts Permissions", "description": "404 Hosts Permissions",
"enum": [ "enum": ["hidden", "view", "manage"]
"hidden",
"view",
"manage"
]
}, },
"proxy_hosts": { "proxy_hosts": {
"type": "string", "type": "string",
"description": "Proxy Hosts Permissions", "description": "Proxy Hosts Permissions",
"enum": [ "enum": ["hidden", "view", "manage"]
"hidden",
"view",
"manage"
]
}, },
"redirection_hosts": { "redirection_hosts": {
"type": "string", "type": "string",
"description": "Redirection Permissions", "description": "Redirection Permissions",
"enum": [ "enum": ["hidden", "view", "manage"]
"hidden",
"view",
"manage"
]
}, },
"streams": { "streams": {
"type": "string", "type": "string",
"description": "Streams Permissions", "description": "Streams Permissions",
"enum": [ "enum": ["hidden", "view", "manage"]
"hidden",
"view",
"manage"
]
}, },
"certificates": { "certificates": {
"type": "string", "type": "string",
"description": "Certificates Permissions", "description": "Certificates Permissions",
"enum": [ "enum": ["hidden", "view", "manage"]
"hidden",
"view",
"manage"
]
} }
} }
}, },

View File

@ -8,10 +8,12 @@ const config = require('../lib/config');
const error = require('../lib/error'); const error = require('../lib/error');
const utils = require('../lib/utils'); const utils = require('../lib/utils');
const certificateModel = require('../models/certificate'); 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 internalAuditLog = require('./audit-log');
const internalNginx = require('./nginx'); const internalNginx = require('./nginx');
const internalHost = require('./host'); const internalHost = require('./host');
const certbot = require('../lib/certbot');
const archiver = require('archiver'); const archiver = require('archiver');
const path = require('path'); const path = require('path');
const { isArray } = require('lodash'); const { isArray } = require('lodash');
@ -26,10 +28,11 @@ function omissions() {
const internalCertificate = { const internalCertificate = {
allowedSslFiles: ['certificate', 'certificate_key', 'intermediate_certificate'], allowedSslFiles: ['certificate', 'certificate_key', 'intermediate_certificate'],
intervalTimeout: 1000 * 60 * 60, // 1 hour intervalTimeout: 1000 * 60 * 60, // 1 hour
interval: null, interval: null,
intervalProcessing: false, intervalProcessing: false,
renewBeforeExpirationBy: [30, 'days'],
initTimer: () => { initTimer: () => {
logger.info('Let\'s Encrypt Renewal Timer initialized'); logger.info('Let\'s Encrypt Renewal Timer initialized');
@ -44,62 +47,51 @@ const internalCertificate = {
processExpiringHosts: () => { processExpiringHosts: () => {
if (!internalCertificate.intervalProcessing) { if (!internalCertificate.intervalProcessing) {
internalCertificate.intervalProcessing = true; 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 ' + const expirationThreshold = moment().add(internalCertificate.renewBeforeExpirationBy[0], internalCertificate.renewBeforeExpirationBy[1]).format('YYYY-MM-DD HH:mm:ss');
'--config "' + letsencryptConfig + '" ' +
'--work-dir "/tmp/letsencrypt-lib" ' +
'--logs-dir "/tmp/letsencrypt-log" ' +
'--preferred-challenges "dns,http" ' +
'--disable-hook-validation ' +
(letsencryptStaging ? '--staging' : '');
return utils.exec(cmd) // Fetch all the letsencrypt certs from the db that will expire within the configured threshold
.then((result) => { certificateModel
if (result) { .query()
logger.info('Renew Result: ' + result); .where('is_deleted', 0)
.andWhere('provider', 'letsencrypt')
.andWhere('expires_on', '<', expirationThreshold)
.then((certificates) => {
if (!certificates || !certificates.length) {
return null;
} }
return internalNginx.reload() /**
.then(() => { * Renews must be run sequentially or we'll get an error 'Another
logger.info('Renew Complete'); * instance of Certbot is already running.'
return result; */
}); let sequence = Promise.resolve();
})
.then(() => { certificates.forEach(function (certificate) {
// Now go and fetch all the letsencrypt certs from the db and query the files and update expiry times sequence = sequence.then(() =>
return certificateModel internalCertificate
.query() .renew(
.where('is_deleted', 0) {
.andWhere('provider', 'letsencrypt') can: () =>
.then((certificates) => { Promise.resolve({
if (certificates && certificates.length) { permission_visibility: 'all',
let promises = []; }),
token: new tokenModel(),
certificates.map(function (certificate) { },
promises.push( { id: certificate.id },
internalCertificate.getCertificateInfoFromFile('/etc/letsencrypt/live/npm-' + certificate.id + '/fullchain.pem') )
.then((cert_info) => { .catch((err) => {
return certificateModel // Don't want to stop the train here, just log the error
.query() logger.error(err.message);
.where('id', certificate.id) }),
.andWhere('provider', 'letsencrypt') );
.patch({ });
expires_on: moment(cert_info.dates.to, 'X').format('YYYY-MM-DD HH:mm:ss')
}); return sequence;
})
.catch((err) => {
// Don't want to stop the train here, just log the error
logger.error(err.message);
})
);
});
return Promise.all(promises);
}
});
}) })
.then(() => { .then(() => {
logger.info('Completed SSL cert renew process');
internalCertificate.intervalProcessing = false; internalCertificate.intervalProcessing = false;
}) })
.catch((err) => { .catch((err) => {
@ -858,26 +850,20 @@ const internalCertificate = {
/** /**
* @param {Object} certificate the certificate row * @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 | null} credentials the content of this providers credentials file
* @param {String} propagation_seconds the cloudflare api token * @param {String} propagation_seconds
* @returns {Promise} * @returns {Promise}
*/ */
requestLetsEncryptSslWithDnsChallenge: (certificate) => { requestLetsEncryptSslWithDnsChallenge: async (certificate) => {
const dns_plugin = dnsPlugins[certificate.meta.dns_provider]; await certbot.installPlugin(certificate.meta.dns_provider);
const dnsPlugin = dnsPlugins[certificate.meta.dns_provider];
if (!dns_plugin) { logger.info(`Requesting Let'sEncrypt certificates via ${dnsPlugin.name} for Cert #${certificate.id}: ${certificate.domain_names.join(', ')}`);
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(', ')}`);
const credentialsLocation = '/etc/letsencrypt/credentials/credentials-' + certificate.id; const credentialsLocation = '/etc/letsencrypt/credentials/credentials-' + certificate.id;
// Escape single quotes and backslashes // Escape single quotes and backslashes
const escapedCredentials = certificate.meta.dns_provider_credentials.replaceAll('\'', '\\\'').replaceAll('\\', '\\\\'); 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 + '\''; 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';
// Whether the plugin has a --<name>-credentials argument // Whether the plugin has a --<name>-credentials argument
const hasConfigArg = certificate.meta.dns_provider !== 'route53'; const hasConfigArg = certificate.meta.dns_provider !== 'route53';
@ -890,15 +876,15 @@ const internalCertificate = {
'--agree-tos ' + '--agree-tos ' +
'--email "' + certificate.meta.letsencrypt_email + '" ' + '--email "' + certificate.meta.letsencrypt_email + '" ' +
'--domains "' + certificate.domain_names.join(',') + '" ' + '--domains "' + certificate.domain_names.join(',') + '" ' +
'--authenticator ' + dns_plugin.full_plugin_name + ' ' + '--authenticator ' + dnsPlugin.full_plugin_name + ' ' +
( (
hasConfigArg hasConfigArg
? '--' + dns_plugin.full_plugin_name + '-credentials "' + credentialsLocation + '"' ? '--' + dnsPlugin.full_plugin_name + '-credentials "' + credentialsLocation + '"'
: '' : ''
) + ) +
( (
certificate.meta.propagation_seconds !== undefined 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' : ''); (letsencryptStaging ? ' --staging' : '');
@ -908,24 +894,23 @@ const internalCertificate = {
mainCmd = 'AWS_CONFIG_FILE=\'' + credentialsLocation + '\' ' + mainCmd; 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) logger.info('Command:', `${credentialsCmd} && && ${mainCmd}`);
.then(() => {
return utils.exec(prepareCmd) try {
.then(() => { await utils.exec(credentialsCmd);
return utils.exec(mainCmd) const result = await utils.exec(mainCmd);
.then(async (result) => { logger.info(result);
logger.info(result); return result;
return result; } catch (err) {
}); // Don't fail if file does not exist
}); const delete_credentialsCmd = `rm -f '${credentialsLocation}' || true`;
}).catch(async (err) => { await utils.exec(delete_credentialsCmd);
// Don't fail if file does not exist throw err;
const delete_credentialsCmd = `rm -f '${credentialsLocation}' || true`; }
await utils.exec(delete_credentialsCmd);
throw err;
});
}, },
@ -1004,15 +989,15 @@ const internalCertificate = {
* @returns {Promise} * @returns {Promise}
*/ */
renewLetsEncryptSslWithDnsChallenge: (certificate) => { 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}'`); 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 + '" ' + '--config "' + letsencryptConfig + '" ' +
'--work-dir "/tmp/letsencrypt-lib" ' + '--work-dir "/tmp/letsencrypt-lib" ' +
'--logs-dir "/tmp/letsencrypt-log" ' + '--logs-dir "/tmp/letsencrypt-log" ' +
@ -1046,6 +1031,8 @@ const internalCertificate = {
const mainCmd = certbotCommand + ' revoke ' + const mainCmd = certbotCommand + ' revoke ' +
'--config "' + letsencryptConfig + '" ' + '--config "' + letsencryptConfig + '" ' +
'--work-dir "/tmp/letsencrypt-lib" ' +
'--logs-dir "/tmp/letsencrypt-log" ' +
'--cert-path "/etc/letsencrypt/live/npm-' + certificate.id + '/fullchain.pem" ' + '--cert-path "/etc/letsencrypt/live/npm-' + certificate.id + '/fullchain.pem" ' +
'--delete-after-revoke ' + '--delete-after-revoke ' +
(letsencryptStaging ? '--staging' : ''); (letsencryptStaging ? '--staging' : '');
@ -1163,6 +1150,7 @@ const internalCertificate = {
const options = { const options = {
method: 'POST', method: 'POST',
headers: { headers: {
'User-Agent': 'Mozilla/5.0',
'Content-Type': 'application/x-www-form-urlencoded', 'Content-Type': 'application/x-www-form-urlencoded',
'Content-Length': Buffer.byteLength(formBody) 'Content-Length': Buffer.byteLength(formBody)
} }
@ -1175,12 +1163,22 @@ const internalCertificate = {
res.on('data', (chunk) => responseBody = responseBody + chunk); res.on('data', (chunk) => responseBody = responseBody + chunk);
res.on('end', function () { res.on('end', function () {
const parsedBody = JSON.parse(responseBody + ''); try {
if (res.statusCode !== 200) { const parsedBody = JSON.parse(responseBody + '');
logger.warn(`Failed to test HTTP challenge for domain ${domain}`, res); 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(undefined);
} }
resolve(parsedBody);
}); });
}); });
@ -1194,6 +1192,9 @@ const internalCertificate = {
if (!result) { if (!result) {
// Some error occurred while trying to get the data // Some error occurred while trying to get the data
return 'failed'; 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') { } else if (`${result.responsecode}` === '200' && result.htmlresponse === 'Success') {
// Server exists and has responded with the correct data // Server exists and has responded with the correct data
return 'ok'; return 'ok';

View File

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

78
backend/lib/certbot.js Normal file
View 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;

View File

@ -82,7 +82,16 @@ module.exports = {
this.message = message; this.message = message;
this.public = false; this.public = false;
this.status = 400; 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) { _.forEach(module.exports, function (error) {

View File

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

View File

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

View File

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

View File

@ -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);
}
});

View File

@ -6,8 +6,7 @@ const userPermissionModel = require('./models/user_permission');
const utils = require('./lib/utils'); const utils = require('./lib/utils');
const authModel = require('./models/auth'); const authModel = require('./models/auth');
const settingModel = require('./models/setting'); 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 * Creates a default admin users if one doesn't already exist in the database
* *
@ -116,10 +115,9 @@ const setupCertbotPlugins = () => {
certificates.map(function (certificate) { certificates.map(function (certificate) {
if (certificate.meta && certificate.meta.dns_challenge === true) { if (certificate.meta && certificate.meta.dns_challenge === true) {
const dns_plugin = dns_plugins[certificate.meta.dns_provider]; if (plugins.indexOf(certificate.meta.dns_provider) === -1) {
plugins.push(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);
// Make sure credentials file exists // Make sure credentials file exists
const credentials_loc = '/etc/letsencrypt/credentials/credentials-' + certificate.id; const credentials_loc = '/etc/letsencrypt/credentials/credentials-' + certificate.id;
@ -130,17 +128,15 @@ const setupCertbotPlugins = () => {
} }
}); });
if (plugins.length) { return certbot.installPlugins(plugins)
const install_cmd = '. /opt/certbot/bin/activate && pip install --no-cache-dir --user ' + plugins.join(' ') + ' && deactivate'; .then(() => {
promises.push(utils.exec(install_cmd)); if (promises.length) {
} return Promise.all(promises)
.then(() => {
if (promises.length) { logger.info('Added Certbot plugins ' + plugins.join(', '));
return Promise.all(promises) });
.then(() => { }
logger.info('Added Certbot plugins ' + plugins.join(', ')); });
});
}
} }
}); });
}; };

View File

@ -2,7 +2,7 @@
{% if ssl_forced == 1 or ssl_forced == true %} {% if ssl_forced == 1 or ssl_forced == true %}
{% if hsts_enabled == 1 or hsts_enabled == true %} {% if hsts_enabled == 1 or hsts_enabled == true %}
# HSTS (ngx_http_headers_module is required) (63072000 seconds = 2 years) # 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 %} {% endif %}
{% endif %} {% endif %}

View File

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

View File

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

View File

@ -1,3 +1,5 @@
{% include "_hsts_map.conf" %}
location {{ path }} { location {{ path }} {
proxy_set_header Host $host; proxy_set_header Host $host;
proxy_set_header X-Forwarded-Scheme $scheme; proxy_set_header X-Forwarded-Scheme $scheme;

View File

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

View File

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

View File

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

View File

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

View File

@ -2850,19 +2850,19 @@ semver-diff@^3.1.1:
semver "^6.3.0" semver "^6.3.0"
semver@^5.3.0, semver@^5.7.1: semver@^5.3.0, semver@^5.7.1:
version "5.7.1" version "5.7.2"
resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.2.tgz#48d55db737c3287cd4835e17fa13feace1c41ef8"
integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== integrity sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==
semver@^6.0.0, semver@^6.2.0, semver@^6.3.0: semver@^6.0.0, semver@^6.2.0, semver@^6.3.0:
version "6.3.0" version "6.3.1"
resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4"
integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==
semver@^7.3.5, semver@^7.3.8: semver@^7.3.5, semver@^7.3.8:
version "7.3.8" version "7.5.4"
resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.8.tgz#07a78feafb3f7b32347d725e33de7e2a2df67798" resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.4.tgz#483986ec4ed38e1c6c48c34894a9182dbff68a6e"
integrity sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A== integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==
dependencies: dependencies:
lru-cache "^6.0.0" lru-cache "^6.0.0"
@ -3396,9 +3396,9 @@ widest-line@^3.1.0:
string-width "^4.0.0" string-width "^4.0.0"
word-wrap@^1.2.3: word-wrap@^1.2.3:
version "1.2.3" version "1.2.4"
resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.4.tgz#cb4b50ec9aca570abd1f52f33cd45b6c61739a9f"
integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ== integrity sha512-2V81OA4ugVo5pRo46hAoD2ivUJx8jXmWXfUkY4KFNw0hEptvN0QfH3K4nHiwzGeKl5rFKedV48QVoqYavy4YpA==
wrap-ansi@^6.2.0: wrap-ansi@^6.2.0:
version "6.2.0" version "6.2.0"

View File

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

View File

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

View File

@ -14,7 +14,8 @@ services:
DB_MYSQL_PASSWORD: 'npm' DB_MYSQL_PASSWORD: 'npm'
DB_MYSQL_NAME: 'npm' DB_MYSQL_NAME: 'npm'
volumes: volumes:
- npm_data:/data - npm_data_mysql:/data
- npm_le_mysql:/etc/letsencrypt
expose: expose:
- 81 - 81
- 80 - 80
@ -22,7 +23,7 @@ services:
depends_on: depends_on:
- db - db
healthcheck: healthcheck:
test: ["CMD", "/bin/check-health"] test: ["CMD", "/usr/bin/check-health"]
interval: 10s interval: 10s
timeout: 3s timeout: 3s
@ -33,14 +34,18 @@ services:
LE_STAGING: 'true' LE_STAGING: 'true'
FORCE_COLOR: 1 FORCE_COLOR: 1
DB_SQLITE_FILE: '/data/mydb.sqlite' DB_SQLITE_FILE: '/data/mydb.sqlite'
PUID: 1000
PGID: 1000
DISABLE_IPV6: 'true'
volumes: volumes:
- npm_data:/data - npm_data_sqlite:/data
- npm_le_sqlite:/etc/letsencrypt
expose: expose:
- 81 - 81
- 80 - 80
- 443 - 443
healthcheck: healthcheck:
test: ["CMD", "/bin/check-health"] test: ["CMD", "/usr/bin/check-health"]
interval: 10s interval: 10s
timeout: 3s timeout: 3s
@ -52,7 +57,7 @@ services:
MYSQL_USER: 'npm' MYSQL_USER: 'npm'
MYSQL_PASSWORD: 'npm' MYSQL_PASSWORD: 'npm'
volumes: volumes:
- db_data:/var/lib/mysql - mysql_data:/var/lib/mysql
cypress-mysql: cypress-mysql:
image: "${IMAGE}-cypress:ci-${BUILD_NUMBER}" image: "${IMAGE}-cypress:ci-${BUILD_NUMBER}"
@ -62,7 +67,7 @@ services:
environment: environment:
CYPRESS_baseUrl: 'http://fullstack-mysql:81' CYPRESS_baseUrl: 'http://fullstack-mysql:81'
volumes: volumes:
- cypress-logs:/results - cypress_logs_mysql:/results
command: cypress run --browser chrome --config-file=${CYPRESS_CONFIG:-cypress/config/ci.json} command: cypress run --browser chrome --config-file=${CYPRESS_CONFIG:-cypress/config/ci.json}
cypress-sqlite: cypress-sqlite:
@ -73,10 +78,14 @@ services:
environment: environment:
CYPRESS_baseUrl: "http://fullstack-sqlite:81" CYPRESS_baseUrl: "http://fullstack-sqlite:81"
volumes: volumes:
- cypress-logs:/results - cypress_logs_sqlite:/results
command: cypress run --browser chrome --config-file=${CYPRESS_CONFIG:-cypress/config/ci.json} command: cypress run --browser chrome --config-file=${CYPRESS_CONFIG:-cypress/config/ci.json}
volumes: volumes:
cypress-logs: cypress_logs_mysql:
npm_data: cypress_logs_sqlite:
db_data: npm_data_mysql:
npm_data_sqlite:
npm_le_sqlite:
npm_le_mysql:
mysql_data:

View File

@ -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
}

View File

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

View File

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

View File

@ -1,3 +1,10 @@
set $test "";
if ($scheme = "http") { 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; return 301 https://$host$request_uri;
} }

View File

@ -1,6 +1,7 @@
# run nginx in foreground # run nginx in foreground
daemon off; daemon off;
pid /run/nginx/nginx.pid; pid /run/nginx/nginx.pid;
user npm;
# Set number of worker processes automatically based on number of CPU cores. # Set number of worker processes automatically based on number of CPU cores.
worker_processes auto; worker_processes auto;

View File

@ -3,20 +3,19 @@
set -e set -e
. /bin/common.sh . /usr/bin/common.sh
cd /app || exit 1
log_info 'Starting backend ...' log_info 'Starting backend ...'
if [ "$DEVELOPMENT" == "true" ]; then if [ "${DEVELOPMENT:-}" = 'true' ]; then
cd /app || exit 1 s6-setuidgid "$PUID:$PGID" yarn install
# If yarn install fails: add --verbose --network-concurrency 1 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"
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'
else else
cd /app || exit 1
while : while :
do 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 sleep 1
done done
fi fi

View File

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

View File

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

View File

@ -3,13 +3,17 @@
set -e set -e
. /bin/common.sh . /usr/bin/common.sh
if [ "$(id -u)" != "0" ]; then 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." 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 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/20-paths.sh
. /etc/s6-overlay/s6-rc.d/prepare/30-ownership.sh . /etc/s6-overlay/s6-rc.d/prepare/30-ownership.sh
. /etc/s6-overlay/s6-rc.d/prepare/40-dynamic.sh . /etc/s6-overlay/s6-rc.d/prepare/40-dynamic.sh

View File

@ -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

View File

@ -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"

View File

@ -8,14 +8,21 @@ log_info 'Setting ownership ...'
# root # root
chown root /tmp/nginx chown root /tmp/nginx
# npmuser # npm user and group
chown -R npmuser:npmuser \ chown -R "$PUID:$PGID" /data
/data \ chown -R "$PUID:$PGID" /etc/letsencrypt
/etc/letsencrypt \ chown -R "$PUID:$PGID" /run/nginx
/etc/nginx \ chown -R "$PUID:$PGID" /tmp/nginx
/run/nginx \ chown -R "$PUID:$PGID" /var/cache/nginx
/tmp/nginx \ chown -R "$PUID:$PGID" /var/lib/logrotate
/var/cache/nginx \ chown -R "$PUID:$PGID" /var/lib/nginx
/var/lib/logrotate \ chown -R "$PUID:$PGID" /var/log/nginx
/var/lib/nginx \
/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
chown -R "$PUID:$PGID" /opt/certbot/lib/python*/site-packages

11
docker/rootfs/etc/s6-overlay/s6-rc.d/prepare/50-ipv6.sh Normal file → Executable file
View 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 # This command reads the `DISABLE_IPV6` env var and will either enable
# or disable ipv6 in all nginx configs based on this setting. # or disable ipv6 in all nginx configs based on this setting.
set -e
log_info 'IPv6 ...' log_info 'IPv6 ...'
# Lowercase # Lowercase
@ -25,11 +28,11 @@ process_folder () {
for FILE in $FILES for FILE in $FILES
do do
echo "- ${FILE}" echo "- ${FILE}"
sed -E -i "$SED_REGEX" "$FILE" echo "$(sed -E "$SED_REGEX" "$FILE")" > $FILE
done done
# ensure the files are still owned by the npmuser # ensure the files are still owned by the npm user
chown -R npmuser:npmuser "$1" chown -R "$PUID:$PGID" "$1"
} }
process_folder /etc/nginx/conf.d process_folder /etc/nginx/conf.d

View File

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

View File

@ -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
}

View File

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

10
docs/.gitignore vendored
View File

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

View File

@ -1,82 +1,120 @@
module.exports = { import { defineUserConfig } from 'vuepress';
locales: { import { defaultTheme } from 'vuepress'
"/": { import { googleAnalyticsPlugin } from '@vuepress/plugin-google-analytics';
lang: "en-US", import { searchPlugin } from '@vuepress/plugin-search'
title: "Nginx Proxy Manager", import { sitemapPlugin } from 'vuepress-plugin-sitemap2';
description: "Expose your services easily and securely" import zoomingPlugin from 'vuepress-plugin-zooming';
}
}, export default defineUserConfig({
head: [ locales: {
["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" }], lang: "en-US",
["meta", { property: "og:title", content: "Nginx Proxy Manager" }], title: "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"}], description: "Expose your services easily and securely",
["meta", { property: "og:type", content: "website" }], },
["meta", { property: "og:url", content: "https://nginxproxymanager.com/" }], },
["meta", { property: "og:image", content: "https://nginxproxymanager.com/icon.png" }], head: [
["meta", { name: "twitter:card", content: "summary"}], ["link", { rel: "icon", href: "/icon.png" }],
["meta", { name: "twitter:title", content: "Nginx Proxy Manager"}], ["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", { 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", { property: "og:title", content: "Nginx Proxy Manager" }],
["meta", { name: "twitter:image", content: "https://nginxproxymanager.com/icon.png"}], ["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", { name: "twitter:alt", content: "Nginx Proxy Manager"}], ["meta", { property: "og:type", content: "website" }],
], ["meta", { property: "og:url", content: "https://nginxproxymanager.com/" }],
themeConfig: { ["meta", { property: "og:image", content: "https://nginxproxymanager.com/icon.png" }],
logo: "/icon.png", ["meta", { name: "twitter:card", content: "summary"}],
// the GitHub repo path ["meta", { name: "twitter:title", content: "Nginx Proxy Manager"}],
repo: "jc21/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"}],
// the label linking to the repo ["meta", { name: "twitter:image", content: "https://nginxproxymanager.com/icon.png"}],
repoLabel: "GitHub", ["meta", { name: "twitter:alt", content: "Nginx Proxy Manager"}],
// if your docs are not at the root of the repo: ],
docsDir: "docs", theme: defaultTheme({
// defaults to false, set to true to enable logo: '/icon.png',
editLinks: true, repo: "jc21/nginx-proxy-manager",
locales: { docsRepo: 'https://github.com/jc21/nginx-proxy-manager',
"/": { docsBranch: 'develop',
// text for the language dropdown docsDir: 'docs',
selectText: "Languages", editLinkPattern: ':repo/edit/:branch/:path',
// label for this locale in the language dropdown locales: {
label: "English", '/': {
// Custom text for edit link. Defaults to "Edit this page" label: 'English',
editLinkText: "Edit this page on GitHub", selectLanguageText: 'Languages',
// Custom navbar values selectLanguageName: 'English',
nav: [{ text: "Setup", link: "/setup/" }], editLinkText: 'Edit this page on GitHub',
// Custom sidebar values navbar: [
sidebar: [ { text: 'Setup', link: '/setup/' }
"/", ],
["/guide/", "Guide"], sidebar: {
["/screenshots/", "Screenshots"], '/': [
["/setup/", "Setup Instructions"], {
["/advanced-config/", "Advanced Configuration"], text: 'Home',
["/upgrading/", "Upgrading"], link: '/'
["/faq/", "Frequently Asked Questions"], },
["/third-party/", "Third Party"] {
] text: 'Guide',
} link: '/guide/',
} collapsible: true,
}, },
plugins: [ {
[ text: 'Screenshots',
"@vuepress/google-analytics", link: '/screenshots/',
{ collapsible: true,
ga: "UA-99675467-4" },
} {
], text: 'Setup Instructions',
[ link: '/setup/',
"sitemap", collapsible: true,
{ },
hostname: "https://nginxproxymanager.com" {
} text: 'Advanced Configuration',
], link: '/advanced-config/',
[ collapsible: true,
'vuepress-plugin-zooming', },
{ {
selector: '.zooming', text: 'Upgrading',
delay: 1000, link: '/upgrading/',
options: { collapsible: true,
bgColor: 'black', },
zIndex: 10000, {
}, text: 'Frequently Asked Questions',
}, link: '/faq/',
], collapsible: true,
] },
}; {
text: 'Third Party',
link: '/third-party/',
collapsible: true,
},
],
},
}
}
}),
markdown: {
code: {
lineNumbers: false,
},
},
plugins: [
googleAnalyticsPlugin({
id: 'UA-99675467-4'
}),
sitemapPlugin({
hostname: "https://nginxproxymanager.com",
}),
zoomingPlugin({
selector: '.zooming',
delay: 1000,
options: {
bgColor: 'black',
zIndex: 10000,
},
}),
searchPlugin({
locales: {
'/': {
placeholder: 'Search',
},
},
}),
],
});

View File

@ -0,0 +1,258 @@
:root {
// brand colors
--c-brand: #f15833;
--c-brand-light: #f15833;
// background colors
--c-bg: #ffffff;
--c-bg-light: #f3f4f5;
--c-bg-lighter: #eeeeee;
--c-bg-dark: #ebebec;
--c-bg-darker: #e6e6e6;
--c-bg-navbar: var(--c-bg);
--c-bg-sidebar: var(--c-bg);
--c-bg-arrow: #cccccc;
// text colors
--c-text: #663015;
--c-text-accent: var(--c-brand);
--c-text-light: #863f1c;
--c-text-lighter: #b65626;
--c-text-lightest: #f15833;
--c-text-quote: #999999;
// border colors
--c-border: #eaecef;
--c-border-dark: #dfe2e5;
// custom container colors
--c-tip: #42b983;
--c-tip-bg: var(--c-bg-light);
--c-tip-title: var(--c-text);
--c-tip-text: var(--c-text);
--c-tip-text-accent: var(--c-text-accent);
--c-warning: #ffc310;
--c-warning-bg: #fffae3;
--c-warning-bg-light: #fff3ba;
--c-warning-bg-lighter: #fff0b0;
--c-warning-border-dark: #f7dc91;
--c-warning-details-bg: #fff5ca;
--c-warning-title: #f1b300;
--c-warning-text: #746000;
--c-warning-text-accent: #edb100;
--c-warning-text-light: #c1971c;
--c-warning-text-quote: #ccab49;
--c-danger: #f11e37;
--c-danger-bg: #ffe0e0;
--c-danger-bg-light: #ffcfde;
--c-danger-bg-lighter: #ffc9c9;
--c-danger-border-dark: #f1abab;
--c-danger-details-bg: #ffd4d4;
--c-danger-title: #ed1e2c;
--c-danger-text: #660000;
--c-danger-text-accent: #bd1a1a;
--c-danger-text-light: #b5474d;
--c-danger-text-quote: #c15b5b;
--c-details-bg: #eeeeee;
// badge component colors
--c-badge-tip: var(--c-tip);
--c-badge-warning: #ecc808;
--c-badge-warning-text: var(--c-bg);
--c-badge-danger: #dc2626;
--c-badge-danger-text: var(--c-bg);
// transition vars
--t-color: 0.3s ease;
--t-transform: 0.3s ease;
// code blocks vars
--code-bg-color: #282c34;
--code-hl-bg-color: rgba(0, 0, 0, 0.66);
--code-ln-color: #9e9e9e;
--code-ln-wrapper-width: 3.5rem;
// font vars
--font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen,
Ubuntu, Cantarell, 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif;
--font-family-code: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
// layout vars
--navbar-height: 3.6rem;
--navbar-padding-v: 0.7rem;
--navbar-padding-h: 1.5rem;
--sidebar-width: 20rem;
--sidebar-width-mobile: calc(var(--sidebar-width) * 0.82);
--content-width: 740px;
--homepage-width: 960px;
}
html.dark {
// brand colors
--c-brand: #f15833;
--c-brand-light: #f15833;
// background colors
--c-bg: #22272e;
--c-bg-light: #2b313a;
--c-bg-lighter: #262c34;
--c-bg-dark: #343b44;
--c-bg-darker: #37404c;
// text colors
--c-text: #adbac7;
--c-text-light: #96a7b7;
--c-text-lighter: #8b9eb0;
--c-text-lightest: #8094a8;
// border colors
--c-border: #3e4c5a;
--c-border-dark: #34404c;
// custom container colors
--c-tip: #318a62;
--c-warning: #e0ad15;
--c-warning-bg: #2d2f2d;
--c-warning-bg-light: #423e2a;
--c-warning-bg-lighter: #44442f;
--c-warning-border-dark: #957c35;
--c-warning-details-bg: #39392d;
--c-warning-title: #fdca31;
--c-warning-text: #d8d96d;
--c-warning-text-accent: #ffbf00;
--c-warning-text-light: #ddb84b;
--c-warning-text-quote: #ccab49;
--c-danger: #fc1e38;
--c-danger-bg: #39232c;
--c-danger-bg-light: #4b2b35;
--c-danger-bg-lighter: #553040;
--c-danger-border-dark: #a25151;
--c-danger-details-bg: #482936;
--c-danger-title: #fc2d3b;
--c-danger-text: #ea9ca0;
--c-danger-text-accent: #fd3636;
--c-danger-text-light: #d9777c;
--c-danger-text-quote: #d56b6b;
--c-details-bg: #323843;
// badge component colors
--c-badge-warning: var(--c-warning);
--c-badge-warning-text: #3c2e05;
--c-badge-danger: var(--c-danger);
--c-badge-danger-text: #401416;
// code blocks vars
--code-hl-bg-color: #363b46;
}
// plugin-back-to-top
.back-to-top {
--back-to-top-color: var(--c-brand);
--back-to-top-color-hover: var(--c-brand-light);
}
// plugin-docsearch
.DocSearch {
--docsearch-primary-color: var(--c-brand);
--docsearch-text-color: var(--c-text);
--docsearch-highlight-color: var(--c-brand);
--docsearch-muted-color: var(--c-text-quote);
--docsearch-container-background: rgba(9, 10, 17, 0.8);
--docsearch-modal-background: var(--c-bg-light);
--docsearch-searchbox-background: var(--c-bg-lighter);
--docsearch-searchbox-focus-background: var(--c-bg);
--docsearch-searchbox-shadow: inset 0 0 0 2px var(--c-brand);
--docsearch-hit-color: var(--c-text-light);
--docsearch-hit-active-color: var(--c-bg);
--docsearch-hit-background: var(--c-bg);
--docsearch-hit-shadow: 0 1px 3px 0 var(--c-border-dark);
--docsearch-footer-background: var(--c-bg);
}
// dark plugin-docsearch
html.dark .DocSearch {
--docsearch-logo-color: var(--c-text);
--docsearch-modal-shadow: inset 1px 1px 0 0 #2c2e40, 0 3px 8px 0 #000309;
--docsearch-key-shadow: inset 0 -2px 0 0 #282d55, inset 0 0 1px 1px #51577d,
0 2px 2px 0 rgba(3, 4, 9, 0.3);
--docsearch-key-gradient: linear-gradient(-225deg, #444950, #1c1e21);
--docsearch-footer-shadow: inset 0 1px 0 0 rgba(73, 76, 106, 0.5),
0 -4px 8px 0 rgba(0, 0, 0, 0.2);
}
// plugin-external-link-icon
.external-link-icon {
--external-link-icon-color: var(--c-text-quote);
}
// plugin-medium-zoom
.medium-zoom-overlay {
--medium-zoom-bg-color: var(--c-bg);
}
// plugin-nprogress
#nprogress {
--nprogress-color: var(--c-brand);
}
// plugin-pwa-popup
.pwa-popup {
--pwa-popup-text-color: var(--c-text);
--pwa-popup-bg-color: var(--c-bg);
--pwa-popup-border-color: var(--c-brand);
--pwa-popup-shadow: 0 4px 16px var(--c-brand);
--pwa-popup-btn-text-color: var(--c-bg);
--pwa-popup-btn-bg-color: var(--c-brand);
--pwa-popup-btn-hover-bg-color: var(--c-brand-light);
}
// plugin-search
.search-box {
--search-bg-color: var(--c-bg);
--search-accent-color: var(--c-brand);
--search-text-color: var(--c-text);
--search-border-color: var(--c-border);
--search-item-text-color: var(--c-text-lighter);
--search-item-focus-bg-color: var(--c-bg-light);
}
.home .hero img {
max-width: 500px !important;
height: 100%;
width: 100%
}
.center {
margin: 0 auto;
width: 80%
}
#main-title {
display: none
}
.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;
}

View File

@ -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;

View File

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

893
docs/.yarn/releases/yarn-4.0.2.cjs vendored Normal file

File diff suppressed because one or more lines are too long

3
docs/.yarnrc.yml Normal file
View File

@ -0,0 +1,3 @@
nodeLinker: node-modules
yarnPath: .yarn/releases/yarn-4.0.2.cjs

View File

@ -1,8 +1,10 @@
--- ---
home: true home: true
heroImage: /logo.png heroImage: /logo.png
actionText: Get Started → actions:
actionLink: /guide/ - text: Get Started
link: /guide/
type: primary
footer: MIT Licensed | Copyright © 2016-present jc21.com footer: MIT Licensed | Copyright © 2016-present jc21.com
--- ---

View File

@ -1,5 +1,26 @@
# Advanced Configuration # 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 ## Best Practice: Use a Docker network
For those who have a few of their upstream services running in Docker on the same Docker For those who have a few of their upstream services running in Docker on the same Docker
@ -55,7 +76,7 @@ feature by adding the following to the service in your `docker-compose.yml` file
```yml ```yml
healthcheck: healthcheck:
test: ["CMD", "/bin/check-health"] test: ["CMD", "/usr/bin/check-health"]
interval: 10s interval: 10s
timeout: 3s timeout: 3s
``` ```
@ -117,8 +138,9 @@ services:
MYSQL_USER: "npm" MYSQL_USER: "npm"
# MYSQL_PASSWORD: "npm" # use secret instead # MYSQL_PASSWORD: "npm" # use secret instead
MYSQL_PASSWORD__FILE: /run/secrets/MYSQL_PWD MYSQL_PASSWORD__FILE: /run/secrets/MYSQL_PWD
MARIADB_AUTO_UPGRADE: '1'
volumes: volumes:
- ./data/mysql:/var/lib/mysql - ./mysql:/var/lib/mysql
secrets: secrets:
- DB_ROOT_PWD - DB_ROOT_PWD
- MYSQL_PWD - MYSQL_PWD
@ -172,3 +194,17 @@ value by specifying it as a Docker environment variable. The default if not spec
X_FRAME_OPTIONS: "sameorigin" 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).

View File

@ -3,775 +3,21 @@
"version": "1.0.0", "version": "1.0.0",
"description": "", "description": "",
"main": "index.js", "main": "index.js",
"dependencies": { "devDependencies": {
"@vuepress/plugin-google-analytics": "^1.5.3", "vuepress": "^2.0.0-rc.0"
"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": { "scripts": {
"dev": "vuepress dev", "dev": "vuepress dev",
"build": "vuepress build" "build": "vuepress build"
}, },
"author": "", "author": "",
"license": "ISC" "license": "ISC",
"packageManager": "yarn@4.0.2",
"dependencies": {
"@vuepress/plugin-google-analytics": "2.0.0-rc.0",
"@vuepress/plugin-search": "2.0.0-rc.0",
"@vuepress/theme-default": "^2.0.0-rc.0",
"vuepress-plugin-sitemap2": "^2.0.0-rc.5",
"vuepress-plugin-zooming": "^1.1.8"
}
} }

View File

@ -35,7 +35,7 @@ services:
Then: Then:
```bash ```bash
docker-compose up -d docker compose up -d
``` ```
## Using MySQL / MariaDB Database ## Using MySQL / MariaDB Database
@ -64,9 +64,6 @@ services:
# Add any other Stream port you want to expose # Add any other Stream port you want to expose
# - '21:21' # FTP # - '21:21' # FTP
environment: environment:
# Unix user and group IDs, optional
PUID: 1000
PGID: 1000
# Mysql/Maria connection parameters: # Mysql/Maria connection parameters:
DB_MYSQL_HOST: "db" DB_MYSQL_HOST: "db"
DB_MYSQL_PORT: 3306 DB_MYSQL_PORT: 3306
@ -89,8 +86,9 @@ services:
MYSQL_DATABASE: 'npm' MYSQL_DATABASE: 'npm'
MYSQL_USER: 'npm' MYSQL_USER: 'npm'
MYSQL_PASSWORD: 'npm' MYSQL_PASSWORD: 'npm'
MARIADB_AUTO_UPGRADE: '1'
volumes: volumes:
- ./data/mysql:/var/lib/mysql - ./mysql:/var/lib/mysql
``` ```
::: warning ::: warning

View File

@ -7,7 +7,7 @@ Known integrations:
- [HomeAssistant Hass.io plugin](https://github.com/hassio-addons/addon-nginx-proxy-manager) - [HomeAssistant Hass.io plugin](https://github.com/hassio-addons/addon-nginx-proxy-manager)
- [UnRaid / Synology](https://github.com/jlesage/docker-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) - [nginxproxymanagerGraf](https://github.com/ma-karai/nginxproxymanagerGraf)

File diff suppressed because it is too large Load Diff

View File

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

View File

@ -74,7 +74,7 @@
<option <option
value="<%- plugin_name %>" value="<%- plugin_name %>"
<%- getDnsProvider() === plugin_name ? 'selected' : '' %> <%- getDnsProvider() === plugin_name ? 'selected' : '' %>
><%- plugin_info.display_name %></option> ><%- plugin_info.name %></option>
<% }); %> <% }); %>
</select> </select>
</div> </div>

View File

@ -11,7 +11,7 @@ require('selectize');
function sortProvidersAlphabetically(obj) { function sortProvidersAlphabetically(obj) {
return Object.entries(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) => { .reduce((result, entry) => {
result[entry[0]] = entry[1]; result[entry[0]] = entry[1];
return result; return result;
@ -265,7 +265,7 @@ module.exports = Mn.View.extend({
this.ui.domain_names.selectize({ this.ui.domain_names.selectize({
delimiter: ',', delimiter: ',',
persist: false, persist: false,
maxOptions: 15, maxOptions: 30,
create: function (input) { create: function (input) {
return { return {
value: input, value: input,

View File

@ -28,7 +28,7 @@
</div> </div>
</td> </td>
<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>
<td class="<%- isExpired() ? 'text-danger' : '' %>"> <td class="<%- isExpired() ? 'text-danger' : '' %>">
<%- formatDbDate(expires_on, 'Do MMMM YYYY, h:mm a') %> <%- formatDbDate(expires_on, 'Do MMMM YYYY, h:mm a') %>

View File

@ -114,7 +114,7 @@
<option <option
value="<%- plugin_name %>" value="<%- plugin_name %>"
<%- getDnsProvider() === plugin_name ? 'selected' : '' %> <%- getDnsProvider() === plugin_name ? 'selected' : '' %>
><%- plugin_info.display_name %></option> ><%- plugin_info.name %></option>
<% }); %> <% }); %>
</select> </select>
</div> </div>

View File

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

View File

@ -182,7 +182,7 @@
<option <option
value="<%- plugin_name %>" value="<%- plugin_name %>"
<%- getDnsProvider() === plugin_name ? 'selected' : '' %> <%- getDnsProvider() === plugin_name ? 'selected' : '' %>
><%- plugin_info.display_name %></option> ><%- plugin_info.name %></option>
<% }); %> <% }); %>
</select> </select>
</div> </div>

View File

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

View File

@ -45,7 +45,7 @@
<div class="col-sm-4 col-md-4"> <div class="col-sm-4 col-md-4">
<div class="form-group"> <div class="form-group">
<label class="form-label"><%- i18n('proxy-hosts', 'forward-port') %> <span class="form-required">*</span></label> <label class="form-label"><%- i18n('proxy-hosts', 'forward-port') %> <span class="form-required">*</span></label>
<input name="forward_port" type="number" class="form-control text-monospace model" placeholder="80" value="<%- forward_port %>" required> <input name="forward_port" type="number" class="form-control text-monospace model" placeholder="80" min="1" max="65535" value="<%- forward_port %>" required>
</div> </div>
</div> </div>
</div> </div>

View File

@ -161,7 +161,7 @@
<option <option
value="<%- plugin_name %>" value="<%- plugin_name %>"
<%- getDnsProvider() === plugin_name ? 'selected' : '' %> <%- getDnsProvider() === plugin_name ? 'selected' : '' %>
><%- plugin_info.display_name %></option> ><%- plugin_info.name %></option>
<% }); %> <% }); %>
</select> </select>
</div> </div>

View File

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

View File

@ -9,7 +9,7 @@
<div class="col-sm-12 col-md-12"> <div class="col-sm-12 col-md-12">
<div class="form-group"> <div class="form-group">
<label class="form-label"><%- i18n('streams', 'incoming-port') %> <span class="form-required">*</span></label> <label class="form-label"><%- i18n('streams', 'incoming-port') %> <span class="form-required">*</span></label>
<input name="incoming_port" type="number" class="form-control text-monospace" placeholder="eg: 8080" value="<%- incoming_port %>" required> <input name="incoming_port" type="number" class="form-control text-monospace" placeholder="eg: 8080" min="1" max="65535" value="<%- incoming_port %>" required>
</div> </div>
</div> </div>
<div class="col-sm-8 col-md-8"> <div class="col-sm-8 col-md-8">
@ -21,7 +21,7 @@
<div class="col-sm-4 col-md-4"> <div class="col-sm-4 col-md-4">
<div class="form-group"> <div class="form-group">
<label class="form-label"><%- i18n('streams', 'forwarding-port') %> <span class="form-required">*</span></label> <label class="form-label"><%- i18n('streams', 'forwarding-port') %> <span class="form-required">*</span></label>
<input name="forwarding_port" type="number" class="form-control text-monospace" placeholder="eg: 80" value="<%- forwarding_port %>" required> <input name="forwarding_port" type="number" class="form-control text-monospace" placeholder="eg: 80" min="1" max="65535" value="<%- forwarding_port %>" required>
</div> </div>
</div> </div>
<div class="col-sm-6 col-md-6"> <div class="col-sm-6 col-md-6">

View File

@ -8,7 +8,7 @@
<div class="row"> <div class="row">
<div class="col-sm-12 col-md-12"> <div class="col-sm-12 col-md-12">
<div class="form-group"> <div class="form-group">
<div class="form-label"><%- description %></div> <div class="form-label"><%- i18n('settings', 'default-site-description') %></div>
<div class="custom-controls-stacked"> <div class="custom-controls-stacked">
<label class="custom-control custom-radio"> <label class="custom-control custom-radio">
<input class="custom-control-input" name="value" value="congratulations" type="radio" required <%- value === 'congratulations' ? 'checked' : '' %>> <input class="custom-control-input" name="value" value="congratulations" type="radio" required <%- value === 'congratulations' ? 'checked' : '' %>>
@ -18,6 +18,10 @@
<input class="custom-control-input" name="value" value="404" type="radio" required <%- value === '404' ? 'checked' : '' %>> <input class="custom-control-input" name="value" value="404" type="radio" required <%- value === '404' ? 'checked' : '' %>>
<div class="custom-control-label"><%- i18n('settings', 'default-site-404') %></div> <div class="custom-control-label"><%- i18n('settings', 'default-site-404') %></div>
</label> </label>
<label class="custom-control custom-radio">
<input class="custom-control-input" name="value" value="444" type="radio" required <%- value === '444' ? 'checked' : '' %>>
<div class="custom-control-label"><%- i18n('settings', 'default-site-444') %></div>
</label>
<label class="custom-control custom-radio"> <label class="custom-control custom-radio">
<input class="custom-control-input" name="value" value="redirect" type="radio" required <%- value === 'redirect' ? 'checked' : '' %>> <input class="custom-control-input" name="value" value="redirect" type="radio" required <%- value === 'redirect' ? 'checked' : '' %>>
<div class="custom-control-label"><%- i18n('settings', 'default-site-redirect') %></div> <div class="custom-control-label"><%- i18n('settings', 'default-site-redirect') %></div>

View File

@ -1,7 +1,7 @@
<td> <td>
<div><%- name %></div> <div><%- i18n('settings', 'default-site') %></div>
<div class="small text-muted"> <div class="small text-muted">
<%- description %> <%- i18n('settings', 'default-site-description') %>
</div> </div>
</td> </td>
<td> <td>

View File

@ -60,7 +60,7 @@
}, },
"footer": { "footer": {
"fork-me": "Fork me on Github", "fork-me": "Fork me on Github",
"copy": "&copy; 2022 <a href=\"{url}\" target=\"_blank\">jc21.com</a>.", "copy": "&copy; 2024 <a href=\"{url}\" target=\"_blank\">jc21.com</a>.",
"theme": "Theme by <a href=\"{url}\" target=\"_blank\">Tabler</a>" "theme": "Theme by <a href=\"{url}\" target=\"_blank\">Tabler</a>"
}, },
"dashboard": { "dashboard": {
@ -285,8 +285,10 @@
"settings": { "settings": {
"title": "Settings", "title": "Settings",
"default-site": "Default Site", "default-site": "Default Site",
"default-site-description": "What to show when Nginx is hit with an unknown Host",
"default-site-congratulations": "Congratulations Page", "default-site-congratulations": "Congratulations Page",
"default-site-404": "404 Page", "default-site-404": "404 Page",
"default-site-444": "No Response (444)",
"default-site-html": "Custom Page", "default-site-html": "Custom Page",
"default-site-redirect": "Redirect" "default-site-redirect": "Redirect"
} }

View File

@ -27,10 +27,10 @@
"messageformat-loader": "^0.8.1", "messageformat-loader": "^0.8.1",
"mini-css-extract-plugin": "^0.9.0", "mini-css-extract-plugin": "^0.9.0",
"moment": "^2.29.4", "moment": "^2.29.4",
"node-sass": "^6.0.1", "node-sass": "^9.0.0",
"nodemon": "^2.0.2", "nodemon": "^2.0.2",
"numeral": "^2.0.6", "numeral": "^2.0.6",
"sass-loader": "10.2.0", "sass-loader": "^10.0.0",
"style-loader": "^1.1.3", "style-loader": "^1.1.3",
"tabler-ui": "git+https://github.com/tabler/tabler.git#00f78ad823311bc3ad974ac3e5b0126198f0a813", "tabler-ui": "git+https://github.com/tabler/tabler.git#00f78ad823311bc3ad974ac3e5b0126198f0a813",
"underscore": "^1.12.1", "underscore": "^1.12.1",

File diff suppressed because it is too large Load Diff

21
global/README.md Normal file
View File

@ -0,0 +1,21 @@
# certbot-dns-plugins
This file contains info about available Certbot DNS plugins.
This only works for plugins which use the standard argument structure, so:
--authenticator <plugin-name> --<plugin-name>-credentials <FILE> --<plugin-name>-propagation-seconds <number>
File Structure:
```json
{
"cloudflare": {
"display_name": "Name displayed to the user",
"package_name": "Package name in PyPi repo",
"version_requirement": "Optional package version requirements (e.g. ==1.3 or >=1.2,<2.0, see https://www.python.org/dev/peps/pep-0440/#version-specifiers)",
"dependencies": "Additional dependencies, space separated (as you would pass it to pip install)",
"credentials": "Template of the credentials file",
"full_plugin_name": "The full plugin name as used in the commandline with certbot, e.g. 'dns-njalla'"
},
...
}
```

View File

@ -1,563 +0,0 @@
/**
* This file contains info about available Certbot DNS plugins.
* This only works for plugins which use the standard argument structure, so:
* --authenticator <plugin-name> --<plugin-name>-credentials <FILE> --<plugin-name>-propagation-seconds <number>
*
* File Structure:
*
* {
* cloudflare: {
* display_name: "Name displayed to the user",
* package_name: "Package name in PyPi repo",
* version_requirement: "Optional package version requirements (e.g. ==1.3 or >=1.2,<2.0, see https://www.python.org/dev/peps/pep-0440/#version-specifiers)",
* dependencies: "Additional dependencies, space separated (as you would pass it to pip install)",
* credentials: `Template of the credentials file`,
* full_plugin_name: "The full plugin name as used in the commandline with certbot, e.g. 'dns-njalla'",
* },
* ...
* }
*
*/
module.exports = {
//####################################################//
acmedns: {
display_name: 'ACME-DNS',
package_name: 'certbot-dns-acmedns',
version_requirement: '~=0.1.0',
dependencies: '',
credentials: `dns_acmedns_api_url = http://acmedns-server/
dns_acmedns_registration_file = /data/acme-registration.json`,
full_plugin_name: 'dns-acmedns',
},
aliyun: {
display_name: 'Aliyun',
package_name: 'certbot-dns-aliyun',
version_requirement: '~=0.38.1',
dependencies: '',
credentials: `dns_aliyun_access_key = 12345678
dns_aliyun_access_key_secret = 1234567890abcdef1234567890abcdef`,
full_plugin_name: 'dns-aliyun',
},
//####################################################//
azure: {
display_name: 'Azure',
package_name: 'certbot-dns-azure',
version_requirement: '~=1.2.0',
dependencies: '',
credentials: `# This plugin supported API authentication using either Service Principals or utilizing a Managed Identity assigned to the virtual machine.
# Regardless which authentication method used, the identity will need the “DNS Zone Contributor” role assigned to it.
# As multiple Azure DNS Zones in multiple resource groups can exist, the config file needs a mapping of zone to resource group ID. Multiple zones -> ID mappings can be listed by using the key dns_azure_zoneX where X is a unique number. At least 1 zone mapping is required.
# Using a service principal (option 1)
dns_azure_sp_client_id = 912ce44a-0156-4669-ae22-c16a17d34ca5
dns_azure_sp_client_secret = E-xqXU83Y-jzTI6xe9fs2YC~mck3ZzUih9
dns_azure_tenant_id = ed1090f3-ab18-4b12-816c-599af8a88cf7
# Using used assigned MSI (option 2)
# dns_azure_msi_client_id = 912ce44a-0156-4669-ae22-c16a17d34ca5
# Using system assigned MSI (option 3)
# dns_azure_msi_system_assigned = true
# Zones (at least one always required)
dns_azure_zone1 = example.com:/subscriptions/c135abce-d87d-48df-936c-15596c6968a5/resourceGroups/dns1
dns_azure_zone2 = example.org:/subscriptions/99800903-fb14-4992-9aff-12eaf2744622/resourceGroups/dns2`,
full_plugin_name: 'dns-azure',
},
//####################################################//
cloudflare: {
display_name: 'Cloudflare',
package_name: 'certbot-dns-cloudflare',
version_requirement: '==$(certbot --version | grep -Eo \'[0-9](\\.[0-9]+)+\')', // official plugin, use certbot version
dependencies: 'cloudflare',
credentials: `# Cloudflare API token
dns_cloudflare_api_token = 0123456789abcdef0123456789abcdef01234567`,
full_plugin_name: 'dns-cloudflare',
},
//####################################################//
cloudns: {
display_name: 'ClouDNS',
package_name: 'certbot-dns-cloudns',
version_requirement: '~=0.4.0',
dependencies: '',
credentials: `# Target user ID (see https://www.cloudns.net/api-settings/)
dns_cloudns_auth_id=1234
# Alternatively, one of the following two options can be set:
# dns_cloudns_sub_auth_id=1234
# dns_cloudns_sub_auth_user=foobar
# API password
dns_cloudns_auth_password=password1`,
full_plugin_name: 'dns-cloudns',
},
//####################################################//
cloudxns: {
display_name: 'CloudXNS',
package_name: 'certbot-dns-cloudxns',
version_requirement: '==$(certbot --version | grep -Eo \'[0-9](\\.[0-9]+)+\')', // official plugin, use certbot version
dependencies: '',
credentials: `dns_cloudxns_api_key = 1234567890abcdef1234567890abcdef
dns_cloudxns_secret_key = 1122334455667788`,
full_plugin_name: 'dns-cloudxns',
},
//####################################################//
constellix: {
display_name: 'Constellix',
package_name: 'certbot-dns-constellix',
version_requirement: '~=0.2.1',
dependencies: '',
credentials: `dns_constellix_apikey = 5fb4e76f-ac91-43e5-f982458bc595
dns_constellix_secretkey = 47d99fd0-32e7-4e07-85b46d08e70b
dns_constellix_endpoint = https://api.dns.constellix.com/v1`,
full_plugin_name: 'dns-constellix',
},
//####################################################//
corenetworks: {
display_name: 'Core Networks',
package_name: 'certbot-dns-corenetworks',
version_requirement: '~=0.1.4',
dependencies: '',
credentials: `dns_corenetworks_username = asaHB12r
dns_corenetworks_password = secure_password`,
full_plugin_name: 'dns-corenetworks',
},
//####################################################//
cpanel: {
display_name: 'cPanel',
package_name: 'certbot-dns-cpanel',
version_requirement: '~=0.2.2',
dependencies: '',
credentials: `cpanel_url = https://cpanel.example.com:2083
cpanel_username = user
cpanel_password = hunter2`,
full_plugin_name: 'cpanel',
},
//####################################################//
desec: {
display_name: 'deSEC',
package_name: 'certbot-dns-desec',
version_requirement: '~=1.2.1',
dependencies: '',
credentials: `dns_desec_token = YOUR_DESEC_API_TOKEN
dns_desec_endpoint = https://desec.io/api/v1/`,
full_plugin_name: 'dns-desec',
},
//####################################################//
duckdns: {
display_name: 'DuckDNS',
package_name: 'certbot-dns-duckdns',
version_requirement: '~=0.9',
dependencies: '',
credentials: 'dns_duckdns_token=your-duckdns-token',
full_plugin_name: 'dns-duckdns',
},
//####################################################//
digitalocean: {
display_name: 'DigitalOcean',
package_name: 'certbot-dns-digitalocean',
version_requirement: '==$(certbot --version | grep -Eo \'[0-9](\\.[0-9]+)+\')', // official plugin, use certbot version
dependencies: '',
credentials: 'dns_digitalocean_token = 0000111122223333444455556666777788889999aaaabbbbccccddddeeeeffff',
full_plugin_name: 'dns-digitalocean',
},
//####################################################//
directadmin: {
display_name: 'DirectAdmin',
package_name: 'certbot-dns-directadmin',
version_requirement: '~=0.0.23',
dependencies: '',
credentials: `directadmin_url = https://my.directadminserver.com:2222
directadmin_username = username
directadmin_password = aSuperStrongPassword`,
full_plugin_name: 'directadmin',
},
//####################################################//
dnsimple: {
display_name: 'DNSimple',
package_name: 'certbot-dns-dnsimple',
version_requirement: '==$(certbot --version | grep -Eo \'[0-9](\\.[0-9]+)+\')', // official plugin, use certbot version
dependencies: '',
credentials: 'dns_dnsimple_token = MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw',
full_plugin_name: 'dns-dnsimple',
},
//####################################################//
dnsmadeeasy: {
display_name: 'DNS Made Easy',
package_name: 'certbot-dns-dnsmadeeasy',
version_requirement: '==$(certbot --version | grep -Eo \'[0-9](\\.[0-9]+)+\')', // official plugin, use certbot version
dependencies: '',
credentials: `dns_dnsmadeeasy_api_key = 1c1a3c91-4770-4ce7-96f4-54c0eb0e457a
dns_dnsmadeeasy_secret_key = c9b5625f-9834-4ff8-baba-4ed5f32cae55`,
full_plugin_name: 'dns-dnsmadeeasy',
},
//####################################################//
dnspod: {
display_name: 'DNSPod',
package_name: 'certbot-dns-dnspod',
version_requirement: '~=0.1.0',
dependencies: '',
credentials: `dns_dnspod_email = "email@example.com"
dns_dnspod_api_token = "id,key"`,
full_plugin_name: 'dns-dnspod',
},
//####################################################//
domainoffensive: {
display_name: 'DomainOffensive (do.de)',
package_name: 'certbot-dns-do',
version_requirement: '~=0.31.0',
dependencies: '',
credentials: 'dns_do_api_token = YOUR_DO_DE_AUTH_TOKEN',
full_plugin_name: 'dns-do',
},
//####################################################//
domeneshop: {
display_name: 'Domeneshop',
package_name: 'certbot-dns-domeneshop',
version_requirement: '~=0.2.8',
dependencies: '',
credentials: `dns_domeneshop_client_token=YOUR_DOMENESHOP_CLIENT_TOKEN
dns_domeneshop_client_secret=YOUR_DOMENESHOP_CLIENT_SECRET`,
full_plugin_name: 'dns-domeneshop',
},
//####################################################//
dynu: {
display_name: 'Dynu',
package_name: 'certbot-dns-dynu',
version_requirement: '~=0.0.1',
dependencies: '',
credentials: 'dns_dynu_auth_token = YOUR_DYNU_AUTH_TOKEN',
full_plugin_name: 'dns-dynu',
},
//####################################################//
eurodns: {
display_name: 'EuroDNS',
package_name: 'certbot-dns-eurodns',
version_requirement: '~=0.0.4',
dependencies: '',
credentials: `dns_eurodns_applicationId = myuser
dns_eurodns_apiKey = mysecretpassword
dns_eurodns_endpoint = https://rest-api.eurodns.com/user-api-gateway/proxy`,
full_plugin_name: 'dns-eurodns',
},
//####################################################//
gandi: {
display_name: 'Gandi Live DNS',
package_name: 'certbot_plugin_gandi',
version_requirement: '~=1.3.2',
dependencies: '',
credentials: `# live dns v5 api key
dns_gandi_api_key=APIKEY
# optional organization id, remove it if not used
dns_gandi_sharing_id=SHARINGID`,
full_plugin_name: 'dns-gandi',
},
//####################################################//
godaddy: {
display_name: 'GoDaddy',
package_name: 'certbot-dns-godaddy',
version_requirement: '~=0.2.0',
dependencies: '',
credentials: `dns_godaddy_secret = 0123456789abcdef0123456789abcdef01234567
dns_godaddy_key = abcdef0123456789abcdef01234567abcdef0123`,
full_plugin_name: 'dns-godaddy',
},
//####################################################//
google: {
display_name: 'Google',
package_name: 'certbot-dns-google',
version_requirement: '==$(certbot --version | grep -Eo \'[0-9](\\.[0-9]+)+\')', // official plugin, use certbot version
dependencies: '',
credentials: `{
"type": "service_account",
...
}`,
full_plugin_name: 'dns-google',
},
//####################################################//
googledomains: {
display_name: 'GoogleDomainsDNS',
package_name: 'certbot-dns-google-domains',
version_requirement: '~=0.1.5',
dependencies: '',
credentials: `dns_google_domains_access_token = 0123456789abcdef0123456789abcdef01234567
dns_google_domains_zone = "example.com"`,
full_plugin_name: 'dns-google-domains',
},
//####################################################//
hetzner: {
display_name: 'Hetzner',
package_name: 'certbot-dns-hetzner',
version_requirement: '~=1.0.4',
dependencies: '',
credentials: 'dns_hetzner_api_token = 0123456789abcdef0123456789abcdef',
full_plugin_name: 'dns-hetzner',
},
//####################################################//
infomaniak: {
display_name: 'Infomaniak',
package_name: 'certbot-dns-infomaniak',
version_requirement: '~=0.1.12',
dependencies: '',
credentials: 'dns_infomaniak_token = XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX',
full_plugin_name: 'dns-infomaniak',
},
//####################################################//
inwx: {
display_name: 'INWX',
package_name: 'certbot-dns-inwx',
version_requirement: '~=2.1.2',
dependencies: '',
credentials: `dns_inwx_url = https://api.domrobot.com/xmlrpc/
dns_inwx_username = your_username
dns_inwx_password = your_password
dns_inwx_shared_secret = your_shared_secret optional`,
full_plugin_name: 'dns-inwx',
},
//####################################################//
ionos: {
display_name: 'IONOS',
package_name: 'certbot-dns-ionos',
version_requirement: '==2022.11.24',
dependencies: '',
credentials: `dns_ionos_prefix = myapikeyprefix
dns_ionos_secret = verysecureapikeysecret
dns_ionos_endpoint = https://api.hosting.ionos.com`,
full_plugin_name: 'dns-ionos',
},
//####################################################//
ispconfig: {
display_name: 'ISPConfig',
package_name: 'certbot-dns-ispconfig',
version_requirement: '~=0.2.0',
dependencies: '',
credentials: `dns_ispconfig_username = myremoteuser
dns_ispconfig_password = verysecureremoteuserpassword
dns_ispconfig_endpoint = https://localhost:8080`,
full_plugin_name: 'dns-ispconfig',
},
//####################################################//
isset: {
display_name: 'Isset',
package_name: 'certbot-dns-isset',
version_requirement: '~=0.0.3',
dependencies: '',
credentials: `dns_isset_endpoint="https://customer.isset.net/api"
dns_isset_token="<token>"`,
full_plugin_name: 'dns-isset',
},
joker: {
display_name: 'Joker',
package_name: 'certbot-dns-joker',
version_requirement: '~=1.1.0',
dependencies: '',
credentials: `dns_joker_username = <Dynamic DNS Authentication Username>
dns_joker_password = <Dynamic DNS Authentication Password>
dns_joker_domain = <Dynamic DNS Domain>`,
full_plugin_name: 'dns-joker',
},
//####################################################//
linode: {
display_name: 'Linode',
package_name: 'certbot-dns-linode',
version_requirement: '==$(certbot --version | grep -Eo \'[0-9](\\.[0-9]+)+\')', // official plugin, use certbot version
dependencies: '',
credentials: `dns_linode_key = 0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ64
dns_linode_version = [<blank>|3|4]`,
full_plugin_name: 'dns-linode',
},
//####################################################//
loopia: {
display_name: 'Loopia',
package_name: 'certbot-dns-loopia',
version_requirement: '~=1.0.0',
dependencies: '',
credentials: `dns_loopia_user = user@loopiaapi
dns_loopia_password = abcdef0123456789abcdef01234567abcdef0123`,
full_plugin_name: 'dns-loopia',
},
//####################################################//
luadns: {
display_name: 'LuaDNS',
package_name: 'certbot-dns-luadns',
version_requirement: '==$(certbot --version | grep -Eo \'[0-9](\\.[0-9]+)+\')', // official plugin, use certbot version
dependencies: '',
credentials: `dns_luadns_email = user@example.com
dns_luadns_token = 0123456789abcdef0123456789abcdef`,
full_plugin_name: 'dns-luadns',
},
//####################################################//
namecheap: {
display_name: 'Namecheap',
package_name: 'certbot-dns-namecheap',
version_requirement: '~=1.0.0',
dependencies: '',
credentials: `dns_namecheap_username = 123456
dns_namecheap_api_key = 0123456789abcdef0123456789abcdef01234567`,
full_plugin_name: 'dns-namecheap',
},
//####################################################//
netcup: {
display_name: 'netcup',
package_name: 'certbot-dns-netcup',
version_requirement: '~=1.0.0',
dependencies: '',
credentials: `dns_netcup_customer_id = 123456
dns_netcup_api_key = 0123456789abcdef0123456789abcdef01234567
dns_netcup_api_password = abcdef0123456789abcdef01234567abcdef0123`,
full_plugin_name: 'dns-netcup',
},
//####################################################//
njalla: {
display_name: 'Njalla',
package_name: 'certbot-dns-njalla',
version_requirement: '~=1.0.0',
dependencies: '',
credentials: 'dns_njalla_token = 0123456789abcdef0123456789abcdef01234567',
full_plugin_name: 'dns-njalla',
},
//####################################################//
nsone: {
display_name: 'NS1',
package_name: 'certbot-dns-nsone',
version_requirement: '==$(certbot --version | grep -Eo \'[0-9](\\.[0-9]+)+\')', // official plugin, use certbot version
dependencies: '',
credentials: 'dns_nsone_api_key = MDAwMDAwMDAwMDAwMDAw',
full_plugin_name: 'dns-nsone',
},
//####################################################//
oci: {
display_name: 'Oracle Cloud Infrastructure DNS',
package_name: 'certbot-dns-oci',
package_version: '0.3.6',
dependencies: 'oci',
credentials: `[DEFAULT]
user = ocid1.user.oc1...
fingerprint = xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx
tenancy = ocid1.tenancy.oc1...
region = us-ashburn-1
key_file = ~/.oci/oci_api_key.pem`,
full_plugin_name: 'dns-oci',
},
//####################################################//
online: {
display_name: 'Online',
package_name: 'certbot-dns-online',
version_requirement: '~=0.0.8',
dependencies: '',
credentials: 'dns_online_token=0123456789abcdef0123456789abcdef01234567',
full_plugin_name: 'dns-online',
},
//####################################################//
ovh: {
display_name: 'OVH',
package_name: 'certbot-dns-ovh',
version_requirement: '==$(certbot --version | grep -Eo \'[0-9](\\.[0-9]+)+\')', // official plugin, use certbot version
dependencies: '',
credentials: `dns_ovh_endpoint = ovh-eu
dns_ovh_application_key = MDAwMDAwMDAwMDAw
dns_ovh_application_secret = MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw
dns_ovh_consumer_key = MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw`,
full_plugin_name: 'dns-ovh',
},
//####################################################//
porkbun: {
display_name: 'Porkbun',
package_name: 'certbot-dns-porkbun',
version_requirement: '~=0.2',
dependencies: '',
credentials: `dns_porkbun_key=your-porkbun-api-key
dns_porkbun_secret=your-porkbun-api-secret`,
full_plugin_name: 'dns-porkbun',
},
//####################################################//
powerdns: {
display_name: 'PowerDNS',
package_name: 'certbot-dns-powerdns',
version_requirement: '~=0.2.0',
dependencies: '',
credentials: `dns_powerdns_api_url = https://api.mypowerdns.example.org
dns_powerdns_api_key = AbCbASsd!@34`,
full_plugin_name: 'dns-powerdns',
},
//####################################################//
regru: {
display_name: 'reg.ru',
package_name: 'certbot-regru',
version_requirement: '~=1.0.2',
dependencies: '',
credentials: `dns_username=username
dns_password=password`,
full_plugin_name: 'dns',
},
//####################################################//
rfc2136: {
display_name: 'RFC 2136',
package_name: 'certbot-dns-rfc2136',
version_requirement: '==$(certbot --version | grep -Eo \'[0-9](\\.[0-9]+)+\')', // official plugin, use certbot version
dependencies: '',
credentials: `# Target DNS server
dns_rfc2136_server = 192.0.2.1
# Target DNS port
dns_rfc2136_port = 53
# TSIG key name
dns_rfc2136_name = keyname.
# TSIG key secret
dns_rfc2136_secret = 4q4wM/2I180UXoMyN4INVhJNi8V9BCV+jMw2mXgZw/CSuxUT8C7NKKFs AmKd7ak51vWKgSl12ib86oQRPkpDjg==
# TSIG key algorithm
dns_rfc2136_algorithm = HMAC-SHA512`,
full_plugin_name: 'dns-rfc2136',
},
//####################################################//
route53: {
display_name: 'Route 53 (Amazon)',
package_name: 'certbot-dns-route53',
version_requirement: '==$(certbot --version | grep -Eo \'[0-9](\\.[0-9]+)+\')', // official plugin, use certbot version
dependencies: '',
credentials: `[default]
aws_access_key_id=AKIAIOSFODNN7EXAMPLE
aws_secret_access_key=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY`,
full_plugin_name: 'dns-route53',
},
//####################################################//
transip: {
display_name: 'TransIP',
package_name: 'certbot-dns-transip',
version_requirement: '~=0.4.3',
dependencies: '',
credentials: `dns_transip_username = my_username
dns_transip_key_file = /etc/letsencrypt/transip-rsa.key`,
full_plugin_name: 'dns-transip',
},
//####################################################//
tencentcloud: {
display_name: 'Tencent Cloud',
package_name: 'certbot-dns-tencentcloud',
version_requirement: '~=2.0.0',
dependencies: '',
credentials: `dns_tencentcloud_secret_id = TENCENT_CLOUD_SECRET_ID
dns_tencentcloud_secret_key = TENCENT_CLOUD_SECRET_KEY`,
full_plugin_name: 'dns-tencentcloud',
},
//####################################################//
vultr: {
display_name: 'Vultr',
package_name: 'certbot-dns-vultr',
version_requirement: '~=1.0.3',
dependencies: '',
credentials: 'dns_vultr_key = YOUR_VULTR_API_KEY',
full_plugin_name: 'dns-vultr',
},
//####################################################//
websupportsk: {
display_name: 'Websupport.sk',
package_name: 'certbot-dns-websupportsk',
version_requirement: '~=0.1.6',
dependencies: '',
credentials: `dns_websupportsk_api_key = <api_key>
dns_websupportsk_secret = <secret>
dns_websupportsk_domain = example.com`,
full_plugin_name: 'dns-websupportsk',
},
};

View File

@ -0,0 +1,426 @@
{
"acmedns": {
"name": "ACME-DNS",
"package_name": "certbot-dns-acmedns",
"version": "~=0.1.0",
"dependencies": "",
"credentials": "dns_acmedns_api_url = http://acmedns-server/\ndns_acmedns_registration_file = /data/acme-registration.json",
"full_plugin_name": "dns-acmedns"
},
"aliyun": {
"name": "Aliyun",
"package_name": "certbot-dns-aliyun",
"version": "~=0.38.1",
"dependencies": "",
"credentials": "dns_aliyun_access_key = 12345678\ndns_aliyun_access_key_secret = 1234567890abcdef1234567890abcdef",
"full_plugin_name": "dns-aliyun"
},
"azure": {
"name": "Azure",
"package_name": "certbot-dns-azure",
"version": "~=1.2.0",
"dependencies": "",
"credentials": "# This plugin supported API authentication using either Service Principals or utilizing a Managed Identity assigned to the virtual machine.\n# Regardless which authentication method used, the identity will need the “DNS Zone Contributor” role assigned to it.\n# As multiple Azure DNS Zones in multiple resource groups can exist, the config file needs a mapping of zone to resource group ID. Multiple zones -> ID mappings can be listed by using the key dns_azure_zoneX where X is a unique number. At least 1 zone mapping is required.\n\n# Using a service principal (option 1)\ndns_azure_sp_client_id = 912ce44a-0156-4669-ae22-c16a17d34ca5\ndns_azure_sp_client_secret = E-xqXU83Y-jzTI6xe9fs2YC~mck3ZzUih9\ndns_azure_tenant_id = ed1090f3-ab18-4b12-816c-599af8a88cf7\n\n# Using used assigned MSI (option 2)\n# dns_azure_msi_client_id = 912ce44a-0156-4669-ae22-c16a17d34ca5\n\n# Using system assigned MSI (option 3)\n# dns_azure_msi_system_assigned = true\n\n# Zones (at least one always required)\ndns_azure_zone1 = example.com:/subscriptions/c135abce-d87d-48df-936c-15596c6968a5/resourceGroups/dns1\ndns_azure_zone2 = example.org:/subscriptions/99800903-fb14-4992-9aff-12eaf2744622/resourceGroups/dns2",
"full_plugin_name": "dns-azure"
},
"bunny": {
"name": "bunny.net",
"package_name": "certbot-dns-bunny",
"version": "~=0.0.9",
"dependencies": "",
"credentials": "# Bunny API token used by Certbot (see https://dash.bunny.net/account/settings)\ndns_bunny_api_key = xxxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxxxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxx",
"full_plugin_name": "dns-bunny"
},
"cloudflare": {
"name": "Cloudflare",
"package_name": "certbot-dns-cloudflare",
"version": "=={{certbot-version}}",
"dependencies": "cloudflare acme=={{certbot-version}}",
"credentials": "# Cloudflare API token\ndns_cloudflare_api_token = 0123456789abcdef0123456789abcdef01234567",
"full_plugin_name": "dns-cloudflare"
},
"cloudns": {
"name": "ClouDNS",
"package_name": "certbot-dns-cloudns",
"version": "~=0.6.0",
"dependencies": "",
"credentials": "# Target user ID (see https://www.cloudns.net/api-settings/)\n\tdns_cloudns_auth_id=1234\n\t# Alternatively, one of the following two options can be set:\n\t# dns_cloudns_sub_auth_id=1234\n\t# dns_cloudns_sub_auth_user=foobar\n\n\t# API password\n\tdns_cloudns_auth_password=password1",
"full_plugin_name": "dns-cloudns"
},
"cloudxns": {
"name": "CloudXNS",
"package_name": "certbot-dns-cloudxns",
"version": "~=1.32.0",
"dependencies": "",
"credentials": "dns_cloudxns_api_key = 1234567890abcdef1234567890abcdef\ndns_cloudxns_secret_key = 1122334455667788",
"full_plugin_name": "dns-cloudxns"
},
"constellix": {
"name": "Constellix",
"package_name": "certbot-dns-constellix",
"version": "~=0.2.1",
"dependencies": "",
"credentials": "dns_constellix_apikey = 5fb4e76f-ac91-43e5-f982458bc595\ndns_constellix_secretkey = 47d99fd0-32e7-4e07-85b46d08e70b\ndns_constellix_endpoint = https://api.dns.constellix.com/v1",
"full_plugin_name": "dns-constellix"
},
"corenetworks": {
"name": "Core Networks",
"package_name": "certbot-dns-corenetworks",
"version": "~=0.1.4",
"dependencies": "",
"credentials": "dns_corenetworks_username = asaHB12r\ndns_corenetworks_password = secure_password",
"full_plugin_name": "dns-corenetworks"
},
"cpanel": {
"name": "cPanel",
"package_name": "certbot-dns-cpanel",
"version": "~=0.2.2",
"dependencies": "",
"credentials": "cpanel_url = https://cpanel.example.com:2083\ncpanel_username = user\ncpanel_password = hunter2",
"full_plugin_name": "cpanel"
},
"desec": {
"name": "deSEC",
"package_name": "certbot-dns-desec",
"version": "~=1.2.1",
"dependencies": "",
"credentials": "dns_desec_token = YOUR_DESEC_API_TOKEN\ndns_desec_endpoint = https://desec.io/api/v1/",
"full_plugin_name": "dns-desec"
},
"duckdns": {
"name": "DuckDNS",
"package_name": "certbot-dns-duckdns",
"version": "~=0.9",
"dependencies": "",
"credentials": "dns_duckdns_token=your-duckdns-token",
"full_plugin_name": "dns-duckdns"
},
"digitalocean": {
"name": "DigitalOcean",
"package_name": "certbot-dns-digitalocean",
"version": "=={{certbot-version}}",
"dependencies": "acme=={{certbot-version}}",
"credentials": "dns_digitalocean_token = 0000111122223333444455556666777788889999aaaabbbbccccddddeeeeffff",
"full_plugin_name": "dns-digitalocean"
},
"directadmin": {
"name": "DirectAdmin",
"package_name": "certbot-dns-directadmin",
"version": "~=0.0.23",
"dependencies": "",
"credentials": "directadmin_url = https://my.directadminserver.com:2222\ndirectadmin_username = username\ndirectadmin_password = aSuperStrongPassword",
"full_plugin_name": "directadmin"
},
"dnsimple": {
"name": "DNSimple",
"package_name": "certbot-dns-dnsimple",
"version": "=={{certbot-version}}",
"dependencies": "acme=={{certbot-version}}",
"credentials": "dns_dnsimple_token = MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw",
"full_plugin_name": "dns-dnsimple"
},
"dnsmadeeasy": {
"name": "DNS Made Easy",
"package_name": "certbot-dns-dnsmadeeasy",
"version": "=={{certbot-version}}",
"dependencies": "acme=={{certbot-version}}",
"credentials": "dns_dnsmadeeasy_api_key = 1c1a3c91-4770-4ce7-96f4-54c0eb0e457a\ndns_dnsmadeeasy_secret_key = c9b5625f-9834-4ff8-baba-4ed5f32cae55",
"full_plugin_name": "dns-dnsmadeeasy"
},
"dnspod": {
"name": "DNSPod",
"package_name": "certbot-dns-dnspod",
"version": "~=0.1.0",
"dependencies": "",
"credentials": "dns_dnspod_email = \"email@example.com\"\ndns_dnspod_api_token = \"id,key\"",
"full_plugin_name": "dns-dnspod"
},
"domainoffensive": {
"name": "DomainOffensive (do.de)",
"package_name": "certbot-dns-do",
"version": "~=0.31.0",
"dependencies": "",
"credentials": "dns_do_api_token = YOUR_DO_DE_AUTH_TOKEN",
"full_plugin_name": "dns-do"
},
"domeneshop": {
"name": "Domeneshop",
"package_name": "certbot-dns-domeneshop",
"version": "~=0.2.8",
"dependencies": "",
"credentials": "dns_domeneshop_client_token=YOUR_DOMENESHOP_CLIENT_TOKEN\ndns_domeneshop_client_secret=YOUR_DOMENESHOP_CLIENT_SECRET",
"full_plugin_name": "dns-domeneshop"
},
"dynu": {
"name": "Dynu",
"package_name": "certbot-dns-dynu",
"version": "~=0.0.1",
"dependencies": "",
"credentials": "dns_dynu_auth_token = YOUR_DYNU_AUTH_TOKEN",
"full_plugin_name": "dns-dynu"
},
"eurodns": {
"name": "EuroDNS",
"package_name": "certbot-dns-eurodns",
"version": "~=0.0.4",
"dependencies": "",
"credentials": "dns_eurodns_applicationId = myuser\ndns_eurodns_apiKey = mysecretpassword\ndns_eurodns_endpoint = https://rest-api.eurodns.com/user-api-gateway/proxy",
"full_plugin_name": "dns-eurodns"
},
"gandi": {
"name": "Gandi Live DNS",
"package_name": "certbot_plugin_gandi",
"version": "~=1.5.0",
"dependencies": "",
"credentials": "# Gandi personal access token\ndns_gandi_token=PERSONAL_ACCESS_TOKEN",
"full_plugin_name": "dns-gandi"
},
"godaddy": {
"name": "GoDaddy",
"package_name": "certbot-dns-godaddy",
"version": "=={{certbot-version}}",
"dependencies": "",
"credentials": "dns_godaddy_secret = 0123456789abcdef0123456789abcdef01234567\ndns_godaddy_key = abcdef0123456789abcdef01234567abcdef0123",
"full_plugin_name": "dns-godaddy"
},
"google": {
"name": "Google",
"package_name": "certbot-dns-google",
"version": "=={{certbot-version}}",
"dependencies": "",
"credentials": "{\n\"type\": \"service_account\",\n...\n}",
"full_plugin_name": "dns-google"
},
"googledomains": {
"name": "GoogleDomainsDNS",
"package_name": "certbot-dns-google-domains",
"version": "~=0.1.5",
"dependencies": "",
"credentials": "dns_google_domains_access_token = 0123456789abcdef0123456789abcdef01234567\ndns_google_domains_zone = \"example.com\"",
"full_plugin_name": "dns-google-domains"
},
"he": {
"name": "Hurricane Electric",
"package_name": "certbot-dns-he",
"version": "~=1.0.0",
"dependencies": "",
"credentials": "dns_he_user = Me\ndns_he_pass = my HE password",
"full_plugin_name": "dns-he"
},
"hetzner": {
"name": "Hetzner",
"package_name": "certbot-dns-hetzner",
"version": "~=1.0.4",
"dependencies": "",
"credentials": "dns_hetzner_api_token = 0123456789abcdef0123456789abcdef",
"full_plugin_name": "dns-hetzner"
},
"infomaniak": {
"name": "Infomaniak",
"package_name": "certbot-dns-infomaniak",
"version": "~=0.1.12",
"dependencies": "",
"credentials": "dns_infomaniak_token = XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
"full_plugin_name": "dns-infomaniak"
},
"inwx": {
"name": "INWX",
"package_name": "certbot-dns-inwx",
"version": "~=2.1.2",
"dependencies": "",
"credentials": "dns_inwx_url = https://api.domrobot.com/xmlrpc/\ndns_inwx_username = your_username\ndns_inwx_password = your_password\ndns_inwx_shared_secret = your_shared_secret optional",
"full_plugin_name": "dns-inwx"
},
"ionos": {
"name": "IONOS",
"package_name": "certbot-dns-ionos",
"version": "==2022.11.24",
"dependencies": "",
"credentials": "dns_ionos_prefix = myapikeyprefix\ndns_ionos_secret = verysecureapikeysecret\ndns_ionos_endpoint = https://api.hosting.ionos.com",
"full_plugin_name": "dns-ionos"
},
"ispconfig": {
"name": "ISPConfig",
"package_name": "certbot-dns-ispconfig",
"version": "~=0.2.0",
"dependencies": "",
"credentials": "dns_ispconfig_username = myremoteuser\ndns_ispconfig_password = verysecureremoteuserpassword\ndns_ispconfig_endpoint = https://localhost:8080",
"full_plugin_name": "dns-ispconfig"
},
"isset": {
"name": "Isset",
"package_name": "certbot-dns-isset",
"version": "~=0.0.3",
"dependencies": "",
"credentials": "dns_isset_endpoint=\"https://customer.isset.net/api\"\ndns_isset_token=\"<token>\"",
"full_plugin_name": "dns-isset"
},
"joker": {
"name": "Joker",
"package_name": "certbot-dns-joker",
"version": "~=1.1.0",
"dependencies": "",
"credentials": "dns_joker_username = <Dynamic DNS Authentication Username>\ndns_joker_password = <Dynamic DNS Authentication Password>\ndns_joker_domain = <Dynamic DNS Domain>",
"full_plugin_name": "dns-joker"
},
"linode": {
"name": "Linode",
"package_name": "certbot-dns-linode",
"version": "=={{certbot-version}}",
"dependencies": "acme=={{certbot-version}}",
"credentials": "dns_linode_key = 0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ64\ndns_linode_version = [<blank>|3|4]",
"full_plugin_name": "dns-linode"
},
"loopia": {
"name": "Loopia",
"package_name": "certbot-dns-loopia",
"version": "~=1.0.0",
"dependencies": "",
"credentials": "dns_loopia_user = user@loopiaapi\ndns_loopia_password = abcdef0123456789abcdef01234567abcdef0123",
"full_plugin_name": "dns-loopia"
},
"luadns": {
"name": "LuaDNS",
"package_name": "certbot-dns-luadns",
"version": "=={{certbot-version}}",
"dependencies": "acme=={{certbot-version}}",
"credentials": "dns_luadns_email = user@example.com\ndns_luadns_token = 0123456789abcdef0123456789abcdef",
"full_plugin_name": "dns-luadns"
},
"namecheap": {
"name": "Namecheap",
"package_name": "certbot-dns-namecheap",
"version": "~=1.0.0",
"dependencies": "",
"credentials": "dns_namecheap_username = 123456\ndns_namecheap_api_key = 0123456789abcdef0123456789abcdef01234567",
"full_plugin_name": "dns-namecheap"
},
"netcup": {
"name": "netcup",
"package_name": "certbot-dns-netcup",
"version": "~=1.0.0",
"dependencies": "",
"credentials": "dns_netcup_customer_id = 123456\ndns_netcup_api_key = 0123456789abcdef0123456789abcdef01234567\ndns_netcup_api_password = abcdef0123456789abcdef01234567abcdef0123",
"full_plugin_name": "dns-netcup"
},
"njalla": {
"name": "Njalla",
"package_name": "certbot-dns-njalla",
"version": "~=1.0.0",
"dependencies": "",
"credentials": "dns_njalla_token = 0123456789abcdef0123456789abcdef01234567",
"full_plugin_name": "dns-njalla"
},
"nsone": {
"name": "NS1",
"package_name": "certbot-dns-nsone",
"version": "=={{certbot-version}}",
"dependencies": "acme=={{certbot-version}}",
"credentials": "dns_nsone_api_key = MDAwMDAwMDAwMDAwMDAw",
"full_plugin_name": "dns-nsone"
},
"oci": {
"name": "Oracle Cloud Infrastructure DNS",
"package_name": "certbot-dns-oci",
"version": "~=0.3.6",
"dependencies": "oci",
"credentials": "[DEFAULT]\nuser = ocid1.user.oc1...\nfingerprint = xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx\ntenancy = ocid1.tenancy.oc1...\nregion = us-ashburn-1\nkey_file = ~/.oci/oci_api_key.pem",
"full_plugin_name": "dns-oci"
},
"ovh": {
"name": "OVH",
"package_name": "certbot-dns-ovh",
"version": "=={{certbot-version}}",
"dependencies": "acme=={{certbot-version}}",
"credentials": "dns_ovh_endpoint = ovh-eu\ndns_ovh_application_key = MDAwMDAwMDAwMDAw\ndns_ovh_application_secret = MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw\ndns_ovh_consumer_key = MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw",
"full_plugin_name": "dns-ovh"
},
"plesk": {
"name": "Plesk",
"package_name": "certbot-dns-plesk",
"version": "~=0.3.0",
"dependencies": "",
"credentials": "dns_plesk_username = your-username\ndns_plesk_password = secret\ndns_plesk_api_url = https://plesk-api-host:8443",
"full_plugin_name": "dns-plesk"
},
"porkbun": {
"name": "Porkbun",
"package_name": "certbot-dns-porkbun",
"version": "~=0.2",
"dependencies": "",
"credentials": "dns_porkbun_key=your-porkbun-api-key\ndns_porkbun_secret=your-porkbun-api-secret",
"full_plugin_name": "dns-porkbun"
},
"powerdns": {
"name": "PowerDNS",
"package_name": "certbot-dns-powerdns",
"version": "~=0.2.1",
"dependencies": "PyYAML==5.3.1",
"credentials": "dns_powerdns_api_url = https://api.mypowerdns.example.org\ndns_powerdns_api_key = AbCbASsd!@34",
"full_plugin_name": "dns-powerdns"
},
"regru": {
"name": "reg.ru",
"package_name": "certbot-regru",
"version": "~=1.0.2",
"dependencies": "",
"credentials": "dns_username=username\ndns_password=password",
"full_plugin_name": "dns"
},
"rfc2136": {
"name": "RFC 2136",
"package_name": "certbot-dns-rfc2136",
"version": "=={{certbot-version}}",
"dependencies": "acme=={{certbot-version}}",
"credentials": "# Target DNS server\ndns_rfc2136_server = 192.0.2.1\n# Target DNS port\ndns_rfc2136_port = 53\n# TSIG key name\ndns_rfc2136_name = keyname.\n# TSIG key secret\ndns_rfc2136_secret = 4q4wM/2I180UXoMyN4INVhJNi8V9BCV+jMw2mXgZw/CSuxUT8C7NKKFs AmKd7ak51vWKgSl12ib86oQRPkpDjg==\n# TSIG key algorithm\ndns_rfc2136_algorithm = HMAC-SHA512",
"full_plugin_name": "dns-rfc2136"
},
"route53": {
"name": "Route 53 (Amazon)",
"package_name": "certbot-dns-route53",
"version": "=={{certbot-version}}",
"dependencies": "acme=={{certbot-version}}",
"credentials": "[default]\naws_access_key_id=AKIAIOSFODNN7EXAMPLE\naws_secret_access_key=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY",
"full_plugin_name": "dns-route53"
},
"strato": {
"name": "Strato",
"package_name": "certbot-dns-strato",
"version": "~=0.1.1",
"dependencies": "",
"credentials": "dns_strato_username = user\ndns_strato_password = pass\n# uncomment if youre using two factor authentication:\n# dns_strato_totp_devicename = 2fa_device\n# dns_strato_totp_secret = 2fa_secret\n#\n# uncomment if domain name contains special characters\n# insert domain display name as seen on your account page here\n# dns_strato_domain_display_name = my-punicode-url.de\n#\n# if youre not using strato.de or another special endpoint you can customise it below\n# you will probably only need to adjust the host, but you can also change the complete endpoint url\n# dns_strato_custom_api_scheme = https\n# dns_strato_custom_api_host = www.strato.de\n# dns_strato_custom_api_port = 443\n# dns_strato_custom_api_path = \"/apps/CustomerService\"",
"full_plugin_name": "dns-strato"
},
"transip": {
"name": "TransIP",
"package_name": "certbot-dns-transip",
"version": "~=0.4.3",
"dependencies": "",
"credentials": "dns_transip_username = my_username\ndns_transip_key_file = /etc/letsencrypt/transip-rsa.key",
"full_plugin_name": "dns-transip"
},
"tencentcloud": {
"name": "Tencent Cloud",
"package_name": "certbot-dns-tencentcloud",
"version": "~=2.0.2",
"dependencies": "",
"credentials": "dns_tencentcloud_secret_id = TENCENT_CLOUD_SECRET_ID\ndns_tencentcloud_secret_key = TENCENT_CLOUD_SECRET_KEY",
"full_plugin_name": "dns-tencentcloud"
},
"vultr": {
"name": "Vultr",
"package_name": "certbot-dns-vultr",
"version": "~=1.1.0",
"dependencies": "",
"credentials": "dns_vultr_key = YOUR_VULTR_API_KEY",
"full_plugin_name": "dns-vultr"
},
"websupportsk": {
"name": "Websupport.sk",
"package_name": "certbot-dns-websupportsk",
"version": "~=0.1.6",
"dependencies": "",
"credentials": "dns_websupportsk_api_key = <api_key>\ndns_websupportsk_secret = <secret>\ndns_websupportsk_domain = example.com",
"full_plugin_name": "dns-websupportsk"
}
}

View File

@ -3,14 +3,22 @@
DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
. "$DIR/../.common.sh" . "$DIR/../.common.sh"
DOCKER_IMAGE=jc21/nginx-full:certbot-node DOCKER_IMAGE=nginxproxymanager/nginx-full:certbot-node
# Ensure docker exists # Ensure docker exists
if hash docker 2>/dev/null; then if hash docker 2>/dev/null; then
docker pull "${DOCKER_IMAGE}" docker pull "${DOCKER_IMAGE}"
cd "${DIR}/../.." cd "${DIR}/../.."
echo -e "${BLUE} ${CYAN}Building Frontend ...${RESET}" echo -e "${BLUE} ${CYAN}Building Frontend ...${RESET}"
docker run --rm -e CI=true -v "$(pwd)/frontend:/app/frontend" -v "$(pwd)/global:/app/global" -w /app/frontend "$DOCKER_IMAGE" sh -c "yarn install && yarn build && yarn build && chown -R $(id -u):$(id -g) /app/frontend"
docker run --rm \
-e CI=true \
-e NODE_OPTIONS=--openssl-legacy-provider \
-v "$(pwd)/frontend:/app/frontend" \
-v "$(pwd)/global:/app/global" \
-w /app/frontend "$DOCKER_IMAGE" \
sh -c "yarn install && yarn build && yarn build && chown -R $(id -u):$(id -g) /app/frontend"
echo -e "${BLUE} ${GREEN}Building Frontend Complete${RESET}" echo -e "${BLUE} ${GREEN}Building Frontend Complete${RESET}"
else else
echo -e "${RED} docker command is not available${RESET}" echo -e "${RED} docker command is not available${RESET}"

View File

@ -1,23 +1,31 @@
#!/bin/bash -e #!/bin/bash -e
DOCKER_IMAGE=jc21/nginx-full:certbot-node DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
. "$DIR/../.common.sh"
DOCKER_IMAGE=nginxproxymanager/nginx-full:certbot-node
docker pull "${DOCKER_IMAGE}" docker pull "${DOCKER_IMAGE}"
# Test # Test
echo -e "${BLUE} ${CYAN}Testing backend ...${RESET}"
docker run --rm \ docker run --rm \
-v "$(pwd)/backend:/app" \ -v "$(pwd)/backend:/app" \
-v "$(pwd)/global:/app/global" \ -v "$(pwd)/global:/app/global" \
-w /app \ -w /app \
"${DOCKER_IMAGE}" \ "${DOCKER_IMAGE}" \
sh -c 'yarn install && yarn eslint . && rm -rf node_modules' sh -c 'yarn install && yarn eslint . && rm -rf node_modules'
echo -e "${BLUE} ${GREEN}Testing Complete${RESET}"
# Build # Build
docker build --pull --no-cache --squash --compress \ echo -e "${BLUE} ${CYAN}Building ...${RESET}"
docker build --pull --no-cache --compress \
-t "${IMAGE}:ci-${BUILD_NUMBER}" \ -t "${IMAGE}:ci-${BUILD_NUMBER}" \
-f docker/Dockerfile \ -f docker/Dockerfile \
--progress=plain \
--build-arg TARGETPLATFORM=linux/amd64 \ --build-arg TARGETPLATFORM=linux/amd64 \
--build-arg BUILDPLATFORM=linux/amd64 \ --build-arg BUILDPLATFORM=linux/amd64 \
--build-arg BUILD_VERSION="${BUILD_VERSION}" \ --build-arg BUILD_VERSION="${BUILD_VERSION}" \
--build-arg BUILD_COMMIT="${BUILD_COMMIT}" \ --build-arg BUILD_COMMIT="${BUILD_COMMIT}" \
--build-arg BUILD_DATE="$(date '+%Y-%m-%d %T %Z')" \ --build-arg BUILD_DATE="$(date '+%Y-%m-%d %T %Z')" \
. .
echo -e "${BLUE} ${GREEN}Building Complete${RESET}"

View File

@ -7,7 +7,7 @@ DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
if hash docker 2>/dev/null; then if hash docker 2>/dev/null; then
cd "${DIR}/.." cd "${DIR}/.."
echo -e "${BLUE} ${CYAN}Building Docs ...${RESET}" echo -e "${BLUE} ${CYAN}Building Docs ...${RESET}"
docker run --rm -e CI=true -v "$(pwd)/docs:/app/docs" -w /app/docs node:alpine sh -c "yarn install && yarn build && chown -R $(id -u):$(id -g) /app/docs" docker run --rm -e CI=true -v "$(pwd)/docs:/app/docs" -w /app/docs node:alpine sh -c "yarn set version berry && yarn install && yarn build && chown -R $(id -u):$(id -g) /app/docs"
echo -e "${BLUE} ${GREEN}Building Docs Complete${RESET}" echo -e "${BLUE} ${GREEN}Building Docs Complete${RESET}"
else else
echo -e "${RED} docker command is not available${RESET}" echo -e "${RED} docker command is not available${RESET}"

View File

@ -0,0 +1,48 @@
/// <reference types="Cypress" />
describe('Hosts endpoints', () => {
let token;
before(() => {
cy.getToken().then((tok) => {
token = tok;
});
});
it('Should be able to create a http host', function() {
cy.task('backendApiPost', {
token: token,
path: '/api/nginx/proxy-hosts',
data: {
domain_names: ['test.example.com'],
forward_scheme: 'http',
forward_host: '1.1.1.1',
forward_port: 80,
access_list_id: '0',
certificate_id: 0,
meta: {
letsencrypt_agree: false,
dns_challenge: false
},
advanced_config: '',
locations: [],
block_exploits: false,
caching_enabled: false,
allow_websocket_upgrade: false,
http2_support: false,
hsts_enabled: false,
hsts_subdomains: false,
ssl_forced: false
}
}).then((data) => {
cy.validateSwaggerSchema('post', 201, '/nginx/proxy-hosts', data);
expect(data).to.have.property('id');
expect(data.id).to.be.greaterThan(0);
expect(data).to.have.property('enabled');
expect(data.enabled).to.be.greaterThan(0);
expect(data).to.have.property('meta');
expect(typeof data.meta.nginx_online).to.be.equal('undefined');
});
});
});

View File

@ -126,7 +126,7 @@ BackendApi.prototype._putPostJson = function(fn, path, data, returnOnError) {
logger('Response data:', data); logger('Response data:', data);
if (!returnOnError && data instanceof Error) { if (!returnOnError && data instanceof Error) {
reject(data); reject(data);
} else if (!returnOnError && response.statusCode != 200) { } else if (!returnOnError && (response.statusCode < 200 || response.statusCode >= 300)) {
if (typeof data === 'object' && typeof data.error === 'object' && typeof data.error.message !== 'undefined') { if (typeof data === 'object' && typeof data.error === 'object' && typeof data.error.message !== 'undefined') {
reject(new Error(data.error.code + ': ' + data.error.message)); reject(new Error(data.error.code + ': ' + data.error.message));
} else { } else {

View File

@ -2061,15 +2061,10 @@ sax@0.5.x:
resolved "https://registry.yarnpkg.com/sax/-/sax-0.5.8.tgz#d472db228eb331c2506b0e8c15524adb939d12c1" resolved "https://registry.yarnpkg.com/sax/-/sax-0.5.8.tgz#d472db228eb331c2506b0e8c15524adb939d12c1"
integrity sha1-1HLbIo6zMcJQaw6MFVJK25OdEsE= integrity sha1-1HLbIo6zMcJQaw6MFVJK25OdEsE=
semver@^7.2.1: semver@^7.2.1, semver@^7.3.2:
version "7.3.2" version "7.5.4"
resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.2.tgz#604962b052b81ed0786aae84389ffba70ffd3938" resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.4.tgz#483986ec4ed38e1c6c48c34894a9182dbff68a6e"
integrity sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ== integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==
semver@^7.3.2:
version "7.3.8"
resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.8.tgz#07a78feafb3f7b32347d725e33de7e2a2df67798"
integrity sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==
dependencies: dependencies:
lru-cache "^6.0.0" lru-cache "^6.0.0"
@ -2450,9 +2445,9 @@ wide-align@1.1.3:
string-width "^1.0.2 || 2" string-width "^1.0.2 || 2"
word-wrap@^1.2.3, word-wrap@~1.2.3: word-wrap@^1.2.3, word-wrap@~1.2.3:
version "1.2.3" version "1.2.4"
resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.4.tgz#cb4b50ec9aca570abd1f52f33cd45b6c61739a9f"
integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ== integrity sha512-2V81OA4ugVo5pRo46hAoD2ivUJx8jXmWXfUkY4KFNw0hEptvN0QfH3K4nHiwzGeKl5rFKedV48QVoqYavy4YpA==
workerpool@6.0.0: workerpool@6.0.0:
version "6.0.0" version "6.0.0"