Version 3 starter

This commit is contained in:
Jamie Curnow
2021-06-14 19:29:35 +10:00
parent 60fc57431a
commit 6205434140
642 changed files with 25817 additions and 32319 deletions

View File

@@ -3,54 +3,105 @@
# This file assumes that the frontend has been built using ./scripts/frontend-build
FROM jc21/nginx-full:node
#===============
# gobuild
#===============
FROM jc21/nginx-full:github-acme.sh-golang AS gobuild
SHELL ["/bin/bash", "-o", "pipefail", "-c"]
ARG GOPROXY
ARG GOPRIVATE
ENV GOPROXY=$GOPROXY \
GOPRIVATE=$GOPRIVATE \
GO111MODULE=on \
CGO_ENABLED=1
# Nancy
RUN go get github.com/sonatype-nexus-community/nancy
RUN mkdir -p /workspace
WORKDIR /workspace
COPY backend/go.mod backend/go.sum backend/.nancy-ignore ./
RUN go mod download
ARG NANCY_TOKEN
ARG NANCY_USER
RUN go list -json -m all | nancy sleuth --quiet --username "${NANCY_USER}" --token "${NANCY_TOKEN}"
RUN rm -rf /workspace
# Code
WORKDIR /app
COPY . .
WORKDIR /app/backend
# Build
RUN go mod download
RUN echo "Testing and compiling project" \
&& [ -z "$(go tool fix -diff ./internal)" ]
# Disabled as CI has issues at the moment
#RUN if [ "$TARGETPLATFORM" == "" ] || [ "$TARGETPLATFORM" == "linux/amd64" ]; then golangci-lint -v run ./...; fi
RUN richgo test -cover -v ./internal/...
RUN richgo test -bench=. ./internal/...
ARG TARGETPLATFORM
ARG BUILD_VERSION
ARG BUILD_COMMIT
ARG BUILD_DATE
ARG SENTRY_DSN
RUN go build \
-ldflags "-w -s -X main.commit=${BUILD_COMMIT} -X main.version=${BUILD_VERSION} -X main.sentryDSN=${SENTRY_DSN:-}" \
-o ../dist/bin/server \
-v ./cmd/server
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}"
#===============
# Final image
#===============
RUN echo "fs.file-max = 65535" > /etc/sysctl.conf \
&& apt-get update \
&& apt-get install -y --no-install-recommends jq \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
FROM jc21/nginx-full:github-acme.sh
COPY --from=gobuild /app/dist /app
COPY --from=gobuild /app/backend/migrations /app/migrations
# COPY frontend/build /app/frontend
ENV SUPPRESS_NO_CONFIG_WARNING=1
ENV S6_FIX_ATTRS_HIDDEN=1
RUN echo "fs.file-max = 65535" > /etc/sysctl.conf
# s6 overlay
COPY scripts/install-s6 /tmp/install-s6
RUN /tmp/install-s6 "${TARGETPLATFORM}" && rm -f /tmp/install-s6
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
EXPOSE 80/tcp 81/tcp 443/tcp
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
VOLUME [ "/data", "/etc/letsencrypt" ]
ENTRYPOINT [ "/init" ]
HEALTHCHECK --interval=5s --timeout=3s CMD /bin/check-health
VOLUME /data
CMD [ "/init" ]
HEALTHCHECK --interval=15s --timeout=3s CMD curl -f http://127.0.0.1:81/api || exit 1
ARG NOW
ARG BUILD_VERSION
ARG BUILD_COMMIT
ARG BUILD_DATE
ENV NPM_BUILD_VERSION="${BUILD_VERSION}" NPM_BUILD_COMMIT="${BUILD_COMMIT}" NPM_BUILD_DATE="${BUILD_DATE}"
ENV DATABASE_URL="sqlite:////data/nginxproxymanager.db" \
DBMATE_MIGRATIONS_DIR="/app/migrations" \
DBMATE_SCHEMA_FILE="/data/schema.sql" \
DBMATE_NO_DUMP_SCHEMA="1"
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.description="Nginx Host Management and Proxy" \
org.label-schema.build-date="$NOW" \
org.label-schema.version="$BUILD_VERSION" \
org.label-schema.url="https://nginxproxymanager.com" \
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"
org.label-schema.vcs-ref="$BUILD_COMMIT" \
org.label-schema.cmd="docker run --rm -ti jc21/nginx-proxy-manager:$BUILD_VERSION"

