Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Location prefix behind reverse proxy + Button For Reload Configuration #53

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -467,3 +467,5 @@ typings/
# Linux trash folder which might appear on any partition or disk

# .nfs files are created when an open file is removed but is still being accessed

docker-compose.windows.yml
11 changes: 10 additions & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,23 @@ FROM python:3.7-alpine

ADD requirements.txt .

RUN apk add python3-dev build-base linux-headers pcre-dev && pip install --no-cache-dir -r requirements.txt
RUN apk add curl python3-dev build-base linux-headers pcre-dev && pip install --no-cache-dir -r requirements.txt

RUN cd /tmp/ \
&& curl -sSL -O https://download.docker.com/linux/static/stable/x86_64/docker-17.06.2-ce.tgz \
&& tar zxf docker-17.06.2-ce.tgz \
&& mkdir -p /usr/local/bin \
&& mv ./docker/docker /usr/local/bin \
&& chmod +x /usr/local/bin/docker \
&& rm -rf /tmp/*

# adding application files
ADD . /webapp

# configure path /webapp to HOME-dir
ENV HOME /webapp
WORKDIR /webapp
EXPOSE 8080

ENTRYPOINT ["uwsgi"]
CMD ["--http", "0.0.0.0:8080", "--wsgi-file", "wsgi.py", "--callable", "app", "--processes", "1", "--threads", "8"]
64 changes: 64 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -114,3 +114,67 @@ server {
2. Run `nginx -t` to make sure, that your config is valid
3. Run `systemctl restart nginx` (or equivalent) to restart your nginx and apply the new settings
4. Your nginx ui is now accessible at nginx.mydomain.com and will correctly prompt for basic auth

### Example NginX-UI + NginX (run in container) behind path '/some-location'

![Image of Nginx UI](https://i.ibb.co/59myNSf/nginx-ui.png)

> If Nginx running as a container separatedly, '$ docker exec {nginx-container-name} nginx -s reload' button will be visible after docker socket and container name provided

docker-compose.yml
```yaml
version: '3'
services:
nginx-ui:
container_name: nginx-ui
build: .
image: schenkd/nginx-ui:latest
# ports:
# - 8080:8080
volumes:
- ./nginx/etc-nginx:/etc/nginx
- /var/run/docker.sock:/var/run/docker.sock
environment:
NGINX_CONTAINER_NAME: nginx
networks:
- my-custom-network
nginx:
container_name: nginx
image: nginx:latest
ports:
- 80:80
volumes:
- ./nginx/etc-nginx:/etc/nginx
networks:
- my-custom-network
networks:
my-custom-network:
name: my-custom-network
external: true
```

default.conf
```none
server {

listen 80;
listen [::]:80;
server_name localhost;

# ...

location /nginx-ui/ {
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;

# Need to pass this header for backend procesing route '/nginx-ui' + '/api'
proxy_set_header X-Forwarded-Prefix /nginx-ui;

# With docker custom network, we can use container name with port
# We cannot access port 8080 directly from outside host server
proxy_pass http://nginx-ui:8080/;
}

}
```
6 changes: 6 additions & 0 deletions app/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,18 @@
from config import config
from flask_moment import Moment

from werkzeug.middleware.proxy_fix import ProxyFix

moment = Moment()


def create_app(config_name):
app = Flask(__name__)

app.wsgi_app = ProxyFix(
app.wsgi_app, x_for=1, x_proto=1, x_host=1, x_prefix=1
)

app.config.from_object(config[config_name])

config[config_name].init_app(app)
Expand Down
28 changes: 28 additions & 0 deletions app/api/endpoints.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,38 @@
import io
import os
import flask
import subprocess

from pathlib import Path
from app.api import api


@api.route('/reload-nginx', methods=['GET'])
def get_reload_nginx():
"""
Runs the command to reload the nginx configuration.

:return: Returns a status from terminal output.
:rtype: str
"""
exec_cmd = 'nginx -s reload'
res = 'No NginX docker container provided'
code = 400

docker_sock = Path('/var/run/docker.sock')
if docker_sock.is_socket() and 'NGINX_CONTAINER_NAME' in os.environ:
exec_cmd = f'docker exec {os.environ.get("NGINX_CONTAINER_NAME")} {exec_cmd}'
proc = subprocess.Popen(exec_cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
out, err = proc.communicate()
if err:
res = str(err.decode('utf-8'))
else:
res = str(out.decode('utf-8'))
code = 200

return flask.make_response({'script': exec_cmd, 'result': res}), code


@api.route('/config/<name>', methods=['GET'])
def get_config(name: str):
"""
Expand Down
25 changes: 20 additions & 5 deletions app/static/custom.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,21 @@ $(document).ready(function() {

});

function reload_nginx() {
$.ajax({
type: 'GET',
url: 'api/reload-nginx',
statusCode: {
200: function() {
alert('NginX reloaded successfully');
},
400: function() {
alert(`Failed to reload NginX`);
}
}
});
}

function load_domains() {
$.when(fetch_html('api/domains')).then(function() {
$('#domain').hide();
Expand All @@ -25,7 +40,7 @@ function add_domain() {

$.ajax({
type: 'POST',
url: '/api/domain/' + name,
url: 'api/domain/' + name,
statusCode: {
201: function() { fetch_domain(name) }
}
Expand All @@ -37,7 +52,7 @@ function enable_domain(name, enable) {

$.ajax({
type: 'POST',
url: '/api/domain/' + name + '/enable',
url: 'api/domain/' + name + '/enable',
contentType: 'application/json; charset=utf-8',
dataType: 'json',
data: JSON.stringify({
Expand All @@ -56,7 +71,7 @@ function update_domain(name) {

$.ajax({
type: 'PUT',
url: '/api/domain/' + name,
url: 'api/domain/' + name,
contentType: 'application/json; charset=utf-8',
dataType: 'json',
data: JSON.stringify({
Expand Down Expand Up @@ -88,7 +103,7 @@ function remove_domain(name) {

$.ajax({
type: 'DELETE',
url: '/api/domain/' + name,
url: 'api/domain/' + name,
statusCode: {
200: function() {
load_domains();
Expand Down Expand Up @@ -121,7 +136,7 @@ function update_config(name) {

$.ajax({
type: 'POST',
url: '/api/config/' + name,
url: 'api/config/' + name,
contentType: 'application/json; charset=utf-8',
dataType: 'json',
data: JSON.stringify({
Expand Down
2 changes: 1 addition & 1 deletion app/static/custom.min.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions app/templates/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,11 @@
</a>

<div class="mobile hidden right item">
{% if reload_nginx: %}
<div class="ui action" style="padding-right: 0.5em;">
<button class="ui green button" onclick="reload_nginx()" tabindex="0">Reload</button>
</div>
{% endif %}
<div class="ui action input">
<input type="text" placeholder="example.com" id="add_domain">
<button class="ui green button" onclick="add_domain()" tabindex="0">
Expand Down
9 changes: 8 additions & 1 deletion app/ui/views.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from app.ui import ui
from pathlib import Path
import flask
import os

Expand All @@ -13,4 +14,10 @@ def index():
"""
nginx_path = flask.current_app.config['NGINX_PATH']
config = [f for f in os.listdir(nginx_path) if os.path.isfile(os.path.join(nginx_path, f))]
return flask.render_template('index.html', config=config)

reload_nginx = False
docker_sock = Path('/var/run/docker.sock')
if docker_sock.is_socket() and 'NGINX_CONTAINER_NAME' in os.environ:
reload_nginx = True

return flask.render_template('index.html', config=config, reload_nginx=reload_nginx)