Ken Schaefer
2 years ago
15 changed files with 1241 additions and 0 deletions
@ -0,0 +1,23 @@
|
||||
# Docker for static html using Nginx |
||||
|
||||
## Introduction |
||||
Use this runbook for your web development rather than setting up a whole Apache server. |
||||
|
||||
## The Dockerfile |
||||
``` |
||||
FROM nginx:alpine |
||||
|
||||
COPY . /usr/share/nginx/html |
||||
|
||||
EXPOSE 80 |
||||
``` |
||||
|
||||
## Build the image |
||||
name:tag |
||||
`docker build -t myproject:v1 .` |
||||
|
||||
## Run a container from the image |
||||
`docker run -d -p 8080:80 --name myproject myproject:v1` |
||||
|
||||
## View the site |
||||
Open a browser at `http://localhost:8080` |
@ -0,0 +1,260 @@
|
||||
# DOCKER BASICS |
||||
|
||||
## Table of Contents |
||||
1. [Introduction](#introduction) |
||||
2. [Installation](#ubuntu-installation) |
||||
3. [Concepts](#concepts) |
||||
4. [Images](#images) |
||||
5. [Managing Images](#managing-images) |
||||
6. [Containers](#containers) |
||||
7. [Managing Containers](#managing-containers) |
||||
8. [Volumes] |
||||
|
||||
## INTRODUCTION |
||||
|
||||
This file contains notes and code examples for using Docker. |
||||
|
||||
I am a big fan of Academind on uDemy and YouTube. Their classes on eDemy are content rich and take you from noob to expert. Maximillian works from hands-on examples that you will actually use in IT. I highly recommend purchasing his course on Docker https://www.udemy.com/course/docker-kubernetes-the-practical-guide/. |
||||
|
||||
## UBUNTU INSTALLATION |
||||
|
||||
hmmmm, this looks like it should be a bash script. |
||||
|
||||
### Base Install |
||||
As usual, update your packages |
||||
|
||||
`sudo apt update` |
||||
|
||||
Prepare Ubuntu for the Docker installation |
||||
|
||||
`sudo apt install apt-transport-https ca-certificates curl software-properties-common` |
||||
|
||||
`curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg` |
||||
|
||||
`echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null` |
||||
|
||||
Update the packages again |
||||
|
||||
`sudo apt update` |
||||
|
||||
Now do the install from Docker |
||||
|
||||
`apt-cache policy docker-ce` |
||||
|
||||
`sudo apt install docker-ce` |
||||
|
||||
Install docker-compose if needed |
||||
|
||||
`sudo apt install docker-compose` |
||||
|
||||
Make sure it is running |
||||
|
||||
`sudo systemctl status docker` |
||||
|
||||
### Put yourself in the Docker group |
||||
Do this so you don't have to use sudo all the time |
||||
|
||||
`sudo usermod -aG docker ${USER}` |
||||
|
||||
You can reboot to make it take effect or... |
||||
|
||||
`su - ${USER}` |
||||
|
||||
## CONCEPTS |
||||
|
||||
### Images |
||||
|
||||
Images are the template (instructions) that define the parameters of the container. The image is used to build containers and a single image can build many containers. |
||||
|
||||
### Containers |
||||
|
||||
Containers are packages that contain the application and the environment in which the application runs. |
||||
|
||||
## IMAGES |
||||
|
||||
### Define your own image using a Dockerfile |
||||
|
||||
Create a Dockerfile in the project directory. This file is a set of instructions for building a container. |
||||
|
||||
``` |
||||
# the baseImage is either a name from DockerHub or is the |
||||
# name of an Image on your system |
||||
FROM node |
||||
|
||||
# tell Docker where to run commands from |
||||
WORKDIR /app |
||||
|
||||
# tell Docker which files go into the image |
||||
# COPY localFolder imageFolder |
||||
COPY . /app |
||||
|
||||
# do some node stuff |
||||
RUN npm install |
||||
|
||||
# show the port to the world outside of Docker so that the |
||||
# web pages are visible |
||||
EXPOSE 80 |
||||
|
||||
# these commands are executed when a container is instanced |
||||
CMD ["node", "server.js"] |
||||
|
||||
``` |
||||
|
||||
### Build an image from the Dockerfile. |
||||
|
||||
Using this command results in a random Image ID that you use to run a container. This is not the way. |
||||
|
||||
`docker build .` |
||||
|
||||
### Assign a Name:Tag to the image |
||||
|
||||
Assign a name and tag to the image because you are not a barbarian. |
||||
|
||||
`docker build -t name:tag .` |
||||
|
||||
|
||||
## MANAGING IMAGES |
||||
|
||||
### List out the images installed on this server |
||||
`docker images` |
||||
|
||||
### Remove an image from this server |
||||
Can't remove images that have containers (started and stopped) |
||||
`docker rmi {imagename}` |
||||
|
||||
### Remove all dangling (untagged) images |
||||
`docker image prune` |
||||
|
||||
### Review detailed information about the image |
||||
`docker image inspect {imageid}` |
||||
|
||||
## CONTAINERS |
||||
|
||||
### Run a container from a DockerHub image |
||||
|
||||
`docker run node` |
||||
|
||||
This command will create and run a container instance from the image. In this example it is using the office nodejs image to create a running instance in a container. Note: this command as it is doesn't do much. |
||||
|
||||
`docker run -it node` |
||||
|
||||
Adding the -it flag creates an interactive terminal instance where you can interact with the instance of node. |
||||
|
||||
### Running a container from your own image |
||||
|
||||
After the image is built you will get an ID for the image. Use the ID to start the container. If you are a good dev, then you assigned a name:tag and you use that instead. |
||||
|
||||
`docker run -p 3000:80 e5a737911cca` |
||||
|
||||
|
||||
## MANAGING CONTAINERS |
||||
|
||||
### Running a container |
||||
Get a list of all parameters for running a container |
||||
`docker run --help` |
||||
|
||||
Common parameters for running a container |
||||
|Switch | Description | |
||||
|-------|-------| |
||||
|-p |(port) map a port| |
||||
|-d |(detached mode) run in the background| |
||||
|-it |(interactive mode) not -d| |
||||
|--rm |(remove) the container when the service is stopped| |
||||
|--name |(name) give the container a name| |
||||
|-v |(volume) assigns a named volume to the container| |
||||
|
||||
`docker run -p 3000:80 -d --rm --name goalsapp goals:latest` |
||||
|
||||
Expose a terminal for console applications. See the Python example. |
||||
`docker run -it {containername}` |
||||
`docker start -a -i {containername}` |
||||
|
||||
### List all running containers |
||||
`docker ps` |
||||
|
||||
### List all containers (running and not running) |
||||
`docker ps -a` |
||||
|
||||
### Stop a container |
||||
`docker stop {containername}` |
||||
|
||||
### Start a stopped container |
||||
This command will start a container in detached mode. |
||||
`docker start {containername}` |
||||
|
||||
### Remove a stopped container (can't remove a running container) |
||||
`docker rm {containername}` |
||||
|
||||
### Remove ALL stopped containers |
||||
`docker container prune` |
||||
|
||||
### Attach to a running container |
||||
Use this if you are running in detached mode and need to attach to see content logged to the console. |
||||
`docker attach {comtainername}` |
||||
|
||||
### View logs from a container |
||||
logs are the console output from a container. This command will let you see the content. |
||||
`docker logs {containername}` |
||||
|
||||
### Copy files into or out of a running container |
||||
Copy in |
||||
`docker cp localpath/. {containername}:/pathincontainer` |
||||
Copy out |
||||
`docker cp {containername}:/pathincontainer/. localpath` |
||||
|
||||
|
||||
## VOLUMES |
||||
|
||||
Volumes store persistent data that survives after a container shuts down. These are folders on the host machine that are mounted in the container. |
||||
|
||||
Volumes are managed by Docker. This means that we do not know where the volume is located and have no ability to manage them. Bind mounts solve that problem. |
||||
|
||||
### Add a volume to the container |
||||
|
||||
This command creates an anonymous volume. Anonymous volumes are not persisted when the container is removed. |
||||
|
||||
`VOLUME ["{path}"]` |
||||
`VOLUME ["app/feedback"]` |
||||
|
||||
Named volumes persist data when the container is removed. Named volumes are NOT defined in the Dockerfile, rather it is done at the command line when running the container. |
||||
|
||||
`-v {volume name}:{mount location in container}` |
||||
|
||||
`docker run -d -p 3000:80 --rm --name feedback-app -v feedback:/app/feedback feedback-node:volumes` |
||||
|
||||
### List volumes |
||||
|
||||
`docker volume ls` |
||||
|
||||
### Troubleshooting |
||||
|
||||
`docker logs {appname}` |
||||
|
||||
## Bind Mounts |
||||
|
||||
Like named volumes but we have management control over the file system. Bind mounts are not created in the Dockerfile. Bind mounts are created from terminal. |
||||
|
||||
A bind mount is created by adding a second -v command. Should use quotes to protect the absolute path. |
||||
|
||||
`-v "{absolute path on host file system}:{mount location in container}"` |
||||
|
||||
`docker run -d -p 3000:80 --rm --name feedback-app -v feedback:/app/feedback -v "/home/kschaefer/repos/webdev/docker/data-volumes-01-starting-setup:/app" feedback-node:volumes` |
||||
|
||||
If you mount a volume to the app folder in the way that this command above does, then the mount will overwrite everything that the COPY and RUN commands do in the Dockerfile. This command is overwriting the container folder with the contents of the local host folder. Since the local host does not have the same npm dependencies as the container then we get an issue. |
||||
|
||||
The solution is to use an anonymous volume. In the following command the folder that is defined in the anon volume is protected. |
||||
|
||||
`docker run -d -p 3000:80 --rm --name feedback-app -v feedback:/app/feedback -v "/home/kschaefer/repos/webdev/docker/data-volumes-01-starting-setup:/app" -v /app/node_modules feedback-node:volumes` |
||||
|
||||
🛸 Why do this? Now we can make changes to the HTML files and we do NOT have to rebuild the container. |
||||
|
||||
### Read Only Volume |
||||
When using a Bind Mount, the local drive that is mapped to the container is writable by the container. Since we probably don't want the container writing back to our source-code marking the volume as read-only is a good idea. Do this by adding :ro to the end of the volume declaration. |
||||
|
||||
`docker run -d -p 3000:80 --rm --name feedback-app -v feedback:/app/feedback -v "/home/kschaefer/repos/webdev/docker/data-volumes-01-starting-setup:/app:ro" -v /app/node_modules feedback-node:volumes` |
||||
|
||||
You can add volume declarations after the bind-mount to make subfolders writable if they need it. Use anonymous folders to do this. In the above example, all of app is read only but node_modules can be written by the container. |
||||
|
||||
## References |
||||
|
||||
[Docker & Kubernetes: The Practical Guide](https://www.udemy.com/course/docker-kubernetes-the-practical-guide/) |
@ -0,0 +1,13 @@
|
||||
|
||||
|
||||
## Networking |
||||
|
||||
### Network information |
||||
``` |
||||
ifconfig -a |
||||
``` |
||||
|
||||
### Change DNS Server |
||||
``` |
||||
sudo nano /etc/resolv.conf |
||||
``` |
@ -0,0 +1,252 @@
|
||||
# Linux Stuff |
||||
|
||||
## Install distro |
||||
|
||||
## Post install |
||||
|
||||
### Update && Upgrade |
||||
``` |
||||
apt update |
||||
apt upgrade |
||||
``` |
||||
|
||||
### Automatic Updates |
||||
``` |
||||
apt install unattended-upgrades |
||||
dpkg-reconfigure --priority=low unattended-upgrades |
||||
``` |
||||
|
||||
### Static IP |
||||
``` |
||||
sudo nano /etc/netplan/01-netcfg.yaml |
||||
|
||||
network: |
||||
version: 2 |
||||
renderer: networkd |
||||
ethernets: |
||||
ens18: |
||||
dhcp4: no |
||||
addresses: [192.168.5.50/24] |
||||
nameservers: |
||||
addresses: [192.168.5.25,8.8.8.8] |
||||
routes: |
||||
- to: default |
||||
via: 192.168.5.99 |
||||
|
||||
sudo netplan apply |
||||
``` |
||||
|
||||
### Install openssh |
||||
You can select this during Ubuntu install |
||||
``` |
||||
sudo apt install openssh-server |
||||
ssh-keygen |
||||
``` |
||||
|
||||
### SSH on Client machine |
||||
LINUX client machine |
||||
``` |
||||
ssh-keygen |
||||
ssh-copy-id username@ipaddress |
||||
``` |
||||
Windows client |
||||
``` |
||||
ssh-keygen |
||||
Get-Content $env:USERPROFILE\.ssh\id_rsa.pub | ssh <user>@<hostname> "cat >> .ssh/authorized_keys" |
||||
``` |
||||
|
||||
### Lockdown Logins to SSH only |
||||
``` |
||||
sudo nano /etc/ssh/sshd_config |
||||
``` |
||||
|
||||
Make the following changes: |
||||
1. Change PasswordAuthentication to **no** |
||||
2. Change ChallengeResponseAuthentication to **no** |
||||
|
||||
Save the file and restart the ssh service |
||||
``` |
||||
sudo systemctl restart sshd |
||||
``` |
||||
|
||||
### Fix LVM |
||||
``` |
||||
sudo lvm |
||||
lvm > lvextend -l +100%FREE /dev/ubuntu-vg/ubuntu-lv |
||||
exit |
||||
|
||||
sudo resize2fs /dev/ubuntu-vg/ubuntu-lv |
||||
``` |
||||
|
||||
### Change timezone |
||||
``` |
||||
timedatectl |
||||
timedatectl list-timezones |
||||
sudo timedatectl set-timezone America/Chicago |
||||
``` |
||||
|
||||
### Configure Firewall |
||||
``` |
||||
sudo ufw status |
||||
sudo ufw default allow outgoing |
||||
sudo ufw default deny incoming |
||||
sudo ufw allow ssh |
||||
sudo ufw enable |
||||
``` |
||||
|
||||
### Install fail2ban |
||||
``` |
||||
sudo apt install fail2ban |
||||
sudo cp /etc/fail2ban/fail2ban.{conf,local} |
||||
sudo cp /etc/fail2ban/jail.{conf,local} |
||||
sudo nano fail2ban.local |
||||
|
||||
loglevel = INFO |
||||
logtarget = /var/log/fail2ban.log |
||||
|
||||
sudo nano /etc/fail2ban/jail.local |
||||
|
||||
bantime = 10m |
||||
findtime = 10m |
||||
maxretry = 5 |
||||
backend = systemd |
||||
|
||||
sudo systemctl restart fail2ban |
||||
|
||||
sudo fail2ban-client status /* use to review banned */ |
||||
``` |
||||
|
||||
## Optional Maintenance |
||||
|
||||
### Create new sudo account |
||||
Ubuntu Server does this by default |
||||
``` |
||||
sudo adduser {username} |
||||
sudo usermod -aG sudo {username} |
||||
``` |
||||
|
||||
### Disable root |
||||
Ubuntu Server does this by default |
||||
``` |
||||
sudo passwd -l root |
||||
``` |
||||
|
||||
### Change HOSTNAME |
||||
``` |
||||
sudo hostnamectl set-hostname {hostname} |
||||
hostnamectl |
||||
|
||||
sudo nano /etc/hosts |
||||
/* change hostname in hosts file */ |
||||
``` |
||||
|
||||
## Optional Services |
||||
|
||||
### Install xRDP |
||||
If you need to use RDP to access a desktop environment |
||||
``` |
||||
sudo apt install xrdp |
||||
sudo systemctl enable xrdp |
||||
``` |
||||
|
||||
### Install GIT |
||||
``` |
||||
sudo apt install git |
||||
``` |
||||
|
||||
### Install Guest Agent for Proxmox |
||||
Applies only if this box is in a Proxmox server |
||||
|
||||
1. Open Proxmox |
||||
2. Click Options |
||||
3. Turn on QEMU Agent |
||||
|
||||
``` |
||||
sudo apt install qemu-guest-agent |
||||
sudo shutdown |
||||
``` |
||||
|
||||
### Install Webmin |
||||
``` |
||||
sudo apt install software-properties-common apt-transport-https |
||||
sudo wget -q http://www.webmin.com/jcameron-key.asc -O- | sudo apt-key add - |
||||
sudo add-apt-repository "deb [arch=amd64] http://download.webmin.com/download/repository sarge contrib" |
||||
sudo apt install webmin |
||||
sudo ufw allow 10000/tcp |
||||
sudo ufw reload |
||||
``` |
||||
|
||||
### bind9 DNS |
||||
``` |
||||
sudo apt install -y bind9 bind9utils bind9-doc dnsutils |
||||
sudo systemctl start named |
||||
sudo systemctl enable named |
||||
sudo ufw allow 53 |
||||
sudo ufw reload |
||||
``` |
||||
|
||||
### Gitea (GitHub alternative) |
||||
``` |
||||
sudo apt install git |
||||
sudo apt install mariadb-server |
||||
|
||||
# Login to MySQL |
||||
sudo mysql -u root -p |
||||
|
||||
# Add the git database |
||||
CREATE DATABASE gitea; |
||||
GRANT ALL PRIVILEGES ON gitea.* TO 'gitea'@'localhost' IDENTIFIED BY "Root"; |
||||
FLUSH PRIVILEGES; |
||||
QUIT; |
||||
|
||||
# Install gitea |
||||
sudo wget -O /usr/local/bin/gitea https://dl.gitea.io/gitea/1.16.7/gitea-1.16.7-linux-amd64 |
||||
sudo chmod +x /usr/local/bin/gitea |
||||
gitea --version |
||||
|
||||
# Create gitea user |
||||
sudo adduser --system --shell /bin/bash --gecos 'Git Version Control' --group --disabled-password --home /home/git git |
||||
sudo mkdir -pv /var/lib/gitea/{custom,data,log} |
||||
sudo chown -Rv git:git /var/lib/gitea |
||||
sudo chown -Rv git:git /var/lib/gitea |
||||
|
||||
sudo mkdir -v /etc/gitea |
||||
sudo chown -Rv root:git /etc/gitea |
||||
sudo chmod -Rv 770 /etc/gitea |
||||
sudo chmod -Rv 770 /etc/gitea |
||||
|
||||
# Append code to the service file |
||||
sudo nano /etc/systemd/system/gitea.service |
||||
|
||||
[Unit] |
||||
Description=Gitea |
||||
After=syslog.target |
||||
After=network.target |
||||
[Service] |
||||
RestartSec=3s |
||||
Type=simple |
||||
User=git |
||||
Group=git |
||||
WorkingDirectory=/var/lib/gitea/ |
||||
|
||||
ExecStart=/usr/local/bin/gitea web --config /etc/gitea/app.ini |
||||
Restart=always |
||||
Environment=USER=git HOME=/home/git GITEA_WORK_DIR=/var/lib/gitea |
||||
[Install] |
||||
WantedBy=multi-user.target |
||||
|
||||
# Start gitea |
||||
sudo systemctl start gitea |
||||
sudo systemctl status gitea |
||||
sudo systemctl enable gitea |
||||
|
||||
# Access gitea |
||||
http://localhost:3000 |
||||
|
||||
# If you ever need to change settings like DOMAIN |
||||
sudo nano /etc/gitea/app.ini |
||||
|
||||
``` |
||||
|
||||
|
||||
### Logging with Prometheus |
@ -0,0 +1,43 @@
|
||||
# Secure Shell (SSH) |
||||
|
||||
SSH is a network protocol for creating a secure connection from a client to a server. |
||||
|
||||
## Client-side setup |
||||
|
||||
### On the server-side |
||||
|
||||
In your home folder create an ssh folder |
||||
|
||||
``` |
||||
mkdir ~/.ssh && chmod 700~/.ssh |
||||
``` |
||||
|
||||
### Create SSH keys on your client |
||||
|
||||
``` |
||||
ssh-keygen -t ed25519 -C "email@domain.com" |
||||
``` |
||||
|
||||
### Copy key to a remote server |
||||
|
||||
On Windows execute the following command to copy the public key up to the server. |
||||
|
||||
``` |
||||
scp $env:USERPROFILE/.ssh/id_rsa.pub username@ip_address:~/.ssh/authorized_keys |
||||
``` |
||||
|
||||
On Linux execute the following |
||||
|
||||
``` |
||||
ssh-copy-id username@ip_address |
||||
``` |
||||
|
||||
When you copy the key over, the server will challenge for your server password. After this initial step, the server will accept your keys as the login and you will not be challenged for the password. |
||||
|
||||
### Copy key to Azure DevOps |
||||
|
||||
Note about git: I have noticed that you need to generate keys for both your user account and root. |
||||
|
||||
### Login to remote server using your key |
||||
|
||||
`ssh username@ip_address` |
@ -0,0 +1,36 @@
|
||||
# Install Ubuntu Server |
||||
|
||||
This guide assumes that the server is a plain-vanilla installation of Ubuntu Server. You can select the option to install OpenSSH Server during the installation wizard or follow the instructions below to install it post-installation. This guide assumes that you did not select any of the Featured Server Snaps during installation. |
||||
|
||||
## Post Installation |
||||
|
||||
Once installation is complete run update and upgrade to ensure that you have the latest version of the server installed along with all of its patches. |
||||
|
||||
``` |
||||
sudo apt update |
||||
sudo apt upgrade |
||||
``` |
||||
|
||||
## Install OpenSSH Server |
||||
|
||||
These days everything should be done over SSH. Install the server so that you can connect to it using this standard protocol rather than FTP or RDP. |
||||
|
||||
``` |
||||
sudo apt install -y openssh-server |
||||
``` |
||||
## Install GIT |
||||
|
||||
If you will be editing or developing anything in this server, install GIT. GIT is the source control tool of choice. |
||||
|
||||
``` |
||||
sudo apt install -y git |
||||
``` |
||||
|
||||
## Install the Lynx browser |
||||
|
||||
Lynx is a command-line browser. This guide assumes that you are installing Ubuntu server without a GUI, therefore you will need lynx to browse the web or to browse sites on this server (e.g., localhost). |
||||
|
||||
``` |
||||
sudo apt install -y lynx |
||||
``` |
||||
|
@ -0,0 +1,40 @@
|
||||
|
||||
[https://www.youtube.com/watch?v=bllS9tkCkaM] |
||||
|
||||
## Setup Image |
||||
|
||||
- Update the system |
||||
|
||||
## Install TOR |
||||
|
||||
``` |
||||
sudo apt install tor |
||||
sudo nano /etc/tor/torrc |
||||
``` |
||||
|
||||
Uncomment HiddenServiceDir and HiddenServicePort |
||||
Save and exit |
||||
|
||||
``` |
||||
sudo service tor stop |
||||
sudo service tor start |
||||
|
||||
cat /var/lib/tor/hidden_service/hostname |
||||
``` |
||||
|
||||
hvikudrnymgd7ffgyrtojl45eawanuswoyslsnt4vq2pd7x6nqasmbad.onion |
||||
|
||||
## Install nginx |
||||
|
||||
``` |
||||
sudo apt install nginx |
||||
sudo service nginx start |
||||
|
||||
sudo nanno /etc/nginx/nginx.conf |
||||
``` |
||||
uncomment server_tokens off and server_name_in_redirect off |
||||
add port_in_redirect off after the server_tokens line |
||||
|
||||
|
||||
|
||||
nginx web site is located at /var/www/html |
@ -0,0 +1,41 @@
|
||||
# OpenEMR Custom Modules |
||||
|
||||
## INTRODUCTION |
||||
Why use a module |
||||
- Package of functionality independent of the core app |
||||
- Administrators can manage functionality |
||||
- SOLID |
||||
Geared toward small scale projects. For larger, more complex modules you may want to use the Laminas framework. |
||||
|
||||
## CUSTOM SQL |
||||
During installation of the module, OpenEMR will run |
||||
table.sql |
||||
|
||||
## FORK THE SKELETON FRAMEWORK |
||||
1. Go to adunsulag/oe-module-custom-skeleton in GitHub |
||||
2. Click the Fork button to make a fork in your GitHub |
||||
|
||||
## INSTALL SKELETON FRAMEWORK |
||||
Take the time to read the instructions provided in the GitHub repo |
||||
1. Launch your development IDE and open OpenEMR |
||||
2. Change to the /interface/modules/custom_modules directory |
||||
3. Clone your fork |
||||
|
||||
```git |
||||
git clone git@github.com:KenSchae/oe-module-cutom-skeleton.git |
||||
``` |
||||
|
||||
## UPDATE composer.json |
||||
``` |
||||
"psr-4": { |
||||
"OpenEMR\\": "src", |
||||
"OpenEMR\\Modules\\CustomModuleSkeleton\\": "interface/modules/custom_modules/oe-module-custom-skeleton/src/" |
||||
} |
||||
``` |
||||
|
||||
Run from the docker folder /docker/development-easy |
||||
`composer dump-autoload` |
||||
|
||||
|
||||
## REFERENCES |
||||
- [OpenEMR Modules YouTube](https://youtu.be/LYA8MosIWF0) |
@ -0,0 +1,107 @@
|
||||
# OpenEMR Development Environment (Docker) |
||||
|
||||
## TABLE OF CONTENTS |
||||
- [OpenEMR Development Environment (Docker)](#openemr-development-environment-docker) |
||||
- [TABLE OF CONTENTS](#table-of-contents) |
||||
- [BUILD DEVELOPMENT SERVER](#build-development-server) |
||||
- [CONNECT WORKSTATION TO SERVER](#connect-workstation-to-server) |
||||
- [CONFIG SERVER](#config-server) |
||||
- [INSTALL OPENEMR-CMD](#install-openemr-cmd) |
||||
- [FORK THE GITHUB REPO](#fork-the-github-repo) |
||||
- [START THE DOCKERS](#start-the-dockers) |
||||
- [BUILD](#build) |
||||
- [TEST OPENEMR](#test-openemr) |
||||
- [SLING SOME CODE](#sling-some-code) |
||||
- [SAMPLE PATIENT DATA WITH SYNTHEA](#sample-patient-data-with-synthea) |
||||
- [MANAGE DOCKERS](#manage-dockers) |
||||
- [Resetting the environment](#resetting-the-environment) |
||||
- [REFERENCES](#references) |
||||
|
||||
## BUILD DEVELOPMENT SERVER |
||||
The OpenEMR video series (and many home lab tutorials) walk you through creating a Linux VM to develop with. The assumption in these videos is that you will use the VM as a workstation AND as a server: everything in one box. I don't like that approach. My preference is to create the VM as a server and then connect to the server from a workstation. |
||||
|
||||
1. Build a Linux Server VM on either an internet accessible private cloud, or on one of the major cloud providers (e.g., Azure, AWS, etc.) |
||||
2. Install OpenSSH (if you did not select it during installation, Azure installs it automatically) |
||||
3. Setup your work computer with ssh keys to login to server |
||||
|
||||
## CONNECT WORKSTATION TO SERVER |
||||
1. In VSCode add Remote - SSH extension |
||||
2. Open SSH Config file and add entry for the server |
||||
``` |
||||
Host arbitrary-name-that-displays-in-vscode |
||||
HostName ip-address-or-dns-hostname |
||||
User username |
||||
Port portnumber-9091 |
||||
``` |
||||
3. Connect VSCode to server and open a new terminal window |
||||
|
||||
## CONFIG SERVER |
||||
1. Install Git |
||||
2. Install Docker |
||||
3. Install Docker-compose |
||||
4. Install OpenEMR-cmd |
||||
|
||||
## INSTALL OPENEMR-CMD |
||||
1. Go to openemr/openemr-devops/utilities on GitHub |
||||
2. Follow installation instructions at GitHub |
||||
|
||||
## FORK THE GITHUB REPO |
||||
1. Create GitHub account |
||||
2. Configure Git and create SSH key on server |
||||
3. Register SSH key with GitHub |
||||
4. Fork the OpenEMR repo into your own account |
||||
5. Clone your fork into the server |
||||
|
||||
## START THE DOCKERS |
||||
1. `cd ~/git/openemr/docker/development-easy` |
||||
2. `openemr-cmd up` |
||||
3. Find the donuts in the breakroom |
||||
4. Enjoy the Phil Collins easy listening tune that is playing |
||||
5. `docker ps` there are 5 dockers for the OpenEMR environment |
||||
6. `openemr-cmd dl` keep running this until the docker is done building (e.g.Apache is running) |
||||
|
||||
### BUILD |
||||
|
||||
If using OpenEMR directly from the code repository, then the following commands will build OpenEMR (Node.js version 16.* is required). This should be done from inside of the docker container |
||||
|
||||
`openemr-cmd s` |
||||
|
||||
```shell |
||||
composer install --no-dev |
||||
npm install |
||||
npm run build |
||||
composer dump-autoload -o |
||||
``` |
||||
|
||||
## TEST OPENEMR |
||||
1. Open a browser |
||||
2. http://hostname-or-ip-of-server:8300 |
||||
3. admin/pass |
||||
4. http://hostname-or-ip-of-server:8310 (opens phpmyadmin) |
||||
5. root/root |
||||
|
||||
## SLING SOME CODE |
||||
1. Make a change |
||||
2. Refresh browser or open the site again |
||||
3. `git checkout -b code-slinging` |
||||
4. `git commit -a -m "slinging"` |
||||
5. `git push origin code-slinging` |
||||
6. Go to GitHub |
||||
7. Click the create pull request to create a pull request to the main openemr |
||||
|
||||
## SAMPLE PATIENT DATA WITH SYNTHEA |
||||
1. `openemr-cmd irp 10` |
||||
2. By now the donuts are all gone except for that gross coconut covered one |
||||
3. Actually I kind of like the coconut donuts |
||||
4. Let's be real, I like all donuts |
||||
5. I am the Homer Simpson of full stack developers |
||||
|
||||
## MANAGE DOCKERS |
||||
|
||||
### Resetting the environment |
||||
|
||||
|
||||
## REFERENCES |
||||
- [OpenEMR Development Docker Environment](https://github.com/openemr/openemr/blob/master/CONTRIBUTING.md#starting-with-openemr-development-docker-environment) |
||||
- [Presentation Slides](https://docs.google.com/presentation/d/13VhN_uL-YptFtM1qv3pJ6DwhMnz9tNrAtUSbMEpHMLU/edit#slide=id.p) |
||||
- [OpenEMR Cmd](https://github.com/openemr/openemr-devops/tree/master/utilities/openemr-cmd#openemr-cmd-documentation) |
@ -0,0 +1,31 @@
|
||||
# Using Markdown to learn Markdown |
||||
|
||||
## Table of contents |
||||
1. [Introduction](#introduction) |
||||
2. [Paragraph 1](#paragraph-1) |
||||
3. [References](#references) |
||||
4. [Other interesting files](#other-interesting-files) |
||||
|
||||
## Introduction <a name="introduction"></a> |
||||
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam nisl nisi, maximus vel elit sed, rutrum suscipit libero. Proin ullamcorper sagittis dui, et luctus odio hendrerit ornare. Sed fringilla fringilla ligula vitae porttitor. Integer odio dui, malesuada a lorem vel, tincidunt malesuada nisi. Suspendisse lacinia vel lectus vel mattis. Etiam iaculis turpis ut sem vulputate viverra. Nunc nec ullamcorper felis, at aliquam purus. Nunc tincidunt sapien purus. Donec interdum iaculis ipsum et maximus. Nam justo metus, volutpat eget libero at, malesuada viverra lorem. Ut sed dictum felis. Aenean tempus ipsum quam, et mollis nunc maximus id. |
||||
|
||||
## Basic Syntax |
||||
|
||||
### Headings |
||||
|
||||
**Headings** in Markdown work like headings in HTML. Create a heading by adding # characters before the content of the heading. The number of # characters determines the *heading level*. |
||||
|
||||
### Formatting |
||||
|
||||
- Bold is delimited with ** characters before and after the bolded text |
||||
- Italic is delimeted with a * character before and after the italic text |
||||
|
||||
## Documenting Code |
||||
|
||||
|
||||
|
||||
## References |
||||
|
||||
1. [Markdown Guide](https://www.markdownguide.org/) |
||||
2. [Markdown Cheatsheet](https://www.markdownguide.org/cheat-sheet/) |
@ -0,0 +1,205 @@
|
||||
# Networking Fundamentals |
||||
|
||||
## Table of Contents |
||||
1. [OSI Network Model](#open-systems-interconnect-(osi)-network-model) |
||||
2. [Protocols and Ports](#protocols-and-ports) |
||||
|
||||
## Open Systems Interconnect (OSI) Network Model |
||||
|
||||
A conceptual model that communicates the ways in which different systems work together in a network. |
||||
|
||||
| Layer | Description | |
||||
|-------|-------| |
||||
| Physical | Responsible for the transmission and reception of unstructured raw data between a device and a physical transmission medium. |
||||
| Data Link | Provides node to node data transfer between two directly connected nodes. |
||||
| Network | Provides the functional and procedural means of transferring packets from one node to another. This is where addressing and routing happens. |
||||
| Transport | Makes the connection between a source and a destination. |
||||
| Session | Controls the connections between computers. |
||||
| Presentation | Establishes context between application layer entities. |
||||
| Appliation | Interacts with software applications that implement communications. |
||||
|
||||
## Protocols and Ports |
||||
|
||||
Protocols are an Application Layer component. Ports are a Transport Layer component that is matched to the protocol. The port number helps the lower layer protocols understand which application is being used in the communication. |
||||
|
||||
|
||||
| Service | Protocol | Port | |
||||
|-------|-------|-------| |
||||
| Transferring data | HTTP / HTTPS | 80 / 443 | |
||||
| File transfer | FTP / sFTP / TFTP / SMB | 20 21 / 22 / 69 / 445 | |
||||
| Email | POP3 / IMAP / SMTP | 110 995 / 143 993 / 25 465| |
||||
| Authentication | LDAP / LDAPs | 389 / 636 | |
||||
|
||||
|
||||
| Network Service | Description | |
||||
|-------|-------| |
||||
| DHCP | Dynamic addresses | |
||||
| DNS | Name resolution | |
||||
| NTP | Network Time Protocol | |
||||
|
||||
### Utilities |
||||
|
||||
`nslookup` |
||||
|
||||
## Tranmission Control Protocol |
||||
|
||||
This is a connection oriented protocol that establishes communications between a client and a server. This protocol prioritizes quality over time, therefore it contains error checking and recovery to ensure that a message is complete. |
||||
|
||||
TCP uses the 3 way handshake to establish a connection. The client starts by sending a SYN message to request a connection, the server sends back an ACK message to confirm the connection, lastly the client uses a protocol (like HTTP) to send the message and get back a response. |
||||
|
||||
Connections are gracefully closed with a 4 way disconnect. The server sends a FIN message and the client sends an ACK message, then they do it again. |
||||
|
||||
## User Datagram Protocol |
||||
|
||||
This is a connection-less protocol that prioritizes time over quality. This services is more like a broadcast than a phone call. Used for things like DNS where efficient data transfer is key. |
||||
|
||||
## Intro to Binary and Hexadecimal |
||||
|
||||
Converting binary to decimal. Multiply the value in the placeholder by the value of the placeholder and add the results together. |
||||
|
||||
``` |
||||
128 64 32 16 8 4 2 1 |
||||
1 1 0 0 0 0 0 0 |
||||
128 64 0 0 0 0 0 0 = 192 |
||||
``` |
||||
|
||||
Converting decimal to binary. Start with the highest place that you can subtract from the decimal number, then continue with the remainder until you get to 0. |
||||
|
||||
Hexadecimal is base 10 where the numbers are 1 - 9 then A - F with 10 being 16. |
||||
|
||||
## IP Addressing |
||||
|
||||
IP addresses live in layer 3 of the OSI model. Every device on the internet must have a unique IP address. An IP address consists of two components, the network address and the host address. |
||||
|
||||
All IP addresses consist of 4 8-bit numbers separated by decimals. |
||||
|
||||
``` |
||||
203.0.113.10 |
||||
11001011 00000000 01110001 00001010 |
||||
``` |
||||
|
||||
### Classful vs Classless addressing |
||||
|
||||
Classless addressing is the modern approach. This approach uses a subnet mask to differentiate the network portion of the address from the host portion. The subnet mask uses 1 to mask out the network portion of the address and 0 for the host portion. |
||||
|
||||
``` |
||||
203.0.113.10 |
||||
11001011 00000000 01110001 00001010 |
||||
|
||||
11111111 11111111 11111111 00000000 |
||||
255.255.255.0 |
||||
``` |
||||
|
||||
Classful addressing was the old way of determining network and host. These were the old A, B, C, D, and E networks. The public internet is still based on the first three networks. |
||||
|
||||
A network address consists of the network address followed by a host portion with only 0s. A broadcast address is the network followed by all 1s in the host portion. The host address is anything in the host portion that is not all 0s and all 1s. |
||||
|
||||
### CIDR Notation |
||||
|
||||
A shortcut method for writing an address that shows the number of bits in the subnet mask. |
||||
|
||||
``` |
||||
203.0.113.10/24 |
||||
``` |
||||
|
||||
### Reserved network addresses |
||||
|
||||
These are reserved for use on private networks. |
||||
|
||||
| Network | Mask | CIDR | |
||||
|-------|-------|-------| |
||||
| 10.0.0.0 | 10.255.255.255 | 10.0.0.0/8 | |
||||
| 172.16.0.0 | 172.31.255.255 | 172.16.0.0/12 | |
||||
| 192.168.0.0 | 192.168.255.255 | 192.168.0.0/16 | |
||||
|
||||
## Subnetting |
||||
|
||||
## IPv6 |
||||
|
||||
### Address sizes |
||||
**IPv4** are 32bits long in 4 octets |
||||
**IPv6** are 128bits long in 8 hextets |
||||
|
||||
IPv6 are written in hex in blocks of 4 digits. |
||||
``` |
||||
2001:0DB8:0002:008D:0000:0000:00A5:52F5 |
||||
``` |
||||
|
||||
In IPv6 the network portion is the first 64 bits and the host portion (interface identifier) is the last 64 bits. |
||||
|
||||
Reduce the address: |
||||
- remove leading 0s |
||||
- Eliminate sets of 0 with a :: |
||||
- Can only use one :: in an address |
||||
|
||||
``` |
||||
2001:DB8:2:8D::A5:52F5 |
||||
``` |
||||
|
||||
## Ethernet and Switching |
||||
|
||||
Ethernet and switching exists at layer 2. The protocols at this level govern how devices connect to each other and communicate from point to point. |
||||
|
||||
CSMA/CD - Carrier Sense Multiple Access with Collision Detection |
||||
|
||||
This was the original standard to describe ethernet. When one device needs to send a message to another device on the network, it will send out a pulse to all devices on the network. All devices will get the message but only the intended device will send back an acknowledgement. |
||||
|
||||
### Ethernet Frame |
||||
|
||||
The ethernet frame has not changed since its beginning. Speeds and hardware have changed, but not the basic form of the frame. The frame information facilitiates the communication on Ethernet. Everything except the data packet are the frame information. |
||||
|
||||
| Destination Mac | Source Mac | Type | Data(Packet) | FCS | |
||||
|-------|-------|-------|-------|-------| |
||||
| 48 bit | 48 bit | 16 bit | MAX 1500 bytes | 32 bit | |
||||
|
||||
The type field tells what type of data is being transferred |
||||
The frame check sequence (FCS) validates the frame |
||||
|
||||
### Switches |
||||
|
||||
Switches work by mapping the ports on the switch to the MAC addresses of the devices connected to that port. |
||||
|
||||
## Switching Features |
||||
|
||||
### VLANS |
||||
|
||||
Splitting a physical switch into multiple domains. Each VLAN exists on its own Layer-3 IP network. |
||||
|
||||
VLANs will sement your network based on specific functions. |
||||
|
||||
## IP Routing |
||||
|
||||
Address Resolution Protocol - gets a Layer-2 MAC address when all we have is a Layer-3 IP address. |
||||
|
||||
The ARP table is stored on the client device. The ARP table can be viewed on your PC. |
||||
|
||||
`arp -a` |
||||
|
||||
The default Gateway and the Router are the same thing. |
||||
|
||||
The router is used when the destination IP address is not on the same network as the source. |
||||
|
||||
The tracert utility shows a listing of all routers that a message crosses. |
||||
|
||||
`tracert -d 8.8.8.8` |
||||
|
||||
## Network Services |
||||
|
||||
### Network Topologies |
||||
|
||||
1. LAN (Local Area Network) |
||||
2. WLAN (Wireless Local Area Network) |
||||
3. WAN (Wide Area Network) |
||||
4. SAN (Storage Area Network) |
||||
5. PAN (Personal Area Network) - Hotspot |
||||
|
||||
### Network Address Translation (NAT) |
||||
|
||||
The default gateway will replace the local private IP address with the public IP address assigned to the router. It will also convert public messages to private. |
||||
|
||||
### Access Control Lists (ACL) |
||||
|
||||
A mechanism for flagging bad servers. |
||||
|
||||
## References |
||||
[Wikipedia Article](https://en.wikipedia.org/wiki/OSI_model) |
@ -0,0 +1,13 @@
|
||||
# Extensions |
||||
This is the list of essential extensions that you should be running with VSCode |
||||
|
||||
|Extension|Description| |
||||
|-----|-----| |
||||
|Prettier| adds capability to auto-format your code| |
||||
|Remote - SSH| better than FTP any day| |
||||
|Docker| adds syntax highlighting for your docker files| |
||||
|Apache Conf Snippets| adds syntax highlighting to your .htaccess files| |
||||
|Drupal Syntax Highlighting| adds syntax highting to .inc files| |
||||
|CodeTour| extension for commenting code| |
||||
|Live Server| adds a simple web server to vscode| |
||||
|
@ -0,0 +1,7 @@
|
||||
# Copy Up/Down |
||||
Shift + Alt + ArrowUp/ArrowDown |
||||
|
||||
# Find and Replace |
||||
To add a line break at the replace add Ctrl + Enter. |
||||
|
||||
For example, in an X12 file, I want to add line breaks after each ~. So I would enter ~ in the find box and ~Ctrl+Enter in the replace box. |
@ -0,0 +1,12 @@
|
||||
Emmet Commands make coding easier |
||||
|
||||
! |
||||
Fills in a basic HTML5 template |
||||
|
||||
.classname |
||||
Creates a div with this classname |
||||
|
||||
#id |
||||
Creates a div with this id |
||||
|
||||
Can use the above 2 items with HTML tags to create the same |
@ -0,0 +1,158 @@
|
||||
# Notes from the Vue complete course |
||||
|
||||
## The Basics of Vue |
||||
|
||||
1. [Creating a Vue app](#creating-a-vue-app) |
||||
2. [Event Handling](#event-handling) |
||||
3. [Data Binding](#data-binding) |
||||
4. [Computed Properties](#computed-properties) |
||||
5. [Watchers](#watchers) |
||||
6. [Shortcuts](#shortcuts) |
||||
|
||||
### Creating a Vue app |
||||
|
||||
```javascript |
||||
const app = Vue.createApp({ |
||||
data() { |
||||
return {}; |
||||
}, |
||||
watch: { |
||||
|
||||
}, |
||||
computed: { |
||||
|
||||
}, |
||||
methods: { |
||||
|
||||
} |
||||
}); |
||||
|
||||
app.mount('#assignment'); |
||||
``` |
||||
|
||||
### Event Handling |
||||
|
||||
### Data Binding |
||||
|
||||
In this example, we want to add a reset button that will reset the contents of the textbox. Rather than using JavaScript to access the textbox directly, we use data binding to bind the textbox to a property and then let the button also access the same property to reset it. |
||||
|
||||
Use the v-bind property to have the textbox value filled from the name property. |
||||
```javascript |
||||
<input type="text" v-bind:value="name" v-on:input="setName($event, 'Schwarzmüller')"> |
||||
``` |
||||
|
||||
Bind the button to a new resetInput method |
||||
```javascript |
||||
<button v-on:click="resetInput">Reset Input</button> |
||||
``` |
||||
|
||||
Add the new method in the app.js file. This method will reset the same property that is now bound to the textbox (it is also bound to the paragraph so that will reset as well) |
||||
```javascript |
||||
resetInput() { |
||||
this.name = ''; |
||||
} |
||||
``` |
||||
|
||||
The textbox shows a very common pattern where you are binding a property to an input AND setting the property on input. All of this can be replaced with a shorter form: |
||||
```javascript |
||||
v-model="name" |
||||
``` |
||||
This is called Two-way binding. We are listening for the event AND writing the value back to the element. Thus, these two elements shown below do the exact same thing. |
||||
```javascript |
||||
<input type="text" v-bind:value="name" v-on:input="setName($event)"> |
||||
<input type="text" v-model="name"> |
||||
``` |
||||
|
||||
### Computed Properties |
||||
|
||||
Next we look at using a method in the paragraph to format the content rather than using binding. |
||||
```javascript |
||||
outputFullName() { |
||||
if (this.name === '') { |
||||
return ''; |
||||
} |
||||
return this.name + ' ' + 'Schaefer'; |
||||
}, |
||||
``` |
||||
|
||||
This pattern creates an inefficiency because Vue must execute this method whenever anything on the message changes. Rather than using methods, computed properties know the dependencies and will only execute when those dependencies change. |
||||
|
||||
Computer properties add a new section to the Vue app. They are methods but they should be named like properties. When called they are called WITHOUT (), they are used like variables. |
||||
```javascript |
||||
computed: { |
||||
fullname() { |
||||
if (this.name === '') { |
||||
return ''; |
||||
} |
||||
return this.name + ' ' + 'Schaefer'; |
||||
} |
||||
}, |
||||
``` |
||||
|
||||
### Watchers |
||||
|
||||
This is a function that executes when a dependency changes. Very similar to computed properties. Watcher methods are connected to a property name by being named the same. |
||||
|
||||
This is also a new section |
||||
```javascript |
||||
data() { |
||||
return { |
||||
counter: 0, |
||||
name: '', |
||||
fullname: '' |
||||
}; |
||||
}, |
||||
watch: { |
||||
name(value) { |
||||
this.fullname = value + ' ' + 'Schaefer'; |
||||
} |
||||
}, |
||||
``` |
||||
|
||||
The difference between watchers and computed properties is that watchers are bound to a single field whereas a computed field can work with more complex situations. Watchers are best used when you are validating or enforcing threshholds. Like having a maximum on the counter field. |
||||
|
||||
### Shortcuts |
||||
|
||||
v-on: can be replaced with @ |
||||
v-bind: can be replaced with just the : |
||||
|
||||
### Dynamic Styling |
||||
|
||||
This is an approach that uses in-line styles |
||||
|
||||
```html |
||||
<section id="styling"> |
||||
<div |
||||
class="demo" |
||||
:style="{borderColor: boxASelected ? 'red' : '#ccc'}" |
||||
@click="boxSelected('A')"></div> |
||||
<div class="demo" @click="boxSelected('B')"></div> |
||||
<div class="demo" @click="boxSelected('C')"></div> |
||||
</section> |
||||
``` |
||||
|
||||
A better approach is to use a css class dynamically |
||||
|
||||
```css |
||||
.active { |
||||
border-color: red; |
||||
background-color: salmon; |
||||
} |
||||
``` |
||||
|
||||
Note in this code that the :style has been removed and now :class in its place |
||||
|
||||
```html |
||||
<div |
||||
:class="boxASelected ? 'demo active' : 'demo'" |
||||
@click="boxSelected('A')"> |
||||
</div> |
||||
``` |
||||
Vue supports a shorthand for css styles |
||||
```html |
||||
<div |
||||
class="demo" |
||||
:class="{active: boxASelected}" |
||||
@click="boxSelected('A')"> |
||||
</div> |
||||
``` |
Loading…
Reference in new issue