commit 2434b3366507d0132332d432032144549a8d240e Author: giles bradshaw Date: Thu Apr 2 13:20:50 2020 +0000 initial diff --git a/.drone copy.yml b/.drone copy.yml new file mode 100644 index 0000000..1442c2c --- /dev/null +++ b/.drone copy.yml @@ -0,0 +1,142 @@ +--- + +kind: pipeline +type: docker +name: default +when: + branch: + - master + +clone: + # skip_verify: true + +steps: +steps: +- name: wait + when: + branch: + - master + image: docker:dind + volumes: + - name: dockersock + path: /var/run + + commands: + - sleep 60 +- name: build-letsencrypt-chat + when: + branch: + - master + image: docker:dind + volumes: + - name: dockersock + path: /var/run + environment: + LOCAL_DOCKER_REGISTRY: + from_secret: local-docker-registry + commands: + - cd letsencrypt-nginx + - sh build.sh chat $${LOCAL_DOCKER_REGISTRY} +- name: scp files + when: + branch: + - master + image: appleboy/drone-scp + settings: + host: + from_secret: ssh-host + username: + from_secret: ssh-user + password: + from_secret: ssh-password + port: + from_secret: ssh-port + command_timeout: 2m + target: ~/gitea-drone-stack + source: + - . +- name: deploy + when: + branch: + - master + image: appleboy/drone-ssh + environment: + DRONE_RPC_SECRET: + from_secret: drone-rpc-secret + DRONE_GITEA_CLIENT_ID: + from_secret: drone-gitea-client-id + DRONE_GITEA_CLIENT_SECRET: + from_secret: drone-gitea-client-secret + LOCAL_DOCKER_REGISTRY: + from_secret: local-docker-registry + SSH_USER: + from_secret: ssh-user + CERTBOT_EMAIL: + from_secret: certbot-email + GIT_DOMAIN: + from_secret: git-domain + DRONE_DOMAIN: + from_secret: drone-domain + CHAT_DOMAIN: + from_secret: chat-domain + REMOTE_DOMAIN: + from_secret: remote-domain + BLOG_DOMAIN: + from_secret: blog-domain + settings: + envs: + - drone_rpc_secret + - drone_gitea_client_id + - drone_gitea_client_secret + - ssh_user + - local_docker_registry + - certbot_email + - git_domain + - drone_domain + - chat_domain + - remote_domain + - blog_domain + host: + from_secret: ssh-host + username: + from_secret: ssh-root-user + password: + from_secret: ssh-root-password + port: + from_secret: ssh-port + script: + - set -e + - export LOCAL_DOCKER_REGISTRY=$LOCAL_DOCKER_REGISTRY + - export DRONE_RPC_SECRET=$DRONE_RPC_SECRET + - export DRONE_GITEA_CLIENT_ID=$DRONE_GITEA_CLIENT_ID + - export DRONE_GITEA_CLIENT_SECRET=$DRONE_GITEA_CLIENT_SECRET + - export SSH_USER=$SSH_USER + - export CERTBOT_EMAIL=$CERTBOT_EMAIL + - export GIT_DOMAIN=$GIT_DOMAIN + - export DRONE_DOMAIN=$DRONE_DOMAIN + - export CHAT_DOMAIN=$CHAT_DOMAIN + - export REMOTE_DOMAIN=$REMOTE_DOMAIN + - export BLOG_DOMAIN=$BLOG_DOMAIN + - docker network prune -f + - cd /home/$SSH_USER/gitea-drone-stack + - docker stack rm gitea + - sleep 60 + - docker stack deploy -c docker-compose.yml gitea + #- sleep 300 + +services: +- name: docker + image: docker:dind + privileged: true + volumes: + - name: dockersock + path: /var/run + - name: ca + path: /etc/docker/certs.d + +volumes: +- name: dockersock + temp: {} +- name: ca + host: + path: /home/giles/gitea-drone-stack/.ca diff --git a/.drone.m.yml b/.drone.m.yml new file mode 100644 index 0000000..e8928f4 --- /dev/null +++ b/.drone.m.yml @@ -0,0 +1,238 @@ +--- + +kind: pipeline +type: docker +name: default +when: + branch: + - remote + +clone: + # skip_verify: true + +steps: +steps: +- name: test-ssh + when: + branch: + - remote + image: appleboy/drone-ssh + environment: + DRONE_RPC_SECRET: + from_secret: drone-rpc-secret + DRONE_GITEA_CLIENT_ID: + from_secret: drone-gitea-client-id + DRONE_GITEA_CLIENT_SECRET: + from_secret: drone-gitea-client-secret + LOCAL_DOCKER_REGISTRY: + from_secret: local-docker-registry + SSH_USER: + from_secret: ssh-user + CERTBOT_EMAIL: + from_secret: certbot-email + GIT_DOMAIN: + from_secret: git-domain + DRONE_DOMAIN: + from_secret: drone-domain + REMOTE_DOMAIN: + from_secret: remote-domain + settings: + envs: + - drone_rpc_secret + - drone_gitea_client_id + - drone_gitea_client_secret + - ssh_user + - local_docker_registry + - certbot_email + - git_domain + - drone_domain + - remote_domain + host: + from_secret: ssh-host + username: + from_secret: ssh-root-user + password: + from_secret: ssh-root-password + port: + from_secret: ssh-port + script: + - echo 'ssh ok' +- name: wait + when: + branch: + - remote + image: docker:dind + volumes: + - name: dockersock + path: /var/run + + commands: + - sleep 60 +- name: build-postgres + when: + branch: + - remote + image: docker:dind + volumes: + - name: dockersock + path: /var/run + environment: + LOCAL_DOCKER_REGISTRY: + from_secret: local-docker-registry + commands: + - cd guacamole-postgresql + - docker build . -t $${LOCAL_DOCKER_REGISTRY}/guacamole-postgresql + - docker push $${LOCAL_DOCKER_REGISTRY}/guacamole-postgresql +- name: build-ngrok + when: + branch: + - remote + image: docker:dind + volumes: + - name: dockersock + path: /var/run + environment: + LOCAL_DOCKER_REGISTRY: + from_secret: local-docker-registry + commands: + - cd ngrok2 + - docker build . -t $${LOCAL_DOCKER_REGISTRY}/ngrok-gitea + - docker push $${LOCAL_DOCKER_REGISTRY}/ngrok-gitea +- name: build-letsencrypt-nginx + when: + branch: + - remote + image: docker:dind + volumes: + - name: dockersock + path: /var/run + environment: + LOCAL_DOCKER_REGISTRY: + from_secret: local-docker-registry + commands: + - cd letsencrypt-nginx + - docker build . -t $${LOCAL_DOCKER_REGISTRY}/letsencrypt-nginx + - docker push $${LOCAL_DOCKER_REGISTRY}/letsencrypt-nginx +- name: build-letsencrypt-drone + when: + branch: + - master + image: docker:dind + volumes: + - name: dockersock + path: /var/run + environment: + LOCAL_DOCKER_REGISTRY: + from_secret: local-docker-registry + commands: + - cd letsencrypt-nginx + - sh build.sh drone $${LOCAL_DOCKER_REGISTRY} +- name: build-letsencrypt-remote + when: + branch: + - master + image: docker:dind + volumes: + - name: dockersock + path: /var/run + environment: + LOCAL_DOCKER_REGISTRY: + from_secret: local-docker-registry + commands: + - cd letsencrypt-nginx + - sh build.sh remote $${LOCAL_DOCKER_REGISTRY} +- name: scp files + when: + branch: + - remote + image: appleboy/drone-scp + settings: + host: + from_secret: ssh-host + username: + from_secret: ssh-user + password: + from_secret: ssh-password + port: + from_secret: ssh-port + command_timeout: 2m + target: ~/gitea-drone-stack + source: + - . +- name: deploy + when: + branch: + - remote + image: appleboy/drone-ssh + environment: + DRONE_RPC_SECRET: + from_secret: drone-rpc-secret + DRONE_GITEA_CLIENT_ID: + from_secret: drone-gitea-client-id + DRONE_GITEA_CLIENT_SECRET: + from_secret: drone-gitea-client-secret + LOCAL_DOCKER_REGISTRY: + from_secret: local-docker-registry + SSH_USER: + from_secret: ssh-user + CERTBOT_EMAIL: + from_secret: certbot-email + GIT_DOMAIN: + from_secret: git-domain + DRONE_DOMAIN: + from_secret: drone-domain + REMOTE_DOMAIN: + from_secret: remote-domain + settings: + envs: + - drone_rpc_secret + - drone_gitea_client_id + - drone_gitea_client_secret + - ssh_user + - local_docker_registry + - certbot_email + - git_domain + - drone_domain + - remote_domain + host: + from_secret: ssh-host + username: + from_secret: ssh-root-user + password: + from_secret: ssh-root-password + port: + from_secret: ssh-port + script: + - set -e + - export LOCAL_DOCKER_REGISTRY=$LOCAL_DOCKER_REGISTRY + - export DRONE_RPC_SECRET=$DRONE_RPC_SECRET + - export DRONE_GITEA_CLIENT_ID=$DRONE_GITEA_CLIENT_ID + - export DRONE_GITEA_CLIENT_SECRET=$DRONE_GITEA_CLIENT_SECRET + - export SSH_USER=$SSH_USER + - export CERTBOT_EMAIL=$CERTBOT_EMAIL + - export GIT_DOMAIN=$GIT_DOMAIN + - export DRONE_DOMAIN=$DRONE_DOMAIN + - export REMOTE_DOMAIN=$REMOTE_DOMAIN + - docker network prune -f + - cd /home/$SSH_USER/gitea-drone-stack + - docker stack rm remote-drone + - sleep 60 + - docker stack deploy -c docker-compose-drone.yml remote-drone + #- sleep 300 + +services: +- name: docker + image: docker:dind + privileged: true + volumes: + - name: dockersock + path: /var/run + - name: ca + path: /etc/docker/certs.d + +volumes: +- name: dockersock + temp: {} +- name: ca + host: + path: /home/giles/gitea-drone-stack/.ca diff --git a/.drone.yml b/.drone.yml new file mode 100644 index 0000000..d4602bb --- /dev/null +++ b/.drone.yml @@ -0,0 +1,243 @@ +--- + +kind: pipeline +type: docker +name: default +when: + branch: + - master + +clone: + # skip_verify: true + +steps: +steps: +- name: wait + when: + branch: + - master + image: docker:dind + volumes: + - name: dockersock + path: /var/run + + commands: + - sleep 60 +- name: build-postgres + when: + branch: + - master + image: docker:dind + volumes: + - name: dockersock + path: /var/run + environment: + LOCAL_DOCKER_REGISTRY: + from_secret: local-docker-registry + commands: + - cd guacamole-postgresql + - docker build . -t $${LOCAL_DOCKER_REGISTRY}/guacamole-postgresql + - docker push $${LOCAL_DOCKER_REGISTRY}/guacamole-postgresql +- name: build-ngrok + when: + branch: + - master + image: docker:dind + volumes: + - name: dockersock + path: /var/run + environment: + LOCAL_DOCKER_REGISTRY: + from_secret: local-docker-registry + commands: + - cd ngrok2 + - docker build . -t $${LOCAL_DOCKER_REGISTRY}/ngrok-gitea + - docker push $${LOCAL_DOCKER_REGISTRY}/ngrok-gitea +- name: build-letsencrypt-nginx + when: + branch: + - master + image: docker:dind + volumes: + - name: dockersock + path: /var/run + environment: + LOCAL_DOCKER_REGISTRY: + from_secret: local-docker-registry + commands: + - cd letsencrypt-nginx + - docker build . -t $${LOCAL_DOCKER_REGISTRY}/letsencrypt-nginx + - docker push $${LOCAL_DOCKER_REGISTRY}/letsencrypt-nginx +- name: build-letsencrypt-blog + when: + branch: + - master + image: docker:dind + volumes: + - name: dockersock + path: /var/run + environment: + LOCAL_DOCKER_REGISTRY: + from_secret: local-docker-registry + commands: + - cd letsencrypt-nginx + - sh build.sh blog $${LOCAL_DOCKER_REGISTRY} +- name: build-letsencrypt-drone + when: + branch: + - master + image: docker:dind + volumes: + - name: dockersock + path: /var/run + environment: + LOCAL_DOCKER_REGISTRY: + from_secret: local-docker-registry + commands: + - cd letsencrypt-nginx + - sh build.sh drone $${LOCAL_DOCKER_REGISTRY} +- name: build-letsencrypt-git + when: + branch: + - master + image: docker:dind + volumes: + - name: dockersock + path: /var/run + environment: + LOCAL_DOCKER_REGISTRY: + from_secret: local-docker-registry + commands: + - cd letsencrypt-nginx + - sh build.sh git $${LOCAL_DOCKER_REGISTRY} +- name: build-letsencrypt-remote + when: + branch: + - master + image: docker:dind + volumes: + - name: dockersock + path: /var/run + environment: + LOCAL_DOCKER_REGISTRY: + from_secret: local-docker-registry + commands: + - cd letsencrypt-nginx + - sh build.sh remote $${LOCAL_DOCKER_REGISTRY} +- name: build-letsencrypt-chat + when: + branch: + - master + image: docker:dind + volumes: + - name: dockersock + path: /var/run + environment: + LOCAL_DOCKER_REGISTRY: + from_secret: local-docker-registry + commands: + - cd letsencrypt-nginx + - sh build.sh chat $${LOCAL_DOCKER_REGISTRY} +- name: scp files + when: + branch: + - master + image: appleboy/drone-scp + settings: + host: + from_secret: ssh-host + username: + from_secret: ssh-user + password: + from_secret: ssh-password + port: + from_secret: ssh-port + command_timeout: 2m + target: ~/gitea-drone-stack + source: + - . +- name: deploy + when: + branch: + - master + image: appleboy/drone-ssh + environment: + DRONE_RPC_SECRET: + from_secret: drone-rpc-secret + DRONE_GITEA_CLIENT_ID: + from_secret: drone-gitea-client-id + DRONE_GITEA_CLIENT_SECRET: + from_secret: drone-gitea-client-secret + LOCAL_DOCKER_REGISTRY: + from_secret: local-docker-registry + SSH_USER: + from_secret: ssh-user + CERTBOT_EMAIL: + from_secret: certbot-email + GIT_DOMAIN: + from_secret: git-domain + DRONE_DOMAIN: + from_secret: drone-domain + CHAT_DOMAIN: + from_secret: chat-domain + REMOTE_DOMAIN: + from_secret: remote-domain + BLOG_DOMAIN: + from_secret: blog-domain + settings: + envs: + - drone_rpc_secret + - drone_gitea_client_id + - drone_gitea_client_secret + - ssh_user + - local_docker_registry + - certbot_email + - git_domain + - drone_domain + - chat_domain + - remote_domain + - blog_domain + host: + from_secret: ssh-host + username: + from_secret: ssh-root-user + password: + from_secret: ssh-root-password + port: + from_secret: ssh-port + script: + - set -e + - export LOCAL_DOCKER_REGISTRY=$LOCAL_DOCKER_REGISTRY + - export DRONE_RPC_SECRET=$DRONE_RPC_SECRET + - export DRONE_GITEA_CLIENT_ID=$DRONE_GITEA_CLIENT_ID + - export DRONE_GITEA_CLIENT_SECRET=$DRONE_GITEA_CLIENT_SECRET + - export SSH_USER=$SSH_USER + - export CERTBOT_EMAIL=$CERTBOT_EMAIL + - export GIT_DOMAIN=$GIT_DOMAIN + - export DRONE_DOMAIN=$DRONE_DOMAIN + - export CHAT_DOMAIN=$CHAT_DOMAIN + - export REMOTE_DOMAIN=$REMOTE_DOMAIN + - export BLOG_DOMAIN=$BLOG_DOMAIN + - docker network prune -f + - cd /home/$SSH_USER/gitea-drone-stack + - docker stack rm gitea + - sleep 60 + - docker stack deploy -c docker-compose.yml gitea + #- sleep 300 + +services: +- name: docker + image: docker:dind + privileged: true + volumes: + - name: dockersock + path: /var/run + - name: ca + path: /etc/docker/certs.d + +volumes: +- name: dockersock + temp: {} +- name: ca + host: + path: /home/giles/gitea-drone-stack/.ca diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..63cd811 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +.certificates +.ca +.secrets diff --git a/README.md b/README.md new file mode 100644 index 0000000..79ca2ab --- /dev/null +++ b/README.md @@ -0,0 +1,241 @@ +# gitea in a stack with drone and guacamole + +Remote system support. + +Consisting of + +* gitea repository - github like self hoisted git and web application +* drone ci system +* guacamole - rdp, vnc and ssh over the internet in the browser + +[![Build Status](https://drone.sigyl.com/api/badges/giles/gitea-drone-stack/status.svg)](https://drone.sigyl.com/giles/gitea-drone-stack) + +(nb when self deploying with drone it will will stick on started and have to be cancelled. This is because the deployment tears down the previous running drone). + +NB each time you deploy this using drone it will leave an orphaned network for example: + +drone-yoZbiXiqssFcSsG0dP5d + +eventually this will start to cause an error with message: Docker “ERROR: could not find an available, non-overlapping IPv4 address pool among the defaults to assign to the network” + + +## installing docker + +Start with a fresh install of Ubuntu server 19.04 connected to the internet + +### update packages + +``` +sudo apt-get update +sudo apt-get upgrade +``` + +### remove old versions of docker + +(if it's a fresh install of linux there shouldn't be any) + +``` +sudo apt-get remove docker docker-engine docker.io +``` + +### install docker + +``` +sudo apt install docker.io +``` + +### add current user to docker group + +logout and back in afterwards + +``` +sudo usermod -aG docker $USER +``` + +### start and enable docker + +``` +sudo systemctl start docker +sudo systemctl enable docker +``` + +### change ssh port to 2022 + +``` +sudo vi /etc/ssh/sshd_config + +``` + +change Port 2022 + +### allow root to ssh + +``` +sudo vi /etc/ssh/sshd_config + +``` + +## set the root password + +``` +sudo passwd root +``` + +change PermitRootLogin yes + +reboot + +start a stack running gitea to host repository. + +## stack + +### labels + +get nodes with + +``` +docker node ls +``` + +add label with + +``` +docker node update --label-add com.sigyl.git-stack=yes [node id] +``` + +### generate certificates + +where [registry-domain] is the domain on which the registry will be served + + sh ca.sh [registry-domain]:5000 + + + sh make-cert.sh [registry-domain] registry + +### ngrok auth + +obtain ngrok auth token and place in .secrets in form + + authtoken: [token] + +### initial deploy + +```shell +export LOCAL_DOCKER_REGISTRY=registry.local-domain:5000 +export CERTBOT_EMAIL=giles.bradshaw@sigyl.com +export GIT_DOMAIN=git.sigyl.com +export REMOTE_DOMAIN=remote.sigyl.com +export DRONE_DOMAIN=drone.sigyl.com +export BLOG_DOMAIN=blog.sigyl.com + +export DRONE_RPC_SECRET=$(openssl rand -base64 48) +docker stack deploy -c docker-compose.yml gitea +``` + +### create gitea drone app with client id and secret + +### add secrets to repository in drone + + +![add secret](./add-secret.png) + +* blog-domain +* certbot-email +* drone-domain +* drone-gitea-client-id +* drone-gitea-client-secret +* drone-rpc-secret +* git-domain +* local-docker-registry +* remote-domain +* ssh-password +* ssh-port +* ssh-root-password +* ssh-root-user +* ssh-user +* ssh-host + +### kill orphan docker:dind containers + +Wen the system is deployed by pushing to repository the docker:dind container will be orphaned and will run forever unless killed.. + + +## guacamole + +np no spaces in postgres password + +docker stack for guacamole + +adapted from https://digitalmccullough.com/posts/setting-up-apache-guacamole-with-docker-stack.html + +### initialising + +find id + +``` +docker ps + +``` + +execute initdb.sql + +``` +docker exec -it [id] psql -U postgres -d guacamole_db -f /initdb.sql +docker exec -it [id] psql -U postgres -d guacamole_db -f /init-user.sql -v password='somepassword' +``` + +initial admin is guacadmin:guacadmin + +create a new admin and delete guacadmin + +## docker-exec-runner on windows + +These instructions are not very good... + +https://exec-runner.docs.drone.io/installation/windows/ + +download and unpack on linux with + +``` +curl -L https://github.com/drone-runners/drone-runner-exec/releases/latest/download/drone_runner_exec_windows_amd64.tar.gz | tar zx +``` + + +rename drone-runner-exec to drone-runner-exec.exe + +make directory c:\Drone\drone-runner-exec on windows + +copy drone-runner-exec.exe to directory + +make config file with + +``` + +DRONE_RPC_PROTO=https +DRONE_RPC_HOST=drone.sigyl.com:443 +DRONE_RPC_SECRET=[rpc secret] +DRONE_LOG_FILE=C:\Drone\drone-runner-exec\log.txt +DRONE_RUNNER_LABELS=web:true +``` + + +install and start service with + +``` +drone-runner-exec service install +drone-runner-exec service start +``` + +## chat + +Once the chat-mongo container is up you need to get its id and do + +``` +docker exec -it [id] mongo --eval "printjson(rs.initiate({_id: 'rs0', members: [ { _id: 0, host: 'localhost:27017' } ]}))" +``` + +then scale up chat + +``` +docker service scale gitea_chat=1 +``` \ No newline at end of file diff --git a/add-secret.png b/add-secret.png new file mode 100644 index 0000000..8dba911 Binary files /dev/null and b/add-secret.png differ diff --git a/certificates/ca.sh b/certificates/ca.sh new file mode 100644 index 0000000..b5f9ab7 --- /dev/null +++ b/certificates/ca.sh @@ -0,0 +1,8 @@ +mkdir -p ../.certificates +openssl genrsa -des3 -out ../.certificates/ca.key 4096 + +openssl req -x509 -new -nodes -key ../.certificates/ca.key -sha256 -days 10000 -subj "/C=GB/ST=Devon/O=SiGyl/OU=SiGyl/CN=CA" -out ../.certificates/ca.crt +mkdir -p ../.ca/$1 +cp ../.certificates/ca.crt ../.ca/$1 +sudo mkdir -p /etc/docker/certs.d/$1 +sudo cp ../.ca/$1/*.* /etc/docker/certs.d/$1 \ No newline at end of file diff --git a/certificates/make-cert.sh b/certificates/make-cert.sh new file mode 100644 index 0000000..af768aa --- /dev/null +++ b/certificates/make-cert.sh @@ -0,0 +1,4 @@ +openssl genrsa -out ../.certificates/$2.key 2048 +openssl req -new -sha256 -key ../.certificates/$2.key -subj "/C=GB/ST=Devon/O=SiGyl/OU=Gitea/CN=$1" -out ../.certificates/$2.csr + +openssl x509 -req -in ../.certificates/$2.csr -CA ../.certificates/ca.crt -CAkey ../.certificates/ca.key -CAcreateserial -out ../.certificates/$2.crt -days 10000 -sha256 diff --git a/docker-compose-do.yml b/docker-compose-do.yml new file mode 100644 index 0000000..e51b912 --- /dev/null +++ b/docker-compose-do.yml @@ -0,0 +1,159 @@ +version: "3.7" +services: + letsencrypt-git: + deploy: + placement: + constraints: [node.labels.com.sigyl.git-stack == yes] + replicas: 1 + restart_policy: + condition: any + image: letsencrypt-git + environment: + - CERTBOT_EMAIL=${CERTBOT_EMAIL} + - SERVER_NAME=${GIT_DOMAIN} + - PROXY_PASS=http://gitea:3000/ + - BLOG_PROXY_PASS=http://ghost:2368 + - CHAT_PROXY_PASS=http://chat:3000 + - LOCATION=/git/ + - BLOG_LOCATION=/blog/ + - CHAT_LOCATION=/chat/ + volumes: + - letsencrypt-git:/etc/letsencrypt + networks: + - appnet + ports: + - 80:80 + - 443:443 + - 5000:5000 + gitea: + deploy: + placement: + constraints: [node.labels.com.sigyl.git-stack == yes] + replicas: 1 + restart_policy: + condition: any + image: gitea/gitea:latest + environment: + - USER_UID=1000 + - USER_GID=1000 + - ROOT_URL=https://${GIT_DOMAIN}/git + - SSH_DOMAIN=${GIT_DOMAIN} + volumes: + - gitea-app:/data + ports: + - 3000 + - 22:22 + networks: + - appnet + ghost: + deploy: + placement: + constraints: [node.labels.com.sigyl.git-stack == yes] + replicas: 1 + restart_policy: + condition: any + image: ghost + volumes: + - ghost-content:/var/lib/ghost/content + - ./ghost/config.production.json:/var/lib/ghost/config.production.json + environment: + - url=https://${GIT_DOMAIN}/blog + networks: + - appnet + chat: + deploy: + placement: + constraints: [node.labels.com.sigyl.git-stack-chat == yes] + replicas: 0 # will scale after mongo initated + restart_policy: + condition: any + image: rocketchat/rocket.chat:latest + networks: + - appnet + environment: + - MONGO_OPLOG_URL=mongodb://chat-mongo:27017/local + - ROOT_URL=https://${GIT_DOMAIN}/chat/ + - ROOT_URL_PATH_PREFIX=chat + - PORT=3000 + - MONGO_URL=mongodb://chat-mongo:27017/rocketchat + volumes: + - chat-uploads:/app/uploads + chat-mongo: + deploy: + placement: + constraints: [node.labels.com.sigyl.git-stack-chat == yes] + replicas: 1 + restart_policy: + condition: any + image: mongo:4.0 + networks: + - appnet + environment: + - MONGO_DATA_DIR=/data/db + - MONGO_LOG_DIR=/dev/null + volumes: + - mongo-chat:/data/db + command: mongod --smallfiles --replSet rs0 --oplogSize 128 + drone-server: + deploy: + placement: + constraints: [node.labels.com.sigyl.git-stack == yes] + replicas: 1 + restart_policy: + condition: any + image: drone/drone:latest + volumes: + - drone:/var/lib/drone + - drone-data:/data + depends_on: + - gitea + environment: + - DRONE_LOGS_DEBUG=true + - DRONE_LOGS_PRETTY=true + - DRONE_GITEA_SERVER=https://${GIT_DOMAIN}/git + - DRONE_GITEA_CLIENT_ID=${DRONE_GITEA_CLIENT_ID} + - DRONE_GITEA_CLIENT_SECRET=${DRONE_GITEA_CLIENT_SECRET} + - DRONE_SERVER_HOST=${GIT_DOMAIN}:5000 # tunnel hostname + - DRONE_ADMIN=giles + - DRONE_SERVER_PROTO=https # tunnel adds https on top + - DRONE_SERVER_PORT=:8080 + - DRONE_RPC_SECRET=${DRONE_RPC_SECRET} + - DRONE_USER_CREATE=username:giles,admin:true + - DRONE_AGENTS_ENABLED=true + #- DRONE_ENV_PLUGIN_ENDPOINT=http://git.local-domain:8888 + #- DRONE_ENV_PLUGIN_TOKEN=anything + networks: + - appnet + drone-docker-runner: + deploy: + placement: + constraints: [node.labels.com.sigyl.git-stack == yes] + replicas: 1 + restart_policy: + condition: any + image: drone/drone-runner-docker:1 + depends_on: + - drone-server + volumes: + - /var/run/docker.sock:/var/run/docker.sock + environment: + - DRONE_RPC_PROTO=https + - DRONE_RPC_HOST=${DRONE_DOMAIN}:5000 + - DRONE_RPC_SECRET=${DRONE_RPC_SECRET} + - DRONE_RUNNER_CAPACITY=8 + - DRONE_RUNNER_NAME="docker-runner" + #- DRONE_ENV_PLUGIN_ENDPOINT=http://git.local-domain:8888 + #- DRONE_ENV_PLUGIN_TOKEN=anything + +volumes: + gitea-db: + gitea-app: + letsencrypt-git: + ghost-content: + mongo-chat: + chat-uploads: + drone: + drone-data: +networks: + appnet: + driver: overlay diff --git a/docker-compose-drone.yml b/docker-compose-drone.yml new file mode 100644 index 0000000..2932a0b --- /dev/null +++ b/docker-compose-drone.yml @@ -0,0 +1,238 @@ +version: "3.7" +services: + letsencrypt-remote: + deploy: + placement: + constraints: [node.labels.com.sigyl.git-stack == yes] + replicas: 1 + restart_policy: + condition: any + image: ${LOCAL_DOCKER_REGISTRY}/letsencrypt-remote + environment: + - SERVER_NAME=${REMOTE_DOMAIN} + - CERTBOT_EMAIL=${CERTBOT_EMAIL} + - PROXY_PASS=http://guacamole:8080/guacamole/ + volumes: + - letsencrypt-remote:/etc/letsencrypt + networks: + - appnet + depends_on: + - guacamole + letsencrypt-drone: + deploy: + placement: + constraints: [node.labels.com.sigyl.git-stack == yes] + replicas: 1 + restart_policy: + condition: any + image: ${LOCAL_DOCKER_REGISTRY}/letsencrypt-drone + environment: + - CERTBOT_EMAIL=${CERTBOT_EMAIL} + - SERVER_NAME=${DRONE_DOMAIN} + - PROXY_PASS=http://drone-server:8080/ + volumes: + - letsencrypt-drone:/etc/letsencrypt + networks: + - appnet + depends_on: + - drone-server + ngrok: + deploy: + placement: + constraints: [node.labels.com.sigyl.git-stack == yes] + replicas: 1 + restart_policy: + condition: any + image: ${LOCAL_DOCKER_REGISTRY}/ngrok-gitea + ports: + - "4040:4040" + volumes: + - ./ngrok2/ngrok.m._yml:/home/ngrok/.ngrok2/ngrok._yml:ro + environment: + - GIT_DOMAIN=${GIT_DOMAIN} + - DRONE_DOMAIN=${DRONE_DOMAIN} + - REMOTE_DOMAIN=${REMOTE_DOMAIN} + - BLOG_DOMAIN=${BLOG_DOMAIN} + depends_on: + - gitea + networks: + - appnet + secrets: + - ngrok-auth-token + drone-server: + deploy: + placement: + constraints: [node.labels.com.sigyl.git-stack == yes] + replicas: 1 + restart_policy: + condition: any + image: drone/drone:latest + volumes: + - drone:/var/lib/drone + - drone-data:/data + depends_on: + - gitea + environment: + - DRONE_LOGS_DEBUG=true + - DRONE_LOGS_PRETTY=true + - DRONE_GITEA_SERVER=https://${GIT_DOMAIN} + - DRONE_GITEA_CLIENT_ID=${DRONE_GITEA_CLIENT_ID} + - DRONE_GITEA_CLIENT_SECRET=${DRONE_GITEA_CLIENT_SECRET} + - DRONE_SERVER_HOST=${DRONE_DOMAIN} # tunnel hostname + - DRONE_ADMIN=giles + - DRONE_SERVER_PROTO=https # tunnel adds https on top + - DRONE_SERVER_PORT=:8080 + - DRONE_RPC_SECRET=${DRONE_RPC_SECRET} + - DRONE_USER_CREATE=username:giles,admin:true + - DRONE_AGENTS_ENABLED=true + #- DRONE_ENV_PLUGIN_ENDPOINT=http://git.local-domain:8888 + #- DRONE_ENV_PLUGIN_TOKEN=anything + networks: + - appnet + drone-docker-runner: + deploy: + placement: + constraints: [node.labels.com.sigyl.git-stack == yes] + replicas: 1 + restart_policy: + condition: any + image: drone/drone-runner-docker:1 + depends_on: + - drone-server + volumes: + - /var/run/docker.sock:/var/run/docker.sock + environment: + - DRONE_RPC_PROTO=https + - DRONE_RPC_HOST=${DRONE_DOMAIN} + - DRONE_RPC_SECRET=${DRONE_RPC_SECRET} + - DRONE_RUNNER_CAPACITY=8 + - DRONE_RUNNER_NAME="docker-runner" + #- DRONE_ENV_PLUGIN_ENDPOINT=http://git.local-domain:8888 + #- DRONE_ENV_PLUGIN_TOKEN=anything + + registry: + deploy: + placement: + constraints: [node.labels.com.sigyl.git-stack == yes] + replicas: 1 + restart_policy: + condition: any + image: registry:2 + ports: + - 5000:5000 + volumes: + - registry-data:/var/lib/registry + environment: + - REGISTRY_HTTP_ADDR=0.0.0.0:5000 + - REGISTRY_HTTP_TLS_CERTIFICATE="/run/secrets/registry-cert" + - REGISTRY_HTTP_TLS_KEY="/run/secrets/registry-key" + networks: + - appnet + secrets: + - registry-cert + - registry-key + registry-cache: + deploy: + placement: + constraints: [node.labels.com.sigyl.git-stack == yes] + replicas: 1 + restart_policy: + condition: any + image: registry:2 + ports: + - 5001:5001 + volumes: + - registry-cache-data:/var/lib/registry + environment: + - REGISTRY_HTTP_ADDR=0.0.0.0:5001 + - REGISTRY_HTTP_TLS_CERTIFICATE="/run/secrets/registry-cert" + - REGISTRY_HTTP_TLS_KEY="/run/secrets/registry-key" + - REGISTRY_PROXY_REMOTEURL=http://registry-1.docker.io + networks: + - appnet + secrets: + - registry-cert + - registry-key + guacamole-postgresql: + deploy: + placement: + constraints: [node.labels.com.sigyl.git-stack == yes] + replicas: 1 + restart_policy: + condition: any + image: ${LOCAL_DOCKER_REGISTRY}/guacamole-postgresql:latest + environment: + POSTGRES_PASSWORD: guacroot + POSTGRES_DB: guacamole_db + volumes: + - guacamole-postgresql-data:/var/lib/postgresql/data + #secrets: + # - source: guacamole-postgresql-password + # target: password + + #- /home/giles/guacamole-stack/initdb.sql:/initdb.sql + networks: + - appnet + + # The backend guacamole server. + guacd: + deploy: + placement: + constraints: [node.labels.com.sigyl.git-stack == yes] + replicas: 1 + restart_policy: + condition: any + image: guacamole/guacd:latest + networks: + - appnet + + guacamole: + deploy: + placement: + constraints: [node.labels.com.sigyl.git-stack == yes] + replicas: 1 + restart_policy: + condition: any + image: guacamole/guacamole:latest + secrets: + - source: guacamole-postgresql-database + target: database + - source: guacamole-postgresql-user + target: user + - source: guacamole-postgresql-password + target: password + environment: + - POSTGRES_HOSTNAME=guacamole-postgresql + - POSTGRES_PORT=5432 + - POSTGRES_USER_FILE=/run/secrets/user + - POSTGRES_PASSWORD_FILE=/run/secrets/password + - POSTGRES_DATABASE_FILE=/run/secrets/database + - GUACD_HOSTNAME=guacd + networks: + - appnet +volumes: + drone: + drone-data: + registry-data: + registry-cache-data: + guacamole-postgresql-data: + letsencrypt-remote: + letsencrypt-drone: + +networks: + appnet: + driver: overlay + #external: true +secrets: + 'registry-cert': + file: .certificates/registry.crt + 'registry-key': + file: .certificates/registry.key + 'guacamole-postgresql-database': + file: .secrets/guacamole-postgresql-database + 'guacamole-postgresql-user': + file: .secrets/guacamole-postgresql-user + 'guacamole-postgresql-password': + file: .secrets/guacamole-postgresql-password + 'ngrok-auth-token': + file: .secrets/ngrok-auth-token diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..d8d7584 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,370 @@ +version: "3.7" +services: + letsencrypt-chat: + deploy: + placement: + constraints: [node.labels.com.sigyl.git-stack == yes] + replicas: 1 + restart_policy: + condition: any + image: ${LOCAL_DOCKER_REGISTRY}/letsencrypt-chat + environment: + - SERVER_NAME=${CHAT_DOMAIN} + - CERTBOT_EMAIL=${CERTBOT_EMAIL} + - PROXY_PASS=http://chat:3000/ + volumes: + - letsencrypt-chat:/etc/letsencrypt + networks: + - appnet + letsencrypt-remote: + deploy: + placement: + constraints: [node.labels.com.sigyl.git-stack == yes] + replicas: 1 + restart_policy: + condition: any + image: ${LOCAL_DOCKER_REGISTRY}/letsencrypt-remote + environment: + - SERVER_NAME=${REMOTE_DOMAIN} + - CERTBOT_EMAIL=${CERTBOT_EMAIL} + - PROXY_PASS=http://guacamole:8080/guacamole/ + volumes: + - letsencrypt-remote:/etc/letsencrypt + networks: + - appnet + depends_on: + - guacamole + letsencrypt-git: + deploy: + placement: + constraints: [node.labels.com.sigyl.git-stack == yes] + replicas: 1 + restart_policy: + condition: any + image: ${LOCAL_DOCKER_REGISTRY}/letsencrypt-git + environment: + - CERTBOT_EMAIL=${CERTBOT_EMAIL} + - SERVER_NAME=${GIT_DOMAIN} + - PROXY_PASS=http://gitea:3000/ + volumes: + - letsencrypt-git:/etc/letsencrypt + networks: + - appnet + depends_on: + - gitea + letsencrypt-drone: + deploy: + placement: + constraints: [node.labels.com.sigyl.git-stack == yes] + replicas: 1 + restart_policy: + condition: any + image: ${LOCAL_DOCKER_REGISTRY}/letsencrypt-drone + environment: + - CERTBOT_EMAIL=${CERTBOT_EMAIL} + - SERVER_NAME=${DRONE_DOMAIN} + - PROXY_PASS=http://drone-server:8080/ + volumes: + - letsencrypt-drone:/etc/letsencrypt + networks: + - appnet + depends_on: + - drone-server + gitea: + deploy: + placement: + constraints: [node.labels.com.sigyl.git-stack == yes] + replicas: 1 + restart_policy: + condition: any + image: gitea/gitea:latest + environment: + - USER_UID=1000 + - USER_GID=1000 + - ROOT_URL=https://${GIT_DOMAIN}/ + - SSH_DOMAIN=${GIT_DOMAIN} + volumes: + - gitea-app:/data + ports: + - 3000:3000 + - 22:22 + networks: + - appnet + ngrok: + deploy: + placement: + constraints: [node.labels.com.sigyl.git-stack == yes] + replicas: 1 + restart_policy: + condition: any + image: ${LOCAL_DOCKER_REGISTRY}/ngrok-gitea + ports: + - "4040:4040" + volumes: + - ./ngrok2/ngrok._yml:/home/ngrok/.ngrok2/ngrok._yml:ro + environment: + - GIT_DOMAIN=${GIT_DOMAIN} + - DRONE_DOMAIN=${DRONE_DOMAIN} + - REMOTE_DOMAIN=${REMOTE_DOMAIN} + - BLOG_DOMAIN=${BLOG_DOMAIN} + - CHAT_DOMAIN=${CHAT_DOMAIN} + #command: /bin/sh -c " cat /run/secrets/ngrok-auth-token /home/ngrok/.ngrok2/ngrok._yml > /home/ngrok/.ngrok2/ngrok.yml && ngrok start --all" + depends_on: + - gitea + networks: + - appnet + secrets: + - ngrok-auth-token + drone-server: + deploy: + placement: + constraints: [node.labels.com.sigyl.git-stack == yes] + replicas: 1 + restart_policy: + condition: any + image: drone/drone:latest + volumes: + - drone:/var/lib/drone + - drone-data:/data + depends_on: + - gitea + environment: + - DRONE_LOGS_DEBUG=true + - DRONE_LOGS_PRETTY=true + - DRONE_GITEA_SERVER=https://${GIT_DOMAIN} + - DRONE_GITEA_CLIENT_ID=${DRONE_GITEA_CLIENT_ID} + - DRONE_GITEA_CLIENT_SECRET=${DRONE_GITEA_CLIENT_SECRET} + - DRONE_SERVER_HOST=${DRONE_DOMAIN} # tunnel hostname + - DRONE_ADMIN=giles + - DRONE_SERVER_PROTO=https # tunnel adds https on top + - DRONE_SERVER_PORT=:8080 + - DRONE_RPC_SECRET=${DRONE_RPC_SECRET} + - DRONE_USER_CREATE=username:giles,admin:true + - DRONE_AGENTS_ENABLED=true + #- DRONE_ENV_PLUGIN_ENDPOINT=http://git.local-domain:8888 + #- DRONE_ENV_PLUGIN_TOKEN=anything + networks: + - appnet + drone-docker-runner: + deploy: + placement: + constraints: [node.labels.com.sigyl.git-stack == yes] + replicas: 1 + restart_policy: + condition: any + image: drone/drone-runner-docker:1 + depends_on: + - drone-server + volumes: + - /var/run/docker.sock:/var/run/docker.sock + environment: + - DRONE_RPC_PROTO=https + - DRONE_RPC_HOST=${DRONE_DOMAIN} + - DRONE_RPC_SECRET=${DRONE_RPC_SECRET} + - DRONE_RUNNER_CAPACITY=8 + - DRONE_RUNNER_NAME="docker-runner" + #- DRONE_ENV_PLUGIN_ENDPOINT=http://git.local-domain:8888 + #- DRONE_ENV_PLUGIN_TOKEN=anything + + registry: + deploy: + placement: + constraints: [node.labels.com.sigyl.git-stack == yes] + replicas: 1 + restart_policy: + condition: any + image: registry:2 + ports: + - 5000:5000 + volumes: + - registry-data:/var/lib/registry + environment: + - REGISTRY_HTTP_ADDR=0.0.0.0:5000 + - REGISTRY_HTTP_TLS_CERTIFICATE="/run/secrets/registry-cert" + - REGISTRY_HTTP_TLS_KEY="/run/secrets/registry-key" + networks: + - appnet + secrets: + - registry-cert + - registry-key + registry-cache: + deploy: + placement: + constraints: [node.labels.com.sigyl.git-stack == yes] + replicas: 1 + restart_policy: + condition: any + image: registry:2 + ports: + - 5001:5001 + volumes: + - registry-cache-data:/var/lib/registry + environment: + - REGISTRY_HTTP_ADDR=0.0.0.0:5001 + - REGISTRY_HTTP_TLS_CERTIFICATE="/run/secrets/registry-cert" + - REGISTRY_HTTP_TLS_KEY="/run/secrets/registry-key" + - REGISTRY_PROXY_REMOTEURL=http://registry-1.docker.io + networks: + - appnet + secrets: + - registry-cert + - registry-key + letsencrypt-blog: + deploy: + placement: + constraints: [node.labels.com.sigyl.git-stack == yes] + replicas: 1 + restart_policy: + condition: any + image: ${LOCAL_DOCKER_REGISTRY}/letsencrypt-blog + environment: + - CERTBOT_EMAIL=${CERTBOT_EMAIL} + - SERVER_NAME=${BLOG_DOMAIN} + - PROXY_PASS=http://ghost:2368 + volumes: + - letsencrypt-blog:/etc/letsencrypt + networks: + - appnet + depends_on: + - blog + + ghost: + deploy: + placement: + constraints: [node.labels.com.sigyl.git-stack == yes] + replicas: 1 + restart_policy: + condition: any + image: ghost + volumes: + - ghost-content:/var/lib/ghost/content + - ./ghost/config.production.json:/var/lib/ghost/config.production.json + environment: + - url=https://${BLOG_DOMAIN} + networks: + - appnet + + guacamole-postgresql: + deploy: + placement: + constraints: [node.labels.com.sigyl.git-stack == yes] + replicas: 1 + restart_policy: + condition: any + image: ${LOCAL_DOCKER_REGISTRY}/guacamole-postgresql:latest + environment: + POSTGRES_PASSWORD: guacroot + POSTGRES_DB: guacamole_db + volumes: + - guacamole-postgresql-data:/var/lib/postgresql/data + #secrets: + # - source: guacamole-postgresql-password + # target: password + + #- /home/giles/guacamole-stack/initdb.sql:/initdb.sql + networks: + - appnet + + # The backend guacamole server. + guacd: + deploy: + placement: + constraints: [node.labels.com.sigyl.git-stack == yes] + replicas: 1 + restart_policy: + condition: any + image: guacamole/guacd:latest + networks: + - appnet + + guacamole: + deploy: + placement: + constraints: [node.labels.com.sigyl.git-stack == yes] + replicas: 1 + restart_policy: + condition: any + image: guacamole/guacamole:latest + secrets: + - source: guacamole-postgresql-database + target: database + - source: guacamole-postgresql-user + target: user + - source: guacamole-postgresql-password + target: password + environment: + - POSTGRES_HOSTNAME=guacamole-postgresql + - POSTGRES_PORT=5432 + - POSTGRES_USER_FILE=/run/secrets/user + - POSTGRES_PASSWORD_FILE=/run/secrets/password + - POSTGRES_DATABASE_FILE=/run/secrets/database + - GUACD_HOSTNAME=guacd + networks: + - appnet + chat: + deploy: + placement: + constraints: [node.labels.com.sigyl.git-stack == yes] + replicas: 0 # will scale after mongo initated + restart_policy: + condition: any + image: rocketchat/rocket.chat:latest + networks: + - appnet + environment: + - MONGO_OPLOG_URL=mongodb://chat-mongo:27017/local + - ROOT_URL=https://${CHAT_DOMAIN} + - PORT=3000 + - MONGO_URL=mongodb://chat-mongo:27017/rocketchat + volumes: + - chat-uploads:/app/uploads + chat-mongo: + deploy: + placement: + constraints: [node.labels.com.sigyl.git-stack == yes] + replicas: 1 + restart_policy: + condition: any + image: mongo:4.0 + networks: + - appnet + environment: + - MONGO_DATA_DIR=/data/db + - MONGO_LOG_DIR=/dev/null + volumes: + - mongo-chat:/data/db + command: mongod --smallfiles --replSet rs0 --oplogSize 128 +volumes: + gitea-app: + gitea-db: + drone: + drone-data: + registry-data: + registry-cache-data: + guacamole-postgresql-data: + letsencrypt-remote: + letsencrypt-chat: + letsencrypt-git: + letsencrypt-drone: + letsencrypt-blog: + ghost-content: + mongo-chat: + chat-uploads: + +networks: + appnet: + driver: overlay + #external: true +secrets: + 'registry-cert': + file: .certificates/registry.crt + 'registry-key': + file: .certificates/registry.key + 'guacamole-postgresql-database': + file: .secrets/guacamole-postgresql-database + 'guacamole-postgresql-user': + file: .secrets/guacamole-postgresql-user + 'guacamole-postgresql-password': + file: .secrets/guacamole-postgresql-password + 'ngrok-auth-token': + file: .secrets/ngrok-auth-token diff --git a/ghost/config.production.json b/ghost/config.production.json new file mode 100644 index 0000000..d1b89b1 --- /dev/null +++ b/ghost/config.production.json @@ -0,0 +1,33 @@ +{ + "url": "https://sigyl.com/ghost", + "server": { + "port": 2368, + "host": "0.0.0.0" + }, + "database": { + "client": "sqlite3", + "connection": { + "filename": "/var/lib/ghost/content/data/ghost.db" + } + }, + "mail": { + "transport": "SMTP", + "options": { + "service": "Mailgun", + "auth": { + "user": "postmaster@sandboxb393ecccde2a4447923b56a149879324.mailgun.org", + "pass": "85828e2f386a89851ddd4b8e32bfebdb" + } + } + }, + "logging": { + "transports": [ + "file", + "stdout" + ] + }, + "process": "systemd", + "paths": { + "contentPath": "/var/lib/ghost/content" + } +} diff --git a/guacamole-postgresql/Dockerfile b/guacamole-postgresql/Dockerfile new file mode 100644 index 0000000..180cf45 --- /dev/null +++ b/guacamole-postgresql/Dockerfile @@ -0,0 +1,3 @@ +FROM postgres:12 + +COPY *.sql / \ No newline at end of file diff --git a/guacamole-postgresql/init-user.sql b/guacamole-postgresql/init-user.sql new file mode 100644 index 0000000..d2f89c9 --- /dev/null +++ b/guacamole-postgresql/init-user.sql @@ -0,0 +1,3 @@ +CREATE USER guacamole_user WITH PASSWORD :'password'; +GRANT SELECT,INSERT,UPDATE,DELETE ON ALL TABLES IN SCHEMA public TO guacamole_user; +GRANT SELECT,USAGE ON ALL SEQUENCES IN SCHEMA public TO guacamole_user; \ No newline at end of file diff --git a/guacamole-postgresql/initdb.sql b/guacamole-postgresql/initdb.sql new file mode 100644 index 0000000..d9e9159 --- /dev/null +++ b/guacamole-postgresql/initdb.sql @@ -0,0 +1,791 @@ +-- +-- Licensed to the Apache Software Foundation (ASF) under one +-- or more contributor license agreements. See the NOTICE file +-- distributed with this work for additional information +-- regarding copyright ownership. The ASF licenses this file +-- to you under the Apache License, Version 2.0 (the +-- "License"); you may not use this file except in compliance +-- with the License. You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, +-- software distributed under the License is distributed on an +-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +-- KIND, either express or implied. See the License for the +-- specific language governing permissions and limitations +-- under the License. +-- + +-- +-- Connection group types +-- + +CREATE TYPE guacamole_connection_group_type AS ENUM( + 'ORGANIZATIONAL', + 'BALANCING' +); + +-- +-- Entity types +-- + +CREATE TYPE guacamole_entity_type AS ENUM( + 'USER', + 'USER_GROUP' +); + +-- +-- Object permission types +-- + +CREATE TYPE guacamole_object_permission_type AS ENUM( + 'READ', + 'UPDATE', + 'DELETE', + 'ADMINISTER' +); + +-- +-- System permission types +-- + +CREATE TYPE guacamole_system_permission_type AS ENUM( + 'CREATE_CONNECTION', + 'CREATE_CONNECTION_GROUP', + 'CREATE_SHARING_PROFILE', + 'CREATE_USER', + 'CREATE_USER_GROUP', + 'ADMINISTER' +); + +-- +-- Guacamole proxy (guacd) encryption methods +-- + +CREATE TYPE guacamole_proxy_encryption_method AS ENUM( + 'NONE', + 'SSL' +); + +-- +-- Table of connection groups. Each connection group has a name. +-- + +CREATE TABLE guacamole_connection_group ( + + connection_group_id serial NOT NULL, + parent_id integer, + connection_group_name varchar(128) NOT NULL, + type guacamole_connection_group_type + NOT NULL DEFAULT 'ORGANIZATIONAL', + + -- Concurrency limits + max_connections integer, + max_connections_per_user integer, + enable_session_affinity boolean NOT NULL DEFAULT FALSE, + + PRIMARY KEY (connection_group_id), + + CONSTRAINT connection_group_name_parent + UNIQUE (connection_group_name, parent_id), + + CONSTRAINT guacamole_connection_group_ibfk_1 + FOREIGN KEY (parent_id) + REFERENCES guacamole_connection_group (connection_group_id) + ON DELETE CASCADE + +); + +CREATE INDEX guacamole_connection_group_parent_id + ON guacamole_connection_group(parent_id); + +-- +-- Table of connections. Each connection has a name, protocol, and +-- associated set of parameters. +-- A connection may belong to a connection group. +-- + +CREATE TABLE guacamole_connection ( + + connection_id serial NOT NULL, + connection_name varchar(128) NOT NULL, + parent_id integer, + protocol varchar(32) NOT NULL, + + -- Concurrency limits + max_connections integer, + max_connections_per_user integer, + + -- Connection Weight + connection_weight integer, + failover_only boolean NOT NULL DEFAULT FALSE, + + -- Guacamole proxy (guacd) overrides + proxy_port integer, + proxy_hostname varchar(512), + proxy_encryption_method guacamole_proxy_encryption_method, + + PRIMARY KEY (connection_id), + + CONSTRAINT connection_name_parent + UNIQUE (connection_name, parent_id), + + CONSTRAINT guacamole_connection_ibfk_1 + FOREIGN KEY (parent_id) + REFERENCES guacamole_connection_group (connection_group_id) + ON DELETE CASCADE + +); + +CREATE INDEX guacamole_connection_parent_id + ON guacamole_connection(parent_id); + +-- +-- Table of base entities which may each be either a user or user group. Other +-- tables which represent qualities shared by both users and groups will point +-- to guacamole_entity, while tables which represent qualities specific to +-- users or groups will point to guacamole_user or guacamole_user_group. +-- + +CREATE TABLE guacamole_entity ( + + entity_id serial NOT NULL, + name varchar(128) NOT NULL, + type guacamole_entity_type NOT NULL, + + PRIMARY KEY (entity_id), + + CONSTRAINT guacamole_entity_name_scope + UNIQUE (type, name) + +); + +-- +-- Table of users. Each user has a unique username and a hashed password +-- with corresponding salt. Although the authentication system will always set +-- salted passwords, other systems may set unsalted passwords by simply not +-- providing the salt. +-- + +CREATE TABLE guacamole_user ( + + user_id serial NOT NULL, + entity_id integer NOT NULL, + + -- Optionally-salted password + password_hash bytea NOT NULL, + password_salt bytea, + password_date timestamptz NOT NULL, + + -- Account disabled/expired status + disabled boolean NOT NULL DEFAULT FALSE, + expired boolean NOT NULL DEFAULT FALSE, + + -- Time-based access restriction + access_window_start time, + access_window_end time, + + -- Date-based access restriction + valid_from date, + valid_until date, + + -- Timezone used for all date/time comparisons and interpretation + timezone varchar(64), + + -- Profile information + full_name varchar(256), + email_address varchar(256), + organization varchar(256), + organizational_role varchar(256), + + PRIMARY KEY (user_id), + + CONSTRAINT guacamole_user_single_entity + UNIQUE (entity_id), + + CONSTRAINT guacamole_user_entity + FOREIGN KEY (entity_id) + REFERENCES guacamole_entity (entity_id) + ON DELETE CASCADE + +); + +-- +-- Table of user groups. Each user group may have an arbitrary set of member +-- users and member groups, with those members inheriting the permissions +-- granted to that group. +-- + +CREATE TABLE guacamole_user_group ( + + user_group_id serial NOT NULL, + entity_id integer NOT NULL, + + -- Group disabled status + disabled boolean NOT NULL DEFAULT FALSE, + + PRIMARY KEY (user_group_id), + + CONSTRAINT guacamole_user_group_single_entity + UNIQUE (entity_id), + + CONSTRAINT guacamole_user_group_entity + FOREIGN KEY (entity_id) + REFERENCES guacamole_entity (entity_id) + ON DELETE CASCADE + +); + +-- +-- Table of users which are members of given user groups. +-- + +CREATE TABLE guacamole_user_group_member ( + + user_group_id integer NOT NULL, + member_entity_id integer NOT NULL, + + PRIMARY KEY (user_group_id, member_entity_id), + + -- Parent must be a user group + CONSTRAINT guacamole_user_group_member_parent + FOREIGN KEY (user_group_id) + REFERENCES guacamole_user_group (user_group_id) ON DELETE CASCADE, + + -- Member may be either a user or a user group (any entity) + CONSTRAINT guacamole_user_group_member_entity + FOREIGN KEY (member_entity_id) + REFERENCES guacamole_entity (entity_id) ON DELETE CASCADE + +); + +-- +-- Table of sharing profiles. Each sharing profile has a name, associated set +-- of parameters, and a primary connection. The primary connection is the +-- connection that the sharing profile shares, and the parameters dictate the +-- restrictions/features which apply to the user joining the connection via the +-- sharing profile. +-- + +CREATE TABLE guacamole_sharing_profile ( + + sharing_profile_id serial NOT NULL, + sharing_profile_name varchar(128) NOT NULL, + primary_connection_id integer NOT NULL, + + PRIMARY KEY (sharing_profile_id), + + CONSTRAINT sharing_profile_name_primary + UNIQUE (sharing_profile_name, primary_connection_id), + + CONSTRAINT guacamole_sharing_profile_ibfk_1 + FOREIGN KEY (primary_connection_id) + REFERENCES guacamole_connection (connection_id) + ON DELETE CASCADE + +); + +CREATE INDEX guacamole_sharing_profile_primary_connection_id + ON guacamole_sharing_profile(primary_connection_id); + +-- +-- Table of connection parameters. Each parameter is simply a name/value pair +-- associated with a connection. +-- + +CREATE TABLE guacamole_connection_parameter ( + + connection_id integer NOT NULL, + parameter_name varchar(128) NOT NULL, + parameter_value varchar(4096) NOT NULL, + + PRIMARY KEY (connection_id,parameter_name), + + CONSTRAINT guacamole_connection_parameter_ibfk_1 + FOREIGN KEY (connection_id) + REFERENCES guacamole_connection (connection_id) ON DELETE CASCADE + +); + +CREATE INDEX guacamole_connection_parameter_connection_id + ON guacamole_connection_parameter(connection_id); + +-- +-- Table of sharing profile parameters. Each parameter is simply +-- name/value pair associated with a sharing profile. These parameters dictate +-- the restrictions/features which apply to the user joining the associated +-- connection via the sharing profile. +-- + +CREATE TABLE guacamole_sharing_profile_parameter ( + + sharing_profile_id integer NOT NULL, + parameter_name varchar(128) NOT NULL, + parameter_value varchar(4096) NOT NULL, + + PRIMARY KEY (sharing_profile_id, parameter_name), + + CONSTRAINT guacamole_sharing_profile_parameter_ibfk_1 + FOREIGN KEY (sharing_profile_id) + REFERENCES guacamole_sharing_profile (sharing_profile_id) ON DELETE CASCADE + +); + +CREATE INDEX guacamole_sharing_profile_parameter_sharing_profile_id + ON guacamole_sharing_profile_parameter(sharing_profile_id); + +-- +-- Table of arbitrary user attributes. Each attribute is simply a name/value +-- pair associated with a user. Arbitrary attributes are defined by other +-- extensions. Attributes defined by this extension will be mapped to +-- properly-typed columns of a specific table. +-- + +CREATE TABLE guacamole_user_attribute ( + + user_id integer NOT NULL, + attribute_name varchar(128) NOT NULL, + attribute_value varchar(4096) NOT NULL, + + PRIMARY KEY (user_id, attribute_name), + + CONSTRAINT guacamole_user_attribute_ibfk_1 + FOREIGN KEY (user_id) + REFERENCES guacamole_user (user_id) ON DELETE CASCADE + +); + +CREATE INDEX guacamole_user_attribute_user_id + ON guacamole_user_attribute(user_id); + +-- +-- Table of arbitrary user group attributes. Each attribute is simply a +-- name/value pair associated with a user group. Arbitrary attributes are +-- defined by other extensions. Attributes defined by this extension will be +-- mapped to properly-typed columns of a specific table. +-- + +CREATE TABLE guacamole_user_group_attribute ( + + user_group_id integer NOT NULL, + attribute_name varchar(128) NOT NULL, + attribute_value varchar(4096) NOT NULL, + + PRIMARY KEY (user_group_id, attribute_name), + + CONSTRAINT guacamole_user_group_attribute_ibfk_1 + FOREIGN KEY (user_group_id) + REFERENCES guacamole_user_group (user_group_id) ON DELETE CASCADE + +); + +CREATE INDEX guacamole_user_group_attribute_user_group_id + ON guacamole_user_group_attribute(user_group_id); + +-- +-- Table of arbitrary connection attributes. Each attribute is simply a +-- name/value pair associated with a connection. Arbitrary attributes are +-- defined by other extensions. Attributes defined by this extension will be +-- mapped to properly-typed columns of a specific table. +-- + +CREATE TABLE guacamole_connection_attribute ( + + connection_id integer NOT NULL, + attribute_name varchar(128) NOT NULL, + attribute_value varchar(4096) NOT NULL, + + PRIMARY KEY (connection_id, attribute_name), + + CONSTRAINT guacamole_connection_attribute_ibfk_1 + FOREIGN KEY (connection_id) + REFERENCES guacamole_connection (connection_id) ON DELETE CASCADE + +); + +CREATE INDEX guacamole_connection_attribute_connection_id + ON guacamole_connection_attribute(connection_id); + +-- +-- Table of arbitrary connection group attributes. Each attribute is simply a +-- name/value pair associated with a connection group. Arbitrary attributes are +-- defined by other extensions. Attributes defined by this extension will be +-- mapped to properly-typed columns of a specific table. +-- + +CREATE TABLE guacamole_connection_group_attribute ( + + connection_group_id integer NOT NULL, + attribute_name varchar(128) NOT NULL, + attribute_value varchar(4096) NOT NULL, + + PRIMARY KEY (connection_group_id, attribute_name), + + CONSTRAINT guacamole_connection_group_attribute_ibfk_1 + FOREIGN KEY (connection_group_id) + REFERENCES guacamole_connection_group (connection_group_id) ON DELETE CASCADE + +); + +CREATE INDEX guacamole_connection_group_attribute_connection_group_id + ON guacamole_connection_group_attribute(connection_group_id); + +-- +-- Table of arbitrary sharing profile attributes. Each attribute is simply a +-- name/value pair associated with a sharing profile. Arbitrary attributes are +-- defined by other extensions. Attributes defined by this extension will be +-- mapped to properly-typed columns of a specific table. +-- + +CREATE TABLE guacamole_sharing_profile_attribute ( + + sharing_profile_id integer NOT NULL, + attribute_name varchar(128) NOT NULL, + attribute_value varchar(4096) NOT NULL, + + PRIMARY KEY (sharing_profile_id, attribute_name), + + CONSTRAINT guacamole_sharing_profile_attribute_ibfk_1 + FOREIGN KEY (sharing_profile_id) + REFERENCES guacamole_sharing_profile (sharing_profile_id) ON DELETE CASCADE + +); + +CREATE INDEX guacamole_sharing_profile_attribute_sharing_profile_id + ON guacamole_sharing_profile_attribute(sharing_profile_id); + +-- +-- Table of connection permissions. Each connection permission grants a user or +-- user group specific access to a connection. +-- + +CREATE TABLE guacamole_connection_permission ( + + entity_id integer NOT NULL, + connection_id integer NOT NULL, + permission guacamole_object_permission_type NOT NULL, + + PRIMARY KEY (entity_id, connection_id, permission), + + CONSTRAINT guacamole_connection_permission_ibfk_1 + FOREIGN KEY (connection_id) + REFERENCES guacamole_connection (connection_id) ON DELETE CASCADE, + + CONSTRAINT guacamole_connection_permission_entity + FOREIGN KEY (entity_id) + REFERENCES guacamole_entity (entity_id) ON DELETE CASCADE + +); + +CREATE INDEX guacamole_connection_permission_connection_id + ON guacamole_connection_permission(connection_id); + +CREATE INDEX guacamole_connection_permission_entity_id + ON guacamole_connection_permission(entity_id); + +-- +-- Table of connection group permissions. Each group permission grants a user +-- or user group specific access to a connection group. +-- + +CREATE TABLE guacamole_connection_group_permission ( + + entity_id integer NOT NULL, + connection_group_id integer NOT NULL, + permission guacamole_object_permission_type NOT NULL, + + PRIMARY KEY (entity_id, connection_group_id, permission), + + CONSTRAINT guacamole_connection_group_permission_ibfk_1 + FOREIGN KEY (connection_group_id) + REFERENCES guacamole_connection_group (connection_group_id) ON DELETE CASCADE, + + CONSTRAINT guacamole_connection_group_permission_entity + FOREIGN KEY (entity_id) + REFERENCES guacamole_entity (entity_id) ON DELETE CASCADE + +); + +CREATE INDEX guacamole_connection_group_permission_connection_group_id + ON guacamole_connection_group_permission(connection_group_id); + +CREATE INDEX guacamole_connection_group_permission_entity_id + ON guacamole_connection_group_permission(entity_id); + +-- +-- Table of sharing profile permissions. Each sharing profile permission grants +-- a user or user group specific access to a sharing profile. +-- + +CREATE TABLE guacamole_sharing_profile_permission ( + + entity_id integer NOT NULL, + sharing_profile_id integer NOT NULL, + permission guacamole_object_permission_type NOT NULL, + + PRIMARY KEY (entity_id, sharing_profile_id, permission), + + CONSTRAINT guacamole_sharing_profile_permission_ibfk_1 + FOREIGN KEY (sharing_profile_id) + REFERENCES guacamole_sharing_profile (sharing_profile_id) ON DELETE CASCADE, + + CONSTRAINT guacamole_sharing_profile_permission_entity + FOREIGN KEY (entity_id) + REFERENCES guacamole_entity (entity_id) ON DELETE CASCADE + +); + +CREATE INDEX guacamole_sharing_profile_permission_sharing_profile_id + ON guacamole_sharing_profile_permission(sharing_profile_id); + +CREATE INDEX guacamole_sharing_profile_permission_entity_id + ON guacamole_sharing_profile_permission(entity_id); + +-- +-- Table of system permissions. Each system permission grants a user or user +-- group a system-level privilege of some kind. +-- + +CREATE TABLE guacamole_system_permission ( + + entity_id integer NOT NULL, + permission guacamole_system_permission_type NOT NULL, + + PRIMARY KEY (entity_id, permission), + + CONSTRAINT guacamole_system_permission_entity + FOREIGN KEY (entity_id) + REFERENCES guacamole_entity (entity_id) ON DELETE CASCADE + +); + +CREATE INDEX guacamole_system_permission_entity_id + ON guacamole_system_permission(entity_id); + +-- +-- Table of user permissions. Each user permission grants a user or user group +-- access to another user (the "affected" user) for a specific type of +-- operation. +-- + +CREATE TABLE guacamole_user_permission ( + + entity_id integer NOT NULL, + affected_user_id integer NOT NULL, + permission guacamole_object_permission_type NOT NULL, + + PRIMARY KEY (entity_id, affected_user_id, permission), + + CONSTRAINT guacamole_user_permission_ibfk_1 + FOREIGN KEY (affected_user_id) + REFERENCES guacamole_user (user_id) ON DELETE CASCADE, + + CONSTRAINT guacamole_user_permission_entity + FOREIGN KEY (entity_id) + REFERENCES guacamole_entity (entity_id) ON DELETE CASCADE + +); + +CREATE INDEX guacamole_user_permission_affected_user_id + ON guacamole_user_permission(affected_user_id); + +CREATE INDEX guacamole_user_permission_entity_id + ON guacamole_user_permission(entity_id); + +-- +-- Table of user group permissions. Each user group permission grants a user +-- or user group access to a another user group (the "affected" user group) for +-- a specific type of operation. +-- + +CREATE TABLE guacamole_user_group_permission ( + + entity_id integer NOT NULL, + affected_user_group_id integer NOT NULL, + permission guacamole_object_permission_type NOT NULL, + + PRIMARY KEY (entity_id, affected_user_group_id, permission), + + CONSTRAINT guacamole_user_group_permission_affected_user_group + FOREIGN KEY (affected_user_group_id) + REFERENCES guacamole_user_group (user_group_id) ON DELETE CASCADE, + + CONSTRAINT guacamole_user_group_permission_entity + FOREIGN KEY (entity_id) + REFERENCES guacamole_entity (entity_id) ON DELETE CASCADE + +); + +CREATE INDEX guacamole_user_group_permission_affected_user_group_id + ON guacamole_user_group_permission(affected_user_group_id); + +CREATE INDEX guacamole_user_group_permission_entity_id + ON guacamole_user_group_permission(entity_id); + +-- +-- Table of connection history records. Each record defines a specific user's +-- session, including the connection used, the start time, and the end time +-- (if any). +-- + +CREATE TABLE guacamole_connection_history ( + + history_id serial NOT NULL, + user_id integer DEFAULT NULL, + username varchar(128) NOT NULL, + remote_host varchar(256) DEFAULT NULL, + connection_id integer DEFAULT NULL, + connection_name varchar(128) NOT NULL, + sharing_profile_id integer DEFAULT NULL, + sharing_profile_name varchar(128) DEFAULT NULL, + start_date timestamptz NOT NULL, + end_date timestamptz DEFAULT NULL, + + PRIMARY KEY (history_id), + + CONSTRAINT guacamole_connection_history_ibfk_1 + FOREIGN KEY (user_id) + REFERENCES guacamole_user (user_id) ON DELETE SET NULL, + + CONSTRAINT guacamole_connection_history_ibfk_2 + FOREIGN KEY (connection_id) + REFERENCES guacamole_connection (connection_id) ON DELETE SET NULL, + + CONSTRAINT guacamole_connection_history_ibfk_3 + FOREIGN KEY (sharing_profile_id) + REFERENCES guacamole_sharing_profile (sharing_profile_id) ON DELETE SET NULL + +); + +CREATE INDEX guacamole_connection_history_user_id + ON guacamole_connection_history(user_id); + +CREATE INDEX guacamole_connection_history_connection_id + ON guacamole_connection_history(connection_id); + +CREATE INDEX guacamole_connection_history_sharing_profile_id + ON guacamole_connection_history(sharing_profile_id); + +CREATE INDEX guacamole_connection_history_start_date + ON guacamole_connection_history(start_date); + +CREATE INDEX guacamole_connection_history_end_date + ON guacamole_connection_history(end_date); + +CREATE INDEX guacamole_connection_history_connection_id_start_date + ON guacamole_connection_history(connection_id, start_date); + +-- +-- User login/logout history +-- + +CREATE TABLE guacamole_user_history ( + + history_id serial NOT NULL, + user_id integer DEFAULT NULL, + username varchar(128) NOT NULL, + remote_host varchar(256) DEFAULT NULL, + start_date timestamptz NOT NULL, + end_date timestamptz DEFAULT NULL, + + PRIMARY KEY (history_id), + + CONSTRAINT guacamole_user_history_ibfk_1 + FOREIGN KEY (user_id) + REFERENCES guacamole_user (user_id) ON DELETE SET NULL + +); + +CREATE INDEX guacamole_user_history_user_id + ON guacamole_user_history(user_id); + +CREATE INDEX guacamole_user_history_start_date + ON guacamole_user_history(start_date); + +CREATE INDEX guacamole_user_history_end_date + ON guacamole_user_history(end_date); + +CREATE INDEX guacamole_user_history_user_id_start_date + ON guacamole_user_history(user_id, start_date); + +-- +-- User password history +-- + +CREATE TABLE guacamole_user_password_history ( + + password_history_id serial NOT NULL, + user_id integer NOT NULL, + + -- Salted password + password_hash bytea NOT NULL, + password_salt bytea, + password_date timestamptz NOT NULL, + + PRIMARY KEY (password_history_id), + + CONSTRAINT guacamole_user_password_history_ibfk_1 + FOREIGN KEY (user_id) + REFERENCES guacamole_user (user_id) ON DELETE CASCADE + +); + +CREATE INDEX guacamole_user_password_history_user_id + ON guacamole_user_password_history(user_id); + +-- +-- Licensed to the Apache Software Foundation (ASF) under one +-- or more contributor license agreements. See the NOTICE file +-- distributed with this work for additional information +-- regarding copyright ownership. The ASF licenses this file +-- to you under the Apache License, Version 2.0 (the +-- "License"); you may not use this file except in compliance +-- with the License. You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, +-- software distributed under the License is distributed on an +-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +-- KIND, either express or implied. See the License for the +-- specific language governing permissions and limitations +-- under the License. +-- + +-- Create default user "guacadmin" with password "guacadmin" +INSERT INTO guacamole_entity (name, type) VALUES ('guacadmin', 'USER'); +INSERT INTO guacamole_user (entity_id, password_hash, password_salt, password_date) +SELECT + entity_id, + decode('CA458A7D494E3BE824F5E1E175A1556C0F8EEF2C2D7DF3633BEC4A29C4411960', 'hex'), -- 'guacadmin' + decode('FE24ADC5E11E2B25288D1704ABE67A79E342ECC26064CE69C5B3177795A82264', 'hex'), + CURRENT_TIMESTAMP +FROM guacamole_entity WHERE name = 'guacadmin' AND guacamole_entity.type = 'USER'; + +-- Grant this user all system permissions +INSERT INTO guacamole_system_permission (entity_id, permission) +SELECT entity_id, permission::guacamole_system_permission_type +FROM ( + VALUES + ('guacadmin', 'CREATE_CONNECTION'), + ('guacadmin', 'CREATE_CONNECTION_GROUP'), + ('guacadmin', 'CREATE_SHARING_PROFILE'), + ('guacadmin', 'CREATE_USER'), + ('guacadmin', 'CREATE_USER_GROUP'), + ('guacadmin', 'ADMINISTER') +) permissions (username, permission) +JOIN guacamole_entity ON permissions.username = guacamole_entity.name AND guacamole_entity.type = 'USER'; + +-- Grant admin permission to read/update/administer self +INSERT INTO guacamole_user_permission (entity_id, affected_user_id, permission) +SELECT guacamole_entity.entity_id, guacamole_user.user_id, permission::guacamole_object_permission_type +FROM ( + VALUES + ('guacadmin', 'guacadmin', 'READ'), + ('guacadmin', 'guacadmin', 'UPDATE'), + ('guacadmin', 'guacadmin', 'ADMINISTER') +) permissions (username, affected_username, permission) +JOIN guacamole_entity ON permissions.username = guacamole_entity.name AND guacamole_entity.type = 'USER' +JOIN guacamole_entity affected ON permissions.affected_username = affected.name AND guacamole_entity.type = 'USER' +JOIN guacamole_user ON guacamole_user.entity_id = affected.entity_id; diff --git a/letsencrypt-nginx-build.sh b/letsencrypt-nginx-build.sh new file mode 100644 index 0000000..fe5d854 --- /dev/null +++ b/letsencrypt-nginx-build.sh @@ -0,0 +1,2 @@ +docker build letsencrypt-nginx -t ${LOCAL_DOCKER_REGISTRY}/letsencrypt-nginx +docker push ${LOCAL_DOCKER_REGISTRY}/letsencrypt-nginx diff --git a/letsencrypt-nginx/Dockerfile b/letsencrypt-nginx/Dockerfile new file mode 100644 index 0000000..ab969c5 --- /dev/null +++ b/letsencrypt-nginx/Dockerfile @@ -0,0 +1,3 @@ +FROM staticfloat/nginx-certbot +COPY run.sh / +CMD sh /run.sh \ No newline at end of file diff --git a/letsencrypt-nginx/Dockerfile.blog b/letsencrypt-nginx/Dockerfile.blog new file mode 100644 index 0000000..57377f8 --- /dev/null +++ b/letsencrypt-nginx/Dockerfile.blog @@ -0,0 +1,3 @@ +ARG image +FROM $image +COPY ./conf/blog.conf /etc/nginx/user.conf.d/server._conf \ No newline at end of file diff --git a/letsencrypt-nginx/Dockerfile.chat b/letsencrypt-nginx/Dockerfile.chat new file mode 100644 index 0000000..f16a835 --- /dev/null +++ b/letsencrypt-nginx/Dockerfile.chat @@ -0,0 +1,3 @@ +ARG image +FROM $image +COPY ./conf/chat.conf /etc/nginx/user.conf.d/server._conf \ No newline at end of file diff --git a/letsencrypt-nginx/Dockerfile.drone b/letsencrypt-nginx/Dockerfile.drone new file mode 100644 index 0000000..f2bfba8 --- /dev/null +++ b/letsencrypt-nginx/Dockerfile.drone @@ -0,0 +1,3 @@ +ARG image +FROM $image +COPY ./conf/drone.conf /etc/nginx/user.conf.d/server._conf \ No newline at end of file diff --git a/letsencrypt-nginx/Dockerfile.git b/letsencrypt-nginx/Dockerfile.git new file mode 100644 index 0000000..4e9cadc --- /dev/null +++ b/letsencrypt-nginx/Dockerfile.git @@ -0,0 +1,3 @@ +ARG image +FROM $image +COPY ./conf/git.conf /etc/nginx/user.conf.d/server._conf \ No newline at end of file diff --git a/letsencrypt-nginx/Dockerfile.remote b/letsencrypt-nginx/Dockerfile.remote new file mode 100644 index 0000000..a8d7475 --- /dev/null +++ b/letsencrypt-nginx/Dockerfile.remote @@ -0,0 +1,3 @@ +ARG image +FROM $image +COPY ./conf/remote.conf /etc/nginx/user.conf.d/server._conf \ No newline at end of file diff --git a/letsencrypt-nginx/build.sh b/letsencrypt-nginx/build.sh new file mode 100644 index 0000000..acb45db --- /dev/null +++ b/letsencrypt-nginx/build.sh @@ -0,0 +1,3 @@ +set -e +docker build . -f Dockerfile.$1 --build-arg image=$2/letsencrypt-nginx -t $2/letsencrypt-$1 +docker push $2/letsencrypt-$1 diff --git a/letsencrypt-nginx/conf/blog.conf b/letsencrypt-nginx/conf/blog.conf new file mode 100644 index 0000000..d703a7e --- /dev/null +++ b/letsencrypt-nginx/conf/blog.conf @@ -0,0 +1,46 @@ + + server { + # resolver 127.0.0.11 valid=30s; ## internal docker dns + #listen [::]:3011 default ipv6only=on; ## listen for ipv6 + listen 80; + client_header_timeout 120s; + client_body_timeout 120s; + client_max_body_size 200m; + + # save logs here + + server_name ${SERVER_NAME}; + + + location / { + return 301 https://${DOLLAR}host${DOLLAR}request_uri; + } + } + + server { + # resolver 127.0.0.11 valid=30s; ## internal docker dns + #listen [::]:3011 default ipv6only=on; ## listen for ipv6 + # listen 444 + listen 443 ssl; + # this should allow large docs + client_header_timeout 120s; + client_body_timeout 120s; + client_max_body_size 200m; + ssl_certificate /etc/letsencrypt/live/${SERVER_NAME}/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/${SERVER_NAME}/privkey.pem; + # save logs here + #access_log /var/log/nginx/access.log compression; + + server_name ${SERVER_NAME}; + + location / { + proxy_set_header Host ${DOLLAR}http_host; + proxy_set_header X-Real-IP ${DOLLAR}remote_addr; + proxy_set_header X-Forwarded-For ${DOLLAR}proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto ${DOLLAR}scheme; + proxy_buffering off; + proxy_pass ${PROXY_PASS}; + } + + } + diff --git a/letsencrypt-nginx/conf/chat.conf b/letsencrypt-nginx/conf/chat.conf new file mode 100644 index 0000000..dd2bfc8 --- /dev/null +++ b/letsencrypt-nginx/conf/chat.conf @@ -0,0 +1,56 @@ + +server { + # resolver 127.0.0.11 valid=30s; ## internal docker dns + #listen [::]:3011 default ipv6only=on; ## listen for ipv6 + listen 80; + client_header_timeout 120s; + client_body_timeout 120s; + client_max_body_size 200m; + + # save logs here + + server_name ${SERVER_NAME}; + + + location / { + return 301 https://${DOLLAR}host${DOLLAR}request_uri; + } + } + server { + # resolver 127.0.0.11 valid=30s; ## internal docker dns + #listen [::]:3011 default ipv6only=on; ## listen for ipv6 + # listen on port 80 + # listen 443 + listen 443 ssl; + # this should allow large docs + client_header_timeout 120s; + client_body_timeout 120s; + client_max_body_size 200m; + ssl_certificate /etc/letsencrypt/live/${SERVER_NAME}/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/${SERVER_NAME}/privkey.pem; + # save logs here + #access_log /var/log/nginx/access.log compression; + + server_name ${SERVER_NAME}; + + location /sockjs { + proxy_pass ${PROXY_PASS}sockjs; + proxy_http_version 1.1; + proxy_set_header Upgrade ${DOLLAR}http_upgrade; + proxy_set_header Connection "Upgrade"; + proxy_set_header Host ${DOLLAR}host; + } + location /sockjs/ { + proxy_pass ${PROXY_PASS}sockjs/; + proxy_http_version 1.1; + proxy_set_header Upgrade ${DOLLAR}http_upgrade; + proxy_set_header Connection "Upgrade"; + proxy_set_header Host ${DOLLAR}host; + } + location / { + proxy_pass ${PROXY_PASS}; + } + } + + + diff --git a/letsencrypt-nginx/conf/drone.conf b/letsencrypt-nginx/conf/drone.conf new file mode 100644 index 0000000..13918e9 --- /dev/null +++ b/letsencrypt-nginx/conf/drone.conf @@ -0,0 +1,40 @@ + + server { + # resolver 127.0.0.11 valid=30s; ## internal docker dns + #listen [::]:3011 default ipv6only=on; ## listen for ipv6 + listen 80; + client_header_timeout 120s; + client_body_timeout 120s; + client_max_body_size 200m; + + # save logs here + + server_name ${SERVER_NAME}; + + + location / { + return 301 https://${DOLLAR}host${DOLLAR}request_uri; + } + } + + server { + # resolver 127.0.0.11 valid=30s; ## internal docker dns + #listen [::]:3011 default ipv6only=on; ## listen for ipv6 + # listen 444 + listen 443 ssl; + # this should allow large docs + client_header_timeout 120s; + client_body_timeout 120s; + client_max_body_size 200m; + ssl_certificate /etc/letsencrypt/live/${SERVER_NAME}/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/${SERVER_NAME}/privkey.pem; + # save logs here + #access_log /var/log/nginx/access.log compression; + + server_name ${SERVER_NAME}; + + location / { + proxy_pass ${PROXY_PASS} ; + } + } + diff --git a/letsencrypt-nginx/conf/git.conf b/letsencrypt-nginx/conf/git.conf new file mode 100644 index 0000000..3486818 --- /dev/null +++ b/letsencrypt-nginx/conf/git.conf @@ -0,0 +1,109 @@ + + server { + # resolver 127.0.0.11 valid=30s; ## internal docker dns + #listen [::]:3011 default ipv6only=on; ## listen for ipv6 + listen 80; + client_header_timeout 120s; + client_body_timeout 120s; + client_max_body_size 200m; + + # save logs here + + server_name ${SERVER_NAME}; + + + location / { + return 301 https://${DOLLAR}host${DOLLAR}request_uri; + } + } + + server { + # resolver 127.0.0.11 valid=30s; ## internal docker dns + #listen [::]:3011 default ipv6only=on; ## listen for ipv6 + # listen 444 + listen 5000 ssl; + # this should allow large docs + client_header_timeout 120s; + client_body_timeout 120s; + client_max_body_size 200m; + ssl_certificate /etc/letsencrypt/live/${SERVER_NAME}/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/${SERVER_NAME}/privkey.pem; + # save logs here + #access_log /var/log/nginx/access.log compression; + + server_name ${SERVER_NAME}; + + location / { + proxy_pass http://drone-server:8080/; + } + } + server { + # resolver 127.0.0.11 valid=30s; ## internal docker dns + #listen [::]:3011 default ipv6only=on; ## listen for ipv6 + # listen 444 + listen 443 ssl; + # this should allow large docs + client_header_timeout 120s; + client_body_timeout 120s; + client_max_body_size 200m; + ssl_certificate /etc/letsencrypt/live/${SERVER_NAME}/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/${SERVER_NAME}/privkey.pem; + # save logs here + #access_log /var/log/nginx/access.log compression; + + server_name ${SERVER_NAME}; + + location ${LOCATION} { + proxy_pass ${PROXY_PASS}; + } + location ${BLOG_LOCATION} { + proxy_set_header Host ${DOLLAR}http_host; + proxy_set_header X-Real-IP ${DOLLAR}remote_addr; + proxy_set_header X-Forwarded-For ${DOLLAR}proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto ${DOLLAR}scheme; + proxy_buffering off; + proxy_pass ${BLOG_PROXY_PASS}; + } + + location ${CHAT_LOCATION}sockjs { + proxy_pass ${CHAT_PROXY_PASS}/chat/sockjs; + proxy_http_version 1.1; + proxy_set_header Upgrade ${DOLLAR}http_upgrade; + proxy_set_header Connection "Upgrade"; + proxy_set_header Host ${DOLLAR}host; + proxy_set_header X-Real-IP ${DOLLAR}remote_addr; + proxy_set_header X-Forwarded-For ${DOLLAR}proxy_add_x_forwarded_for; + proxy_set_header X-Forward-Proto http; + proxy_set_header X-Nginx-Proxy true; + proxy_redirect off; + + } + location ${CHAT_LOCATION}sockjs/ { + proxy_pass ${CHAT_PROXY_PASS}/chat/sockjs/; + proxy_http_version 1.1; + proxy_set_header Upgrade ${DOLLAR}http_upgrade; + proxy_set_header Connection "Upgrade"; + proxy_set_header Host ${DOLLAR}host; + proxy_set_header X-Real-IP ${DOLLAR}remote_addr; + proxy_set_header X-Forwarded-For ${DOLLAR}proxy_add_x_forwarded_for; + proxy_set_header X-Forward-Proto http; + proxy_set_header X-Nginx-Proxy true; + proxy_redirect off; + + + } + location ${CHAT_LOCATION} { + proxy_pass ${CHAT_PROXY_PASS}; + proxy_http_version 1.1; + proxy_set_header Upgrade ${DOLLAR}http_upgrade; + proxy_set_header Connection "upgrade"; + proxy_set_header Host ${DOLLAR}http_host; + proxy_set_header X-Real-IP ${DOLLAR}remote_addr; + proxy_set_header X-Forwarded-For ${DOLLAR}proxy_add_x_forwarded_for; + proxy_set_header X-Forward-Proto http; + proxy_set_header X-Nginx-Proxy true; + proxy_redirect off; + + } + } + diff --git a/letsencrypt-nginx/conf/remote.conf b/letsencrypt-nginx/conf/remote.conf new file mode 100644 index 0000000..36bf254 --- /dev/null +++ b/letsencrypt-nginx/conf/remote.conf @@ -0,0 +1,49 @@ + +server { + # resolver 127.0.0.11 valid=30s; ## internal docker dns + #listen [::]:3011 default ipv6only=on; ## listen for ipv6 + listen 80; + client_header_timeout 120s; + client_body_timeout 120s; + client_max_body_size 200m; + + # save logs here + + server_name ${SERVER_NAME}; + + + location / { + return 301 https://${DOLLAR}host${DOLLAR}request_uri; + } + } + server { + # resolver 127.0.0.11 valid=30s; ## internal docker dns + #listen [::]:3011 default ipv6only=on; ## listen for ipv6 + # listen on port 80 + # listen 443 + listen 443 ssl; + # this should allow large docs + client_header_timeout 120s; + client_body_timeout 120s; + client_max_body_size 200m; + ssl_certificate /etc/letsencrypt/live/${SERVER_NAME}/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/${SERVER_NAME}/privkey.pem; + # save logs here + #access_log /var/log/nginx/access.log compression; + + server_name ${SERVER_NAME}; + + location /websocket-tunnel { + proxy_pass ${PROXY_PASS}websocket-tunnel; + proxy_http_version 1.1; + proxy_set_header Upgrade ${DOLLAR}http_upgrade; + proxy_set_header Connection "Upgrade"; + proxy_set_header Host ${DOLLAR}host; + } + location / { + proxy_pass ${PROXY_PASS}; + } + } + + + diff --git a/letsencrypt-nginx/result b/letsencrypt-nginx/result new file mode 100644 index 0000000..1cbb8b2 --- /dev/null +++ b/letsencrypt-nginx/result @@ -0,0 +1,78 @@ + + server { + # resolver 127.0.0.11 valid=30s; ## internal docker dns + #listen [::]:3011 default ipv6only=on; ## listen for ipv6 + listen 80; + client_header_timeout 120s; + client_body_timeout 120s; + client_max_body_size 200m; + + # save logs here + + server_name sigyl.com; + + + location / { + return 301 https://$host$request_uri; + } + } + + server { + # resolver 127.0.0.11 valid=30s; ## internal docker dns + #listen [::]:3011 default ipv6only=on; ## listen for ipv6 + # listen 444 + listen 443 ssl; + # this should allow large docs + client_header_timeout 120s; + client_body_timeout 120s; + client_max_body_size 200m; + ssl_certificate /etc/letsencrypt/live/sigyl.com/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/sigyl.com/privkey.pem; + # save logs here + #access_log /var/log/nginx/access.log compression; + + server_name sigyl.com; + + location /git/ { + proxy_pass http://gitea:3000/; + } + location /blog/ { + proxy_set_header Host $http_host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_buffering off; + proxy_pass http://ghost:2368; + } + + location /chat/sockjs { + proxy_pass http://chat:3000sockjs; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "Upgrade"; + proxy_set_header Host $host; + } + location /chat/sockjs/ { + proxy_pass http://chat:3000sockjs/; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "Upgrade"; + proxy_set_header Host $host; + } + location /chat/ { + proxy_pass http://chat:3000; + proxy_http_version 1.1; +proxy_set_header Upgrade $http_upgrade; +proxy_set_header Connection "upgrade"; +proxy_set_header Host $http_host; +proxy_set_header X-Real-IP $remote_addr; +proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; +proxy_set_header X-Forward-Proto http; +proxy_set_header X-Nginx-Proxy true; +proxy_redirect off; + + } + } + +templating scripts from /etc/nginx/user.conf.d to /etc/nginx/conf.d +Substituting variables diff --git a/letsencrypt-nginx/run.sh b/letsencrypt-nginx/run.sh new file mode 100644 index 0000000..e9764af --- /dev/null +++ b/letsencrypt-nginx/run.sh @@ -0,0 +1,4 @@ +export DOLLAR='$' +envsubst < /etc/nginx/user.conf.d/server._conf > /etc/nginx/user.conf.d/server.conf +cat /etc/nginx/user.conf.d/server.conf +/bin/bash /scripts/entrypoint.sh \ No newline at end of file diff --git a/ngrok-build.sh b/ngrok-build.sh new file mode 100644 index 0000000..eefa9df --- /dev/null +++ b/ngrok-build.sh @@ -0,0 +1,2 @@ +docker build ngrok2 -t ${LOCAL_DOCKER_REGISTRY}/ngrok-gitea +docker push ${LOCAL_DOCKER_REGISTRY}/ngrok-gitea \ No newline at end of file diff --git a/ngrok2/Dockerfile b/ngrok2/Dockerfile new file mode 100644 index 0000000..4518a14 --- /dev/null +++ b/ngrok2/Dockerfile @@ -0,0 +1,5 @@ +FROM wernight/ngrok +COPY run.sh / +USER root +RUN apk add gettext # enables envsubst +CMD sh /run.sh \ No newline at end of file diff --git a/ngrok2/ngrok._yml b/ngrok2/ngrok._yml new file mode 100644 index 0000000..09c69ee --- /dev/null +++ b/ngrok2/ngrok._yml @@ -0,0 +1,41 @@ +web_addr: 0.0.0.0:4040 +update: false +log: stdout +region: eu +tunnels: + gitea: + addr: letsencrypt-git:80 + proto: http + hostname: ${GIT_DOMAIN} + bind-tls: false + gitea-tls: + addr: letsencrypt-git:443 + proto: tls + hostname: ${GIT_DOMAIN} + drone: + addr: letsencrypt-drone:80 + proto: http + hostname: ${DRONE_DOMAIN} + bind_tls: false + drone-tls: + addr: letsencrypt-drone:443 + proto: tls + hostname: ${DRONE_DOMAIN} + #blog: + # addr: letsencrypt-blog:80 + # proto: http + # hostname: ${BLOG_DOMAIN} + # bind-tls: false + #blog-tls: + # addr: letsencrypt-blog:443 + # proto: tls + # hostname: ${BLOG_DOMAIN} + #chat: + # addr: letsencrypt-chat:80 + # proto: http + # hostname: ${CHAT_DOMAIN} + # bind_tls: false + #chat-tls: + # addr: letsencrypt-chat:443 + # proto: tls + # hostname: ${CHAT_DOMAIN} \ No newline at end of file diff --git a/ngrok2/ngrok.m._yml b/ngrok2/ngrok.m._yml new file mode 100644 index 0000000..bd6bb99 --- /dev/null +++ b/ngrok2/ngrok.m._yml @@ -0,0 +1,24 @@ +web_addr: 0.0.0.0:4040 +update: false +log: stdout +region: eu +tunnels: + drone: + addr: letsencrypt-drone:80 + proto: http + hostname: ${DRONE_DOMAIN} + bind_tls: false + drone-tls: + addr: letsencrypt-drone:443 + proto: tls + hostname: ${DRONE_DOMAIN} + remote: + addr: letsencrypt-remote:80 + proto: http + hostname: ${REMOTE_DOMAIN} + bind-tls: false + remote-tls: + addr: letsencrypt-remote:443 + proto: tls + hostname: ${REMOTE_DOMAIN} + \ No newline at end of file diff --git a/ngrok2/run.sh b/ngrok2/run.sh new file mode 100644 index 0000000..8991e4c --- /dev/null +++ b/ngrok2/run.sh @@ -0,0 +1,4 @@ +cat /run/secrets/ngrok-auth-token /home/ngrok/.ngrok2/ngrok._yml > /home/ngrok/.ngrok2/ngrok.__yml +envsubst < /home/ngrok/.ngrok2/ngrok.__yml > /home/ngrok/.ngrok2/ngrok.yml +ngrok start --all --config /home/ngrok/.ngrok2/ngrok.yml + diff --git a/postgres-build.sh b/postgres-build.sh new file mode 100644 index 0000000..683f849 --- /dev/null +++ b/postgres-build.sh @@ -0,0 +1,2 @@ +docker build guacamole-postgresql -t ${LOCAL_DOCKER_REGISTRY}/guacamole-postgresql +docker push ${LOCAL_DOCKER_REGISTRY}/guacamole-postgresql \ No newline at end of file