Signed-off-by: Zoey <zoey@z0ey.de>
This commit is contained in:
Zoey
2022-12-16 09:05:58 +01:00
parent fd30cfe98b
commit 19a304d9ce
169 changed files with 2074 additions and 27536 deletions

View File

@@ -0,0 +1,5 @@
exclude:
- main
- stable
- develop
delete_closed_pr: true

37
.github/workflows/docker-latest.yml vendored Normal file
View File

@@ -0,0 +1,37 @@
name: Docker push develop to latest
on:
workflow_dispatch:
jobs:
docker:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Login to DockerHub
if: github.event_name != 'pull_request'
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Login to GitHub Container Registry
uses: docker/login-action@v2
with:
registry: ghcr.io
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ github.token }}
- name: Push develop to latest
run: |
curl -L https://github.com/regclient/regclient/releases/latest/download/regctl-linux-amd64 -o ./regctl
chmod +x ./regctl
./regctl image copy ${{ secrets.DOCKER_USERNAME }}/${{ github.event.repository.name }}:${{ github.ref_name }} ${{ secrets.DOCKER_USERNAME }}/${{ github.event.repository.name }}:latest
./regctl image copy ghcr.io/${{ secrets.DOCKER_USERNAME }}/${{ github.event.repository.name }}:${{ github.ref_name }} ghcr.io/${{ secrets.DOCKER_USERNAME }}/${{ github.event.repository.name }}:latest
- name: Show Nginx version
run: |
docker run --rm --entrypoint nginx ${{ secrets.DOCKER_USERNAME }}/${{ github.event.repository.name }}:latest -V
docker run --rm --entrypoint nginx ghcr.io/${{ secrets.DOCKER_USERNAME }}/${{ github.event.repository.name }}:latest -V

132
.github/workflows/docker.yml vendored Normal file
View File

@@ -0,0 +1,132 @@
name: Build Docker Image
on:
push:
branches:
- develop
paths:
- .github/workflows/docker.yml
- Dockerfile
- frontend/**
- backend/**
- global/**
- rootfs/**
pull_request:
paths:
- .github/workflows/docker.yml
- Dockerfile
- frontend/**
- backend/**
- global/**
- rootfs/**
workflow_dispatch:
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Set up QEMU
uses: docker/setup-qemu-action@v2
with:
platforms: arm64 #all
- name: Set up Docker Buildx
id: buildx
uses: docker/setup-buildx-action@v2
with:
driver-opts: env.BUILDKIT_STEP_LOG_MAX_SIZE=-1
- name: Login to DockerHub
if: ${{ github.event_name != 'pull_request' }}
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Login to GitHub Container Registry
uses: docker/login-action@v2
with:
registry: ghcr.io
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ github.token }}
- name: Read .version file
id: version
run: echo "version=$(cat .version)" >> $GITHUB_OUTPUT
- name: Set versions
run: |
sed -i 's/"0.0.0"/"${{ steps.version.outputs.version }}"/g' frontend/package.json
cat frontend/package.json | grep "${{ steps.version.outputs.version }}"
sed -i 's/"0.0.0"/"${{ steps.version.outputs.version }}"/g' backend/package.json
cat backend/package.json | grep "${{ steps.version.outputs.version }}"
- uses: actions/setup-node@v3
with:
node-version: 18
- name: Prepair frontend
run: |
export NODE_OPTIONS=--openssl-legacy-provider
npm install --global yarn
cd frontend
yarn install
yarn build
- name: Test Backend
run: |
export NODE_OPTIONS=--openssl-legacy-provider
export DB_SQLITE_FILE=/home/runner/work/${{ github.event.repository.name }}/${{ github.event.repository.name }}/backend-test/dev.sqlite
export NODE_ENV=dev
mv global backend
cp -r backend backend-test
cd backend-test
npm install --force
timeout 10 node --abort_on_uncaught_exception --max_old_space_size=250 index.js || if [ "$?" == "124" ]; then exit 0; else exit 1; fi
- name: Build
uses: docker/build-push-action@v3
if: ${{ github.event_name != 'pull_request' }}
with:
context: .
file: ./Dockerfile
platforms: linux/amd64,linux/arm64 #,linux/amd64/v2,linux/amd64/v3,linux/amd64/v4 #,linux/ppc64le,linux/s390x,linux/386,linux/arm/v7,linux/arm/v6
push: ${{ github.ref == 'refs/heads/develop' }}
tags: |
ghcr.io/${{ secrets.DOCKER_USERNAME }}/${{ github.event.repository.name }}:${{ github.ref_name }}
${{ secrets.DOCKER_USERNAME }}/${{ github.event.repository.name }}:${{ github.ref_name }}
- name: show version
if: ${{ github.ref == 'refs/heads/develop' }}
run: |
docker run --rm --entrypoint nginx ${{ secrets.DOCKER_USERNAME }}/${{ github.event.repository.name }}:${{ github.ref_name }} -V
docker run --rm --entrypoint nginx ghcr.io/${{ secrets.DOCKER_USERNAME }}/${{ github.event.repository.name }}:${{ github.ref_name }} -V
- name: Set PR-Number (PR)
if: ${{ github.event_name == 'pull_request' }}
id: pr
run: echo "pr=$(echo pr-${{ github.ref_name }} | sed "s/refs\/pull\/://g" | sed "s/\/merge//g")" >> $GITHUB_OUTPUT
- name: Build (PR)
uses: docker/build-push-action@v3
if: ${{ github.event_name == 'pull_request' }}
with:
context: .
file: ./Dockerfile
platforms: linux/amd64,linux/arm64 #,linux/amd64/v2,linux/amd64/v3,linux/amd64/v4 #,linux/ppc64le,linux/s390x,linux/386,linux/arm/v7,linux/arm/v6
push: ${{ github.event_name == 'pull_request' }}
tags: ghcr.io/${{ secrets.DOCKER_USERNAME }}/${{ github.event.repository.name }}:${{ steps.pr.outputs.pr }}
- name: show version (PR)
if: ${{ github.event_name == 'pull_request' }}
run: docker run --rm --entrypoint nginx ghcr.io/${{ secrets.DOCKER_USERNAME }}/${{ github.event.repository.name }}:${{ steps.pr.outputs.pr }} -V
- name: add comment (PR)
uses: mshick/add-pr-comment@v2
if: ${{ github.event_name == 'pull_request' }}
with:
message: "The Docker Image can now be found here: `ghcr.io/${{ secrets.DOCKER_USERNAME }}/${{ github.event.repository.name }}:${{ steps.pr.outputs.pr }}`"
repo-token: ${{ github.token }}

16
.github/workflows/json.yml vendored Normal file
View File

@@ -0,0 +1,16 @@
name: JSON check
on:
push:
pull_request:
workflow_dispatch:
jobs:
test-json:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: json-syntax-check
uses: limitusus/json-syntax-check@v2
with:
pattern: "\\.json$*"

785
.gitignore vendored
View File

@@ -1,5 +1,784 @@
.DS_Store
# User-specific stuff
.idea
desktop.files.json
package-lock.json
yarn.lock
desktop.ini
### macOS ###
# General
.DS_Store
.AppleDouble
.LSOverride
composer.phar
/vendor/
!/jobs
!/.gitignore
!/*.xml
#ignore all files in jobs subdirectories except for folders
#note: git doesn't track folders, only file content
jobs/**
!jobs/**/
#uncomment the following line to save next build numbers with config
#!jobs/**/nextBuildNumber
#exclude only config.xml files in repository subdirectories
!config.xml
#don't track workspaces (when users build on the master)
jobs/**/*workspace
*.iml
*.ipr
*.iws
# IntelliJ
out
# Compiled class file
*.class
# Log file
*.log
# BlueJ files
*.ctxt
# Package Files #
*.jar
*.war
*.nar
*.ear
*.zip
*.tar.gz
*.rar
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
*~
# temporary files which can be created if a process still has a handle open of a deleted file
.fuse_hidden*
# KDE directory preferences
.directory
# Linux trash folder which might appear on any partition or disk
.Trash-*
# .nfs files are created when an open file is removed but is still being accessed
.nfs*
# Icon must end with two \r
Icon
# Thumbnails
._*
.vscode
certbot-help.txt
# Files that might appear in the root of a volume
.DocumentRevisions-V100
.fseventsd
.Spotlight-V100
.TemporaryItems
.Trashes
.VolumeIcon.icns
.com.apple.timemachine.donotpresent
# Directories potentially created on remote AFP share
.AppleDB
.AppleDesktop
Network Trash Folder
Temporary Items
.apdisk
# Windows thumbnail cache files
Thumbs.db
Thumbs.db:encryptable
ehthumbs.db
ehthumbs_vista.db
# Dump file
*.stackdump
# Folder config file
[Dd]esktop.ini
# Recycle Bin used on file shares
$RECYCLE.BIN
# Windows Installer files
*.cab
*.msi
*.msix
*.msm
*.msp
# Windows shortcuts
*.lnk
.gradle
/build/
# Ignore Gradle GUI config
gradle-app.setting
# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored)
!gradle-wrapper.jar
# Cache of project
.gradletasknamecache
target/
pom.xml.tag
pom.xml.releaseBackup
pom.xml.versionsBackup
pom.xml.next
release.properties
dependency-reduced-pom.xml
buildNumber.properties
.mvn/timing.properties
# https://github.com/takari/maven-wrapper#usage-without-binary-jar
.mvn/wrapper/maven-wrapper.jar
.flattened-pom.xml
# Common working directory
run
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*
# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
*.lcov
# nyc test coverage
.nyc_output
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# Bower dependency directory (https://bower.io/)
bower_components
# node-waf configuration
.lock-wscript
# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules/
jspm_packages/
# TypeScript v1 declaration files
typings/
# TypeScript cache
*.tsbuildinfo
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Microbundle cache
.rpt2_cache/
.rts2_cache_cjs/
.rts2_cache_es/
.rts2_cache_umd/
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variables file
.env
.env.test
# parcel-bundler cache (https://parceljs.org/)
.cache
# Next.js build output
.next
# Nuxt.js build / generate output
.nuxt
dist
# Gatsby files
.cache/
# Comment in the public line in if your project uses Gatsby and *not* Next.js
# https://nextjs.org/blog/next-9-1#public-directory-support
# public
# vuepress build output
.vuepress/dist
# Serverless directories
.serverless/
# FuseBox cache
.fusebox/
# DynamoDB Local files
.dynamodb/
# TernJS port file
.tern-port
/vendor/
node_modules/
npm-debug.log
yarn-error.log
# Laravel 4 specific
bootstrap/compiled.php
app/storage/
# Laravel 5 & Lumen specific
public/storage
public/hot
# Laravel 5 & Lumen specific with changed public path
public_html/storage
public_html/hot
storage/*.key
.env
Homestead.yaml
Homestead.json
/.vagrant
.phpunit.result.cache
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
pip-wheel-metadata/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
target/
# Jupyter Notebook
.ipynb_checkpoints
# IPython
profile_default/
ipython_config.py
# pyenv
.python-version
# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
__pypackages__/
# Celery stuff
celerybeat-schedule
celerybeat.pid
# SageMath parsed files
*.sage.py
# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
.dmypy.json
dmypy.json
# Pyre type checker
.pyre/
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
##
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
# User-specific files
*.rsuser
*.suo
*.user
*.userosscache
*.sln.docstates
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
# Mono auto generated files
mono_crash.*
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
[Aa][Rr][Mm]/
[Aa][Rr][Mm]64/
bld/
[Bb]in/
[Oo]bj/
[Ll]og/
[Ll]ogs/
# Visual Studio 2015/2017 cache/options directory
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/
# Visual Studio 2017 auto generated files
Generated\ Files/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
# NUnit
*.VisualState.xml
TestResult.xml
nunit-*.xml
# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c
# Benchmark Results
BenchmarkDotNet.Artifacts/
# .NET Core
project.lock.json
project.fragment.lock.json
artifacts/
# StyleCop
StyleCopReport.xml
# Files built by Visual Studio
*_i.c
*_p.c
*_h.h
*.ilk
*.meta
*.obj
*.iobj
*.pch
*.pdb
*.ipdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*_wpftmp.csproj
*.log
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc
# Chutzpah Test files
_Chutzpah*
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
*.VC.db
*.VC.VC.opendb
# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap
# Visual Studio Trace Files
*.e2e
# TFS 2012 Local Workspace
$tf/
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# AxoCover is a Code Coverage Tool
.axoCover/*
!.axoCover/settings.json
# Visual Studio code coverage results
*.coverage
*.coveragexml
# NCrunch
_NCrunch_*
.*crunch*.local.xml
nCrunchTemp_*
# MightyMoose
*.mm.*
AutoTest.Net/
# Web workbench (sass)
.sass-cache/
# Installshield output folder
[Ee]xpress/
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish/
# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# Note: Comment the next line if you want to checkin your web deploy settings,
# but database connection strings (with potential passwords) will be unencrypted
*.pubxml
*.publishproj
# Microsoft Azure Web App publish settings. Comment the next line if you want to
# checkin your Azure Web App publish settings, but sensitive information contained
# in these scripts will be unencrypted
PublishScripts/
# NuGet Packages
*.nupkg
# NuGet Symbol Packages
*.snupkg
# The packages folder can be ignored because of Package Restore
**/[Pp]ackages/*
# except build/, which is used as an MSBuild target.
!**/[Pp]ackages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/[Pp]ackages/repositories.config
# NuGet v3's project.json files produces more ignorable files
*.nuget.props
*.nuget.targets
# Microsoft Azure Build Output
csx/
*.build.csdef
# Microsoft Azure Emulator
ecf/
rcf/
# Windows Store app package directories and files
AppPackages/
BundleArtifacts/
Package.StoreAssociation.xml
_pkginfo.txt
*.appx
*.appxbundle
*.appxupload
# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!?*.[Cc]ache/
# Others
ClientBin/
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.jfm
*.pfx
*.publishsettings
orleans.codegen.cs
# Including strong name files can present a security risk
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
#*.snk
# Since there are multiple workflows, uncomment next line to ignore bower_components
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
#bower_components/
# RIA/Silverlight projects
Generated_Code/
# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
ServiceFabricBackup/
*.rptproj.bak
# SQL Server files
*.mdf
*.ldf
*.ndf
# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
*.rptproj.rsuser
*- [Bb]ackup.rdl
*- [Bb]ackup ([0-9]).rdl
*- [Bb]ackup ([0-9][0-9]).rdl
# Microsoft Fakes
FakesAssemblies/
# GhostDoc plugin setting file
*.GhostDoc.xml
# Node.js Tools for Visual Studio
.ntvs_analysis.dat
node_modules/
# Visual Studio 6 build log
*.plg
# Visual Studio 6 workspace options file
*.opt
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
*.vbw
# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions
# Paket dependency manager
.paket/paket.exe
paket-files/
# FAKE - F# Make
.fake/
# CodeRush personal settings
.cr/personal
# Python Tools for Visual Studio (PTVS)
__pycache__/
*.pyc
# Cake - Uncomment if you are using it
# tools/**
# !tools/packages.config
# Tabs Studio
*.tss
# Telerik's JustMock configuration file
*.jmconfig
# BizTalk build output
*.btp.cs
*.btm.cs
*.odx.cs
*.xsd.cs
# OpenCover UI analysis results
OpenCover/
# Azure Stream Analytics local run output
ASALocalRun/
# MSBuild Binary and Structured Log
*.binlog
# NVidia Nsight GPU debugger configuration file
*.nvuser
# MFractors (Xamarin productivity tool) working folder
.mfractor/
# Local History for Visual Studio
.localhistory/
# BeatPulse healthcheck temp database
healthchecksdb
# Backup folder for Package Reference Convert tool in Visual Studio 2017
MigrationBackup/
# Ionide (cross platform F# VS Code tools) working folder
.ionide/
# ignore everything in the root except the "wp-content" directory.
!wp-content/
# ignore everything in the "wp-content" directory, except:
# "mu-plugins", "plugins", "themes" directory
wp-content/*
!wp-content/mu-plugins/
!wp-content/plugins/
!wp-content/themes/
# ignore these plugins
wp-content/plugins/hello.php
# ignore specific themes
wp-content/themes/twenty*/
# ignore node dependency directories
node_modules/
# ignore log files and databases
*.log
*.sql
*.sqlite

