init
This commit is contained in:
@@ -0,0 +1,27 @@
|
||||
# Environment variables for docker-compose.yml
|
||||
|
||||
LOG_LEVEL="DEBUG"
|
||||
NETWORK=web
|
||||
## dashboard configs
|
||||
HOST="furyhawk.lol"
|
||||
# subdomain for dashboard.
|
||||
DASHBOARD_HOST="dashboard.furyhawk.lol"
|
||||
|
||||
# The following are the environment variables for the streamlit app
|
||||
FIN_LOCATION="/fin"
|
||||
STREAMLIT_FIN_SERVER_PORT="8501"
|
||||
BAI_LOCATION="/bai"
|
||||
STREAMLIT_BAI_SERVER_PORT="8502"
|
||||
|
||||
# user/pass
|
||||
DASHBOARD_USER=admin
|
||||
DASHBOARD_PASSWORD=pass
|
||||
|
||||
OSRM_ALGORITHM="mld"
|
||||
OSRM_THREADS=2
|
||||
OSRM_PORT=5000
|
||||
OSRM_PROFILE="/opt/car.lua"
|
||||
OSRM_MAP_NAME=${OSRM_MAP_NAME}
|
||||
OSRM_GEOFABRIK_PATH=${OSRM_GEOFABRIK_PATH}
|
||||
# Notify OSRM Manager to restart without stopping container
|
||||
OSRM_NOTIFY_FILEPATH="/data/osrm_notify.txt"
|
||||
+165
@@ -0,0 +1,165 @@
|
||||
# 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/
|
||||
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/
|
||||
cover/
|
||||
|
||||
# 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
|
||||
.pybuilder/
|
||||
target/
|
||||
|
||||
# Jupyter Notebook
|
||||
.ipynb_checkpoints
|
||||
|
||||
# IPython
|
||||
profile_default/
|
||||
ipython_config.py
|
||||
|
||||
# pyenv
|
||||
# For a library or package, you might want to ignore these files since the code is
|
||||
# intended to run in multiple environments; otherwise, check them in:
|
||||
# .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
|
||||
|
||||
# poetry
|
||||
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
|
||||
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
||||
# commonly ignored for libraries.
|
||||
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
|
||||
#poetry.lock
|
||||
|
||||
# pdm
|
||||
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
|
||||
#pdm.lock
|
||||
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
|
||||
# in version control.
|
||||
# https://pdm.fming.dev/#use-with-ide
|
||||
.pdm.toml
|
||||
|
||||
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
|
||||
__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/
|
||||
|
||||
# pytype static type analyzer
|
||||
.pytype/
|
||||
|
||||
# Cython debug symbols
|
||||
cython_debug/
|
||||
|
||||
# PyCharm
|
||||
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
||||
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
||||
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
||||
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
||||
#.idea/
|
||||
|
||||
# ignores production code for traefik and production yml
|
||||
# compose/traefik/
|
||||
# production.yml
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
# Streamlit + Traefik + Docker
|
||||
This simple project uses Traefik as a reverse proxy to a Streamlit application and handles SSL certs with Lets Encrypt.
|
||||
|
||||
## Requirements
|
||||
- Docker Compose
|
||||
- Python 3.9
|
||||
|
||||
## Local Deployment
|
||||
#### Python:
|
||||
1. `cd src`
|
||||
2. `pip install -r requirements.txt`
|
||||
3. `streamlit run app.py`
|
||||
|
||||
#### Docker:
|
||||
1. `sudo docker-compose -f local.yml up --build`
|
||||
|
||||
## Production Deployment
|
||||
1. In `compose/traefik/traefik.yml`, change `example@test.com` to your email.
|
||||
2. In `compose/traefik/traefik.yml`, change `example.com` to your domain.
|
||||
3. `docker compose -f production.yml up --build -d --remove-orphans`
|
||||
|
||||
### Notes:
|
||||
Feel free to make a PR or get in contact with me on Discord at yoyojoe#5510.
|
||||
@@ -0,0 +1,2 @@
|
||||
*
|
||||
!.gitignore
|
||||
Vendored
BIN
Binary file not shown.
@@ -0,0 +1,29 @@
|
||||
# base image
|
||||
FROM python:3.11-slim
|
||||
|
||||
#basic build prep
|
||||
RUN apt-get update && apt-get install -y \
|
||||
build-essential \
|
||||
curl \
|
||||
software-properties-common \
|
||||
git \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# copy over and install packages
|
||||
COPY ./src/requirements.txt ./requirements.txt
|
||||
RUN pip3 install cython
|
||||
RUN pip3 install -r requirements.txt
|
||||
|
||||
# streamlit-specific commands
|
||||
RUN mkdir -p /root/.streamlit
|
||||
RUN bash -c 'echo -e "\
|
||||
[general]\n\
|
||||
email = \"\"\n\
|
||||
" > /root/.streamlit/credentials.toml'
|
||||
# RUN bash -c 'echo -e "\
|
||||
# [server]\n\
|
||||
# baseUrlPath = \"/fin\"\n\
|
||||
# " > /root/.streamlit/config.toml'
|
||||
|
||||
# copying everything over
|
||||
COPY . .
|
||||
@@ -0,0 +1,5 @@
|
||||
FROM traefik:v2.11
|
||||
RUN mkdir -p /etc/traefik/acme \
|
||||
&& touch /etc/traefik/acme/acme.json \
|
||||
&& chmod 600 /etc/traefik/acme/acme.json
|
||||
COPY ./compose/traefik/traefik.yml /etc/traefik
|
||||
@@ -0,0 +1,143 @@
|
||||
log:
|
||||
level: DEBUG
|
||||
api:
|
||||
# Dashboard
|
||||
dashboard: true
|
||||
# https://docs.traefik.io/master/operations/api/#insecure
|
||||
# insecure: true
|
||||
|
||||
|
||||
entryPoints:
|
||||
web:
|
||||
# http
|
||||
address: ":80"
|
||||
http:
|
||||
# https://docs.traefik.io/routing/entrypoints/#entrypoint
|
||||
redirections:
|
||||
entryPoint:
|
||||
to: web-secure
|
||||
|
||||
web-secure:
|
||||
# https
|
||||
address: ":443"
|
||||
|
||||
# osrm:
|
||||
# address: ":5000"
|
||||
|
||||
certificatesResolvers:
|
||||
letsencrypt:
|
||||
# https://docs.traefik.io/master/https/acme/#lets-encrypt
|
||||
acme:
|
||||
email: "furyx@hotmail.com"
|
||||
storage: /etc/traefik/acme/acme.json
|
||||
# https://docs.traefik.io/master/https/acme/#httpchallenge
|
||||
httpChallenge:
|
||||
entryPoint: web
|
||||
|
||||
http:
|
||||
routers:
|
||||
dashboard:
|
||||
rule: "Host(`dashboard.furyhawk.lol`) && (PathPrefix(`/api`) || PathPrefix(`/dashboard`))"
|
||||
service: api@internal
|
||||
middlewares:
|
||||
- auth
|
||||
tls:
|
||||
# https://docs.traefik.io/master/routing/routers/#certresolver
|
||||
certResolver: letsencrypt
|
||||
|
||||
web-secure-router:
|
||||
rule: "Host(`furyhawk.lol`, `www.furyhawk.lol`, `bai.furyhawk.lol`) || PathPrefix(`/bai`)"
|
||||
entryPoints:
|
||||
- web-secure
|
||||
middlewares:
|
||||
- csrf
|
||||
- add-bai
|
||||
service: streamlit_bai_app
|
||||
tls:
|
||||
# https://docs.traefik.io/master/routing/routers/#certresolver
|
||||
certResolver: letsencrypt
|
||||
fin-router:
|
||||
rule: "Host(`fin.furyhawk.lol`)"
|
||||
entryPoints:
|
||||
- web-secure
|
||||
middlewares:
|
||||
- csrf
|
||||
- add-fin
|
||||
service: streamlit_fin_app
|
||||
tls:
|
||||
# https://docs.traefik.io/master/routing/routers/#certresolver
|
||||
certResolver: letsencrypt
|
||||
blog-router:
|
||||
rule: "Host(`blog.furyhawk.lol`)"
|
||||
entryPoints:
|
||||
- web-secure
|
||||
# redirect to external blog
|
||||
middlewares:
|
||||
- redirect-blog
|
||||
|
||||
service: blog
|
||||
tls:
|
||||
# https://docs.traefik.io/master/routing/routers/#certresolver
|
||||
certResolver: letsencrypt
|
||||
|
||||
osrm-router:
|
||||
rule: "Host(`osrm.furyhawk.lol`)"
|
||||
entryPoints:
|
||||
- "web-secure"
|
||||
# - "osrm"
|
||||
middlewares:
|
||||
- csrf
|
||||
service: osrm_service
|
||||
tls:
|
||||
# https://docs.traefik.io/master/routing/routers/#certresolver
|
||||
certResolver: letsencrypt
|
||||
|
||||
middlewares:
|
||||
auth:
|
||||
basicAuth:
|
||||
users:
|
||||
- "test:$apr1$2E4PEW8M$/wEgFNKX71h.YYMywV7WZ/"
|
||||
csrf:
|
||||
# https://doc.traefik.io/traefik/middlewares/http/headers/#hostsproxyheaders
|
||||
# https://docs.djangoproject.com/en/dev/ref/csrf/#ajax
|
||||
headers:
|
||||
hostsProxyHeaders: ["X-CSRFToken"]
|
||||
|
||||
add-bai:
|
||||
addPrefix:
|
||||
prefix: "/bai"
|
||||
|
||||
add-fin:
|
||||
addPrefix:
|
||||
prefix: "/fin"
|
||||
|
||||
redirect-blog:
|
||||
# https://docs.traefik.io/master/middlewares/redirectscheme/
|
||||
redirectregex:
|
||||
regex: "^https://blog.furyhawk.lol/(.*)"
|
||||
replacement: "https://furyhawk.github.io/124c41/${1}"
|
||||
permanent: true
|
||||
|
||||
services:
|
||||
osrm_service:
|
||||
loadBalancer:
|
||||
servers:
|
||||
- url: http://osrm_backend:{{env "OSRM_PORT"}}
|
||||
streamlit_bai_app:
|
||||
loadBalancer:
|
||||
servers:
|
||||
- url: http://streamlit_bai_app:8502/bai
|
||||
streamlit_fin_app:
|
||||
loadBalancer:
|
||||
servers:
|
||||
- url: http://streamlit_fin_app:{{env "STREAMLIT_FIN_SERVER_PORT"}}/{{env "FIN_LOCATION"}}
|
||||
blog:
|
||||
loadBalancer:
|
||||
servers:
|
||||
- url: https://furyhawk.github.io/124c41/
|
||||
|
||||
providers:
|
||||
# https://docs.traefik.io/master/providers/file/
|
||||
file:
|
||||
filename: /etc/traefik/traefik.yml
|
||||
watch: true
|
||||
@@ -0,0 +1,3 @@
|
||||
*
|
||||
!.gitignore
|
||||
!certs.toml
|
||||
@@ -0,0 +1,3 @@
|
||||
[tls.stores.default.defaultCertificate]
|
||||
certFile = "/certs/cert.crt"
|
||||
keyFile = "/certs/cert.key"
|
||||
@@ -0,0 +1,13 @@
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
streamlit-fin:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: ./compose/streamlit-fin/Dockerfile
|
||||
image: streamlit_fin_local
|
||||
container_name: streamlit_fin_app
|
||||
restart: always
|
||||
ports:
|
||||
- 8501:8501
|
||||
command: streamlit run src/app.py
|
||||
@@ -0,0 +1,2 @@
|
||||
*
|
||||
!.gitignore
|
||||
@@ -0,0 +1,68 @@
|
||||
version: '3.7'
|
||||
|
||||
x-environment: &default-environment
|
||||
LOG_LEVEL: "DEBUG"
|
||||
DASHBOARD_USER: ${DASHBOARD_USER}
|
||||
DASHBOARD_PASSWORD: ${DASHBOARD_PASSWORD}
|
||||
FIN_LOCATION: "/fin"
|
||||
STREAMLIT_FIN_SERVER_PORT: "8501"
|
||||
BAI_LOCATION: "/bai"
|
||||
STREAMLIT_BAI_SERVER_PORT: "8502"
|
||||
|
||||
volumes:
|
||||
production_traefik: {}
|
||||
|
||||
services:
|
||||
osrm-backend:
|
||||
environment:
|
||||
# OSRM manager setup
|
||||
- OSRM_ALGORITHM=mld
|
||||
- OSRM_THREADS=2
|
||||
- OSRM_PORT=5000
|
||||
- OSRM_PROFILE=/opt/car.lua
|
||||
- OSRM_MAP_NAME=${OSRM_MAP_NAME}
|
||||
- OSRM_GEOFABRIK_PATH=${OSRM_GEOFABRIK_PATH}
|
||||
# Notify OSRM Manager to restart without stopping container
|
||||
- OSRM_NOTIFY_FILEPATH=/data/osrm_notify.txt
|
||||
image: furyhawk/osrm-backend:${OSRM_VERSION:-latest}
|
||||
container_name: osrm_backend
|
||||
restart: always
|
||||
ports:
|
||||
- ${OSRM_PORT}:${OSRM_PORT}
|
||||
|
||||
streamlit-bai:
|
||||
environment:
|
||||
<<: *default-environment
|
||||
image: furyhawk/beyondallinfo:latest
|
||||
container_name: streamlit_bai_app
|
||||
restart: always
|
||||
expose:
|
||||
- ${STREAMLIT_BAI_SERVER_PORT}
|
||||
command: streamlit run --server.port=$STREAMLIT_BAI_SERVER_PORT --server.address=0.0.0.0 --server.baseUrlPath=$BAI_LOCATION src/app.py
|
||||
|
||||
streamlit-fin:
|
||||
environment:
|
||||
<<: *default-environment
|
||||
build:
|
||||
context: .
|
||||
dockerfile: ./compose/streamlit-fin/Dockerfile
|
||||
image: streamlit_fin_production
|
||||
container_name: streamlit_fin_app
|
||||
restart: always
|
||||
expose:
|
||||
- ${STREAMLIT_FIN_SERVER_PORT}
|
||||
command: streamlit run --server.port=$STREAMLIT_FIN_SERVER_PORT --server.address=0.0.0.0 --server.baseUrlPath=$FIN_LOCATION src/app.py
|
||||
|
||||
traefik:
|
||||
environment:
|
||||
<<: *default-environment
|
||||
build:
|
||||
context: .
|
||||
dockerfile: ./compose/traefik/Dockerfile
|
||||
image: traefik_production
|
||||
volumes:
|
||||
- production_traefik:/etc/traefik/acme:z
|
||||
- /var/run/docker.sock:/var/run/docker.sock:ro
|
||||
ports:
|
||||
- "0.0.0.0:80:80"
|
||||
- "0.0.0.0:443:443"
|
||||
Executable
+7
@@ -0,0 +1,7 @@
|
||||
#!/bin/bash
|
||||
set -ev
|
||||
|
||||
docker-compose config
|
||||
docker-compose pull
|
||||
docker-compose up -d
|
||||
docker-compose ps
|
||||
Executable
+30
@@ -0,0 +1,30 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
eval $(egrep '^HOST' .env | xargs)
|
||||
eval $(egrep '^CERT_PATH' .env | xargs)
|
||||
|
||||
echo "Domain: ${HOST}"
|
||||
echo "Cert Path: ${CERT_PATH}"
|
||||
|
||||
if [ -f certs/cert.crt ] || [ -f certs/cert.key ] || [ -f certs/cert.pem ]; then
|
||||
echo -e "cert already exists in certs directory\nDo you want to overwrite the files? [y]es/[n]o"
|
||||
read -r ANSWER
|
||||
echo
|
||||
if [[ "$ANSWER" =~ ^[Yy](es)?$ ]] ; then
|
||||
echo "Creating Cert"
|
||||
else
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
./scripts/requests.sh
|
||||
|
||||
openssl genrsa -out $CERT_PATH/cert.key
|
||||
openssl req -new -key $CERT_PATH/cert.key -out $CERT_PATH/cert.csr -config $CERT_PATH/csr.conf
|
||||
openssl x509 -req -days 365 -in $CERT_PATH/cert.csr -signkey $CERT_PATH/cert.key -out $CERT_PATH/cert.crt -extensions req_ext -extfile $CERT_PATH/csr.conf
|
||||
|
||||
sudo cp $CERT_PATH/cert.crt /usr/local/share/ca-certificates/cert.crt
|
||||
sudo rm -f /usr/local/share/ca-certificates/certificate.crt
|
||||
# --fresh is needed to remove symlinks to no-longer-present certificates
|
||||
sudo update-ca-certificates --fresh
|
||||
Executable
+9
@@ -0,0 +1,9 @@
|
||||
#!/bin/bash
|
||||
|
||||
echo "Cleaning up..."
|
||||
docker-compose down
|
||||
|
||||
printf "Deleting network: "
|
||||
eval $(egrep '^NETWORK' .env | xargs)
|
||||
printf "$NETWORK\n"
|
||||
docker network rm $NETWORK | echo
|
||||
Executable
+10
@@ -0,0 +1,10 @@
|
||||
#!/bin/bash
|
||||
|
||||
# color
|
||||
RESET=$'\e[1;0m'
|
||||
RED=$'\e[1;31m'
|
||||
GREEN=$'\e[1;32m'
|
||||
YELLOW=$'\e[1;33m'
|
||||
RED_BACK=$'\e[101m'
|
||||
GREEN_BACK=$'\e[102m'
|
||||
YELLOW_BACK=$'\e[103m'
|
||||
Executable
+10
@@ -0,0 +1,10 @@
|
||||
#!/bin/bash
|
||||
set -ev
|
||||
|
||||
eval $(egrep '^HOST' .env | xargs)
|
||||
|
||||
if [ "$HOST" != "localhost" ]; then
|
||||
grep "127.0.0.1 ${HOST}" /etc/hosts || (echo "127.0.0.1 ${HOST}" | sudo tee -a /etc/hosts)
|
||||
fi
|
||||
grep "127.0.0.1 docker.${HOST}" /etc/hosts || (echo "127.0.0.1 docker.${HOST}" | sudo tee -a /etc/hosts)
|
||||
grep "127.0.0.1 dashboard.${HOST}" /etc/hosts || (echo "127.0.0.1 dashboard.${HOST}" | sudo tee -a /etc/hosts)
|
||||
Executable
+26
@@ -0,0 +1,26 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
echo "Copying env file"
|
||||
# Create env from env.example if it doesn't exist
|
||||
if [ -f ".env" ]
|
||||
then
|
||||
echo -e "env file exists"
|
||||
else
|
||||
echo -e "Copying env file"
|
||||
cp env.example .env
|
||||
fi
|
||||
|
||||
echo "creating acme.json"
|
||||
touch acme.json
|
||||
chmod 600 acme.json
|
||||
|
||||
echo "creating provider.key"
|
||||
touch provider.key
|
||||
echo "supersecretkey" | tee provider.key
|
||||
chmod 600 provider.key
|
||||
|
||||
printf "Creating network: "
|
||||
eval $(egrep '^NETWORK' .env | xargs)
|
||||
printf "$NETWORK\n"
|
||||
docker network create $NETWORK | echo
|
||||
Executable
+21
@@ -0,0 +1,21 @@
|
||||
#!/bin/bash
|
||||
set -ex
|
||||
|
||||
if [ -z "$DOCKER_COMPOSE_VERSION" ]; then
|
||||
DOCKER_COMPOSE_VERSION=1.25.4
|
||||
fi
|
||||
|
||||
echo "Installing docker-compose version: $DOCKER_COMPOSE_VERSION"
|
||||
|
||||
if [ -z "`sudo -l 2>/dev/null`" ]; then
|
||||
|
||||
rm /usr/local/bin/docker-compose | echo
|
||||
curl -L https://github.com/docker/compose/releases/download/${DOCKER_COMPOSE_VERSION}/docker-compose-`uname -s`-`uname -m` > docker-compose
|
||||
chmod +x docker-compose
|
||||
mv docker-compose /usr/local/bin
|
||||
else
|
||||
sudo rm /usr/local/bin/docker-compose | echo
|
||||
curl -L https://github.com/docker/compose/releases/download/${DOCKER_COMPOSE_VERSION}/docker-compose-`uname -s`-`uname -m` > docker-compose
|
||||
sudo chmod +x docker-compose
|
||||
sudo mv docker-compose /usr/local/bin
|
||||
fi
|
||||
Executable
+25
@@ -0,0 +1,25 @@
|
||||
#!/bin/bash
|
||||
|
||||
eval $(egrep -v '^#' .env | xargs)
|
||||
|
||||
echo "
|
||||
[req]
|
||||
default_bits = 2048
|
||||
distinguished_name = dn
|
||||
prompt = no
|
||||
|
||||
[dn]
|
||||
C=\"US\"
|
||||
ST=\"Florida\"
|
||||
OU=\"Service\"
|
||||
emailAddress=\"admin@${HOST}\"
|
||||
CN=\"${HOST}\"
|
||||
|
||||
[req_ext]
|
||||
subjectAltName = @alt_names
|
||||
|
||||
[alt_names]
|
||||
DNS.0 = ${HOST}
|
||||
DNS.1 = *.${HOST}
|
||||
DNS.2 = *.docker.${HOST}
|
||||
" > certs/csr.conf
|
||||
Executable
+37
@@ -0,0 +1,37 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
export CURL_CA_BUNDLE=/etc/ssl/certs/ca-certificates.crt
|
||||
|
||||
source ./scripts/color.sh
|
||||
|
||||
shopt -s expand_aliases
|
||||
alias curl="curl -ILsS -X GET"
|
||||
alias grep="grep -C 100 --color=auto"
|
||||
alias echo="echo -e \${RESET}"
|
||||
|
||||
|
||||
eval $(egrep '^HOST' .env | xargs)
|
||||
eval $(egrep '^DASHBOARD_HOST' .env | xargs)
|
||||
|
||||
echo "\n\n${YELLOW_BACK}${RED}Testing Traefik........................${RESET}\n"
|
||||
echo "\nHOST=${HOST}"
|
||||
echo "\nDASHBOARD_HOST=${DASHBOARD_HOST}\n"
|
||||
|
||||
|
||||
echo "\n\n${YELLOW}Rediection test........................${RESET}\n"
|
||||
echo "\n${GREEN}http://${HOST}${RESET}\n"
|
||||
curl http://${HOST} | grep 302 || exit 1
|
||||
echo "\n${GREEN}http://${HOST}${RESET}\n"
|
||||
curl http://${DASHBOARD_HOST} | grep 302 || exit 1
|
||||
|
||||
# echo "\n\nAuthentication test....................\n"
|
||||
|
||||
echo "\n\n${YELLOW}Authentication test....................${RESET}\n"
|
||||
echo "\n${GREEN}https://user:pass@${DASHBOARD_HOST}${RESET}\n"
|
||||
curl -f --anyauth -u user:pass https://${DASHBOARD_HOST} | grep 200 || exit 1
|
||||
|
||||
echo "\n${GREEN}https://user:pass@${DASHBOARD_HOST}/dashboard/${RESET}\n"
|
||||
curl -f --anyauth -u user:pass https://${DASHBOARD_HOST}/dashboard/ | grep 200 || exit 1
|
||||
echo "\n\n${GREEN}.......................................${RESET}\n"
|
||||
Executable
+9
@@ -0,0 +1,9 @@
|
||||
#!/bin/bash
|
||||
set -ev
|
||||
|
||||
./scripts/init.sh
|
||||
./scripts/cert.sh
|
||||
./scripts/host.sh
|
||||
./scripts/build.sh
|
||||
./scripts/wait.sh ${WAIT_FOR}
|
||||
./scripts/test.sh
|
||||
Executable
+13
@@ -0,0 +1,13 @@
|
||||
#!/bin/bash
|
||||
|
||||
x="$1"
|
||||
[[ -z "$x" ]] && x=5
|
||||
|
||||
printf "\n\nWaiting for things to start"
|
||||
while [ $x -gt 0 ]
|
||||
do
|
||||
printf "."
|
||||
sleep 1
|
||||
x=$(( $x - 1 ))
|
||||
done
|
||||
echo "."
|
||||
Vendored
BIN
Binary file not shown.
+127
@@ -0,0 +1,127 @@
|
||||
import streamlit as st
|
||||
import yfinance as yf
|
||||
from ta import volume, trend
|
||||
|
||||
|
||||
st.set_page_config(page_title='Technical Analysis',page_icon='📈', layout='wide')
|
||||
hide_streamlit_style = """
|
||||
<style>
|
||||
.reportview-container {
|
||||
margin-top: -2em;
|
||||
}
|
||||
#MainMenu {
|
||||
|
||||
visibility: hidden;
|
||||
|
||||
}
|
||||
.stDeployButton {display:none;}
|
||||
footer {
|
||||
|
||||
visibility: hidden;
|
||||
|
||||
}
|
||||
footer:after {
|
||||
|
||||
content:'Data Source: Yahoo Finance';
|
||||
visibility: visible;
|
||||
display: block;
|
||||
position: relative;
|
||||
#background-color: red;
|
||||
padding: 5px;
|
||||
top: 2px;
|
||||
|
||||
}
|
||||
</style>
|
||||
"""
|
||||
st.markdown(hide_streamlit_style, unsafe_allow_html=True)
|
||||
|
||||
stock = st.sidebar.text_input(label="Ticker",value='AAPL')
|
||||
|
||||
def get_data(start):
|
||||
ticker = yf.Ticker(stock)
|
||||
try:
|
||||
df = ticker.history(period='max', start=start)
|
||||
except:
|
||||
pass
|
||||
return df
|
||||
|
||||
list_of_indicator_types = ['Volume', 'Trend']
|
||||
volumn_types = ['Volume','Force Index']
|
||||
trend_types = ["Simple Moving Average", "Exponential Moving Average"]
|
||||
|
||||
indicator_types = st.sidebar.selectbox(label='Indicator Type', options = list_of_indicator_types)
|
||||
|
||||
st.sidebar.success('All charts are interactive!')
|
||||
|
||||
if indicator_types == 'Volume':
|
||||
indicator = st.selectbox(label='Indicator', options=volumn_types,key=0)
|
||||
|
||||
start = st.text_input(label='Start Year', value = '2018')
|
||||
start = f'{start}-01-01'
|
||||
|
||||
|
||||
|
||||
df = get_data(start)
|
||||
|
||||
if indicator == 'Volume':
|
||||
df = df[['Close','Volume']]
|
||||
|
||||
price_vs_time = st.line_chart(data= df['Close'], width=500, height=400)
|
||||
volume_vs_time = st.bar_chart(data=df['Volume'], width=500, height=150)
|
||||
|
||||
df = df.to_csv()
|
||||
st.download_button(label=f'Download Data',data=df,file_name=f'{stock}.csv')
|
||||
|
||||
if indicator == 'Force Index':
|
||||
window_slider_expander = st.expander(label='Force Index Parameters')
|
||||
window_slider = window_slider_expander.slider(label='Window', value=13, min_value=1, max_value=20)
|
||||
|
||||
df[f'fi_{window_slider}'] = volume.force_index(close=df['Close'],volume=df['Volume'], window=window_slider)
|
||||
|
||||
df = df[['Close','Volume',f'fi_{window_slider}']]
|
||||
|
||||
price_vs_time = st.line_chart(data= df['Close'], width=500, height=400)
|
||||
fi_vs_time = st.area_chart(data= df[f'fi_{window_slider}'],width=500, height=200)
|
||||
|
||||
df = df.to_csv()
|
||||
st.download_button(label=f'Download Data',data=df,file_name=f'{stock}.csv')
|
||||
|
||||
if indicator_types == 'Trend':
|
||||
indicator = st.selectbox(label='Indicator', options=trend_types, key=1)
|
||||
|
||||
start = st.text_input(label='Start Year', value = '2018')
|
||||
start = f'{start}-01-01'
|
||||
|
||||
df = get_data(start)
|
||||
if indicator == 'Simple Moving Average':
|
||||
|
||||
window_slider_expander = st.expander(label='SMA Parameters')
|
||||
window_slider_1 = window_slider_expander.slider(label='Window 1', value=30, min_value=1, max_value=200)
|
||||
window_slider_2 = window_slider_expander.slider(label='Window 2', value=100, min_value=1, max_value=200)
|
||||
|
||||
df[f'sma{window_slider_1}'] = trend.sma_indicator(close=df['Close'], window=window_slider_1)
|
||||
df[f'sma{window_slider_2}'] = trend.sma_indicator(close=df['Close'], window=window_slider_2)
|
||||
|
||||
df = df[['Close',f'sma{window_slider_1}',f'sma{window_slider_2}']]
|
||||
|
||||
sma_vs_time = st.line_chart(data=df, width=500, height=550)
|
||||
|
||||
df = df.to_csv()
|
||||
st.download_button(label=f'Download Data',data=df,file_name=f'{stock}.csv')
|
||||
|
||||
if indicator == "Exponential Moving Average":
|
||||
|
||||
window_slider_expander = st.expander(label='EMA Parameters')
|
||||
window_slider_1 = window_slider_expander.slider(label='Window 1', value=30, min_value=1, max_value=200)
|
||||
window_slider_2 = window_slider_expander.slider(label='Window 2', value=100, min_value=1, max_value=200)
|
||||
|
||||
df[f'ema{window_slider_1}'] = trend.ema_indicator(close=df['Close'], window=window_slider_1)
|
||||
df[f'ema{window_slider_2}'] = trend.ema_indicator(close=df['Close'], window=window_slider_2)
|
||||
|
||||
df = df[['Close',f'ema{window_slider_1}',f'ema{window_slider_2}']]
|
||||
|
||||
sma_vs_time = st.line_chart(data=df, width=500, height=550)
|
||||
|
||||
df = df.to_csv()
|
||||
st.download_button(label=f'Download Data',data=df,file_name=f'{stock}.csv')
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
pandas==2.1.3
|
||||
streamlit==1.28.2
|
||||
ta==0.11.0
|
||||
yfinance==0.2.32
|
||||
watchdog==3.0.0
|
||||
protobuf==4.25.1
|
||||
Reference in New Issue
Block a user