diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..41d2299 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,7 @@ +name: Build +on: pull_request +jobs: + build: + runs-on: ubuntu-22.04 + steps: + - uses: AvadoDServer/ci-build-action@main diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..bad24b8 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,12 @@ +name: Release +on: + push: + branches: + - master +jobs: + release: + runs-on: ubuntu-22.04 + steps: + - uses: AvadoDServer/ci-release-action@main + with: + rpcToken: ${{ secrets.RPC_TOKEN }} diff --git a/.gitignore b/.gitignore index 2bd624b..c561709 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ build_* +releases.json diff --git a/README.md b/README.md new file mode 100644 index 0000000..0ec5c9f --- /dev/null +++ b/README.md @@ -0,0 +1,78 @@ +# AVADO Ethereum Node (Geth) + +## Prerequisites + + - A WiFi or VPN connection to your AVADO box + - IPFS client installed (optional) + +## Installation + +AVADO uses the AVADO SDK to build packages. + +`npm i -g https://github.com/AvadoDServer/AVADOSDK.git` + +## Testing locally + +you can modify the Dockerfile in the `build` folder and test it locally using `docker-compose build` and `docker-compose up` until it works as expected. + +## Building + +`avadosdk build` will build the package and upload to your AVADO box's IPFS server. + +it will output the IPFS hash that you can use in your package + +` Manifest hash : /ipfs/QmNf8sEHdzD5EbBDxd3HBFpq5zBW2PziJ4vqfa8G7xgVJm` + +## Installing and testing + +Go to your avado DappStore page at http://my.avado/#/installer + +enter the above hash in the input field and press enter. + +You will see the package detail screen - where you can install the package on your box and test it out. + +## Renaming your package + +You want to change the package name you need to change the package name in the following locations +`dappnode_package.json` --> modify the `name` field. +`docker-compose.yml` --> modify the `service` name and the `image` field accordingly. + +## Publishing + +You can distribute the IPFS hash of your package to other AVADO users without requiring anyone's permission - or if you want to have your package added to the DappStore - contact the AVADO team in the Telegram chat. + +## Some random tips + +- the docker-compose file creates a mount point `/data` where you can store data that has to be saved on a seperate volume to be retained after a package restart. +- you can bump the package version number using `avadosdk increase patch` +- upon installing - the AVADO will create a DNS entry called `my.` that resolvves to the docker container's IP address. This is convenient if you want to open a web UI from the package. If you install this package - the hostname `my.avado-dnp-template.public.dappnode.eth` will resolve to its IP address. +- in the AVADO repo - there are several packages published that you can take a look at to get inspired on how to fiddle with parameters. +- The installer currently requires that there is only one docker image per package. So you need to put all your stuff in one container. +- If you change the avatar.png image (needs to be 300x300 pixels) - you need to first upload it to IPFS using the command `ipfs add avatar.png --api /ip4/80.208.229.228/tcp/5001` and put the resulting IPFS hash in the field `avatar` in `dappnode_package.json`. +- If you want to publish for others to use - feel free to use our IPFS node to upload your package to: `avadosdk build --provider http://80.208.229.228:5001` + + +## update flow & tagging your repo + +This is a suggested flow to upgrade your package when you want to release a new version: + +``` +avadosdk increase patch +avadosdk build --provider http://80.208.229.228:5001 +git add dappnode_package.json docker-compose.yml releases.json +git commit -m"new release" +git push +npx release-it +``` + + + + + + + + + + + + diff --git a/avatar.png b/avatar.png new file mode 100644 index 0000000..9a3d804 Binary files /dev/null and b/avatar.png differ diff --git a/build/Dockerfile b/build/Dockerfile index 0f11e46..4c03bf8 100644 --- a/build/Dockerfile +++ b/build/Dockerfile @@ -1,19 +1,30 @@ -# Build Geth in a stock Go builder container -FROM golang:1.11-alpine as builder +FROM --platform=linux/amd64 ethereum/client-go:v1.13.1 as geth -WORKDIR /usr/src/app +RUN apk update && apk add --no-cache \ + bash \ + ca-certificates \ + curl \ + lsb-release \ + nginx \ + openssl \ + supervisor \ + && rm -rf /var/cache/apk/* && rm -rf /tmp/* -RUN apk add --no-cache make gcc musl-dev linux-headers git jq +# Set up nginx config +RUN mkdir -p /etc/nginx/certs/ +WORKDIR /etc/nginx/certs/ +ADD "https://www.random.org/cgi-bin/randbyte?nbytes=10&format=h" skipcache +RUN wget http://iso.ava.do/my.ava.do.crt && wget http://iso.ava.do/my.ava.do.key -ARG COMMIT=cfbb969da803d4cc92e1a64fc1b3c06db299b564 +RUN ls -l /etc/nginx/certs/ +COPY files/nginx.conf /etc/nginx +RUN mkdir -p /run/nginx -RUN git clone https://github.com/ethereum/go-ethereum.git -RUN cd go-ethereum && git checkout $COMMIT && make geth +COPY ./files/supervisord.conf /etc/supervisord.conf -# Pull Geth into a second stage deploy alpine container -FROM alpine:latest +# Startup script +COPY ./files/start.sh /opt/start.sh +COPY ./files/reload-certs.sh /opt/reload-certs.sh +RUN chmod +x /opt/start.sh /opt/reload-certs.sh -RUN apk add --no-cache ca-certificates -COPY --from=builder /usr/src/app/go-ethereum/build/bin/geth /usr/local/bin/ - -ENTRYPOINT geth --datadir /root/.ethereum/ethchain-geth --rpc --rpcaddr 0.0.0.0 --rpccorsdomain "*" --rpcvhosts "*" --ws --wsorigins "*" --wsaddr 0.0.0.0 $EXTRA_OPTS +ENTRYPOINT ["/opt/start.sh"] diff --git a/build/files/nginx.conf b/build/files/nginx.conf new file mode 100644 index 0000000..f441ed9 --- /dev/null +++ b/build/files/nginx.conf @@ -0,0 +1,71 @@ +worker_processes 2; + +events { + worker_connections 1024; +} + +http { + include mime.types; + default_type application/octet-stream; + +# sendfile on; + + keepalive_timeout 65; + + gzip on; + gzip_static on; + gzip_disable "msie6"; + + gzip_vary on; + gzip_types text/plain text/css application/javascript; + + server { + listen 443 ssl; + server_name ethchain-geth.my.ava.do; + + ssl_certificate /etc/nginx/certs/my.ava.do.crt; + ssl_certificate_key /etc/nginx/certs/my.ava.do.key; + + location / { + if ($request_method = 'OPTIONS') { + add_header 'Access-Control-Allow-Origin' '*'; + add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS'; + # + # Custom headers and headers various browsers *should* be OK with but aren't + # + add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range'; + # + # Tell client that this pre-flight info is valid for 20 days + # + add_header 'Access-Control-Max-Age' 1728000; + add_header 'Content-Type' 'text/plain; charset=utf-8'; + add_header 'Content-Length' 0; + return 204; + } + if ($request_method = 'POST') { + add_header 'Access-Control-Allow-Origin' '*'; + add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS'; + add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range'; + add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range'; + } + if ($request_method = 'GET') { + add_header 'Access-Control-Allow-Origin' '*'; + add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS'; + add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range'; + add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range'; + } + + proxy_set_header Host $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; + + # Fix the “It appears that your reverse proxy set up is broken" error. + proxy_pass http://localhost:8545; + proxy_read_timeout 90; + } + + root /usr/share/nginx/wizard; + } + +} \ No newline at end of file diff --git a/build/files/reload-certs.sh b/build/files/reload-certs.sh new file mode 100644 index 0000000..7c37c33 --- /dev/null +++ b/build/files/reload-certs.sh @@ -0,0 +1,21 @@ +#!/bin/sh +while true; do + date > /tmp/reload-certs.txt + + echo "Check for updated certificates" + + md5sumbefore=$(md5sum "/etc/nginx/certs/my.ava.do.crt") + wget -q -O /etc/nginx/certs/my.ava.do.crt "http://dappmanager.my.ava.do/my.ava.do.crt" + wget -q -O /etc/nginx/certs/my.ava.do.key "http://dappmanager.my.ava.do/my.ava.do.key" + md5sumafter=$(md5sum "/etc/nginx/certs/my.ava.do.crt") + + if [ "$md5sumbefore" != "$md5sumafter" ]; then + if [ -e /var/run/nginx/nginx.pid ]; then + echo "Reload nginx" + nginx -s reload + fi + fi + + #sleep one day + sleep 86400 +done diff --git a/build/files/start.sh b/build/files/start.sh new file mode 100644 index 0000000..5a1f5e7 --- /dev/null +++ b/build/files/start.sh @@ -0,0 +1,40 @@ +#!/bin/sh + +# Older installations use the deprecated option "--rpcapi" so replace it by "--http.api" +export EXTRA_OPTS_PARSED=$(echo -n $EXTRA_OPTS | sed s/--rpcapi/--http\.api/g) + +# Get JWT Token +JWT_TOKEN="/root/.ethereum/ethchain-geth/geth/jwttoken" +mkdir -p $(dirname ${JWT_TOKEN}) +until $(curl --silent --fail "http://dappmanager.my.ava.do/jwttoken.txt" --output "${JWT_TOKEN}"); do + echo "Waiting for the JWT Token" + sleep 5 +done + +export GETH_CMD="/usr/local/bin/geth \ + --datadir /root/.ethereum/ethchain-geth\ + --mainnet \ + --http \ + --http.addr=\"0.0.0.0\" \ + --http.corsdomain=\"*\" \ + --http.vhosts=\"*\" \ + --ws \ + --ws.origins=\"*\" \ + --ws.addr=\"0.0.0.0\" \ + --authrpc.vhosts=\"*\" \ + --authrpc.addr=\"0.0.0.0\" \ + --authrpc.port=\"8551\" \ + --authrpc.jwtsecret=\"${JWT_TOKEN}\" \ + --rpc.gascap 0 \ + --cache 4096 \ + ${EXTRA_OPTS_PARSED}" + +echo "EXTRA_OPTS=$EXTRA_OPTS_PARSED" +echo "GETH_CMD=$GETH_CMD" + +# Print version to the log +/usr/local/bin/geth version + +# Start supervisor +# (using exec: https://madflojo.medium.com/shutdown-signals-with-docker-entry-point-scripts-5e560f4e2d45) +exec /usr/bin/supervisord -c /etc/supervisord.conf diff --git a/build/files/supervisord.conf b/build/files/supervisord.conf new file mode 100644 index 0000000..103389a --- /dev/null +++ b/build/files/supervisord.conf @@ -0,0 +1,42 @@ +[unix_http_server] +file=/dev/shm/supervisor.sock +chmod=0700 + +[supervisord] +nodaemon=true +user=root + +[supervisorctl] + +[rpcinterface:supervisor] +supervisor.rpcinterface_factory=supervisor.rpcinterface:make_main_rpcinterface + +[supervisorctl] +serverurl=unix:///dev/shm/supervisor.sock + +[program:geth] +command=%(ENV_GETH_CMD)s +autostart=true +stdout_logfile=/dev/stdout +stdout_logfile_maxbytes=0 +stderr_logfile=/dev/stderr +stderr_logfile_maxbytes=0 +killasgroup=true +stopasgroup=true +stopwaitsecs=120 + +[program:nginx] +command=nginx -c /etc/nginx/nginx.conf -g "daemon off;" +autostart=true +stdout_logfile=/dev/stdout +stdout_logfile_maxbytes=0 +stderr_logfile=/dev/stderr +stderr_logfile_maxbytes=0 + +[program:reload-certs] +command=/opt/reload-certs.sh +autostart=true +stdout_logfile=/dev/stdout +stdout_logfile_maxbytes=0 +stderr_logfile=/dev/stderr +stderr_logfile_maxbytes=0 diff --git a/dappnode_package.json b/dappnode_package.json index 2a97c86..c0c6bcb 100644 --- a/dappnode_package.json +++ b/dappnode_package.json @@ -1,30 +1,32 @@ { "name": "ethchain-geth.public.dappnode.eth", - "version": "0.0.3", - "description": "Mainnet Geth", - "avatar": "/ipfs/QmTfnrUdZWaMgr2Zi1h1Z7zS5CbYtQZRs72yqKZQHj5fxT", + "version": "10.0.57", + "upstream": "v1.13.1", + "autoupdate": true, + "title": "Ethereum node (Geth + mainnet)", + "description": "Ethereum Client - based on Geth", + "avatar": "/ipfs/QmVQUEapZGZ7tWfDWP4XUQBxCe2rLbdPJLXu3QaLiPp542", "type": "library", "chain": "ethereum", "image": { - "path": "ethchain-geth.public.dappnode.eth_0.0.3.tar.xz", - "hash": "/ipfs/QmdQF3arvXiEkJ8DSR1auzCqxyhpmv1fGL1acTBQYyZvfr", - "size": 16184810, "restart": "always", "ports": [ - "61313:30303", - "61313:30303/udp", - "61314:30304" + "30303:30303", + "30303:30303/udp" ], "volumes": [ "ethchain-geth:/root/.ethereum/ethchain-geth" ], "environment": [ - "EXTRA_OPTS=--rpcapi eth,net,web3,txpool" + "EXTRA_OPTS=--http.api eth,net,web3,txpool" ] }, - "author": "nanexcool", - "license": "GLP-3.0", + "author": "AVADO", + "license": "(C)", "links": { - "endpoint": "http://my.ethchain-geth.public.dappnode.eth:8545" + "RPC endpoint": "http://ethchain-geth.my.ava.do:8545", + "RPC endpoint (SSL)": "https://ethchain-geth.my.ava.do", + "WS endpoint": "ws://ethchain-geth.my.ava.do:8546", + "EE endpoint (http)": "http://ethchain-geth.my.ava.do:8551" } } \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index 677b6e4..65bef70 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,17 +1,18 @@ version: '3.4' services: ethchain-geth.public.dappnode.eth: - image: 'ethchain-geth.public.dappnode.eth:0.0.3' + image: 'ethchain-geth.public.dappnode.eth:10.0.57' build: ./build volumes: - 'ethchain-geth:/root/.ethereum/ethchain-geth' environment: - EXTRA_OPTS= ports: - - '127.0.0.1:8546:8546' - - '127.0.0.1:8545:8545' - - '61313:30303' - - '61313:30303/udp' - - '61314:30304/udp' + - '443:443' + - '8545:8545' + - '8546:8546' + - '8551:8551' + - '30303:30303' + - '30303:30303/udp' volumes: - ethchain-geth: {} \ No newline at end of file + ethchain-geth: {}