6
.imgbotconfig Normal file
View File

@@ -0,0 +1,6 @@
{
"schedule": "daily",
"aggressiveCompression": "true",
"compressWiki": "true",
"minKBReduced": 0
}

13
.whitesource Normal file
View File

@@ -0,0 +1,13 @@
{
"scanSettings": {
"baseBranches": []
},
"checkRunSettings": {
"vulnerableCheckRunConclusionLevel": "failure",
"displayMode": "diff"
},
"issueSettings": {
"minSeverityLevel": "LOW",
"issueType": "DEPENDENCY"
}
}

30
Dockerfile Normal file
View File

@@ -0,0 +1,30 @@
FROM zoeyvid/nginx-quic:20
COPY rootfs /
COPY backend /app
COPY frontend/dist /app/frontend
WORKDIR /app
RUN apk upgrade --no-cache && \
apk add --no-cache ca-certificates wget tzdata \
python3 \
nodejs-current npm \
openssl apache2-utils jq \
gcc g++ libffi-dev python3-dev && \
# Install pip
wget https://bootstrap.pypa.io/get-pip.py -O - | python3 && \
# Change permission
chmod +x /usr/local/bin/start && \
chmod +x /usr/local/bin/check-health && \
# Build Backend
npm install --force && \
pip install --no-cache-dir certbot && \
apk del --no-cache gcc g++ libffi-dev python3-dev npm
ENV NODE_ENV=production \
DB_SQLITE_FILE=/data/database.sqlite
ENTRYPOINT ["start"]
HEALTHCHECK CMD check-health

253
Jenkinsfile vendored
View File

@@ -1,253 +0,0 @@
pipeline {
agent {
label 'docker-multiarch'
}
options {
buildDiscarder(logRotator(numToKeepStr: '5'))
disableConcurrentBuilds()
ansiColor('xterm')
}
environment {
IMAGE = "nginx-proxy-manager"
BUILD_VERSION = getVersion()
MAJOR_VERSION = "2"
BRANCH_LOWER = "${BRANCH_NAME.toLowerCase().replaceAll('/', '-')}"
COMPOSE_PROJECT_NAME = "npm_${BRANCH_LOWER}_${BUILD_NUMBER}"
COMPOSE_FILE = 'docker/docker-compose.ci.yml'
COMPOSE_INTERACTIVE_NO_CLI = 1
BUILDX_NAME = "${COMPOSE_PROJECT_NAME}"
}
stages {
stage('Environment') {
parallel {
stage('Master') {
when {
branch 'master'
}
steps {
script {
env.BUILDX_PUSH_TAGS = "-t docker.io/jc21/${IMAGE}:${BUILD_VERSION} -t docker.io/jc21/${IMAGE}:${MAJOR_VERSION} -t docker.io/jc21/${IMAGE}:latest"
}
}
}
stage('Other') {
when {
not {
branch 'master'
}
}
steps {
script {
// Defaults to the Branch name, which is applies to all branches AND pr's
env.BUILDX_PUSH_TAGS = "-t docker.io/jc21/${IMAGE}:github-${BRANCH_LOWER}"
}
}
}
stage('Versions') {
steps {
sh 'cat frontend/package.json | jq --arg BUILD_VERSION "${BUILD_VERSION}" \'.version = $BUILD_VERSION\' | sponge frontend/package.json'
sh 'echo -e "\\E[1;36mFrontend Version is:\\E[1;33m $(cat frontend/package.json | jq -r .version)\\E[0m"'
sh 'cat backend/package.json | jq --arg BUILD_VERSION "${BUILD_VERSION}" \'.version = $BUILD_VERSION\' | sponge backend/package.json'
sh 'echo -e "\\E[1;36mBackend Version is:\\E[1;33m $(cat backend/package.json | jq -r .version)\\E[0m"'
sh 'sed -i -E "s/(version-)[0-9]+\\.[0-9]+\\.[0-9]+(-green)/\\1${BUILD_VERSION}\\2/" README.md'
}
}
}
}
stage('Frontend') {
steps {
sh './scripts/frontend-build'
}
}
stage('Backend') {
steps {
echo 'Checking Syntax ...'
sh 'docker pull nginxproxymanager/nginx-full:certbot-node'
// See: https://github.com/yarnpkg/yarn/issues/3254
sh '''docker run --rm \\
-v "$(pwd)/backend:/app" \\
-v "$(pwd)/global:/app/global" \\
-w /app \\
nginxproxymanager/nginx-full:certbot-node \\
sh -c "yarn install && yarn eslint . && rm -rf node_modules"
'''
echo 'Docker Build ...'
sh '''docker build --pull --no-cache --squash --compress \\
-t "${IMAGE}:ci-${BUILD_NUMBER}" \\
-f docker/Dockerfile \\
--build-arg TARGETPLATFORM=linux/amd64 \\
--build-arg BUILDPLATFORM=linux/amd64 \\
--build-arg BUILD_VERSION="${BUILD_VERSION}" \\
--build-arg BUILD_COMMIT="${BUILD_COMMIT}" \\
--build-arg BUILD_DATE="$(date '+%Y-%m-%d %T %Z')" \\
.
'''
}
}
stage('Integration Tests Sqlite') {
steps {
// Bring up a stack
sh 'docker-compose up -d fullstack-sqlite'
sh './scripts/wait-healthy $(docker-compose ps -q fullstack-sqlite) 120'
// Run tests
sh 'rm -rf test/results'
sh 'docker-compose up cypress-sqlite'
// Get results
sh 'docker cp -L "$(docker-compose ps -q cypress-sqlite):/test/results" test/'
}
post {
always {
// Dumps to analyze later
sh 'mkdir -p debug'
sh 'docker-compose logs fullstack-sqlite | gzip > debug/docker_fullstack_sqlite.log.gz'
sh 'docker-compose logs db | gzip > debug/docker_db.log.gz'
// Cypress videos and screenshot artifacts
dir(path: 'test/results') {
archiveArtifacts allowEmptyArchive: true, artifacts: '**/*', excludes: '**/*.xml'
}
junit 'test/results/junit/*'
}
}
}
stage('Integration Tests Mysql') {
steps {
// Bring up a stack
sh 'docker-compose up -d fullstack-mysql'
sh './scripts/wait-healthy $(docker-compose ps -q fullstack-mysql) 120'
// Run tests
sh 'rm -rf test/results'
sh 'docker-compose up cypress-mysql'
// Get results
sh 'docker cp -L "$(docker-compose ps -q cypress-mysql):/test/results" test/'
}
post {
always {
// Dumps to analyze later
sh 'mkdir -p debug'
sh 'docker-compose logs fullstack-mysql | gzip > debug/docker_fullstack_mysql.log.gz'
sh 'docker-compose logs db | gzip > debug/docker_db.log.gz'
// 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'
}
dir(path: 'docs/.vuepress/dist') {
sh 'tar -czf ../../docs.tgz *'
}
archiveArtifacts(artifacts: 'docs/docs.tgz', allowEmptyArchive: false)
}
}
stage('MultiArch Build') {
when {
not {
equals expected: 'UNSTABLE', actual: currentBuild.result
}
}
steps {
withCredentials([usernamePassword(credentialsId: 'jc21-dockerhub', passwordVariable: 'dpass', usernameVariable: 'duser')]) {
// Docker Login
sh "docker login -u '${duser}' -p '${dpass}'"
// Buildx with push from cache
sh "./scripts/buildx --push ${BUILDX_PUSH_TAGS}"
}
}
}
stage('Docs Deploy') {
when {
allOf {
branch 'master'
not {
equals expected: 'UNSTABLE', actual: currentBuild.result
}
}
}
steps {
withCredentials([[$class: 'AmazonWebServicesCredentialsBinding', accessKeyVariable: 'AWS_ACCESS_KEY_ID', credentialsId: 'npm-s3-docs', secretKeyVariable: 'AWS_SECRET_ACCESS_KEY']]) {
sh """docker run --rm \\
--name \${COMPOSE_PROJECT_NAME}-docs-upload \\
-e S3_BUCKET=jc21-npm-site \\
-e AWS_ACCESS_KEY_ID=$AWS_ACCESS_KEY_ID \\
-e AWS_SECRET_ACCESS_KEY=$AWS_SECRET_ACCESS_KEY \\
-v \$(pwd):/app \\
-w /app \\
jc21/ci-tools \\
scripts/docs-upload /app/docs/.vuepress/dist/
"""
sh """docker run --rm \\
--name \${COMPOSE_PROJECT_NAME}-docs-invalidate \\
-e AWS_ACCESS_KEY_ID=$AWS_ACCESS_KEY_ID \\
-e AWS_SECRET_ACCESS_KEY=$AWS_SECRET_ACCESS_KEY \\
jc21/ci-tools \\
aws cloudfront create-invalidation --distribution-id EN1G6DEWZUTDT --paths '/*'
"""
}
}
}
stage('PR Comment') {
when {
allOf {
changeRequest()
not {
equals expected: 'UNSTABLE', actual: currentBuild.result
}
}
}
steps {
script {
def comment = pullRequest.comment("This is an automated message from CI:\n\nDocker 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.")
}
}
}
}
post {
always {
sh 'docker-compose down --remove-orphans --volumes -t 30'
sh 'echo Reverting ownership'
sh 'docker run --rm -v $(pwd):/data jc21/ci-tools chown -R $(id -u):$(id -g) /data'
}
success {
juxtapose event: 'success'
sh 'figlet "SUCCESS"'
}
failure {
archiveArtifacts(artifacts: 'debug/**.*', allowEmptyArchive: true)
juxtapose event: 'failure'
sh 'figlet "FAILURE"'
}
unstable {
archiveArtifacts(artifacts: 'debug/**.*', allowEmptyArchive: true)
juxtapose event: 'unstable'
sh 'figlet "UNSTABLE"'
}
}
}
def getVersion() {
ver = sh(script: 'cat .version', returnStdout: true)
return ver.trim()
}
def getCommit() {
ver = sh(script: 'git log -n 1 --format=%h', returnStdout: true)
return ver.trim()
}