View File

@@ -1,15 +1,30 @@
FROM jc21/nginx-full:node
FROM jc21/nginx-full:github-acme.sh-golang
LABEL maintainer="Jamie Curnow <jc@jc21.com>"
ENV S6_LOGGING=0 \
SUPPRESS_NO_CONFIG_WARNING=1 \
S6_FIX_ATTRS_HIDDEN=1
SHELL ["/bin/bash", "-o", "pipefail", "-c"]
RUN echo "fs.file-max = 65535" > /etc/sysctl.conf \
ARG GOPROXY
ARG GOPRIVATE
ENV GOPROXY=$GOPROXY \
GOPRIVATE=$GOPRIVATE \
S6_LOGGING=0 \
SUPPRESS_NO_CONFIG_WARNING=1 \
S6_FIX_ATTRS_HIDDEN=1 \
DATABASE_URL="sqlite:////data/nginxproxymanager.db" \
DBMATE_MIGRATIONS_DIR="/app/backend/migrations" \
DBMATE_SCHEMA_FILE="/data/schema.sql"
RUN echo "fs.file-max = 65535" > /etc/sysctl.conf
# Sqlite client and litecli client, and node
RUN curl -fsSL https://deb.nodesource.com/setup_14.x | bash - \
&& apt-get update \
&& apt-get install -y certbot jq python3-pip \
&& apt-get install -y --no-install-recommends nodejs \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
&& rm -rf /var/lib/apt/lists/* \
&& pip install -U litecli \
&& npm install -g yarn
# Task
RUN cd /usr \
@@ -23,6 +38,9 @@ RUN rm -f /etc/nginx/conf.d/production.conf
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" ]
HEALTHCHECK --interval=5s --timeout=3s CMD /bin/check-health
# Fix for golang dev:
RUN chown -R 1000:1000 /opt/go
EXPOSE 80
CMD [ "/init" ]
HEALTHCHECK --interval=15s --timeout=3s CMD curl -f http://127.0.0.1:81/api || exit 1

View File

@@ -2,71 +2,25 @@
version: "3"
services:
fullstack-mysql:
fullstack:
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"
- LOG_LEVEL=debug
volumes:
- npm_data:/data
expose:
- 81
- 80
- 443
depends_on:
- db
- npm_data_ci:/data
- ../docs:/temp-docs
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
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:
cypress:
image: ${IMAGE}-cypress:ci-${BUILD_NUMBER}
build:
context: ../test/
dockerfile: cypress/Dockerfile
context: ../
dockerfile: test/cypress/Dockerfile
environment:
CYPRESS_baseUrl: "http://fullstack-mysql:81"
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"
CYPRESS_baseUrl: "http://fullstack: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:
npm_data_ci:

View File

@@ -1,4 +1,4 @@
# WARNING: This is a DEVELOPMENT docker-compose file, it should not be used for production.
# WARNING: This is a DEVELOPMENT docker-compose file used for development of the entire app, it should not be used for production.
version: "3"
services:
@@ -11,57 +11,25 @@ services:
- 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"
- DEVELOPMENT=true
- GOPROXY=${GOPROXY:-}
- GOPRIVATE=${GOPRIVATE:-}
- LOG_LEVEL=debug
- PUID=1000
- PGID=1000
volumes:
- npm_data:/data
- le_data:/etc/letsencrypt
- ../backend:/app
- ../frontend:/app/frontend
- ../global:/app/global
depends_on:
- db
- ../:/app
- ./rootfs/var/www/html:/var/www/html
- ../data:/data
working_dir: /app
db:
image: jc21/mariadb-aria
networks:
- nginx_proxy_manager
environment:
MYSQL_ROOT_PASSWORD: "npm"
MYSQL_DATABASE: "npm"
MYSQL_USER: "npm"
MYSQL_PASSWORD: "npm"
volumes:
- db_data:/var/lib/mysql
swagger:
image: 'swaggerapi/swagger-ui:latest'
ports:
- 3001:80
networks:
- nginx_proxy_manager
environment:
URL: "http://127.0.0.1:3081/api/schema"
URL: "http://${SWAGGER_PUBLIC_DOMAIN:-127.0.0.1:3081}/api/schema"
PORT: '80'
depends_on:
- npm
volumes:
npm_data:
le_data:
db_data:
networks:
nginx_proxy_manager:

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,3 +0,0 @@
*
!.gitignore
!*.sh

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
# seach 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

@@ -0,0 +1,44 @@
#!/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 \
/data/acme.sh
touch /var/log/nginx/error.log && chmod 777 /var/log/nginx/error.log && chmod -R 777 /var/cache/nginx
# Dynamically generate resolvers file
echo resolver "$(awk 'BEGIN{ORS=" "} $1=="nameserver" {print $2}' /etc/resolv.conf)" ";" > /etc/nginx/conf.d/include/resolvers.conf
# 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=Nginx Proxy Manager/OU=Dummy Certificate/CN=localhost' \
-keyout /data/nginx/dummykey.pem \
-out /data/nginx/dummycert.pem
echo "Complete"
else
echo "Skipping generation of dummy SSL cert"
fi

View File

@@ -0,0 +1,33 @@
#!/usr/bin/with-contenv bash
PUID=${PUID:-911}
PGID=${PGID:-911}
groupmod -g 1000 users || exit 1
useradd -u "${PUID}" -U -d /data -s /bin/false npmuser || exit 1
usermod -G users npmuser || exit 1
groupmod -o -g "$PGID" npmuser || exit 1
echo "-------------------------------------
_ _ ____ __ __
| \ | | _ \| \/ |
| \| | |_) | |\/| |
| |\ | __/| | | |
|_| \_|_| |_| |_|
-------------------------------------
User UID: $(id -u npmuser)
User GID: $(id -g npmuser)
-------------------------------------
"
chown -R npmuser:npmuser /data
chown -R npmuser:npmuser /run/nginx
chown -R npmuser:npmuser /etc/nginx
chown -R npmuser:npmuser /tmp/nginx
chown -R npmuser:npmuser /var/cache/nginx
chown -R npmuser:npmuser /var/lib/nginx
chown -R npmuser:npmuser /var/log/nginx
# Home for npmuser
mkdir -p /tmp/npmuserhome
chown -R npmuser:npmuser /tmp/npmuserhome

View File

@@ -0,0 +1,16 @@
#!/usr/bin/with-contenv bash
CYAN='\E[1;36m'
YELLOW='\E[1;33m'
MAGENTA='\E[1;35m'
RESET='\E[0m'
if [ "$LOG_LEVEL" == "debug" ]; then
echo -e "${MAGENTA}[DEBUG] ${CYAN}DATABASE_URL=${YELLOW}${DATABASE_URL}${RESET}"
fi
# Firstly create the sqlite database if it doesn't already exist
# and run any migrations required
echo -e "${YELLOW}Running dbmate migrations ...${RESET}"
s6-setuidgid npmuser /bin/dbmate up || exit 1
echo -e "${GREEN}Completed dbmate migrations!${RESET}"

View File

@@ -1,4 +0,0 @@
text = True
non-interactive = True
authenticator = webroot
webroot-path = /data/letsencrypt-acme-challenge

View File

@@ -1,17 +1,9 @@
# "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/default.log standard;
error_log /dev/null crit;
include conf.d/include/assets.conf;
server_name localhost;
include conf.d/include/block-exploits.conf;
access_log /data/logs/default.log proxy;
location / {
index index.html;
@@ -22,15 +14,10 @@ server {
# 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/default.log standard;
error_log /dev/null crit;
include conf.d/include/block-exploits.conf;
access_log /data/logs/default.log proxy;
ssl_certificate /data/nginx/dummycert.pem;
ssl_certificate_key /data/nginx/dummykey.pem;
include conf.d/include/ssl-ciphers.conf;

View File

@@ -1,10 +1,6 @@
server {
listen 81 default;
listen [::]:81 default;
server_name nginxproxymanager-dev;
root /app/frontend/dist;
access_log /dev/null;
location /api {
return 302 /api/;
@@ -16,14 +12,22 @@ server {
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_pass http://127.0.0.1:3000/api/;
}
proxy_read_timeout 15m;
proxy_send_timeout 15m;
location ~ .html {
try_files $uri =404;
}
location / {
index index.html;
try_files $uri $uri.html $uri/ /index.html;
add_header X-Served-By $host;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
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:9000;
}
}

View File

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

View File

@@ -1,31 +1,31 @@
location ~* ^.*\.(css|js|jpe?g|gif|png|woff|eot|ttf|svg|ico|css\.map|js\.map)$ {
if_modified_since off;
if_modified_since off;
# use the public cache
proxy_cache public-cache;
proxy_cache_key $host$request_uri;
# 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;
# 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;
# 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;
# 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_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;
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;
expires @30m;
access_log off;
include conf.d/include/proxy.conf;
include conf.d/include/proxy.conf;
}

View File

@@ -2,92 +2,92 @@
set $block_sql_injections 0;
if ($query_string ~ "union.*select.*\(") {
set $block_sql_injections 1;
set $block_sql_injections 1;
}
if ($query_string ~ "union.*all.*select.*") {
set $block_sql_injections 1;
set $block_sql_injections 1;
}
if ($query_string ~ "concat.*\(") {
set $block_sql_injections 1;
set $block_sql_injections 1;
}
if ($block_sql_injections = 1) {
return 403;
return 403;
}
## Block file injections
set $block_file_injections 0;
if ($query_string ~ "[a-zA-Z0-9_]=http://") {
set $block_file_injections 1;
set $block_file_injections 1;
}
if ($query_string ~ "[a-zA-Z0-9_]=(\.\.//?)+") {
set $block_file_injections 1;
set $block_file_injections 1;
}
if ($query_string ~ "[a-zA-Z0-9_]=/([a-z0-9_.]//?)+") {
set $block_file_injections 1;
set $block_file_injections 1;
}
if ($block_file_injections = 1) {
return 403;
return 403;
}
## Block common exploits
set $block_common_exploits 0;
if ($query_string ~ "(<|%3C).*script.*(>|%3E)") {
set $block_common_exploits 1;
set $block_common_exploits 1;
}
if ($query_string ~ "GLOBALS(=|\[|\%[0-9A-Z]{0,2})") {
set $block_common_exploits 1;
set $block_common_exploits 1;
}
if ($query_string ~ "_REQUEST(=|\[|\%[0-9A-Z]{0,2})") {
set $block_common_exploits 1;
set $block_common_exploits 1;
}
if ($query_string ~ "proc/self/environ") {
set $block_common_exploits 1;
set $block_common_exploits 1;
}
if ($query_string ~ "mosConfig_[a-zA-Z_]{1,21}(=|\%3D)") {
set $block_common_exploits 1;
set $block_common_exploits 1;
}
if ($query_string ~ "base64_(en|de)code\(.*\)") {
set $block_common_exploits 1;
set $block_common_exploits 1;
}
if ($block_common_exploits = 1) {
return 403;
return 403;
}
## Block spam
set $block_spam 0;
if ($query_string ~ "\b(ultram|unicauca|valium|viagra|vicodin|xanax|ypxaieo)\b") {
set $block_spam 1;
set $block_spam 1;
}
if ($query_string ~ "\b(erections|hoodia|huronriveracres|impotence|levitra|libido)\b") {
set $block_spam 1;
set $block_spam 1;
}
if ($query_string ~ "\b(ambien|blue\spill|cialis|cocaine|ejaculation|erectile)\b") {
set $block_spam 1;
set $block_spam 1;
}
if ($query_string ~ "\b(lipitor|phentermin|pro[sz]ac|sandyauer|tramadol|troyhamby)\b") {
set $block_spam 1;
set $block_spam 1;
}
if ($block_spam = 1) {
return 403;
return 403;
}
## Block user agents
@@ -95,42 +95,42 @@ set $block_user_agents 0;
# Disable Akeeba Remote Control 2.5 and earlier
if ($http_user_agent ~ "Indy Library") {
set $block_user_agents 1;
set $block_user_agents 1;
}
# Common bandwidth hoggers and hacking tools.
if ($http_user_agent ~ "libwww-perl") {
set $block_user_agents 1;
set $block_user_agents 1;
}
if ($http_user_agent ~ "GetRight") {
set $block_user_agents 1;
set $block_user_agents 1;
}
if ($http_user_agent ~ "GetWeb!") {
set $block_user_agents 1;
set $block_user_agents 1;
}
if ($http_user_agent ~ "Go!Zilla") {
set $block_user_agents 1;
set $block_user_agents 1;
}
if ($http_user_agent ~ "Download Demon") {
set $block_user_agents 1;
set $block_user_agents 1;
}
if ($http_user_agent ~ "Go-Ahead-Got-It") {
set $block_user_agents 1;
set $block_user_agents 1;
}
if ($http_user_agent ~ "TurnitinBot") {
set $block_user_agents 1;
set $block_user_agents 1;
}
if ($http_user_agent ~ "GrabNet") {
set $block_user_agents 1;
set $block_user_agents 1;
}
if ($block_user_agents = 1) {
return 403;
return 403;
}

View File

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

@@ -3,6 +3,4 @@ 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_set_header X-Real-IP $remote_addr;
proxy_pass $forward_scheme://$server:$port;

View File

@@ -0,0 +1 @@
# Intentionally blank

View File

@@ -1,33 +1,14 @@
# 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/ {
location / {
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;
proxy_pass http://localhost:3000/;
}
}

View File

@@ -1,7 +1,6 @@
# run nginx in foreground
daemon off;
user root;
pid /run/nginx/nginx.pid;
# Set number of worker processes automatically based on number of CPU cores.
worker_processes auto;
@@ -26,15 +25,12 @@ http {
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;
keepalive_timeout 65;
ssl_prefer_server_ciphers on;
gzip on;
proxy_ignore_client_abort off;
client_max_body_size 2000m;
server_names_hash_bucket_size 1024;
client_max_body_size 200m;
server_names_hash_bucket_size 64;
proxy_http_version 1.1;
proxy_set_header X-Forwarded-Scheme $scheme;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
@@ -43,54 +39,27 @@ http {
proxy_cache_path /var/lib/nginx/cache/public levels=1:2 keys_zone=public-cache:30m max_size=192m;
proxy_cache_path /var/lib/nginx/cache/private levels=1:2 keys_zone=private-cache:5m max_size=1024m;
log_format proxy '[$time_local] $upstream_cache_status $upstream_status $status - $request_method $scheme $host "$request_uri" [Client $remote_addr] [Length $body_bytes_sent] [Gzip $gzip_ratio] [Sent-to $server] "$http_user_agent" "$http_referer"';
log_format standard '[$time_local] $status - $request_method $scheme $host "$request_uri" [Client $remote_addr] [Length $body_bytes_sent] [Gzip $gzip_ratio] "$http_user_agent" "$http_referer"';
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] "$http_user_agent" "$http_referer"';
access_log /data/logs/default.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;
# Docker subnet:
set_real_ip_from 172.0.0.0/8;
# NPM generated CDN ip ranges:
include conf.d/include/ip_ranges.conf;
#include conf.d/include/ip_ranges.conf;
# always put the following 2 lines after ip subnets:
real_ip_header X-Real-IP;
real_ip_header X-Forwarded-For;
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

@@ -0,0 +1,5 @@
#!/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

@@ -0,0 +1,23 @@
#!/usr/bin/with-contenv bash
RESET='\E[0m'
YELLOW='\E[1;33m'
echo -e "${YELLOW}Starting backend API ...${RESET}"
if [ "$DEVELOPMENT" == "true" ]; then
HOME=/tmp/npmuserhome
GOPATH="$HOME/go"
mkdir -p "$GOPATH"
chown -R npmuser:npmuser "$GOPATH"
export HOME GOPATH
cd /app/backend || exit 1
s6-setuidgid npmuser task -w
else
cd /app/bin || exit 1
while :
do
s6-setuidgid npmuser /app/bin/server
sleep 1
done
fi

View File

@@ -3,4 +3,3 @@ if { s6-test ${1} -ne 0 }
if { s6-test ${1} -ne 256 }
s6-svscanctl -t /var/run/s6/services

View File

@@ -3,9 +3,13 @@
# This service is DEVELOPMENT only.
if [ "$DEVELOPMENT" == "true" ]; then
CI=true
HOME=/tmp/npmuserhome
export CI
export HOME
cd /app/frontend || exit 1
yarn install
yarn watch
s6-setuidgid npmuser yarn install
s6-setuidgid npmuser yarn start
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,18 +0,0 @@
#!/usr/bin/with-contenv bash
mkdir -p /data/letsencrypt-acme-challenge
cd /app || echo
if [ "$DEVELOPMENT" == "true" ]; then
cd /app || exit 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

@@ -0,0 +1,6 @@
#!/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,49 +1,3 @@
#!/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
echo resolver "$(awk 'BEGIN{ORS=" "} $1=="nameserver" {print ($2 ~ ":")? "["$2"]": $2}' /etc/resolv.conf);" > /etc/nginx/conf.d/include/resolvers.conf
# 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=Nginx Proxy Manager/OU=Dummy Certificate/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
exec s6-setuidgid npmuser nginx

View File

@@ -16,7 +16,5 @@ alias h='cd ~;clear;'
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'
echo -e "\E[1;36mVersion \E[1;32m${NPM_BUILD_VERSION:-3.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, Debian \E[1;32m${VERSION_ID:-unknown}\E[1;36m, Kernel \E[1;32m$(uname -r)\E[0m"
echo

View File

@@ -0,0 +1,13 @@
[main]
multi_line = True
log_level = INFO
table_format = psql
syntax_style = monokai
wider_completion_menu = True
prompt = '\d> '
prompt_continuation = '-> '
less_chatty = True
auto_vertical_output = True
[favorite_queries]
show_users = select * from user

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 820 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

View File

@@ -1,24 +1,30 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Default Site</title>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
<style>
.jumbotron { margin-top: 50px; }
</style>
</head>
<body>
<div class="container">
<div class="jumbotron">
<h1>Congratulations!</h1>
<p>You've successfully started the Nginx Proxy Manager.</p>
<p>If you're seeing this site then you're trying to access a host that isn't set up yet.</p>
<p>Log in to the Admin panel to get started.</p>
</div>
<p class="text-center"><small>Powered by <a href="https://github.com/jc21/nginx-proxy-manager" target="_blank">Nginx Proxy Manager</a></small></p>
</div>
</body>
<head>
<title>Site not found :: Nginx Proxy Manager</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet" integrity="sha384-wvfXpqpZZVQGK6TAh5PVlGOfQNHSoD2xbE+QkPxCAFlNEevoEH3Sl0sibVcOQVnN" crossorigin="anonymous">
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.4.1/css/bootstrap.css">
<link rel="stylesheet" type="text/css" href="main.css">
</head>
<body>
<div class="bg-img1 size1 overlay1 p-t-24" style="background-image: url('images/bg.jpg');">
<div class="flex-w flex-sb-m p-l-80 p-r-74 p-b-175 respon5">
<div class="wrappic1 m-r-30 m-t-10 m-b-10">
<a href="#"><img src="images/logo.png" alt="Logo" class="logo-img"></a>
</div>
<div class="flex-w m-t-10 m-b-10">
<a href="https://github.com/jc21/nginx-proxy-manager" class="size3 flex-c-m how-social trans-04 m-r-6" title="Nginx Proxy Manager on Github"><i class="fa fa-github"></i></a>
<a href="https://nginxproxymanager.jc21.com" class="size3 flex-c-m how-social trans-04 m-r-6" title="Nginx Proxy Manager Website"><i class="fa fa-globe"></i></a>
</div>
</div>
<div class="flex-w flex-sa p-r-200 respon1">
<div class="p-t-34 p-b-60 respon3">
<p class="l1-txt1 p-b-10 respon2">This site is</p>
<h3 class="l1-txt2 p-b-45 respon2 respon4">not yet configured</h3>
</div>
</div>
</div>
</body>
</html>

View File

@@ -0,0 +1,399 @@
*, *:before, *:after {
margin: 0px;
padding: 0px;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
body, html {
font-family: Arial, sans-serif;
font-size: 15px;
color: #666666;
height: 100%;
background-color: #fff;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
a:focus {outline: none;}
a:hover {text-decoration: none;}
h1,h2,h3,h4,h5,h6,p {margin: 0px;}
ul, li {
margin: 0px;
list-style-type: none;
}
.logo-img {
border: 2px solid #3c99b9;
border-radius: 50%;
}
.p-t-24 {padding-top: 24px;}
.p-t-34 {padding-top: 34px;}
.p-b-10 {padding-bottom: 10px;}
.p-b-45 {padding-bottom: 45px;}
.p-b-60 {padding-bottom: 60px;}
.p-b-175 {padding-bottom: 175px;}
.p-l-80 {padding-left: 80px;}
.p-r-74 {padding-right: 74px;}
.p-r-200 {padding-right: 200px;}
.m-t-10 {margin-top: 10px;}
.m-b-10 {margin-bottom: 10px;}
.m-r-6 {margin-right: 6px;}
.m-r-30 {margin-right: 30px;}
.bo-cir {border-radius: 50%;}
.of-hidden {overflow: hidden;}
.visible-false {visibility: hidden;}
.visible-true {visibility: visible;}
.trans-04 {
-webkit-transition: all 0.4s;
-o-transition: all 0.4s;
-moz-transition: all 0.4s;
transition: all 0.4s;
}
.flex-w,
.flex-sa,
.flex-c-m,
.flex-sb-m,
.dis-flex {
display: -webkit-box;
display: -webkit-flex;
display: -moz-box;
display: -ms-flexbox;
display: flex;
}
.flex-w {
-webkit-flex-wrap: wrap;
-moz-flex-wrap: wrap;
-ms-flex-wrap: wrap;
-o-flex-wrap: wrap;
flex-wrap: wrap;
}
.flex-sa {
justify-content: space-around;
}
.flex-c-m {
justify-content: center;
-ms-align-items: center;
align-items: center;
}
.flex-sb-m {
justify-content: space-between;
-ms-align-items: center;
align-items: center;
}
.flex-row {
-webkit-flex-direction: row;
-moz-flex-direction: row;
-ms-flex-direction: row;
-o-flex-direction: row;
flex-direction: row;
}
@font-face {
font-family: Poppins-Regular;
src: url('fonts/Poppins-Regular.ttf');
}
@font-face {
font-family: Poppins-Bold;
src: url('fonts/Poppins-Bold.ttf');
}
@font-face {
font-family: Aldrich-Regular;
src: url('fonts/Aldrich-Regular.ttf');
}
.container {max-width: 1200px;}
.cl0 {color: #fff;}
.s1-txt1 {
font-family: Poppins-Bold;
font-size: 15px;
color: #555;
line-height: 1.2;
}
.s1-txt2 {
font-family: Poppins-Bold;
font-size: 15px;
color: #fff;
line-height: 1.2;
}
.s1-txt3 {
font-family: Poppins-Regular;
font-size: 13px;
color: #999;
line-height: 1.5;
}
.l1-txt1 {
font-family: Poppins-Regular;
font-size: 30px;
color: #fff;
line-height: 1.2;
text-transform: uppercase;
}
.l1-txt2 {
font-family: Poppins-Bold;
font-size: 70px;
color: #fff;
line-height: 1.1;
text-transform: uppercase;
}
.l1-txt3 {
font-family: Poppins-Bold;
font-size: 30px;
color: #333;
line-height: 1.2;
text-transform: uppercase;
}
.size1 {
width: 100%;
min-height: 100vh;
}
.size2 {
width: 100%;
height: 50px;
}
.size3 {
width: 36px;
height: 36px;
}
.wsize1 {
width: 390px;
max-width: 100%;
}
.bg0 {background-color: #fff;}
.bg-img1 {
background-position: center;
background-repeat: no-repeat;
background-size: cover;
}
.bor1 {
border-radius: 10px;
}
.overlay1 {
position: relative;
z-index: 1;
}
.overlay1::before {
content: "";
display: block;
position: absolute;
z-index: -1;
width: 100%;
height: 100%;
top: 0;
left: 0;
background: #30bab6;
background: -webkit-linear-gradient(top, #00B4DB, #240b36);
background: -o-linear-gradient(top, #00B4DB, #240b36);
background: -moz-linear-gradient(top, #00B4DB, #240b36);
background: linear-gradient(top, #00B4DB, #240b36);
opacity: 0.8;
}
.how-btn1 {
border-radius: 25px;
background-color: #240b36;
padding-right: 20px;
padding-left: 20px;
}
.how-btn1:hover {
background-color: #333333;
}
.wrappic1 {
display: block;
flex-grow: 1;
}
.wrappic1 img {
max-width: 100%;
}
.how-social {
color: #fff;
font-size: 22px;
background-color: transparent;
border: 2px solid #fff;
border-radius: 2px;
}
.how-social:hover {
background-color: #240b36;
color: #fff;
}
.focus-in0:focus::-webkit-input-placeholder { color:transparent; }
.focus-in0:focus:-moz-placeholder { color:transparent; }
.focus-in0:focus::-moz-placeholder { color:transparent; }
.focus-in0:focus:-ms-input-placeholder { color:transparent; }
.hov-cl0:hover {color: #fff;}
.hov-bg0:hover {background-color: #fff;}
@media (max-width: 1400px) {
.respon1 {
padding: 15px;
}
}
@media (max-width: 1200px) {
.m-0-xl {margin: 0;}
.m-lr-0-xl {margin-left: 0; margin-right: 0;}
.m-lr-15-xl {margin-left: 15px; margin-right: 15px;}
.m-l-0-xl {margin-left: 0;}
.m-r-0-xl {margin-right: 0;}
.m-l-15-xl {margin-left: 15px;}
.m-r-15-xl {margin-right: 15px;}
.p-0-xl {padding: 0;}
.p-lr-0-xl {padding-left: 0; padding-right: 0;}
.p-lr-15-xl {padding-left: 15px; padding-right: 15px;}
.p-l-0-xl {padding-left: 0;}
.p-r-0-xl {padding-right: 0;}
.p-l-15-xl {padding-left: 15px;}
.p-r-15-xl {padding-right: 15px;}
.w-full-xl {width: 100%;}
.respon1 {
flex-direction: column;
align-items: center;
}
.respon2 {
text-align: center;
}
.respon3 {
display: -webkit-box;
display: -webkit-flex;
display: -moz-box;
display: -ms-flexbox;
display: flex;
flex-direction: column;
align-items: center;
}
}
@media (max-width: 992px) {
.m-0-lg {margin: 0;}
.m-lr-0-lg {margin-left: 0; margin-right: 0;}
.m-lr-15-lg {margin-left: 15px; margin-right: 15px;}
.m-l-0-lg {margin-left: 0;}
.m-r-0-lg {margin-right: 0;}
.m-l-15-lg {margin-left: 15px;}
.m-r-15-lg {margin-right: 15px;}
.p-0-lg {padding: 0;}
.p-lr-0-lg {padding-left: 0; padding-right: 0;}
.p-lr-15-lg {padding-left: 15px; padding-right: 15px;}
.p-l-0-lg {padding-left: 0;}
.p-r-0-lg{padding-right: 0;}
.p-l-15-lg {padding-left: 15px;}
.p-r-15-lg {padding-right: 15px;}
.w-full-lg {width: 100%;}
}
@media (max-width: 768px) {
.m-0-md {margin: 0;}
.m-lr-0-md {margin-left: 0; margin-right: 0;}
.m-lr-15-md {margin-left: 15px; margin-right: 15px;}
.m-l-0-md {margin-left: 0;}
.m-r-0-md {margin-right: 0;}
.m-l-15-md {margin-left: 15px;}
.m-r-15-md {margin-right: 15px;}
.p-0-md {padding: 0;}
.p-lr-0-md {padding-left: 0; padding-right: 0;}
.p-lr-15-md {padding-left: 15px; padding-right: 15px;}
.p-l-0-md {padding-left: 0;}
.p-r-0-md{padding-right: 0;}
.p-l-15-md {padding-left: 15px;}
.p-r-15-md {padding-right: 15px;}
.w-full-md {width: 100%;}
}
@media (max-width: 576px) {
.m-0-sm {margin: 0;}
.m-lr-0-sm {margin-left: 0; margin-right: 0;}
.m-lr-15-sm {margin-left: 15px; margin-right: 15px;}
.m-l-0-sm {margin-left: 0;}
.m-r-0-sm {margin-right: 0;}
.m-l-15-sm {margin-left: 15px;}
.m-r-15-sm {margin-right: 15px;}
.p-0-sm {padding: 0;}
.p-lr-0-sm {padding-left: 0; padding-right: 0;}
.p-lr-15-sm {padding-left: 15px; padding-right: 15px;}
.p-l-0-sm {padding-left: 0;}
.p-r-0-sm{padding-right: 0;}
.p-l-15-sm {padding-left: 15px;}
.p-r-15-sm {padding-right: 15px;}
.w-full-sm {width: 100%;}
.respon4 {
font-size: 50px;
}
.respon5 {
padding-left: 20px;
padding-right: 14px;
padding-bottom: 50px;
}
}
@media (max-width: 480px) {
.m-0-ssm {margin: 0;}
.m-lr-0-ssm {margin-left: 0; margin-right: 0;}
.m-lr-15-ssm {margin-left: 15px; margin-right: 15px;}
.m-l-0-ssm {margin-left: 0;}
.m-r-0-ssm {margin-right: 0;}
.m-l-15-ssm {margin-left: 15px;}
.m-r-15-ssm {margin-right: 15px;}
.p-0-ssm {padding: 0;}
.p-lr-0-ssm {padding-left: 0; padding-right: 0;}
.p-lr-15-ssm {padding-left: 15px; padding-right: 15px;}
.p-l-0-ssm {padding-left: 0;}
.p-r-0-ssm{padding-right: 0;}
.p-l-15-ssm {padding-left: 15px;}
.p-r-15-ssm {padding-right: 15px;}
.w-full-ssm {width: 100%;}
}