컨텐츠로 건너뛰기

포아봇 구축

포아봇을 구축하기 위한 과정입니다.

Vultr 회원가입
  1. “Products” 를 클릭합니다
  2. “Compute” 를 클릭합니다
  3. “Deploy” 를 클릭합니다
  4. “Deploy New Server” 를 클릭합니다
Vultr 회원가입
  1. “Shared CPU” 를 선택합니다
  2. “Asia” 를 선택합니다
  3. “Seoul” 혹은 “Osaka” 를 선택합니다
  4. “Cloud Compute” 를 선택합니다
  5. “vc2-1c-1gb” 를 선택합니다
  6. “Automatic Backups”“disabled” 합니다
  7. “$5” 인지 확인합니다
  8. “Configure Software” 를 선택합니다
Vultr 회원가입
  1. “Ubuntu 24.04 LTS” 를 선택합니다
Vultr 회원가입
  1. “Public IPv4” 를 선택합니다

  2. “Cloud-Init User-data” 를 선택합니다

  3. ”User Data” 에 아래 포아봇 설치 스크립트를 붙여 넣습니다
    포아봇 설치 스크립트
    #cloud-config
    apt:
    preserve_sources_list: true
    conf: |
    Dpkg::Options {
    "--force-confdef";
    "--force-confold";
    }
    APT::Get::Assume-Yes "true";
    APT::Get::force-yes "true";
    Debian::Frontend "noninteractive";
    package_update: true
    package_upgrade: true
    locale: ko_KR.UTF-8
    timezone: Asia/Seoul
    packages:
    - net-tools
    - unzip
    - chrony
    - ca-certificates
    - curl
    - podman
    - cockpit
    - cockpit-podman
    - gettext
    - libpam-google-authenticator
    write_files:
    - path: /root/poabot.env
    content: |
    # Required
    PASSWORD=""
    DISCORD_WEBHOOK_URL=""
    # Optional
    UPBIT_KEY=""
    UPBIT_SECRET=""
    BITHUMB_KEY=""
    BITHUMB_SECRET=""
    BINANCE_KEY=""
    BINANCE_SECRET=""
    BYBIT_KEY=""
    BYBIT_SECRET=""
    OKX_KEY=""
    OKX_SECRET=""
    OKX_PASSPHRASE=""
    BITGET_KEY=""
    BITGET_SECRET=""
    BITGET_PASSPHRASE=""
    KIS1_KEY=""
    KIS1_SECRET=""
    KIS1_ACCOUNT_NUMBER=""
    KIS1_ACCOUNT_CODE=""
    KIS2_KEY=""
    KIS2_SECRET=""
    KIS2_ACCOUNT_NUMBER=""
    KIS2_ACCOUNT_CODE=""
    KIS3_KEY=""
    KIS3_SECRET=""
    KIS3_ACCOUNT_NUMBER=""
    KIS3_ACCOUNT_CODE=""
    KIS4_KEY=""
    KIS4_SECRET=""
    KIS4_ACCOUNT_NUMBER=""
    KIS4_ACCOUNT_CODE=""
    WHITELIST=[""]
    TIMEZONE="Asia/Seoul"
    - path: /etc/systemd/system/pm2-root.service
    content: |
    [Unit]
    Description=PM2 process manager
    Documentation=https://pm2.keymetrics.io/
    After=network.target
    [Service]
    Type=forking
    User=root
    LimitNOFILE=infinity
    LimitNPROC=infinity
    LimitCORE=infinity
    Environment=PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin
    Environment=PM2_HOME=/root/.pm2
    PIDFile=/root/.pm2/pm2.pid
    Restart=on-failure
    ExecStart=/usr/bin/pm2 resurrect
    ExecReload=/usr/bin/pm2 reload all
    ExecStop=/usr/bin/pm2 kill
    [Install]
    WantedBy=multi-user.target
    - path: /etc/chrony/chrony.conf
    content: |
    confdir /etc/chrony/conf.d
    server time.bora.net iburst
    server time.kornet.net iburst
    server kr.pool.ntp.org iburst
    server 0.asia.pool.ntp.org iburst
    server 1.asia.pool.ntp.org iburst
    server 2.asia.pool.ntp.org iburst
    server 3.asia.pool.ntp.org iburst
    pool ntp.ubuntu.com iburst maxsources 4
    pool 0.ubuntu.pool.ntp.org iburst maxsources 1
    pool 1.ubuntu.pool.ntp.org iburst maxsources 1
    pool 2.ubuntu.pool.ntp.org iburst maxsources 2
    sourcedir /run/chrony-dhcp
    sourcedir /etc/chrony/sources.d
    keyfile /etc/chrony/chrony.keys
    driftfile /var/lib/chrony/chrony.drift
    ntsdumpdir /var/lib/chrony
    maxupdateskew 100.0
    leapsectz right/UTC
    makestep 1.0 3
    rtcsync
    logdir /var/log/chrony
    - path: /etc/containers/registries.conf
    content: |
    unqualified-search-registries = ["docker.io"]
    - path: /usr/local/bin/setup-google-auth
    permissions: "0755"
    content: |
    #!/bin/bash
    if [ ! -f $HOME/.google_authenticator ]; then
    google-authenticator -t -d -f -r 3 -R 30 -w 3
    echo "Two-factor authentication is now set up."
    echo "Setup is complete. Scan the above QR code with the Google Authenticator app."
    echo "Also, please keep the recovery code in a safe place."
    if [[ $EUID -ne 0 ]]; then
    echo "Error: This script must be run with root privileges. (e.g. sudo $0)"
    exit 1
    fi
    PAM_FILE="/etc/pam.d/cockpit"
    AUTH_LINE_APPEND="auth required pam_google_authenticator.so nullok"
    AUTH_LINE_CREATE="auth required pam_google_authenticator.so"
    CHECK_PATTERN="^[[:space:]]*auth.*pam_google_authenticator.so"
    echo "Check $PAM_FILE file..."
    if [ -f "$PAM_FILE" ]; then
    echo "$PAM_FILE file exists."
    if grep -qE "$CHECK_PATTERN" "$PAM_FILE"; then
    echo "Google Authenticator is already set up in '$PAM_FILE' file. No changes will be made."
    else
    echo "Google Authenticator is not set up in '$PAM_FILE' file. Append '$AUTH_LINE_APPEND' to the end of the file."
    if [ -n "$(tail -c1 "$PAM_FILE")" ]; then
    echo "" >> "$PAM_FILE"
    fi
    echo "$AUTH_LINE_APPEND" >> "$PAM_FILE"
    echo "'$AUTH_LINE_APPEND' is added."
    fi
    else
    echo "$PAM_FILE file does not exist. Create a new file."
    echo "$AUTH_LINE_CREATE" > "$PAM_FILE"
    echo "'$AUTH_LINE_CREATE' is added to $PAM_FILE file."
    fi
    systemctl restart cockpit.socket
    else
    echo "Google Authenticator is already set up."
    echo "If you want to reconfigure, remove $HOME/.google_authenticator file first."
    fi
    - path: /usr/local/bin/start-poabot
    permissions: "0755"
    content: |
    #!/bin/bash
    function show_status() {
    echo "$1"
    }
    show_status "poabot ready"
    podman stop -i poabot 2>/dev/null
    show_status "poabot stopped"
    COMMAND="mkdir -p $HOME/logs && chmod -R 777 $HOME/logs && podman run --replace -d -p 8000:8000 -v $HOME/logs:/app/logs --env-file $HOME/poabot.env --restart unless-stopped --name poabot poabot"
    if eval $COMMAND; then
    show_status "poabot started"
    else
    show_status "poabot start failed"
    exit 1
    fi
    - path: /usr/local/bin/stop-poabot
    permissions: "0755"
    content: |
    #!/bin/bash
    podman stop -i poabot 2>/dev/null
    show_status "poabot stopped"
    - path: /etc/systemd/system/caddy.service
    content: |
    [Unit]
    Description=Caddy
    Documentation=https://caddyserver.com/docs/
    After=network.target network-online.target
    Requires=network-online.target
    [Service]
    Type=notify
    User=caddy
    Group=caddy
    ExecStart=/usr/bin/caddy run --environ --config /etc/caddy/Caddyfile
    ExecReload=/usr/bin/caddy reload --config /etc/caddy/Caddyfile --force
    TimeoutStopSec=5s
    LimitNOFILE=1048576
    PrivateTmp=true
    ProtectSystem=full
    AmbientCapabilities=CAP_NET_ADMIN CAP_NET_BIND_SERVICE
    [Install]
    WantedBy=multi-user.target
    - path: /etc/caddy/Caddyfile
    content: |
    :80 {
    @manager {
    path /manager
    path /manager/*
    }
    @poa_whitelist {
    remote_ip 52.89.214.238 34.212.75.30 54.218.53.128 52.32.178.7 127.0.0.1
    }
    redir /manager /manager/
    route {
    handle @manager {
    reverse_proxy localhost:9090
    }
    handle @poa_whitelist {
    reverse_proxy 127.0.0.1:8000
    }
    handle {
    respond 403
    }
    }
    }
    runcmd:
    - export DEBIAN_FRONTEND=noninteractive
    - |
    if command -v ufw > /dev/null; then
    if [ "false" = "true" ]; then
    ufw allow ssh
    else
    ufw delete allow 22/tcp
    ufw delete allow ssh
    fi
    ufw allow 123/udp
    ufw allow https
    ufw allow http
    ufw allow 9090/tcp
    ufw --force enable
    ufw reload
    elif command -v firewall-cmd > /dev/null; then
    if [ "false" = "true" ]; then
    firewall-cmd --permanent --add-service=ssh
    else
    firewall-cmd --permanent --remove-service=ssh
    fi
    firewall-cmd --permanent --add-port=123/udp
    firewall-cmd --permanent --add-service=https
    firewall-cmd --permanent --add-service=http
    firewall-cmd --permanent --add-port=9090/tcp
    firewall-cmd --reload
    fi
    # caddy
    - n=0; while [ $n -lt 5 ] && ! wget "https://github.com/caddyserver/caddy/releases/download/v2.8.4/caddy_2.8.4_linux_amd64.tar.gz"; do echo "Command failed. Retrying in 5 seconds..."; sleep 5; n=$((n+1)); done
    - tar -xf caddy_*_linux_amd64.tar.gz
    - mv caddy /usr/bin/
    - groupadd --system caddy
    - useradd --system --gid caddy --create-home --home-dir /var/lib/caddy --shell /usr/sbin/nologin --comment "Caddy web server" caddy
    - chmod +x /usr/bin/caddy
    - rm -rf caddy_*_linux_amd64.tar.gz
    # NODEJS
    - echo "==removing existing nodejs=="
    - sudo apt-get remove nodejs nodejs-doc libnode* npm -y || echo "Node.js not found, continuing..."
    - sudo apt-get autoremove -y
    - echo "==installing node 20=="
    - curl -fsSL https://deb.nodesource.com/setup_lts.x | sudo -E bash -
    - sudo apt-get update -y --allow-insecure-repositories
    - sudo apt-get install nodejs -y --allow-unauthenticated
    - sudo apt-get install npm -y --allow-unauthenticated
    - node -v
    - npm -v
    # cockpit
    - echo "==cockpit-navigator=="
    - |
    if command -v apt > /dev/null; then
    wget https://github.com/45Drives/cockpit-navigator/releases/download/v0.5.10/cockpit-navigator_0.5.10-1focal_all.deb
    apt install -y ./cockpit-navigator_0.5.10-1focal_all.deb
    elif command -v yum > /dev/null; then
    yum install -y https://github.com/45Drives/cockpit-navigator/releases/download/v0.5.10/cockpit-navigator-0.5.10-1.el7.noarch.rpm
    elif command -v dnf > /dev/null; then
    dnf install -y https://github.com/45Drives/cockpit-navigator/releases/download/v0.5.10/cockpit-navigator-0.5.10-1.el8.noarch.rpm
    fi
    - |
    if [ -f /etc/cockpit/disallowed-users ] && grep -qxF 'root' /etc/cockpit/disallowed-users; then
    sed -i '/^root$/d' /etc/cockpit/disallowed-users
    fi
    - IP=$(hostname -I | awk '{print $1}')
    - mkdir -p /etc/cockpit
    - |
    cat > /etc/cockpit/cockpit.conf <<EOF
    [WebService]
    Origins = http://$IP wss://$IP
    ProtocolHeader = X-Forwarded-Proto
    UrlRoot = /manager
    EOF
    # poabot-manager
    - echo "==poabot-manager=="
    - cd /root
    - |
    LATEST_TAG=$(curl -s "https://api.github.com/repos/jangdokang/poabot-manager/releases/latest" | grep -o '"tag_name": "[^"]*' | cut -d'"' -f4)
    echo "Latest poabot-manager version: $LATEST_TAG"
    curl -sSL "https://github.com/jangdokang/poabot-manager/releases/download/$LATEST_TAG/poabot-manager-${LATEST_TAG#v}.tar.xz" -o "poabot-manager-${LATEST_TAG#v}.tar.xz"
    tar -xf "poabot-manager-${LATEST_TAG#v}.tar.xz"
    ls -la
    if [ -d cockpit-poabot ]; then cd cockpit-poabot; elif [ -d poabot-manager ]; then cd poabot-manager; else echo "Directory not found"; exit 1; fi
    if [ -f Makefile ]; then make && make install; else echo "Makefile not found - skipping make install"; fi
    # poabot
    - |
    POABOT_LATEST_TAG=$(curl -s "https://hub.docker.com/v2/repositories/jangdokang/poabot/tags" | grep -o '"name":"[^"]*' | grep -v latest | head -1 | cut -d'"' -f4)
    echo "poabot - $POABOT_LATEST_TAG"
    podman pull jangdokang/poabot:$POABOT_LATEST_TAG
    podman tag jangdokang/poabot:$POABOT_LATEST_TAG jangdokang/poabot:latest
    # systemctl
    - echo "==systemctl=="
    - systemctl daemon-reload
    - systemctl enable cockpit.socket
    - systemctl restart cockpit.socket
    - systemctl enable chrony
    - systemctl restart chrony
    - systemctl enable caddy
    - systemctl restart caddy
  4. “Deploy” 를 클릭합니다