View File

@@ -1,21 +1,22 @@
<p align="center">
<img src="https://nginxproxymanager.com/github.png">
<br><br>
<img src="https://img.shields.io/badge/version-2.9.19-green.svg?style=for-the-badge">
<a href="https://hub.docker.com/repository/docker/jc21/nginx-proxy-manager">
<img src="https://img.shields.io/docker/stars/jc21/nginx-proxy-manager.svg?style=for-the-badge">
<img src="https://img.shields.io/badge/version-2.9.19+-green.svg?style=for-the-badge">
<a href="https://hub.docker.com/r/zoeyvid/nginx-proxy-manager">
<img src="https://img.shields.io/docker/stars/zoeyvid/nginx-proxy-manager.svg?style=for-the-badge">
</a>
<a href="https://hub.docker.com/repository/docker/jc21/nginx-proxy-manager">
<img src="https://img.shields.io/docker/pulls/jc21/nginx-proxy-manager.svg?style=for-the-badge">
<a href="https://hub.docker.com/r/zoeyvid/nginx-proxy-manager">
<img src="https://img.shields.io/docker/pulls/zoeyvid/nginx-proxy-manager.svg?style=for-the-badge">
</a>
</p>
This project comes as a pre-built docker image that enables you to easily forward to your websites
running at home or otherwise, including free SSL, without having to know too much about Nginx or Letsencrypt.
- [Quick Setup](#quick-setup)
- [Full Setup](https://nginxproxymanager.com/setup/)
- [Screenshots](https://nginxproxymanager.com/screenshots/)
- [Screenshots](https://nginxproxymanager.com/screenshots)
## Project Goal
@@ -37,6 +38,26 @@ so that the barrier for entry here is low.
- User management, permissions and audit log
# New Features
- HTTP/3 (QUIC) Support if you enable HTTP/2 (can not be enabled separate)
- Fix Proxy Hosts, if origin only accepts TLSv1.3
- Only use TLSv1.2 and TLSv1.3
- Uses OCSP Stapling
- Needs manual migration if you use custom certificates, just upload the CA/Intermediate Certificate (file name: `chain.pem`) in the `/opt/npm/custom_ssl/npm-[certificate-id]` folder
- Smaller then the original
- Runs the admin interface on port 81 with ssl (https)
- Default page runs also with ssl (https)
- Uses [fancyindex](https://gitHub.com/Naereen/Nginx-Fancyindex-Theme) if you use the npm directly as webserver
- Expose INTERNAL backend api only to localhost
- Easy security headers, see [here](https://github.com/GetPageSpeed/ngx_security_headers), enabled by default if you enable hsts
- Access Log disabled
- Error Log written to console
## Soon
- more
- I will try to create a pr to contribute to the original project
## Hosting your home network
I won't go in to too much detail here but here are the basics for someone new to this self-hosted world.
@@ -48,36 +69,34 @@ I won't go in to too much detail here but here are the basics for someone new to
## Quick Setup
1. Install Docker and Docker-Compose
1. Install Docker and Docker Compose
- [Docker Install documentation](https://docs.docker.com/install/)
- [Docker-Compose Install documentation](https://docs.docker.com/compose/install/)
- [Docker Install documentation](https://docs.docker.com/engine)
- [Docker Compose Install documentation](https://docs.docker.com/compose/install/linux)
2. Create a docker-compose.yml file similar to this:
2. Create a compose.yaml file similar to this:
```yml
version: '3'
version: "3"
services:
app:
image: 'jc21/nginx-proxy-manager:latest'
restart: unless-stopped
ports:
- '80:80'
- '81:81'
- '443:443'
volumes:
- ./data:/data
- ./letsencrypt:/etc/letsencrypt
nginx-proxy-manager:
container_name: nginx-proxy-manager
image: zoeyvid/nginx-proxy-manager
restart: always
network_mode: host
volumes:
- "/opt/npm:/data"
- "/opt/npm-letsencrypt:/etc/letsencrypt" # Only needed for first time migration from original nginx-proxy-manager to this fork
- "/var/www:/var/www" # optional, if you want to use it as webserver for html
environment:
- "TZ=Europe/Berlin"
# - "NGINX_LOG_NOT_FOUND=true" # Allow logging of 404 errors
# - "NPM_LISTEN_LOCALHOST=true" # Bind the NPM Dashboard on Port 81 only to localhost
```
3. Bring up your stack by running
```bash
docker-compose up -d
# If using docker-compose-plugin
docker compose up -d
```
4. Log in to the Admin UI
@@ -85,12 +104,12 @@ docker compose up -d
When your docker container is running, connect to it on port `81` for the admin interface.
Sometimes this can take a little bit because of the entropy of keys.
[http://127.0.0.1:81](http://127.0.0.1:81)
[https://127.0.0.1:81](https://127.0.0.1:81)
Default Admin User:
```
Email: admin@example.com
Password: changeme
Password: 9KcvfmAvcVonB7YOMqdjJGsTG2JL058Rx6xFNMintAeaGETsRBRlSbfXdi1inoCa
```
Immediately after logging in with this default user you will be asked to modify your details and change your password.
@@ -101,9 +120,13 @@ Immediately after logging in with this default user you will be asked to modify
Special thanks to [all of our contributors](https://github.com/NginxProxyManager/nginx-proxy-manager/graphs/contributors).
# Please report Bugs first to this fork before reporting them to the original Repository
## Getting Support
1. [Found a bug?](https://github.com/NginxProxyManager/nginx-proxy-manager/issues)
2. [Discussions](https://github.com/NginxProxyManager/nginx-proxy-manager/discussions)
1. [Found a bug?](https://github.com/ZoeyVid/nginx-proxy-manager/issues)
2. [Discussions](https://github.com/ZoeyVid/nginx-proxy-manager/discussions)
<!---
3. [Development Gitter](https://gitter.im/nginx-proxy-manager/community)
4. [Reddit](https://reddit.com/r/nginxproxymanager)
--->

View File

@@ -1,4 +1,5 @@
const config = require('config');
const fs = require('fs');
if (!config.has('database')) {
throw new Error('Database config does not exist! Please read the instructions: https://github.com/jc21/nginx-proxy-manager/blob/master/doc/INSTALL.md');
@@ -7,8 +8,8 @@ if (!config.has('database')) {
function generateDbConfig() {
if (config.database.engine === 'knex-native') {
return config.database.knex;
} else
return {
} else {
let newConfig = {
client: config.database.engine,
connection: {
host: config.database.host,
@@ -21,6 +22,16 @@ function generateDbConfig() {
tableName: 'migrations'
}
};
if (process.env.DB_MYSQL_CA) {
newConfig.connection.ssl = {
ca: fs.readFileSync(process.env.DB_MYSQL_CA),
rejectUnauthorized: true
};
}
return newConfig;
}
}
@@ -30,4 +41,4 @@ if (typeof config.database.version !== 'undefined') {
data.version = config.database.version;
}
module.exports = require('knex')(data);
module.exports = require('knex')(data);

View File

@@ -1151,7 +1151,7 @@
"type": "string",
"minLength": 1,
"maxLength": 64,
"example": "changeme"
"example": "9KcvfmAvcVonB7YOMqdjJGsTG2JL058Rx6xFNMintAeaGETsRBRlSbfXdi1inoCa"
},
"secret": {
"type": "string",

View File

@@ -24,8 +24,8 @@ async function appStart () {
internalCertificate.initTimer();
internalIpRanges.initTimer();
const server = app.listen(3000, () => {
logger.info('Backend PID ' + process.pid + ' listening on port 3000 ...');
const server = app.listen(48693, '127.0.0.1', () => {
logger.info('Backend PID ' + process.pid + ' listening on port 48693 ...');
process.on('SIGTERM', () => {
logger.info('PID ' + process.pid + ' received SIGTERM');
@@ -132,4 +132,3 @@ try {
logger.error(err.message, err);
process.exit(1);
}

View File

@@ -12,8 +12,8 @@ const internalAuditLog = require('./audit-log');
const internalNginx = require('./nginx');
const internalHost = require('./host');
const letsencryptStaging = process.env.NODE_ENV !== 'production';
const letsencryptConfig = '/etc/letsencrypt.ini';
const certbotCommand = 'certbot';
const letsencryptConfig = '/usr/local/nginx/conf/letsencrypt.ini';
const certbotCommand = 'certbot --config-dir /data/letsencrypt';
const archiver = require('archiver');
const path = require('path');
const { isArray } = require('lodash');
@@ -74,7 +74,7 @@ const internalCertificate = {
certificates.map(function (certificate) {
promises.push(
internalCertificate.getCertificateInfoFromFile('/etc/letsencrypt/live/npm-' + certificate.id + '/fullchain.pem')
internalCertificate.getCertificateInfoFromFile('/data/letsencrypt/live/npm-' + certificate.id + '/fullchain.pem')
.then((cert_info) => {
return certificateModel
.query()
@@ -204,7 +204,7 @@ const internalCertificate = {
.then(() => {
// At this point, the letsencrypt cert should exist on disk.
// Lets get the expiry date from the file and update the row silently
return internalCertificate.getCertificateInfoFromFile('/etc/letsencrypt/live/npm-' + certificate.id + '/fullchain.pem')
return internalCertificate.getCertificateInfoFromFile('/data/letsencrypt/live/npm-' + certificate.id + '/fullchain.pem')
.then((cert_info) => {
return certificateModel
.query()
@@ -354,7 +354,7 @@ const internalCertificate = {
})
.then((certificate) => {
if (certificate.provider === 'letsencrypt') {
const zipDirectory = '/etc/letsencrypt/live/npm-' + data.id;
const zipDirectory = '/data/letsencrypt/live/npm-' + data.id;
if (!fs.existsSync(zipDirectory)) {
throw new error.ItemNotFoundError('Certificate ' + certificate.nice_name + ' does not exists');
@@ -548,6 +548,14 @@ const internalCertificate = {
resolve();
}
});
fs.writeFile(dir + '/chain.pem', certificate.meta.intermediate_certificate, function (err) {
if (err) {
reject(err);
} else {
resolve();
}
});
})
.then(() => {
return new Promise((resolve, reject) => {
@@ -868,12 +876,12 @@ const internalCertificate = {
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(', ')}`);
logger.info(`Requesting Let's Encrypt certificates via ${dns_plugin.display_name} for Cert #${certificate.id}: ${certificate.domain_names.join(', ')}`);
const credentialsLocation = '/etc/letsencrypt/credentials/credentials-' + certificate.id;
const credentialsLocation = '/data/letsencrypt/credentials/credentials-' + certificate.id;
// Escape single quotes and backslashes
const escapedCredentials = certificate.meta.dns_provider_credentials.replaceAll('\'', '\\\'').replaceAll('\\', '\\\\');
const credentialsCmd = 'mkdir -p /etc/letsencrypt/credentials 2> /dev/null; echo \'' + escapedCredentials + '\' > \'' + credentialsLocation + '\' && chmod 600 \'' + credentialsLocation + '\'';
const credentialsCmd = 'mkdir -p /data/letsencrypt/credentials 2> /dev/null; echo \'' + escapedCredentials + '\' > \'' + credentialsLocation + '\' && chmod 600 \'' + credentialsLocation + '\'';
let prepareCmd = 'pip install ' + dns_plugin.package_name + (dns_plugin.version_requirement || '') + ' ' + dns_plugin.dependencies;
// Special case for cloudflare
@@ -946,7 +954,7 @@ const internalCertificate = {
return renewMethod(certificate)
.then(() => {
return internalCertificate.getCertificateInfoFromFile('/etc/letsencrypt/live/npm-' + certificate.id + '/fullchain.pem');
return internalCertificate.getCertificateInfoFromFile('/data/letsencrypt/live/npm-' + certificate.id + '/fullchain.pem');
})
.then((cert_info) => {
return certificateModel
@@ -1008,7 +1016,7 @@ const internalCertificate = {
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's Encrypt certificates via ${dns_plugin.display_name} for Cert #${certificate.id}: ${certificate.domain_names.join(', ')}`);
let mainCmd = certbotCommand + ' renew ' +
'--config "' + letsencryptConfig + '" ' +
@@ -1019,7 +1027,7 @@ const internalCertificate = {
// Prepend the path to the credentials file as an environment variable
if (certificate.meta.dns_provider === 'route53') {
const credentialsLocation = '/etc/letsencrypt/credentials/credentials-' + certificate.id;
const credentialsLocation = '/data/letsencrypt/credentials/credentials-' + certificate.id;
mainCmd = 'AWS_CONFIG_FILE=\'' + credentialsLocation + '\' ' + mainCmd;
}
@@ -1042,12 +1050,12 @@ const internalCertificate = {
const mainCmd = certbotCommand + ' revoke ' +
'--config "' + letsencryptConfig + '" ' +
'--cert-path "/etc/letsencrypt/live/npm-' + certificate.id + '/fullchain.pem" ' +
'--cert-path "/data/letsencrypt/live/npm-' + certificate.id + '/fullchain.pem" ' +
'--delete-after-revoke ' +
(letsencryptStaging ? '--staging' : '');
// Don't fail command if file does not exist
const delete_credentialsCmd = `rm -f '/etc/letsencrypt/credentials/credentials-${certificate.id}' || true`;
const delete_credentialsCmd = `rm -f '/data/letsencrypt/credentials/credentials-${certificate.id}' || true`;
logger.info('Command:', mainCmd + '; ' + delete_credentialsCmd);
@@ -1071,7 +1079,7 @@ const internalCertificate = {
* @returns {Boolean}
*/
hasLetsEncryptSslCerts: (certificate) => {
const letsencryptPath = '/etc/letsencrypt/live/npm-' + certificate.id;
const letsencryptPath = '/data/letsencrypt/live/npm-' + certificate.id;
return fs.existsSync(letsencryptPath + '/fullchain.pem') && fs.existsSync(letsencryptPath + '/privkey.pem');
},
@@ -1147,7 +1155,7 @@ const internalCertificate = {
}
// Create a test challenge file
const testChallengeDir = '/data/letsencrypt-acme-challenge/.well-known/acme-challenge';
const testChallengeDir = '/tmp/letsencrypt-acme-challenge/.well-known/acme-challenge';
const testChallengeFile = testChallengeDir + '/test-challenge';
fs.mkdirSync(testChallengeDir, {recursive: true});
fs.writeFileSync(testChallengeFile, 'Success', {encoding: 'utf8'});

View File

@@ -125,7 +125,7 @@ const internalIpRanges = {
return new Promise((resolve, reject) => {
let template = null;
let filename = '/etc/nginx/conf.d/include/ip_ranges.conf';
let filename = '/usr/local/nginx/conf/conf.d/include/ip_ranges.conf';
try {
template = fs.readFileSync(__dirname + '/../templates/ip_ranges.conf', {encoding: 'utf8'});
} catch (err) {

View File

@@ -59,7 +59,7 @@ const internalNginx = {
let valid_lines = [];
let err_lines = err.message.split('\n');
err_lines.map(function (line) {
if (line.indexOf('/var/log/nginx/error.log') === -1) {
if (line.indexOf('/data/nginx/error.log') === -1) {
valid_lines.push(line);
}
});
@@ -101,7 +101,7 @@ const internalNginx = {
logger.info('Testing Nginx configuration');
}
return utils.exec('/usr/sbin/nginx -t -g "error_log off;"');
return utils.exec('nginx -t -g "error_log off;"');
},
/**
@@ -111,7 +111,7 @@ const internalNginx = {
return internalNginx.test()
.then(() => {
logger.info('Reloading Nginx');
return utils.exec('/usr/sbin/nginx -s reload');
return utils.exec('nginx -s reload');
});
},
@@ -124,7 +124,7 @@ const internalNginx = {
host_type = host_type.replace(new RegExp('-', 'g'), '_');
if (host_type === 'default') {
return '/data/nginx/default_host/site.conf';
return '/data/nginx/default.conf';
}
return '/data/nginx/' + host_type + '/' + host_id + '.conf';
@@ -287,7 +287,7 @@ const internalNginx = {
return new Promise((resolve, reject) => {
let template = null;
let filename = '/data/nginx/temp/letsencrypt_' + certificate.id + '.conf';
let filename = '/usr/local/nginx/conf/conf.d/letsencrypt_' + certificate.id + '.conf';
try {
template = fs.readFileSync(__dirname + '/../templates/letsencrypt-request.conf', {encoding: 'utf8'});
@@ -329,7 +329,7 @@ const internalNginx = {
deleteLetsEncryptRequestConfig: (certificate, throw_errors) => {
return new Promise((resolve, reject) => {
try {
let config_file = '/data/nginx/temp/letsencrypt_' + certificate.id + '.conf';
let config_file = '/usr/local/nginx/conf/conf.d/letsencrypt_' + certificate.id + '.conf';
if (debug_mode) {
logger.warn('Deleting nginx config: ' + config_file);

View File

@@ -1,6 +1,6 @@
const error = require('../error');
const path = require('path');
const parser = require('json-schema-ref-parser');
const parser = require('@apidevtools/json-schema-ref-parser');
const ajv = require('ajv')({
verbose: true,

View File

@@ -95,7 +95,7 @@ class AccessList extends Model {
}
get passauth() {
return this.pass_auth ? '' : 'proxy_set_header Authorization "";';
return this.pass_auth ? 'proxy_set_header Authorization "";' : '';
}
}

View File

@@ -4,40 +4,35 @@
"description": "A beautiful interface for creating Nginx endpoints",
"main": "js/index.js",
"dependencies": {
"ajv": "^6.12.0",
"archiver": "^5.3.0",
"batchflow": "^0.4.0",
"bcrypt": "^5.0.0",
"body-parser": "^1.19.0",
"compression": "^1.7.4",
"config": "^3.3.1",
"express": "^4.17.1",
"express-fileupload": "^1.1.9",
"gravatar": "^1.8.0",
"json-schema-ref-parser": "^8.0.0",
"jsonwebtoken": "^8.5.1",
"knex": "^0.20.13",
"liquidjs": "^9.11.10",
"lodash": "^4.17.21",
"moment": "^2.29.4",
"mysql": "^2.18.1",
"node-rsa": "^1.0.8",
"nodemon": "^2.0.2",
"objection": "^2.2.16",
"path": "^0.12.7",
"signale": "^1.4.0",
"sqlite3": "^4.1.1",
"temp-write": "^4.0.0"
"@apidevtools/json-schema-ref-parser": "9.1.0",
"ajv": "6.12.6",
"archiver": "5.3.1",
"batchflow": "0.4.0",
"bcrypt": "5.1.0",
"body-parser": "1.20.1",
"compression": "1.7.4",
"config": "3.3.8",
"express": "4.18.2",
"express-fileupload": "1.4.0",
"gravatar": "1.8.2",
"jsonwebtoken": "8.5.1",
"knex": "2.3.0",
"liquidjs": "9.43.0",
"lodash": "4.17.21",
"moment": "2.29.4",
"mysql": "2.18.1",
"node-rsa": "1.1.1",
"nodemon": "2.0.20",
"objection": "2.2.18",
"path": "0.12.7",
"signale": "1.4.0",
"sqlite3": "5.1.4",
"temp-write": "4.0.0"
},
"signale": {
"displayDate": true,
"displayTimestamp": true
},
"author": "Jamie Curnow <jc@jc21.com>",
"license": "MIT",
"devDependencies": {
"eslint": "^6.8.0",
"eslint-plugin-align-assignments": "^1.1.2",
"prettier": "^2.0.4"
}
"license": "MIT"
}

View File

@@ -80,7 +80,7 @@ const setupDefaultUser = () => {
.then((row) => {
if (!row.count) {
// Create a new user and set password
logger.info('Creating a new user: admin@example.com with password: changeme');
logger.info('Creating a new user: admin@example.com with password: 9KcvfmAvcVonB7YOMqdjJGsTG2JL058Rx6xFNMintAeaGETsRBRlSbfXdi1inoCa');
let data = {
is_deleted: 0,
@@ -100,7 +100,7 @@ const setupDefaultUser = () => {
.insert({
user_id: user.id,
type: 'password',
secret: 'changeme',
secret: '9KcvfmAvcVonB7YOMqdjJGsTG2JL058Rx6xFNMintAeaGETsRBRlSbfXdi1inoCa',
meta: {},
})
.then(() => {
@@ -185,10 +185,10 @@ const setupCertbotPlugins = () => {
}
// Make sure credentials file exists
const credentials_loc = '/etc/letsencrypt/credentials/credentials-' + certificate.id;
const credentials_loc = '/data/letsencrypt/credentials/credentials-' + certificate.id;
// Escape single quotes and backslashes
const escapedCredentials = certificate.meta.dns_provider_credentials.replaceAll('\'', '\\\'').replaceAll('\\', '\\\\');
const credentials_cmd = '[ -f \'' + credentials_loc + '\' ] || { mkdir -p /etc/letsencrypt/credentials 2> /dev/null; echo \'' + escapedCredentials + '\' > \'' + credentials_loc + '\' && chmod 600 \'' + credentials_loc + '\'; }';
const credentials_cmd = '[ -f \'' + credentials_loc + '\' ] || { mkdir -p /data/letsencrypt/credentials 2> /dev/null; echo \'' + escapedCredentials + '\' > \'' + credentials_loc + '\' && chmod 600 \'' + credentials_loc + '\'; }';
promises.push(utils.exec(credentials_cmd));
}
});
@@ -212,31 +212,9 @@ const setupCertbotPlugins = () => {
});
};
/**
* Starts a timer to call run the logrotation binary every two days
* @returns {Promise}
*/
const setupLogrotation = () => {
const intervalTimeout = 1000 * 60 * 60 * 24 * 2; // 2 days
const runLogrotate = async () => {
try {
await utils.exec('logrotate /etc/logrotate.d/nginx-proxy-manager');
logger.info('Logrotate completed.');
} catch (e) { logger.warn(e); }
};
logger.info('Logrotate Timer initialized');
setInterval(runLogrotate, intervalTimeout);
// And do this now as well
return runLogrotate();
};
module.exports = function () {
return setupJwt()
.then(setupDefaultUser)
.then(setupDefaultSettings)
.then(setupCertbotPlugins)
.then(setupLogrotation);
.then(setupCertbotPlugins);
};

View File

@@ -1,4 +0,0 @@
{% if caching_enabled == 1 or caching_enabled == true -%}
# Asset Caching
include conf.d/include/assets.conf;
{% endif %}

View File

@@ -1,14 +1,19 @@
{% if certificate and certificate_id > 0 -%}
{% if certificate.provider == "letsencrypt" %}
# Let's Encrypt SSL
include conf.d/include/letsencrypt-acme-challenge.conf;
include conf.d/include/ssl-ciphers.conf;
ssl_certificate /etc/letsencrypt/live/npm-{{ certificate_id }}/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/npm-{{ certificate_id }}/privkey.pem;
ssl_certificate /data/letsencrypt/live/npm-{{ certificate_id }}/fullchain.pem;
ssl_certificate_key /data/letsencrypt/live/npm-{{ certificate_id }}/privkey.pem;
ssl_trusted_certificate /data/letsencrypt/live/npm-{{ certificate_id }}/chain.pem;
ssl_stapling on;
ssl_stapling_verify on;
{% else %}
# Custom SSL
include conf.d/include/ssl-ciphers.conf;
ssl_certificate /data/custom_ssl/npm-{{ certificate_id }}/fullchain.pem;
ssl_certificate_key /data/custom_ssl/npm-{{ certificate_id }}/privkey.pem;
ssl_trusted_certificate /data/custom_ssl/npm-{{ certificate_id }}/chain.pem;
ssl_stapling on;
ssl_stapling_verify on;
{% endif %}
{% endif %}

View File

@@ -1,8 +1,7 @@
{% if certificate and certificate_id > 0 -%}
{% if ssl_forced == 1 or ssl_forced == true %}
{% if hsts_enabled == 1 or hsts_enabled == true %}
# HSTS (ngx_http_headers_module is required) (63072000 seconds = 2 years)
add_header Strict-Transport-Security "max-age=63072000;{% if hsts_subdomains == 1 or hsts_subdomains == true -%} includeSubDomains;{% endif %} preload" always;
security_headers on;
{% endif %}
{% endif %}
{% endif %}

View File

@@ -1,15 +1,14 @@
listen 80;
{% if ipv6 -%}
listen [::]:80;
{% else -%}
#listen [::]:80;
{% endif %}
{% if certificate -%}
listen 443 ssl{% if http2_support %} http2{% endif %};
{% if ipv6 -%}
listen [::]:443 ssl{% if http2_support %} http2{% endif %};
{% else -%}
#listen [::]:443;
{% if http2_support -%}
listen 443 http3;
listen [::]:443 http3;
add_header alt-svc 'h3=":443"; ma=86400, h3-29=":443"; ma=86400';
{% endif %}
{% endif %}
server_name {{ domain_names | join: " " }};

View File

@@ -1,9 +1,11 @@
location {{ path }} {
proxy_set_header Accept-Encoding "";
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Scheme $scheme;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_http_version 1.1;
proxy_pass {{ forward_scheme }}://{{ forward_host }}:{{ forward_port }}{{ forward_path }};
{% if access_list_id > 0 %}
@@ -27,19 +29,10 @@
{% endif %}
{% include "_assets.conf" %}
{% include "_exploits.conf" %}
{% include "_forced_ssl.conf" %}
{% include "_hsts.conf" %}
{% if allow_websocket_upgrade == 1 or allow_websocket_upgrade == true %}
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $http_connection;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
{% endif %}
{{ advanced_config }}
}

View File

@@ -7,14 +7,11 @@ server {
{% include "_hsts.conf" %}
{% include "_forced_ssl.conf" %}
access_log /data/logs/dead-host-{{ id }}_access.log standard;
error_log /data/logs/dead-host-{{ id }}_error.log warn;
{{ advanced_config }}
include conf.d/include/letsencrypt-acme-challenge.conf;
{% if use_default_location %}
location / {
{% include "_hsts.conf" %}
include conf.d/include/letsencrypt-acme-challenge.conf;
return 404;
}
{% endif %}

View File

@@ -5,36 +5,73 @@
# Skipping output, congratulations page configration is baked in.
{%- else %}
server {
listen 80 default;
{% if ipv6 -%}
listen [::]:80 default;
{% else -%}
#listen [::]:80 default;
{% endif %}
server_name default-host.localhost;
access_log /data/logs/default-host_access.log combined;
error_log /data/logs/default-host_error.log warn;
{% include "_exploits.conf" %}
listen 80 default_server;
listen [::]:80 default_server;
listen 443 ssl http2 default_server;
listen [::]:443 ssl http2 default_server;
listen 443 http3 default_server;
listen [::]:443 http3 default_server;
server_name default-host;
include conf.d/include/force-ssl.conf;
include conf.d/include/ssl-ciphers.conf;
include conf.d/include/letsencrypt-acme-challenge.conf;
include conf.d/include/block-exploits.conf;
add_header alt-svc 'h3=":443"; ma=86400, h3-29=":443"; ma=86400';
ssl_certificate /data/nginx/dummycert.pem;
ssl_certificate_key /data/nginx/dummykey.pem;
{%- if value == "404" %}
location / {
include conf.d/include/letsencrypt-acme-challenge.conf;
return 404;
}
{% endif %}
{%- if value == "redirect" %}
location / {
return 301 {{ meta.redirect }};
include conf.d/include/letsencrypt-acme-challenge.conf;
return 307 {{ meta.redirect }};
}
{%- endif %}
{%- if value == "html" %}
root /data/nginx/default_www;
location / {
include conf.d/include/letsencrypt-acme-challenge.conf;
try_files $uri /index.html;
}
{%- endif %}
}
{% endif %}
# ------------------------------------------------------------
# prevent processing requests with undefined server names
# ------------------------------------------------------------
server {
listen 80;
listen [::]:80;
listen 443 ssl http2;
listen [::]:443 ssl http2;
listen 443 http3;
listen [::]:443 http3;
server_name "";
return 444;
include conf.d/include/force-ssl.conf;
include conf.d/include/ssl-ciphers.conf;
include conf.d/include/letsencrypt-acme-challenge.conf;
include conf.d/include/block-exploits.conf;
add_header alt-svc 'h3=":443"; ma=86400, h3-29=":443"; ma=86400';
ssl_certificate /data/nginx/dummycert.pem;
ssl_certificate_key /data/nginx/dummykey.pem;
}

View File

@@ -2,18 +2,14 @@
server {
listen 80;
{% if ipv6 -%}
listen [::]:80;
{% endif %}
server_name {{ domain_names | join: " " }};
access_log /data/logs/letsencrypt-requests_access.log standard;
error_log /data/logs/letsencrypt-requests_error.log warn;
include conf.d/include/letsencrypt-acme-challenge.conf;
location / {
include conf.d/include/letsencrypt-acme-challenge.conf;
return 404;
}
}

View File

@@ -8,28 +8,23 @@ server {
{% include "_listen.conf" %}
{% include "_certificates.conf" %}
{% include "_assets.conf" %}
{% include "_exploits.conf" %}
{% include "_hsts.conf" %}
{% include "_forced_ssl.conf" %}
{% if allow_websocket_upgrade == 1 or allow_websocket_upgrade == true %}
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $http_connection;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $http_connection;
{% endif %}
access_log /data/logs/proxy-host-{{ id }}_access.log proxy;
error_log /data/logs/proxy-host-{{ id }}_error.log warn;
{{ advanced_config }}
{{ locations }}
include conf.d/include/letsencrypt-acme-challenge.conf;
{% if use_default_location %}
location / {
include conf.d/include/letsencrypt-acme-challenge.conf;
{% if access_list_id > 0 %}
{% if access_list.items.length > 0 %}
# Authorization
@@ -51,12 +46,9 @@ proxy_http_version 1.1;
{% endif %}
{% include "_hsts.conf" %}
{% if allow_websocket_upgrade == 1 or allow_websocket_upgrade == true %}
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $http_connection;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
{% endif %}
# Proxy!
@@ -65,6 +57,6 @@ proxy_http_version 1.1;
{% endif %}
# Custom
include /data/nginx/custom/server_proxy[.]conf;
include /data/nginx/custom/server_proxy.conf;
}
{% endif %}

View File

@@ -4,20 +4,15 @@
server {
{% include "_listen.conf" %}
{% include "_certificates.conf" %}
{% include "_assets.conf" %}
{% include "_exploits.conf" %}
{% include "_hsts.conf" %}
{% include "_forced_ssl.conf" %}
access_log /data/logs/redirection-host-{{ id }}_access.log standard;
error_log /data/logs/redirection-host-{{ id }}_error.log warn;
{{ advanced_config }}
include conf.d/include/letsencrypt-acme-challenge.conf;
{% if use_default_location %}
location / {
{% include "_hsts.conf" %}
include conf.d/include/letsencrypt-acme-challenge.conf;
{% if preserve_path == 1 or preserve_path == true %}
return {{ forward_http_code }} {{ forward_scheme }}://{{ forward_domain_name }}$request_uri;
{% else %}
@@ -27,6 +22,6 @@ server {
{% endif %}
# Custom
include /data/nginx/custom/server_redirect[.]conf;
include /data/nginx/custom/server_redirect.conf;
}
{% endif %}

View File

@@ -6,32 +6,24 @@
{% if tcp_forwarding == 1 or tcp_forwarding == true -%}
server {
listen {{ incoming_port }};
{% if ipv6 -%}
listen [::]:{{ incoming_port }};
{% else -%}
#listen [::]:{{ incoming_port }};
{% endif %}
proxy_pass {{ forwarding_host }}:{{ forwarding_port }};
# Custom
include /data/nginx/custom/server_stream[.]conf;
include /data/nginx/custom/server_stream_tcp[.]conf;
include /data/nginx/custom/server_stream.conf;
include /data/nginx/custom/server_stream_tcp.conf;
}
{% endif %}
{% if udp_forwarding == 1 or udp_forwarding == true %}
server {
listen {{ incoming_port }} udp;
{% if ipv6 -%}
listen [::]:{{ incoming_port }} udp;
{% else -%}
#listen [::]:{{ incoming_port }} udp;
{% endif %}
proxy_pass {{ forwarding_host }}:{{ forwarding_port }};
# Custom
include /data/nginx/custom/server_stream[.]conf;
include /data/nginx/custom/server_stream_udp[.]conf;
include /data/nginx/custom/server_stream.conf;
include /data/nginx/custom/server_stream_udp.conf;
}
{% endif %}
{% endif %}
{% endif %}

File diff suppressed because it is too large Load Diff

15
compose.yaml Normal file
View File

@@ -0,0 +1,15 @@
version: "3"
services:
nginx-proxy-manager:
container_name: nginx-proxy-manager
image: zoeyvid/nginx-proxy-manager
restart: always
network_mode: host
volumes:
- "/opt/npm:/data"
- "/opt/npm-letsencrypt:/etc/letsencrypt" # Only needed for first time migration from original nginx-proxy-manager to this fork
- "/var/www:/var/www" # optional, if you want to use it as webserver for html
environment:
- "TZ=Europe/Berlin"
# - "NGINX_LOG_NOT_FOUND=true" # Allow logging of 404 errors
# - "NPM_LISTEN_LOCALHOST=true" # Bind the NPM Dashboard on Port 81 only to localhost

View File

@@ -1,14 +0,0 @@
rules:
# If the efficiency is measured below X%, mark as failed.
# Expressed as a ratio between 0-1.
lowestEfficiency: 0.99
# If the amount of wasted space is at least X or larger than X, mark as failed.
# Expressed in B, KB, MB, and GB.
highestWastedBytes: 15MB
# If the amount of wasted space makes up for X% or more of the image, mark as failed.
# Note: the base image layer is NOT included in the total image size.
# Expressed as a ratio between 0-1; fails if the threshold is met or crossed.
highestUserWastedPercent: 0.02

View File

@@ -1,63 +0,0 @@
# This is a Dockerfile intended to be built using `docker buildx`
# for multi-arch support. Building with `docker build` may have unexpected results.
# This file assumes that the frontend has been built using ./scripts/frontend-build
FROM nginxproxymanager/nginx-full:certbot-node
ARG TARGETPLATFORM
ARG BUILD_VERSION
ARG BUILD_COMMIT
ARG BUILD_DATE
ENV SUPPRESS_NO_CONFIG_WARNING=1 \
S6_FIX_ATTRS_HIDDEN=1 \
S6_BEHAVIOUR_IF_STAGE2_FAILS=1 \
NODE_ENV=production \
NPM_BUILD_VERSION="${BUILD_VERSION}" \
NPM_BUILD_COMMIT="${BUILD_COMMIT}" \
NPM_BUILD_DATE="${BUILD_DATE}"
RUN echo "fs.file-max = 65535" > /etc/sysctl.conf \
&& apt-get update \
&& apt-get install -y --no-install-recommends jq logrotate \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
# s6 overlay
COPY scripts/install-s6 /tmp/install-s6
RUN /tmp/install-s6 "${TARGETPLATFORM}" && rm -f /tmp/install-s6
EXPOSE 80 81 443
COPY backend /app
COPY frontend/dist /app/frontend
COPY global /app/global
WORKDIR /app
RUN yarn install
# add late to limit cache-busting by modifications
COPY docker/rootfs /
# Remove frontend service not required for prod, dev nginx config as well
RUN rm -rf /etc/services.d/frontend /etc/nginx/conf.d/dev.conf
# Change permission of logrotate config file
RUN chmod 644 /etc/logrotate.d/nginx-proxy-manager
# fix for pip installs
# https://github.com/NginxProxyManager/nginx-proxy-manager/issues/1769
RUN pip uninstall --yes setuptools \
&& pip install "setuptools==58.0.0"
VOLUME [ "/data", "/etc/letsencrypt" ]
ENTRYPOINT [ "/init" ]
LABEL org.label-schema.schema-version="1.0" \
org.label-schema.license="MIT" \
org.label-schema.name="nginx-proxy-manager" \
org.label-schema.description="Docker container for managing Nginx proxy hosts with a simple, powerful interface " \
org.label-schema.url="https://github.com/jc21/nginx-proxy-manager" \
org.label-schema.vcs-url="https://github.com/jc21/nginx-proxy-manager.git" \
org.label-schema.cmd="docker run --rm -ti jc21/nginx-proxy-manager:latest"

View File

@@ -1,29 +0,0 @@
FROM nginxproxymanager/nginx-full:certbot-node
LABEL maintainer="Jamie Curnow <jc@jc21.com>"
ENV S6_LOGGING=0 \
SUPPRESS_NO_CONFIG_WARNING=1 \
S6_FIX_ATTRS_HIDDEN=1
RUN echo "fs.file-max = 65535" > /etc/sysctl.conf \
&& apt-get update \
&& apt-get install -y certbot jq python3-pip logrotate \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
# Task
RUN cd /usr \
&& curl -sL https://taskfile.dev/install.sh | sh \
&& cd /root
COPY rootfs /
RUN rm -f /etc/nginx/conf.d/production.conf
RUN chmod 644 /etc/logrotate.d/nginx-proxy-manager
# s6 overlay
RUN curl -L -o /tmp/s6-overlay-amd64.tar.gz "https://github.com/just-containers/s6-overlay/releases/download/v1.22.1.0/s6-overlay-amd64.tar.gz" \
&& tar -xzf /tmp/s6-overlay-amd64.tar.gz -C /
EXPOSE 80 81 443
ENTRYPOINT [ "/init" ]

View File

@@ -1,80 +0,0 @@
# WARNING: This is a CI docker-compose file used for building and testing of the entire app, it should not be used for production.
version: "3"
services:
fullstack-mysql:
image: ${IMAGE}:ci-${BUILD_NUMBER}
environment:
NODE_ENV: "development"
FORCE_COLOR: 1
DB_MYSQL_HOST: "db"
DB_MYSQL_PORT: 3306
DB_MYSQL_USER: "npm"
DB_MYSQL_PASSWORD: "npm"
DB_MYSQL_NAME: "npm"
volumes:
- npm_data:/data
expose:
- 81
- 80
- 443
depends_on:
- db
healthcheck:
test: ["CMD", "/bin/check-health"]
interval: 10s
timeout: 3s
fullstack-sqlite:
image: ${IMAGE}:ci-${BUILD_NUMBER}
environment:
NODE_ENV: "development"
FORCE_COLOR: 1
DB_SQLITE_FILE: "/data/database.sqlite"
volumes:
- npm_data:/data
expose:
- 81
- 80
- 443
healthcheck:
test: ["CMD", "/bin/check-health"]
interval: 10s
timeout: 3s
db:
image: jc21/mariadb-aria
environment:
MYSQL_ROOT_PASSWORD: "npm"
MYSQL_DATABASE: "npm"
MYSQL_USER: "npm"
MYSQL_PASSWORD: "npm"
volumes:
- db_data:/var/lib/mysql
cypress-mysql:
image: ${IMAGE}-cypress:ci-${BUILD_NUMBER}
build:
context: ../test/
dockerfile: cypress/Dockerfile
environment:
CYPRESS_baseUrl: "http://fullstack-mysql:81"
volumes:
- cypress-logs:/results
command: cypress run --browser chrome --config-file=${CYPRESS_CONFIG:-cypress/config/ci.json}
cypress-sqlite:
image: ${IMAGE}-cypress:ci-${BUILD_NUMBER}
build:
context: ../test/
dockerfile: cypress/Dockerfile
environment:
CYPRESS_baseUrl: "http://fullstack-sqlite:81"
volumes:
- cypress-logs:/results
command: cypress run --browser chrome --config-file=${CYPRESS_CONFIG:-cypress/config/ci.json}
volumes:
cypress-logs:
npm_data:
db_data:

View File

@@ -1,62 +0,0 @@
# WARNING: This is a DEVELOPMENT docker-compose file, it should not be used for production.
version: "3.5"
services:
npm:
image: nginxproxymanager:dev
container_name: npm_core
build:
context: ./
dockerfile: ./dev/Dockerfile
ports:
- 3080:80
- 3081:81
- 3443:443
networks:
- nginx_proxy_manager
environment:
NODE_ENV: "development"
FORCE_COLOR: 1
DEVELOPMENT: "true"
DB_MYSQL_HOST: "db"
DB_MYSQL_PORT: 3306
DB_MYSQL_USER: "npm"
DB_MYSQL_PASSWORD: "npm"
DB_MYSQL_NAME: "npm"
# DB_SQLITE_FILE: "/data/database.sqlite"
# DISABLE_IPV6: "true"
volumes:
- npm_data:/data
- le_data:/etc/letsencrypt
- ../backend:/app
- ../frontend:/app/frontend
- ../global:/app/global
depends_on:
- db
working_dir: /app
db:
image: jc21/mariadb-aria
container_name: npm_db
ports:
- 33306:3306
networks:
- nginx_proxy_manager
environment:
MYSQL_ROOT_PASSWORD: "npm"
MYSQL_DATABASE: "npm"
MYSQL_USER: "npm"
MYSQL_PASSWORD: "npm"
volumes:
- db_data:/var/lib/mysql
volumes:
npm_data:
name: npm_core_data
le_data:
name: npm_le_data
db_data:
name: npm_db_data
networks:
nginx_proxy_manager:
name: npm_network

View File

@@ -1,11 +0,0 @@
#!/bin/bash
OK=$(curl --silent http://127.0.0.1:81/api/ | jq --raw-output '.status')
if [ "$OK" == "OK" ]; then
echo "OK"
exit 0
else
echo "NOT OK"
exit 1
fi

View File

@@ -1,46 +0,0 @@
#!/bin/bash
# This command reads the `DISABLE_IPV6` env var and will either enable
# or disable ipv6 in all nginx configs based on this setting.
# Lowercase
DISABLE_IPV6=$(echo "${DISABLE_IPV6:-}" | tr '[:upper:]' '[:lower:]')
CYAN='\E[1;36m'
BLUE='\E[1;34m'
YELLOW='\E[1;33m'
RED='\E[1;31m'
RESET='\E[0m'
FOLDER=$1
if [ "$FOLDER" == "" ]; then
echo -e "${RED} $0 requires a absolute folder path as the first argument!${RESET}"
echo -e "${YELLOW} ie: $0 /data/nginx${RESET}"
exit 1
fi
FILES=$(find "$FOLDER" -type f -name "*.conf")
if [ "$DISABLE_IPV6" == "true" ] || [ "$DISABLE_IPV6" == "on" ] || [ "$DISABLE_IPV6" == "1" ] || [ "$DISABLE_IPV6" == "yes" ]; then
# IPV6 is disabled
echo "Disabling IPV6 in hosts"
echo -e "${BLUE} ${CYAN}Disabling IPV6 in hosts: ${YELLOW}${FOLDER}${RESET}"
# Iterate over configs and run the regex
for FILE in $FILES
do
echo -e " ${BLUE} ${YELLOW}${FILE}${RESET}"
sed -E -i 's/^([^#]*)listen \[::\]/\1#listen [::]/g' "$FILE"
done
else
# IPV6 is enabled
echo -e "${BLUE} ${CYAN}Enabling IPV6 in hosts: ${YELLOW}${FOLDER}${RESET}"
# Iterate over configs and run the regex
for FILE in $FILES
do
echo -e " ${BLUE} ${YELLOW}${FILE}${RESET}"
sed -E -i 's/^(\s*)#listen \[::\]/\1listen [::]/g' "$FILE"
done
fi

View File

@@ -1,2 +0,0 @@
*
!.gitignore

View File

@@ -1,3 +0,0 @@
*
!.gitignore
!*.sh

View File

@@ -1,7 +0,0 @@
#!/usr/bin/with-contenv bash
set -e
mkdir -p /data/logs
echo "Changing ownership of /data/logs to $(id -u):$(id -g)"
chown -R "$(id -u):$(id -g)" /data/logs

View File

@@ -1,29 +0,0 @@
#!/usr/bin/with-contenv bash
# ref: https://github.com/linuxserver/docker-baseimage-alpine/blob/master/root/etc/cont-init.d/01-envfile
# in s6, environmental variables are written as text files for s6 to monitor
# search through full-path filenames for files ending in "__FILE"
for FILENAME in $(find /var/run/s6/container_environment/ | grep "__FILE$"); do
echo "[secret-init] Evaluating ${FILENAME##*/} ..."
# set SECRETFILE to the contents of the full-path textfile
SECRETFILE=$(cat ${FILENAME})
# SECRETFILE=${FILENAME}
# echo "[secret-init] Set SECRETFILE to ${SECRETFILE}" # DEBUG - rm for prod!
# if SECRETFILE exists / is not null
if [[ -f ${SECRETFILE} ]]; then
# strip the appended "__FILE" from environmental variable name ...
STRIPFILE=$(echo ${FILENAME} | sed "s/__FILE//g")
# echo "[secret-init] Set STRIPFILE to ${STRIPFILE}" # DEBUG - rm for prod!
# ... and set value to contents of secretfile
# since s6 uses text files, this is effectively "export ..."
printf $(cat ${SECRETFILE}) > ${STRIPFILE}
# echo "[secret-init] Set ${STRIPFILE##*/} to $(cat ${STRIPFILE})" # DEBUG - rm for prod!"
echo "[secret-init] Success! ${STRIPFILE##*/} set from ${FILENAME##*/}"
else
echo "[secret-init] cannot find secret in ${FILENAME}"
fi
done

View File

@@ -1,2 +0,0 @@
*
!.gitignore

View File

@@ -1,25 +0,0 @@
/data/logs/*_access.log /data/logs/*/access.log {
create 0644 root root
weekly
rotate 4
missingok
notifempty
compress
sharedscripts
postrotate
/bin/kill -USR1 `cat /run/nginx.pid 2>/dev/null` 2>/dev/null || true
endscript
}
/data/logs/*_error.log /data/logs/*/error.log {
create 0644 root root
weekly
rotate 10
missingok
notifempty
compress
sharedscripts
postrotate
/bin/kill -USR1 `cat /run/nginx.pid 2>/dev/null` 2>/dev/null || true
endscript
}

View File

@@ -1,40 +0,0 @@
# "You are not configured" page, which is the default if another default doesn't exist
server {
listen 80;
listen [::]:80;
set $forward_scheme "http";
set $server "127.0.0.1";
set $port "80";
server_name localhost-nginx-proxy-manager;
access_log /data/logs/fallback_access.log standard;
error_log /data/logs/fallback_error.log warn;
include conf.d/include/assets.conf;
include conf.d/include/block-exploits.conf;
include conf.d/include/letsencrypt-acme-challenge.conf;
location / {
index index.html;
root /var/www/html;
}
}
# First 443 Host, which is the default if another default doesn't exist
server {
listen 443 ssl;
listen [::]:443 ssl;
set $forward_scheme "https";
set $server "127.0.0.1";
set $port "443";
server_name localhost;
access_log /data/logs/fallback_access.log standard;
error_log /dev/null crit;
ssl_certificate /data/nginx/dummycert.pem;
ssl_certificate_key /data/nginx/dummykey.pem;
include conf.d/include/ssl-ciphers.conf;
return 444;
}

View File

@@ -1,29 +0,0 @@
server {
listen 81 default;
listen [::]:81 default;
server_name nginxproxymanager-dev;
root /app/frontend/dist;
access_log /dev/null;
location /api {
return 302 /api/;
}
location /api/ {
add_header X-Served-By $host;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Scheme $scheme;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_pass http://127.0.0.1:3000/;
proxy_read_timeout 15m;
proxy_send_timeout 15m;
}
location / {
index index.html;
try_files $uri $uri.html $uri/ /index.html;
}
}

View File

@@ -1 +0,0 @@
resolvers.conf

View File

@@ -1,31 +0,0 @@
location ~* ^.*\.(css|js|jpe?g|gif|png|webp|woff|eot|ttf|svg|ico|css\.map|js\.map)$ {
if_modified_since off;
# use the public cache
proxy_cache public-cache;
proxy_cache_key $host$request_uri;
# ignore these headers for media
proxy_ignore_headers Set-Cookie Cache-Control Expires X-Accel-Expires;
# cache 200s and also 404s (not ideal but there are a few 404 images for some reason)
proxy_cache_valid any 30m;
proxy_cache_valid 404 1m;
# strip this header to avoid If-Modified-Since requests
proxy_hide_header Last-Modified;
proxy_hide_header Cache-Control;
proxy_hide_header Vary;
proxy_cache_bypass 0;
proxy_no_cache 0;
proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504 http_404;
proxy_connect_timeout 5s;
proxy_read_timeout 45s;
expires @30m;
access_log off;
include conf.d/include/proxy.conf;
}

View File

@@ -1,3 +0,0 @@
if ($scheme = "http") {
return 301 https://$host$request_uri;
}

View File

@@ -1,2 +0,0 @@
# This should be left blank is it is populated programatically
# by the application backend.

View File

@@ -1,30 +0,0 @@
# Rule for legitimate ACME Challenge requests (like /.well-known/acme-challenge/xxxxxxxxx)
# We use ^~ here, so that we don't check other regexes (for speed-up). We actually MUST cancel
# other regex checks, because in our other config files have regex rule that denies access to files with dotted names.
location ^~ /.well-known/acme-challenge/ {
# Since this is for letsencrypt authentication of a domain and they do not give IP ranges of their infrastructure
# we need to open up access by turning off auth and IP ACL for this location.
auth_basic off;
auth_request off;
allow all;
# Set correct content type. According to this:
# https://community.letsencrypt.org/t/using-the-webroot-domain-verification-method/1445/29
# Current specification requires "text/plain" or no content header at all.
# It seems that "text/plain" is a safe option.
default_type "text/plain";
# This directory must be the same as in /etc/letsencrypt/cli.ini
# as "webroot-path" parameter. Also don't forget to set "authenticator" parameter
# there to "webroot".
# Do NOT use alias, use root! Target directory is located here:
# /var/www/common/letsencrypt/.well-known/acme-challenge/
root /data/letsencrypt-acme-challenge;
}
# Hide /acme-challenge subdirectory and return 404 on all requests.
# It is somewhat more secure than letting Nginx return 403.
# Ending slash is important!
location = /.well-known/acme-challenge/ {
return 404;
}

View File

@@ -1,8 +0,0 @@
add_header X-Served-By $host;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Scheme $scheme;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Real-IP $remote_addr;
proxy_pass $forward_scheme://$server:$port$request_uri;

View File

@@ -1,7 +0,0 @@
ssl_session_timeout 5m;
ssl_session_cache shared:SSL:50m;
# intermediate configuration. tweak to your needs.
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384';
ssl_prefer_server_ciphers off;

View File

@@ -1,33 +0,0 @@
# Admin Interface
server {
listen 81 default;
listen [::]:81 default;
server_name nginxproxymanager;
root /app/frontend;
access_log /dev/null;
location /api {
return 302 /api/;
}
location /api/ {
add_header X-Served-By $host;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Scheme $scheme;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_pass http://127.0.0.1:3000/;
proxy_read_timeout 15m;
proxy_send_timeout 15m;
}
location / {
index index.html;
if ($request_uri ~ ^/(.*)\.html$) {
return 302 /$1;
}
try_files $uri $uri.html $uri/ /index.html;
}
}

View File

@@ -1,96 +0,0 @@
types {
text/html html htm shtml;
text/css css;
text/xml xml;
image/gif gif;
image/jpeg jpeg jpg;
application/javascript js;
application/atom+xml atom;
application/rss+xml rss;
text/mathml mml;
text/plain txt;
text/vnd.sun.j2me.app-descriptor jad;
text/vnd.wap.wml wml;
text/x-component htc;
image/png png;
image/svg+xml svg svgz;
image/tiff tif tiff;
image/vnd.wap.wbmp wbmp;
image/webp webp;
image/x-icon ico;
image/x-jng jng;
image/x-ms-bmp bmp;
font/woff woff;
font/woff2 woff2;
application/java-archive jar war ear;
application/json json;
application/mac-binhex40 hqx;
application/msword doc;
application/pdf pdf;
application/postscript ps eps ai;
application/rtf rtf;
application/vnd.apple.mpegurl m3u8;
application/vnd.google-earth.kml+xml kml;
application/vnd.google-earth.kmz kmz;
application/vnd.ms-excel xls;
application/vnd.ms-fontobject eot;
application/vnd.ms-powerpoint ppt;
application/vnd.oasis.opendocument.graphics odg;
application/vnd.oasis.opendocument.presentation odp;
application/vnd.oasis.opendocument.spreadsheet ods;
application/vnd.oasis.opendocument.text odt;
application/vnd.openxmlformats-officedocument.presentationml.presentation
pptx;
application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
xlsx;
application/vnd.openxmlformats-officedocument.wordprocessingml.document
docx;
application/vnd.wap.wmlc wmlc;
application/x-7z-compressed 7z;
application/x-cocoa cco;
application/x-java-archive-diff jardiff;
application/x-java-jnlp-file jnlp;
application/x-makeself run;
application/x-perl pl pm;
application/x-pilot prc pdb;
application/x-rar-compressed rar;
application/x-redhat-package-manager rpm;
application/x-sea sea;
application/x-shockwave-flash swf;
application/x-stuffit sit;
application/x-tcl tcl tk;
application/x-x509-ca-cert der pem crt;
application/x-xpinstall xpi;
application/xhtml+xml xhtml;
application/xspf+xml xspf;
application/zip zip;
application/octet-stream bin exe dll;
application/octet-stream deb;
application/octet-stream dmg;
application/octet-stream iso img;
application/octet-stream msi msp msm;
audio/midi mid midi kar;
audio/mpeg mp3;
audio/ogg ogg;
audio/x-m4a m4a;
audio/x-realaudio ra;
video/3gpp 3gpp 3gp;
video/mp2t ts;
video/mp4 mp4;
video/mpeg mpeg mpg;
video/quicktime mov;
video/webm webm;
video/x-flv flv;
video/x-m4v m4v;
video/x-mng mng;
video/x-ms-asf asx asf;
video/x-ms-wmv wmv;
video/x-msvideo avi;
}

View File

@@ -1,95 +0,0 @@
# run nginx in foreground
daemon off;
user root;
# Set number of worker processes automatically based on number of CPU cores.
worker_processes auto;
# Enables the use of JIT for regular expressions to speed-up their processing.
pcre_jit on;
error_log /data/logs/fallback_error.log warn;
# Includes files with directives to load dynamic modules.
include /etc/nginx/modules/*.conf;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
sendfile on;
server_tokens off;
tcp_nopush on;
tcp_nodelay on;
client_body_temp_path /tmp/nginx/body 1 2;
keepalive_timeout 90s;
proxy_connect_timeout 90s;
proxy_send_timeout 90s;
proxy_read_timeout 90s;
ssl_prefer_server_ciphers on;
gzip on;
proxy_ignore_client_abort off;
client_max_body_size 2000m;
server_names_hash_bucket_size 1024;
proxy_http_version 1.1;
proxy_set_header X-Forwarded-Scheme $scheme;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Accept-Encoding "";
proxy_cache off;
proxy_cache_path /var/lib/nginx/cache/public levels=1:2 keys_zone=public-cache:30m max_size=192m;
proxy_cache_path /var/lib/nginx/cache/private levels=1:2 keys_zone=private-cache:5m max_size=1024m;
log_format proxy '[$time_local] $upstream_cache_status $upstream_status $status - $request_method $scheme $host "$request_uri" [Client $remote_addr] [Length $body_bytes_sent] [Gzip $gzip_ratio] [Sent-to $server] "$http_user_agent" "$http_referer"';
log_format standard '[$time_local] $status - $request_method $scheme $host "$request_uri" [Client $remote_addr] [Length $body_bytes_sent] [Gzip $gzip_ratio] "$http_user_agent" "$http_referer"';
access_log /data/logs/fallback_access.log proxy;
# Dynamically generated resolvers file
include /etc/nginx/conf.d/include/resolvers.conf;
# Default upstream scheme
map $host $forward_scheme {
default http;
}
# Real IP Determination
# Local subnets:
set_real_ip_from 10.0.0.0/8;
set_real_ip_from 172.16.0.0/12; # Includes Docker subnet
set_real_ip_from 192.168.0.0/16;
# NPM generated CDN ip ranges:
include conf.d/include/ip_ranges.conf;
# always put the following 2 lines after ip subnets:
real_ip_header X-Real-IP;
real_ip_recursive on;
# Custom
include /data/nginx/custom/http_top[.]conf;
# Files generated by NPM
include /etc/nginx/conf.d/*.conf;
include /data/nginx/default_host/*.conf;
include /data/nginx/proxy_host/*.conf;
include /data/nginx/redirection_host/*.conf;
include /data/nginx/dead_host/*.conf;
include /data/nginx/temp/*.conf;
# Custom
include /data/nginx/custom/http[.]conf;
}
stream {
# Files generated by NPM
include /data/nginx/stream/*.conf;
# Custom
include /data/nginx/custom/stream[.]conf;
}
# Custom
include /data/nginx/custom/root[.]conf;

View File

@@ -1,6 +0,0 @@
#!/usr/bin/execlineb -S1
if { s6-test ${1} -ne 0 }
if { s6-test ${1} -ne 256 }
s6-svscanctl -t /var/run/s6/services

View File

@@ -1,12 +0,0 @@
#!/usr/bin/with-contenv bash
# This service is DEVELOPMENT only.
if [ "$DEVELOPMENT" == "true" ]; then
cd /app/frontend || exit 1
# If yarn install fails: add --verbose --network-concurrency 1
yarn install
yarn watch
else
exit 0
fi

View File

@@ -1,3 +0,0 @@
#!/usr/bin/with-contenv bash
s6-svscanctl -t /var/run/s6/services

View File

@@ -1,19 +0,0 @@
#!/usr/bin/with-contenv bash
mkdir -p /data/letsencrypt-acme-challenge
cd /app || echo
if [ "$DEVELOPMENT" == "true" ]; then
cd /app || exit 1
# If yarn install fails: add --verbose --network-concurrency 1
yarn install
node --max_old_space_size=250 --abort_on_uncaught_exception node_modules/nodemon/bin/nodemon.js
else
cd /app || exit 1
while :
do
node --abort_on_uncaught_exception --max_old_space_size=250 index.js
sleep 1
done
fi

View File

@@ -1 +0,0 @@
/bin/true

View File

@@ -1,53 +0,0 @@
#!/usr/bin/with-contenv bash
# Create required folders
mkdir -p /tmp/nginx/body \
/run/nginx \
/var/log/nginx \
/data/nginx \
/data/custom_ssl \
/data/logs \
/data/access \
/data/nginx/default_host \
/data/nginx/default_www \
/data/nginx/proxy_host \
/data/nginx/redirection_host \
/data/nginx/stream \
/data/nginx/dead_host \
/data/nginx/temp \
/var/lib/nginx/cache/public \
/var/lib/nginx/cache/private \
/var/cache/nginx/proxy_temp
touch /var/log/nginx/error.log && chmod 777 /var/log/nginx/error.log && chmod -R 777 /var/cache/nginx
chown root /tmp/nginx
# Dynamically generate resolvers file, if resolver is IPv6, enclose in `[]`
# thanks @tfmm
if [ "$DISABLE_IPV6" == "true" ] || [ "$DISABLE_IPV6" == "on" ] || [ "$DISABLE_IPV6" == "1" ] || [ "$DISABLE_IPV6" == "yes" ];
then
echo resolver "$(awk 'BEGIN{ORS=" "} $1=="nameserver" { sub(/%.*$/,"",$2); print ($2 ~ ":")? "["$2"]": $2}' /etc/resolv.conf) ipv6=off valid=10s;" > /etc/nginx/conf.d/include/resolvers.conf
else
echo resolver "$(awk 'BEGIN{ORS=" "} $1=="nameserver" { sub(/%.*$/,"",$2); print ($2 ~ ":")? "["$2"]": $2}' /etc/resolv.conf) valid=10s;" > /etc/nginx/conf.d/include/resolvers.conf
fi
# Generate dummy self-signed certificate.
if [ ! -f /data/nginx/dummycert.pem ] || [ ! -f /data/nginx/dummykey.pem ]
then
echo "Generating dummy SSL certificate..."
openssl req \
-new \
-newkey rsa:2048 \
-days 3650 \
-nodes \
-x509 \
-subj '/O=localhost/OU=localhost/CN=localhost' \
-keyout /data/nginx/dummykey.pem \
-out /data/nginx/dummycert.pem
echo "Complete"
fi
# Handle IPV6 settings
/bin/handle-ipv6-setting /etc/nginx/conf.d
/bin/handle-ipv6-setting /data/nginx
exec nginx

View File

@@ -1,22 +0,0 @@
#!/bin/bash
if [ -t 1 ]; then
export PS1="\e[1;34m[\e[1;33m\u@\e[1;32mdocker-\h\e[1;37m:\w\[\e[1;34m]\e[1;36m\\$ \e[0m"
fi
# Aliases
alias l='ls -lAsh --color'
alias ls='ls -C1 --color'
alias cp='cp -ip'
alias rm='rm -i'
alias mv='mv -i'
alias h='cd ~;clear;'
. /etc/os-release
echo -e -n '\E[1;34m'
figlet -w 120 "NginxProxyManager"
echo -e "\E[1;36mVersion \E[1;32m${NPM_BUILD_VERSION:-2.0.0-dev} (${NPM_BUILD_COMMIT:-dev}) ${NPM_BUILD_DATE:-0000-00-00}\E[1;36m, OpenResty \E[1;32m${OPENRESTY_VERSION:-unknown}\E[1;36m, ${ID:-debian} \E[1;32m${VERSION:-unknown}\E[1;36m, Certbot \E[1;32m$(certbot --version)\E[0m"
echo -e -n '\E[1;34m'
cat /built-for-arch
echo -e '\E[0m'

3
docs/.gitignore vendored
View File

@@ -1,3 +0,0 @@
.vuepress/dist
node_modules
ts

View File

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 57 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 13 KiB

View File

@@ -1,2 +0,0 @@
User-agent: *
Disallow:

Binary file not shown.

Before

Width:  |  Height:  |  Size: 106 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 178 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 173 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 141 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 102 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 150 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 92 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 151 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 207 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 181 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 162 KiB

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

View File

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

View File

@@ -1,174 +0,0 @@
# Advanced Configuration
## Best Practice: Use a Docker network
For those who have a few of their upstream services running in Docker on the same Docker
host as NPM, here's a trick to secure things a bit better. By creating a custom Docker network,
you don't need to publish ports for your upstream services to all of the Docker host's interfaces.
Create a network, ie "scoobydoo":
```bash
docker network create scoobydoo
```
Then add the following to the `docker-compose.yml` file for both NPM and any other
services running on this Docker host:
```yml
networks:
default:
external: true
name: scoobydoo
```
Let's look at a Portainer example:
```yml
version: '3'
services:
portainer:
image: portainer/portainer
privileged: true
volumes:
- './data:/data'
- '/var/run/docker.sock:/var/run/docker.sock'
restart: unless-stopped
networks:
default:
external: true
name: scoobydoo
```
Now in the NPM UI you can create a proxy host with `portainer` as the hostname,
and port `9000` as the port. Even though this port isn't listed in the docker-compose
file, it's "exposed" by the Portainer Docker image for you and not available on
the Docker host outside of this Docker network. The service name is used as the
hostname, so make sure your service names are unique when using the same network.
## Docker Healthcheck
The `Dockerfile` that builds this project does not include a `HEALTHCHECK` but you can opt in to this
feature by adding the following to the service in your `docker-compose.yml` file:
```yml
healthcheck:
test: ["CMD", "/bin/check-health"]
interval: 10s
timeout: 3s
```
## Docker Secrets
This image supports the use of Docker secrets to import from file and keep sensitive usernames or passwords from being passed or preserved in plaintext.
You can set any environment variable from a file by appending `__FILE` (double-underscore FILE) to the environmental variable name.
```yml
version: "3.7"
secrets:
# Secrets are single-line text files where the sole content is the secret
# Paths in this example assume that secrets are kept in local folder called ".secrets"
DB_ROOT_PWD:
file: .secrets/db_root_pwd.txt
MYSQL_PWD:
file: .secrets/mysql_pwd.txt
services:
app:
image: 'jc21/nginx-proxy-manager:latest'
restart: unless-stopped
ports:
# Public HTTP Port:
- '80:80'
# Public HTTPS Port:
- '443:443'
# Admin Web Port:
- '81:81'
environment:
# These are the settings to access your db
DB_MYSQL_HOST: "db"
DB_MYSQL_PORT: 3306
DB_MYSQL_USER: "npm"
# DB_MYSQL_PASSWORD: "npm" # use secret instead
DB_MYSQL_PASSWORD__FILE: /run/secrets/MYSQL_PWD
DB_MYSQL_NAME: "npm"
# If you would rather use Sqlite uncomment this
# and remove all DB_MYSQL_* lines above
# DB_SQLITE_FILE: "/data/database.sqlite"
# Uncomment this if IPv6 is not enabled on your host
# DISABLE_IPV6: 'true'
volumes:
- ./data:/data
- ./letsencrypt:/etc/letsencrypt
secrets:
- MYSQL_PWD
depends_on:
- db
db:
image: jc21/mariadb-aria
restart: unless-stopped
environment:
# MYSQL_ROOT_PASSWORD: "npm" # use secret instead
MYSQL_ROOT_PASSWORD__FILE: /run/secrets/DB_ROOT_PWD
MYSQL_DATABASE: "npm"
MYSQL_USER: "npm"
# MYSQL_PASSWORD: "npm" # use secret instead
MYSQL_PASSWORD__FILE: /run/secrets/MYSQL_PWD
volumes:
- ./data/mysql:/var/lib/mysql
secrets:
- DB_ROOT_PWD
- MYSQL_PWD
```
## Disabling IPv6
On some Docker hosts IPv6 may not be enabled. In these cases, the following message may be seen in the log:
> Address family not supported by protocol
The easy fix is to add a Docker environment variable to the Nginx Proxy Manager stack:
```yml
environment:
DISABLE_IPV6: 'true'
```
## Custom Nginx Configurations
If you are a more advanced user, you might be itching for extra Nginx customizability.
NPM has the ability to include different custom configuration snippets in different places.
You can add your custom configuration snippet files at `/data/nginx/custom` as follow:
- `/data/nginx/custom/root.conf`: Included at the very end of nginx.conf
- `/data/nginx/custom/http_top.conf`: Included at the top of the main http block
- `/data/nginx/custom/http.conf`: Included at the end of the main http block
- `/data/nginx/custom/stream.conf`: Included at the end of the main stream block
- `/data/nginx/custom/server_proxy.conf`: Included at the end of every proxy server block
- `/data/nginx/custom/server_redirect.conf`: Included at the end of every redirection server block
- `/data/nginx/custom/server_stream.conf`: Included at the end of every stream server block
- `/data/nginx/custom/server_stream_tcp.conf`: Included at the end of every TCP stream server block
- `/data/nginx/custom/server_stream_udp.conf`: Included at the end of every UDP stream server block
Every file is optional.
## X-FRAME-OPTIONS Header
You can configure the [`X-FRAME-OPTIONS`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Frame-Options) header
value by specifying it as a Docker environment variable. The default if not specified is `deny`.
```yml
...
environment:
X_FRAME_OPTIONS: "sameorigin"
...
```

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,182 +0,0 @@
# Full Setup Instructions
## Running the App
Create a `docker-compose.yml` file:
```yml
version: "3"
services:
app:
image: 'jc21/nginx-proxy-manager:latest'
restart: unless-stopped
ports:
# These ports are in format <host-port>:<container-port>
- '80:80' # Public HTTP Port
- '443:443' # Public HTTPS Port
- '81:81' # Admin Web Port
# Add any other Stream port you want to expose
# - '21:21' # FTP
# Uncomment the next line if you uncomment anything in the section
# environment:
# Uncomment this if you want to change the location of
# the SQLite DB file within the container
# DB_SQLITE_FILE: "/data/database.sqlite"
# Uncomment this if IPv6 is not enabled on your host
# DISABLE_IPV6: 'true'
volumes:
- ./data:/data
- ./letsencrypt:/etc/letsencrypt
```
Then:
```bash
docker-compose up -d
```
## Using MySQL / MariaDB Database
If you opt for the MySQL configuration you will have to provide the database server yourself. You can also use MariaDB. Here are the minimum supported versions:
- MySQL v5.7.8+
- MariaDB v10.2.7+
It's easy to use another docker container for your database also and link it as part of the docker stack, so that's what the following examples
are going to use.
Here is an example of what your `docker-compose.yml` will look like when using a MariaDB container:
```yml
version: "3"
services:
app:
image: 'jc21/nginx-proxy-manager:latest'
restart: unless-stopped
ports:
# These ports are in format <host-port>:<container-port>
- '80:80' # Public HTTP Port
- '443:443' # Public HTTPS Port
- '81:81' # Admin Web Port
# Add any other Stream port you want to expose
# - '21:21' # FTP
environment:
DB_MYSQL_HOST: "db"
DB_MYSQL_PORT: 3306
DB_MYSQL_USER: "npm"
DB_MYSQL_PASSWORD: "npm"
DB_MYSQL_NAME: "npm"
# Uncomment this if IPv6 is not enabled on your host
# DISABLE_IPV6: 'true'
volumes:
- ./data:/data
- ./letsencrypt:/etc/letsencrypt
depends_on:
- db
db:
image: 'jc21/mariadb-aria:latest'
restart: unless-stopped
environment:
MYSQL_ROOT_PASSWORD: 'npm'
MYSQL_DATABASE: 'npm'
MYSQL_USER: 'npm'
MYSQL_PASSWORD: 'npm'
volumes:
- ./data/mysql:/var/lib/mysql
```
::: warning
Please note, that `DB_MYSQL_*` environment variables will take precedent over `DB_SQLITE_*` variables. So if you keep the MySQL variables, you will not be able to use SQLite.
:::
## Running on Raspberry PI / ARM devices
The docker images support the following architectures:
- amd64
- arm64
- armv7
The docker images are a manifest of all the architecture docker builds supported, so this means
you don't have to worry about doing anything special and you can follow the common instructions above.
Check out the [dockerhub tags](https://hub.docker.com/r/jc21/nginx-proxy-manager/tags)
for a list of supported architectures and if you want one that doesn't exist,
[create a feature request](https://github.com/NginxProxyManager/nginx-proxy-manager/issues/new?assignees=&labels=enhancement&template=feature_request.md&title=).
Also, if you don't know how to already, follow [this guide to install docker and docker-compose](https://manre-universe.net/how-to-run-docker-and-docker-compose-on-raspbian/)
on Raspbian.
Please note that the `jc21/mariadb-aria:latest` image might have some problems on some ARM devices, if you want a separate database container, use the `yobasystems/alpine-mariadb:latest` image.
## Initial Run
After the app is running for the first time, the following will happen:
1. The database will initialize with table structures
2. GPG keys will be generated and saved in the configuration file
3. A default admin user will be created
This process can take a couple of minutes depending on your machine.
## Default Administrator User
```
Email: admin@example.com
Password: changeme
```
Immediately after logging in with this default user you will be asked to modify your details and change your password.
## Configuration File
::: warning
This section is meant for advanced users
:::
If you would like more control over the database settings you can define a custom config JSON file.
Here's an example for `sqlite` configuration as it is generated from the environment variables:
```json
{
"database": {
"engine": "knex-native",
"knex": {
"client": "sqlite3",
"connection": {
"filename": "/data/database.sqlite"
},
"useNullAsDefault": true
}
}
}
```
You can modify the `knex` object with your custom configuration, but note that not all knex clients might be installed in the image.
Once you've created your configuration file you can mount it to `/app/config/production.json` inside you container using:
```
[...]
services:
app:
image: 'jc21/nginx-proxy-manager:latest'
[...]
volumes:
- ./config.json:/app/config/production.json
[...]
[...]
```
**Note:** After the first run of the application, the config file will be altered to include generated encryption keys unique to your installation.
These keys affect the login and session management of the application. If these keys change for any reason, all users will be logged out.

View File

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

View File

@@ -1,11 +0,0 @@
# Upgrading
```bash
docker-compose pull
docker-compose up -d
```
This project will automatically update any databases or other requirements so you don't have to follow
any crazy instructions. These steps above will pull the latest updates and recreate the docker
containers.

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 56 KiB

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 15 KiB

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