diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml new file mode 100644 index 00000000..f859b127 --- /dev/null +++ b/.github/workflows/stale.yml @@ -0,0 +1,21 @@ +name: 'Close stale issues and PRs' +on: + schedule: + - cron: '30 1 * * *' + workflow_dispatch: + +jobs: + stale: + runs-on: ubuntu-latest + steps: + - uses: actions/stale@v9 + with: + stale-issue-label: 'stale' + stale-pr-label: 'stale' + stale-issue-message: 'Issue is now considered stale. If you want to keep it open, please comment :+1:' + stale-pr-message: 'PR is now considered stale. If you want to keep it open, please comment :+1:' + close-issue-message: 'Issue was closed due to inactivity.' + close-pr-message: 'PR was closed due to inactivity.' + days-before-stale: 182 + days-before-close: 365 + operations-per-run: 50 diff --git a/.gitignore b/.gitignore index 08462849..fbb8167e 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,7 @@ ._* .vscode certbot-help.txt +test/node_modules +*/node_modules +docker/dev/dnsrouter-config.json.tmp +docker/dev/resolv.conf diff --git a/.version b/.version index 8bcbcd5c..22e3b6b0 100644 --- a/.version +++ b/.version @@ -1 +1 @@ -2.9.8 \ No newline at end of file +2.11.3 diff --git a/Jenkinsfile b/Jenkinsfile index 3161a254..1d8680a6 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,3 +1,9 @@ +import groovy.transform.Field + +@Field +def shOutput = "" +def buildxPushTags = "" + pipeline { agent { label 'docker-multiarch' @@ -8,14 +14,12 @@ pipeline { ansiColor('xterm') } environment { - IMAGE = "nginx-proxy-manager" + 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' + MAJOR_VERSION = '2' + BRANCH_LOWER = "${BRANCH_NAME.toLowerCase().replaceAll('\\\\', '-').replaceAll('/', '-').replaceAll('\\.', '-')}" + BUILDX_NAME = "npm_${BRANCH_LOWER}_${BUILD_NUMBER}" COMPOSE_INTERACTIVE_NO_CLI = 1 - BUILDX_NAME = "${COMPOSE_PROJECT_NAME}" } stages { stage('Environment') { @@ -26,7 +30,7 @@ pipeline { } 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" + buildxPushTags = "-t docker.io/jc21/${IMAGE}:${BUILD_VERSION} -t docker.io/jc21/${IMAGE}:${MAJOR_VERSION} -t docker.io/jc21/${IMAGE}:latest" } } } @@ -39,7 +43,7 @@ pipeline { 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}" + buildxPushTags = "-t docker.io/jc21/${IMAGE}:github-${BRANCH_LOWER}" } } } @@ -54,105 +58,96 @@ pipeline { } } } - stage('Frontend') { - steps { - sh './scripts/frontend-build' - } - } - stage('Backend') { - steps { - echo 'Checking Syntax ...' - // See: https://github.com/yarnpkg/yarn/issues/3254 - sh '''docker run --rm \\ - -v "$(pwd)/backend:/app" \\ - -v "$(pwd)/global:/app/global" \\ - -w /app \\ - node:latest \\ - 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' + stage('Builds') { + parallel { + stage('Project') { + steps { + script { + // Frontend and Backend + def shStatusCode = sh(label: 'Checking and Building', returnStatus: true, script: ''' + set -e + ./scripts/ci/frontend-build > ${WORKSPACE}/tmp-sh-build 2>&1 + ./scripts/ci/test-and-build > ${WORKSPACE}/tmp-sh-build 2>&1 + ''') + shOutput = readFile "${env.WORKSPACE}/tmp-sh-build" + if (shStatusCode != 0) { + error "${shOutput}" + } + } + } + post { + always { + sh 'rm -f ${WORKSPACE}/tmp-sh-build' + } + failure { + npmGithubPrComment("CI Error:\n\n```\n${shOutput}\n```", true) + } + } + } + stage('Docs') { + steps { + dir(path: 'docs') { + sh 'yarn install' + sh 'yarn build' + } } - 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/' + stage('Test Sqlite') { + environment { + COMPOSE_PROJECT_NAME = "npm_${BRANCH_LOWER}_${BUILD_NUMBER}_sqlite" + COMPOSE_FILE = 'docker/docker-compose.ci.yml:docker/docker-compose.ci.sqlite.yml' } - post { - always { - // Dumps to analyze later - sh 'mkdir -p debug' - sh 'docker-compose logs fullstack-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' + sh 'rm -rf ./test/results/junit/*' + sh './scripts/ci/fulltest-cypress' + } + post { + always { + // Dumps to analyze later + sh 'mkdir -p debug/sqlite' + sh 'docker logs $(docker-compose ps --all -q fullstack) > debug/sqlite/docker_fullstack.log 2>&1' + sh 'docker logs $(docker-compose ps --all -q stepca) > debug/sqlite/docker_stepca.log 2>&1' + sh 'docker logs $(docker-compose ps --all -q pdns) > debug/sqlite/docker_pdns.log 2>&1' + sh 'docker logs $(docker-compose ps --all -q pdns-db) > debug/sqlite/docker_pdns-db.log 2>&1' + sh 'docker logs $(docker-compose ps --all -q dnsrouter) > debug/sqlite/docker_dnsrouter.log 2>&1' + junit 'test/results/junit/*' + sh 'docker-compose down --remove-orphans --volumes -t 30 || true' } - - dir(path: 'docs/.vuepress/dist') { - sh 'tar -czf ../../docs.tgz *' + } + } + stage('Test Mysql') { + environment { + COMPOSE_PROJECT_NAME = "npm_${BRANCH_LOWER}_${BUILD_NUMBER}_mysql" + COMPOSE_FILE = 'docker/docker-compose.ci.yml:docker/docker-compose.ci.mysql.yml' + } + when { + not { + equals expected: 'UNSTABLE', actual: currentBuild.result + } + } + steps { + sh 'rm -rf ./test/results/junit/*' + sh './scripts/ci/fulltest-cypress' + } + post { + always { + // Dumps to analyze later + sh 'mkdir -p debug/mysql' + sh 'docker logs $(docker-compose ps --all -q fullstack) > debug/mysql/docker_fullstack.log 2>&1' + sh 'docker logs $(docker-compose ps --all -q stepca) > debug/mysql/docker_stepca.log 2>&1' + sh 'docker logs $(docker-compose ps --all -q pdns) > debug/mysql/docker_pdns.log 2>&1' + sh 'docker logs $(docker-compose ps --all -q pdns-db) > debug/mysql/docker_pdns-db.log 2>&1' + sh 'docker logs $(docker-compose ps --all -q dnsrouter) > debug/mysql/docker_dnsrouter.log 2>&1' + junit 'test/results/junit/*' + sh 'docker-compose down --remove-orphans --volumes -t 30 || true' } - - archiveArtifacts(artifacts: 'docs/docs.tgz', allowEmptyArchive: false) } } stage('MultiArch Build') { @@ -163,78 +158,60 @@ pipeline { } 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}" + sh 'docker login -u "${duser}" -p "${dpass}"' + sh "./scripts/buildx --push ${buildxPushTags}" } } } - stage('Docs Deploy') { - when { - allOf { - branch 'master' - not { - equals expected: 'UNSTABLE', actual: currentBuild.result + stage('Docs / Comment') { + parallel { + stage('Docs Job') { + when { + allOf { + branch pattern: "^(develop|master)\$", comparator: "REGEXP" + not { + equals expected: 'UNSTABLE', actual: currentBuild.result + } + } + } + steps { + build wait: false, job: 'nginx-proxy-manager-docs', parameters: [string(name: 'docs_branch', value: "$BRANCH_NAME")] } } - } - steps { - 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 + stage('PR Comment') { + when { + allOf { + changeRequest() + not { + equals expected: 'UNSTABLE', actual: currentBuild.result + } + } + } + steps { + script { + npmGithubPrComment("Docker Image for build ${BUILD_NUMBER} is available on [DockerHub](https://cloud.docker.com/repository/docker/jc21/${IMAGE}) as `jc21/${IMAGE}:github-${BRANCH_LOWER}`\n\n**Note:** ensure you backup your NPM instance before testing this PR image! Especially if this PR contains database changes.", true) + } } - } - } - steps { - script { - 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 --rmi all --remove-orphans --volumes -t 30' sh 'echo Reverting ownership' - sh 'docker run --rm -v $(pwd):/data jc21/ci-tools chown -R $(id -u):$(id -g) /data' + sh 'docker run --rm -v "$(pwd):/data" jc21/ci-tools chown -R "$(id -u):$(id -g)" /data' } success { juxtapose event: 'success' sh 'figlet "SUCCESS"' } failure { - archiveArtifacts(artifacts: 'debug/**.*', allowEmptyArchive: true) + archiveArtifacts(artifacts: 'debug/**/*.*', allowEmptyArchive: true) juxtapose event: 'failure' sh 'figlet "FAILURE"' } unstable { - archiveArtifacts(artifacts: 'debug/**.*', allowEmptyArchive: true) + archiveArtifacts(artifacts: 'debug/**/*.*', allowEmptyArchive: true) juxtapose event: 'unstable' sh 'figlet "UNSTABLE"' } diff --git a/README.md b/README.md index 3665eb92..55a986d1 100644 --- a/README.md +++ b/README.md @@ -1,22 +1,13 @@
This project comes as a pre-built docker image that enables you to easily forward to your websites @@ -28,7 +19,7 @@ running at home or otherwise, including free SSL, without having to know too muc ## Project Goal -I created this project to fill a personal need to provide users with a easy way to accomplish reverse +I created this project to fill a personal need to provide users with an easy way to accomplish reverse proxying hosts with SSL termination and it had to be so easy that a monkey could do it. This goal hasn't changed. While there might be advanced options they are optional and the project should be as simple as possible so that the barrier for entry here is low. @@ -65,40 +56,29 @@ I won't go in to too much detail here but here are the basics for someone new to 2. Create a docker-compose.yml file similar to this: ```yml -version: '3' services: app: - image: 'jc21/nginx-proxy-manager:latest' + image: 'docker.io/jc21/nginx-proxy-manager:latest' restart: unless-stopped ports: - '80:80' - '81:81' - '443:443' - environment: - DB_MYSQL_HOST: "db" - DB_MYSQL_PORT: 3306 - DB_MYSQL_USER: "npm" - DB_MYSQL_PASSWORD: "npm" - DB_MYSQL_NAME: "npm" volumes: - ./data:/data - ./letsencrypt:/etc/letsencrypt - 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 ``` -3. Bring up your stack +This is the bare minimum configuration required. See the [documentation](https://nginxproxymanager.com/setup/) for more. + +3. Bring up your stack by running ```bash docker-compose up -d + +# If using docker-compose-plugin +docker compose up -d + ``` 4. Log in to the Admin UI @@ -117,373 +97,24 @@ Password: changeme Immediately after logging in with this default user you will be asked to modify your details and change your password. -## Contributors +## Contributing -Special thanks to the following contributors: +All are welcome to create pull requests for this project, against the `develop` branch. Official releases are created from the `master` branch. - - -- Expose web services on your network · - Free SSL with Let's Encrypt · - Designed with security in mind · - Perfect for home networks -
-Expose your private network Web services and get connected anywhere.
-Based on Tabler, the interface is a pleasure to use. Configuring a server has never been so fun.
-Built in Let’s Encrypt support allows you to secure your Web services at no cost to you. The certificates even renew themselves!
-Built as a Docker Image, Nginx Proxy Manager only requires a database.
-Configure other users to either view or manage their own hosts. Full access permissions are available.
-
-
-
-
-
-
-
-
-
-
diff --git a/docs/setup/README.md b/docs/setup/README.md
deleted file mode 100644
index 99fbd7bb..00000000
--- a/docs/setup/README.md
+++ /dev/null
@@ -1,209 +0,0 @@
-# Full Setup Instructions
-
-## MySQL Database
-
-If you opt for the MySQL configuration you will have to provide the database server yourself. You can also use MariaDB. Here are the minimum supported versions:
-
-- 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.
-
-::: warning
-
-When using a `mariadb` database, the NPM configuration file should still use the `mysql` engine!
-
-:::
-
-## Running the App
-
-Via `docker-compose`:
-
-```yml
-version: "3"
-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'
- # Add any other Stream port you want to expose
- # - '21:21' # FTP
- environment:
- # These are the settings to access your db
- DB_MYSQL_HOST: "db"
- DB_MYSQL_PORT: 3306
- DB_MYSQL_USER: "npm"
- DB_MYSQL_PASSWORD: "npm"
- DB_MYSQL_NAME: "npm"
- # If you would rather use Sqlite uncomment this
- # and remove all DB_MYSQL_* lines above
- # DB_SQLITE_FILE: "/data/database.sqlite"
- # Uncomment this if IPv6 is not enabled on your host
- # DISABLE_IPV6: 'true'
- volumes:
- - ./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
-```
-
-_Please note, that `DB_MYSQL_*` environment variables will take precedent over `DB_SQLITE_*` variables. So if you keep the MySQL variables, you will not be able to use Sqlite._
-
-Then:
-
-```bash
-docker-compose up -d
-```
-
-## 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/jc21/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.
-
-Via `docker-compose`:
-
-```yml
-version: "3"
-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: "changeuser"
- DB_MYSQL_PASSWORD: "changepass"
- 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/nginx-proxy-manager:/data
- - ./letsencrypt:/etc/letsencrypt
- depends_on:
- - db
- db:
- image: yobasystems/alpine-mariadb:latest
- restart: unless-stopped
- environment:
- MYSQL_ROOT_PASSWORD: "changeme"
- MYSQL_DATABASE: "npm"
- MYSQL_USER: "changeuser"
- MYSQL_PASSWORD: "changepass"
- volumes:
- - ./data/mariadb:/var/lib/mysql
-```
-
-_Please note, that `DB_MYSQL_*` environment variables will take precedent over `DB_SQLITE_*` var>
-
-Then:
-
-```bash
-docker-compose up -d
-```
-
-## 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.
diff --git a/docs/advanced-config/README.md b/docs/src/advanced-config/index.md
similarity index 76%
rename from docs/advanced-config/README.md
rename to docs/src/advanced-config/index.md
index 20271783..b93f2a20 100644
--- a/docs/advanced-config/README.md
+++ b/docs/src/advanced-config/index.md
@@ -1,5 +1,30 @@
+---
+outline: deep
+---
+
# Advanced Configuration
+## Running processes as a user/group
+
+By default, the services (nginx etc) will run as `root` user inside the docker container.
+You can change this behaviour by setting the following environment variables.
+Not only will they run the services as this user/group, they will change the ownership
+on the `data` and `letsencrypt` folders at startup.
+
+```yml
+services:
+ app:
+ image: 'jc21/nginx-proxy-manager:latest'
+ environment:
+ PUID: 1000
+ PGID: 1000
+ # ...
+```
+
+This may have the side effect of a failed container start due to permission denied trying
+to open port 80 on some systems. The only course to fix that is to remove the variables
+and run as the default root user.
+
## Best Practice: Use a Docker network
For those who have a few of their upstream services running in Docker on the same Docker
@@ -18,14 +43,14 @@ services running on this Docker host:
```yml
networks:
default:
- external:
- name: scoobydoo
+ external: true
+ name: scoobydoo
```
Let's look at a Portainer example:
```yml
-version: '3'
+version: '3.8'
services:
portainer:
@@ -38,8 +63,8 @@ services:
networks:
default:
- external:
- name: scoobydoo
+ external: true
+ name: scoobydoo
```
Now in the NPM UI you can create a proxy host with `portainer` as the hostname,
@@ -55,19 +80,19 @@ feature by adding the following to the service in your `docker-compose.yml` file
```yml
healthcheck:
- test: ["CMD", "/bin/check-health"]
+ test: ["CMD", "/usr/bin/check-health"]
interval: 10s
timeout: 3s
```
-## Docker Secrets
+## Docker File 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.
+This image supports the use of Docker secrets to import from files 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"
+version: '3.8'
secrets:
# Secrets are single-line text files where the sole content is the secret
@@ -96,9 +121,7 @@ services:
# 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"
+ # If you would rather use Sqlite, remove all DB_MYSQL_* lines above
# Uncomment this if IPv6 is not enabled on your host
# DISABLE_IPV6: 'true'
volumes:
@@ -108,6 +131,7 @@ services:
- MYSQL_PWD
depends_on:
- db
+
db:
image: jc21/mariadb-aria
restart: unless-stopped
@@ -118,8 +142,9 @@ services:
MYSQL_USER: "npm"
# MYSQL_PASSWORD: "npm" # use secret instead
MYSQL_PASSWORD__FILE: /run/secrets/MYSQL_PWD
+ MARIADB_AUTO_UPGRADE: '1'
volumes:
- - ./data/mysql:/var/lib/mysql
+ - ./mysql:/var/lib/mysql
secrets:
- DB_ROOT_PWD
- MYSQL_PWD
@@ -148,9 +173,11 @@ NPM has the ability to include different custom configuration snippets in differ
You can add your custom configuration snippet files at `/data/nginx/custom` as follow:
+ - `/data/nginx/custom/root_top.conf`: Included at the top of nginx.conf
- `/data/nginx/custom/root.conf`: Included at the very end of nginx.conf
- `/data/nginx/custom/http_top.conf`: Included at the top of the main http block
- `/data/nginx/custom/http.conf`: Included at the end of the main http block
+ - `/data/nginx/custom/events.conf`: Included at the end of the events 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
@@ -195,3 +222,25 @@ The proxy adds some headers based on the authentication result from the identity
- `X-OIDC-EMAIL`: The email of the user that logged in, as specified in the `id_token` returned from the identity provider. The same value that will be checked for the email whitelist.
- `X-OIDC-NAME`: The user's name claim from the `id_token`, please note that not all id tokens necessarily contain this claim.
+## Customising logrotate settings
+
+By default, NPM rotates the access- and error logs weekly and keeps 4 and 10 log files respectively.
+Depending on the usage, this can lead to large log files, especially access logs.
+You can customise the logrotate configuration through a mount (if your custom config is `logrotate.custom`):
+
+```yml
+ volumes:
+ ...
+ - ./logrotate.custom:/etc/logrotate.d/nginx-proxy-manager
+```
+
+For reference, the default configuration can be found [here](https://github.com/NginxProxyManager/nginx-proxy-manager/blob/develop/docker/rootfs/etc/logrotate.d/nginx-proxy-manager).
+
+## Enabling the geoip2 module
+
+To enable the geoip2 module, you can create the custom configuration file `/data/nginx/custom/root_top.conf` and include the following snippet:
+
+```
+load_module /usr/lib/nginx/modules/ngx_http_geoip2_module.so;
+load_module /usr/lib/nginx/modules/ngx_stream_geoip2_module.so;
+```
diff --git a/docs/src/faq/index.md b/docs/src/faq/index.md
new file mode 100644
index 00000000..ea375f47
--- /dev/null
+++ b/docs/src/faq/index.md
@@ -0,0 +1,26 @@
+---
+outline: deep
+---
+
+# FAQ
+
+## Do I have to use Docker?
+
+Yes, that's how this project is packaged.
+
+This makes it easier to support the project when we have control over the version of Nginx other packages
+use by the project.
+
+## Can I run it on a Raspberry Pi?
+
+Yes! The docker image is multi-arch and is built for a variety of architectures. If yours is
+[not listed](https://hub.docker.com/r/jc21/nginx-proxy-manager/tags) please open a
+[GitHub issue](https://github.com/NginxProxyManager/nginx-proxy-manager/issues/new?assignees=&labels=enhancement&template=feature_request.md&title=).
+
+## I can't get my service to proxy properly?
+
+Your best bet is to ask the [Reddit community for support](https://www.reddit.com/r/nginxproxymanager/). There's safety in numbers.
+
+## 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.
diff --git a/docs/src/guide/index.md b/docs/src/guide/index.md
new file mode 100644
index 00000000..ad350b3b
--- /dev/null
+++ b/docs/src/guide/index.md
@@ -0,0 +1,126 @@
+---
+outline: deep
+---
+
+# Guide
+
+::: raw
+
+:::
+
+This project comes as a pre-built docker image that enables you to easily forward to your websites
+running at home or otherwise, including free SSL, without having to know too much about Nginx or Letsencrypt.
+
+- [Quick Setup](#quick-setup)
+- [Full Setup](/setup/)
+- [Screenshots](/screenshots/)
+
+## Project Goal
+
+I created this project to fill a personal need to provide users with an easy way to accomplish reverse
+proxying hosts with SSL termination and it had to be so easy that a monkey could do it. This goal hasn't changed.
+While there might be advanced options they are optional and the project should be as simple as possible
+so that the barrier for entry here is low.
+
+::: raw
+
+:::
+
+## Features
+
+- Beautiful and Secure Admin Interface based on [Tabler](https://tabler.github.io/)
+- Easily create forwarding domains, redirections, streams and 404 hosts without knowing anything about Nginx
+- Free SSL using Let's Encrypt or provide your own custom SSL certificates
+- Access Lists and basic HTTP Authentication for your hosts
+- Advanced Nginx configuration available for super users
+- User management, permissions and audit log
+
+
+## Hosting your home network
+
+I won't go in to too much detail here but here are the basics for someone new to this self-hosted world.
+
+1. Your home router will have a Port Forwarding section somewhere. Log in and find it
+2. Add port forwarding for port 80 and 443 to the server hosting this project
+3. Configure your domain name details to point to your home, either with a static ip or a service like DuckDNS or [Amazon Route53](https://github.com/jc21/route53-ddns)
+4. Use the Nginx Proxy Manager as your gateway to forward to your other web based services
+
+## Quick Setup
+
+1. Install Docker and Docker-Compose
+
+- [Docker Install documentation](https://docs.docker.com/get-docker/)
+- [Docker-Compose Install documentation](https://docs.docker.com/compose/install/)
+
+2. Create a docker-compose.yml file similar to this:
+
+```yml
+version: '3.8'
+services:
+ app:
+ image: 'jc21/nginx-proxy-manager:latest'
+ restart: unless-stopped
+ ports:
+ - '80:80'
+ - '81:81'
+ - '443:443'
+ volumes:
+ - ./data:/data
+ - ./letsencrypt:/etc/letsencrypt
+```
+
+This is the bare minimum configuration required. See the [documentation](https://nginxproxymanager.com/setup/) for more.
+
+3. Bring up your stack by running
+
+```bash
+docker-compose up -d
+
+# If using docker-compose-plugin
+docker compose up -d
+```
+
+4. Log in to the Admin UI
+
+When your docker container is running, connect to it on port `81` for the admin interface.
+Sometimes this can take a little bit because of the entropy of keys.
+
+[http://127.0.0.1:81](http://127.0.0.1:81)
+
+Default Admin User:
+```
+Email: admin@example.com
+Password: changeme
+```
+
+Immediately after logging in with this default user you will be asked to modify your details and change your password.
+
+
+## Contributing
+
+All are welcome to create pull requests for this project, against the `develop` branch. Official releases are created from the `master` branch.
+
+CI is used in this project. All PR's must pass before being considered. After passing,
+docker builds for PR's are available on dockerhub for manual verifications.
+
+Documentation within the `develop` branch is available for preview at
+[https://develop.nginxproxymanager.com](https://develop.nginxproxymanager.com)
+
+
+### Contributors
+
+Special thanks to [all of our contributors](https://github.com/NginxProxyManager/nginx-proxy-manager/graphs/contributors).
+
+
+## Getting Support
+
+1. [Found a bug?](https://github.com/NginxProxyManager/nginx-proxy-manager/issues)
+2. [Discussions](https://github.com/NginxProxyManager/nginx-proxy-manager/discussions)
+3. [Reddit](https://reddit.com/r/nginxproxymanager)
diff --git a/docs/src/index.md b/docs/src/index.md
new file mode 100644
index 00000000..74a263bd
--- /dev/null
+++ b/docs/src/index.md
@@ -0,0 +1,32 @@
+---
+# https://vitepress.dev/reference/default-theme-home-page
+layout: home
+
+hero:
+ name: "Nginx Proxy Manager"
+ tagline: Expose your services easily and securely
+ image:
+ src: /logo.svg
+ alt: NPM Logo
+ actions:
+ - theme: brand
+ text: Get Started
+ link: /guide/
+ - theme: alt
+ text: GitHub
+ link: https://github.com/NginxProxyManager/nginx-proxy-manager
+
+features:
+ - title: Get Connected
+ details: Expose web services on your network · Free SSL with Let's Encrypt · Designed with security in mind · Perfect for home networks
+ - title: Proxy Hosts
+ details: Expose your private network Web services and get connected anywhere.
+ - title: Beautiful UI
+ details: Based on Tabler, the interface is a pleasure to use. Configuring a server has never been so fun.
+ - title: Free SSL
+ details: Built in Let’s Encrypt support allows you to secure your Web services at no cost to you. The certificates even renew themselves!
+ - title: Docker FTW
+ details: Built as a Docker Image, Nginx Proxy Manager only requires a database.
+ - title: Multiple Users
+ details: Configure other users to either view or manage their own hosts. Full access permissions are available.
+---
diff --git a/docs/.vuepress/public/github.png b/docs/src/public/github.png
similarity index 100%
rename from docs/.vuepress/public/github.png
rename to docs/src/public/github.png
diff --git a/docs/.vuepress/public/icon.png b/docs/src/public/icon.png
similarity index 100%
rename from docs/.vuepress/public/icon.png
rename to docs/src/public/icon.png
diff --git a/docs/.vuepress/public/logo.svg b/docs/src/public/logo.svg
similarity index 100%
rename from docs/.vuepress/public/logo.svg
rename to docs/src/public/logo.svg
diff --git a/docs/.vuepress/public/robots.txt b/docs/src/public/robots.txt
similarity index 100%
rename from docs/.vuepress/public/robots.txt
rename to docs/src/public/robots.txt
diff --git a/docs/.vuepress/public/screenshots/access-lists.png b/docs/src/public/screenshots/access-lists.png
similarity index 100%
rename from docs/.vuepress/public/screenshots/access-lists.png
rename to docs/src/public/screenshots/access-lists.png
diff --git a/docs/.vuepress/public/screenshots/audit-log.png b/docs/src/public/screenshots/audit-log.png
similarity index 100%
rename from docs/.vuepress/public/screenshots/audit-log.png
rename to docs/src/public/screenshots/audit-log.png
diff --git a/docs/.vuepress/public/screenshots/certificates.png b/docs/src/public/screenshots/certificates.png
similarity index 100%
rename from docs/.vuepress/public/screenshots/certificates.png
rename to docs/src/public/screenshots/certificates.png
diff --git a/docs/.vuepress/public/screenshots/custom-settings.png b/docs/src/public/screenshots/custom-settings.png
similarity index 100%
rename from docs/.vuepress/public/screenshots/custom-settings.png
rename to docs/src/public/screenshots/custom-settings.png
diff --git a/docs/.vuepress/public/screenshots/dashboard.png b/docs/src/public/screenshots/dashboard.png
similarity index 100%
rename from docs/.vuepress/public/screenshots/dashboard.png
rename to docs/src/public/screenshots/dashboard.png
diff --git a/docs/.vuepress/public/screenshots/dead-hosts.png b/docs/src/public/screenshots/dead-hosts.png
similarity index 100%
rename from docs/.vuepress/public/screenshots/dead-hosts.png
rename to docs/src/public/screenshots/dead-hosts.png
diff --git a/docs/.vuepress/public/screenshots/login.png b/docs/src/public/screenshots/login.png
similarity index 100%
rename from docs/.vuepress/public/screenshots/login.png
rename to docs/src/public/screenshots/login.png
diff --git a/docs/.vuepress/public/screenshots/permissions.png b/docs/src/public/screenshots/permissions.png
similarity index 100%
rename from docs/.vuepress/public/screenshots/permissions.png
rename to docs/src/public/screenshots/permissions.png
diff --git a/docs/.vuepress/public/screenshots/proxy-hosts-add.png b/docs/src/public/screenshots/proxy-hosts-add.png
similarity index 100%
rename from docs/.vuepress/public/screenshots/proxy-hosts-add.png
rename to docs/src/public/screenshots/proxy-hosts-add.png
diff --git a/docs/.vuepress/public/screenshots/proxy-hosts.png b/docs/src/public/screenshots/proxy-hosts.png
similarity index 100%
rename from docs/.vuepress/public/screenshots/proxy-hosts.png
rename to docs/src/public/screenshots/proxy-hosts.png
diff --git a/docs/.vuepress/public/screenshots/redirection-hosts.png b/docs/src/public/screenshots/redirection-hosts.png
similarity index 100%
rename from docs/.vuepress/public/screenshots/redirection-hosts.png
rename to docs/src/public/screenshots/redirection-hosts.png
diff --git a/docs/src/screenshots/index.md b/docs/src/screenshots/index.md
new file mode 100644
index 00000000..8bd21028
--- /dev/null
+++ b/docs/src/screenshots/index.md
@@ -0,0 +1,20 @@
+---
+outline: deep
+---
+
+# Screenshots
+
+::: raw
+
+:::
diff --git a/docs/src/setup/index.md b/docs/src/setup/index.md
new file mode 100644
index 00000000..9b1505be
--- /dev/null
+++ b/docs/src/setup/index.md
@@ -0,0 +1,141 @@
+---
+outline: deep
+---
+
+# Full Setup Instructions
+
+## Running the App
+
+Create a `docker-compose.yml` file:
+
+```yml
+version: '3.8'
+services:
+ app:
+ image: 'jc21/nginx-proxy-manager:latest'
+ restart: unless-stopped
+ ports:
+ # These ports are in format