다원 플러그 로컬 연동 (CSS님) 서버 Docker 설치 및 구동하기
안녕하세요? 도정진입니다.
다원 플러그의 최신 펌부터 로컬 연동이 막히기 시작하면서 일단은 CSS님 서버를 이용해서 설치를 해보려고 아래의 시도를 했습니다.
다만, 그 때에도 설치과정이 매우 어려운데다 특히 인증서를 활용하는 과정은 너무 이해가 안되어서 설치를 하고 나서도 연동을 못하고 있었는데요.
전의 글은 아래의 글입니다.
https://blog.djjproject.com/798
이때, 알 수 없는 이유로 연동을 실패하여 여러번 재설치 과정을 거치고 밤도 새고 해보았는데 죽어도 안되더라구요.
윈도우에서 동일한 방법으로 구동하면 문제없이 작동하길래.. 할말을 잃어버려... 일단 다음에 이어서 해보기로 그냥 서랍에 고히 .. 내용을 모셔둔 상태였습니다.
일단은 CSS님께 문의를 드리려면 컨테이너화 해서, 그리고 설치글을 작성해서 여쭤봐야 해결이 될 것 같아 이렇게 docker 컨테이너 제작과 내용을 상세하게 작성합니다.
1. 구조
정확하게 알지는 못하지만 현재 최신버전의 다원 WIFI 플러그는 아래의 연동과정을 거쳐 연동이 됩니다.
다원의 API 서버 접근 후, mqtt 에 접속할 MQTT 비밀번호를 할당받게 되고, CSS님 께서도 이 비밀번호가 생성되는 방법을 인지하지 못하셔서, 실제 다원 서버에서 값을 받아와서 사설 서버에 저장하는 형태로 진행하고 계십니다.
사설 서버의 구조는 아래와 같습니다.
처음에 등록할 때, 설정용 PC 가 다원 플러그에 설정값을 넘겨줍니다.
이때 설정값은 AP 가 192.168.1.1 로 할당되어 있는 하위 공유기로 연결하게 되고, 하위 공유기는 Custom Dawon Server 가 설치된 192.168.0.200 의 DNS 값을 가지고 있습니다.
다원 플러그는 DNS 를 192.168.0.200 으로 받아들이며
192.168.0.200 에 설치된 bind9 는 dawonai.com / dwmqtt.dawonai.com / dwapi.dawonai.com 을 192.168.0.200 으로 변경한 DNS 레코드를 가지고 있습니다.
처음에 설정값을 넘겨주고, PC가 본래 사용하던 인터넷 연결을 활용하게 되면
실제 dwapi.dawonai.com 으로 플러그 정보를 전송하여 mqtt 비밀번호 값을 넘겨받게 됩니다.
이 mqtt 비밀번호 값을 192.168.0.200 (Dawon Custom Server) 에 등록하여 플러그와 연동하는 방법입니다.
즉, 요는 하위 공유기가 있거나 hostapd 를 통해 와이파이 존을 하나 운영해야 이 방법이 가능한 것입니다.
2. 컨테이너 작성 (Dockerfile)
아래와 같이 컨테이너를 작성하였으며, 필요한 설치 과정은 모두 포함되어 있는 상태입니다.
https://github.com/djjproject/dawon_css_server_docker
일단 작동하는 것이 목표라서 컨테이너의 레이어 관계등을 고려하지 않고 1개 레이어로 퉁쳐버린 좋지 않은 모습입니다만, 일단 추후에 유지보수를 통해서 레이어를 잘게 잘게 쪼개서 추후 업데이트때 용량 효율성을 도모하도록 하겠습니다.
코드는 아래와 같습니다.
먼저 Dockerfile 입니다.
FROM ubuntu:18.04 MAINTAINER djjproject <djj9404@gmail.com> WORKDIR /app # ports EXPOSE 18080 18443 1803 80 8883 443 53 # locales ENV LANG=en_US.UTF-8 \ LANGUAGE=en_US:en \ LC_ALL=en_US.UTF-8 # copy files COPY . /app # run install script RUN bash /app/install.sh # run script CMD ["/bin/bash", "/app/init.sh"] |
각각 쪼개서 설명을 드리겠습니다.
# 베이스로 하는 컨테이너 이름을 작성합니다. # 저는 ubuntu:18.04 를 기준으로 작성했습니다. FROM ubuntu:18.04 # 메인테이너 정보를 기입합니다. MAINTAINER djjproject <djj9404@gmail.com></djj9404@gmail.com> # WORKDIR 를 지정합니다. 컨테이너의 홈폴더 개념으로 보시면 됩니다. WORKDIR /app |
# 말 그대로 포트입니다. macvlan 을 사용하지 않고 docker port forwarding 을 사용할 때 expose 할 포트들을 명기했습니다. # ports EXPOSE 18080 18443 1803 80 8883 443 53 |
# 로케일 설정입니다. # locales ENV LANG=en_US.UTF-8 \ LANGUAGE=en_US:en \ LC_ALL=en_US.UTF-8 |
# 현 폴더에 있는 파일을 컨테이너의 /app 폴더에 복사합니다. # copy files COPY . /app # /app 폴더의 install.sh 를 수행합니다. # run install script RUN bash /app/install.sh |
--> 이때 RUN 구문은 1개의 레이어로 작성되어 매번 빌드시 마다 해쉬값이 바뀌어 다른 레이어로 지정됩니다. 따라서 이때 용량 과다 발생 문제가 발생하여 차후에는 install.sh 에 있는 내용을 RUN으로 최대한 변경하여 다수의 레이어를 가지도록 할 예정입니다.
아래를 보시면 레이어 해쉬가 매번 다릅니다.
용량은 같게 나오지만, install.sh 내용이 조금이라도 변하면 157.86MB가 매번 빌드할때마다 늘어난다고 보시면 됩니다.
# 기본적으로 실행할 스크립트를 작성합니다. # entrypoint 와 다른점은 docker run 시 명령을 지정하면 아래 CMD 는 무시됩니다. # entrypoint 는 CMD와 별개로 실행되는 것으로 고정을 하고 싶으면 ENTRYPOINT 로 작성해도 무방합니다. # run script CMD ["/bin/bash", "/app/init.sh"] |
3. 컨테이너 작성 (install.sh)
스크립트 전체는 아래와 같습니다.
#!/bin/bash # 차후 컨테이너 설정이 바뀌는 것을 대비하여 아래와 같이 변수를 설정했습니다. TIMEZONE="Asia/Seoul" # 앱 실행파일들을 가져올 경로입니다. SERVER_URL="https://github.com/SeongSikChae/PowerManagerServerV2/releases/download/449885d5/Linux64-449885d5.zip" CERTI_URL="https://github.com/SeongSikChae/Certificate/releases/download/v1.0.0/Certificate.zip" # 디렉터리 값을 변수로 지정했습니다. ROOT=/app CERTI_DIR=$ROOT/certificate SERVER_DIR=$ROOT/server TEMP_DIR=$ROOT/temp DATA_DIR=$ROOT/data # 의존성 패키지 설치 부분입니다. # install dependencies apt update DEBIAN_FRONTEND=noninteractive apt install -y sudo curl git wget vim dialog ca-certificates libicu60 locales \ tzdata openssl unzip dos2unix net-tools dnsutils bind9 # 필요한 경로를 생성하는 부분입니다. # dir create mkdir -p $CERTI_DIR $SERVER_DIR $TEMP_DIR $DATA_DIR # 로케일을 기본 영어로 설정하는 부분입니다. # 한국어로 나오면 오히려 구글 검색이 힘들어서 로케일은 영어로 설정하는 편입니다. # 이때 non-interactive 가 중요하여 스크립트 기법이 들어가 있습니다. # locale sed -i -e 's/# en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/' /etc/locale.gen dpkg-reconfigure --frontend=noninteractive locales update-locale LANG=en_US.UTF-8 # non-interactive 로 타임존을 설정하는 부분입니다. # timezone ln -sf /usr/share/zoneinfo/${TIMEZONE} /etc/localtime dpkg-reconfigure -f noninteractive tzdata # CSS님의 파워매니저 서버 파일을 다운받는 부분입니다. # get powermanager server / certificate wget ${SERVER_URL} -O $TEMP_DIR/server.zip wget ${CERTI_URL} -O $TEMP_DIR/certificate.zip # 압축을 지정한 경로에 풉니다. # install server / certificate unzip $TEMP_DIR/server.zip -d $SERVER_DIR unzip $TEMP_DIR/certificate.zip -d $CERTI_DIR # 인증서의 경우 윈도우 줄바꿈이 있어 dos2unix 로 변경을 합니다. # certificate cd $CERTI_DIR dos2unix Server.cfg dos2unix Client.cfg # 인증서가 있는 HOME 경로를 맞춰주고 # RANDOM 파일을 기본 default 로 주기 위해 코멘트 처리합니다. sed -i -e "s,HOME\t\t\t=.*,HOME\t\t\t= $CERTI_DIR,g" $CERTI_DIR/Server.cfg sed -i -e "s,HOME\t\t\t=.*,HOME\t\t\t= $CERTI_DIR,g" $CERTI_DIR/Client.cfg sed -i -e 's,RANDFILE\t\t=.*,#RANDFILE\t\t=,g' $CERTI_DIR/Server.cfg sed -i -e 's,RANDFILE\t\t=.*,#RANDFILE\t\t=,g' $CERTI_DIR/Client.cfg # DNS 설정값입니다. # DJJPROJECT_ 는 추후 config.sh 를 실행하면서 치환됩니다. # 정방향과 역방향에 대해서 설정하는 부분으로 첫번째는 정방향 # 두번째는 역방향입니다. # dns server configuration cat << 'EOF' > /etc/bind/named.conf.local zone "dawonai.com" IN { type master; file "/etc/bind/db.dawonai.com"; allow-update { none; }; allow-transfer { none; }; }; zone "DJJPROJECT_CONF_3_ADDR.in-addr.arpa" IN { type master; file "/etc/bind/db.DJJPROJECT_CONF_3_ADDR"; allow-update { none; }; allow-transfer { none; }; }; EOF cat << 'EOF' > /etc/bind/db.dawonai.com $TTL 86400 @ IN SOA dawonai.com. root ( 1 ; Serial 604800 ; Refresh 86400 ; Retry 2419200 ; Expire 86400 ) ; Negative Cache TTL ; @ IN NS dawonai.com. @ IN A DJJPROJECT_CONF_SERVER_IP dwmqtt IN A DJJPROJECT_CONF_SERVER_IP dwapi IN A DJJPROJECT_CONF_SERVER_IP EOF # 기본 설정파일을 yml.example 로 변경합니다. # 그리고 PowerMangerServer 파일에 실행권한을 줍니다. # server config.yml mv $SERVER_DIR/config/config.yml $SERVER_DIR/config/config.yml.example chmod a+x $SERVER_DIR/PowerManagerServer # 그리고 openssl 의 seclevel 이 2로 되어 있어서 플러그 연동이 안되는 문제를 해결하는 openssl.cnf 파일을 복사합니다. # openssl seclevel cp $ROOT/openssl.cnf /etc/ssl/openssl.cnf # cleanup apt clean rm -rf /app/temp |
너무 길어서 스크립트에 설명을 추가하였습니다.
원본은 아래에서 참고를 하시면 됩니다.
https://github.com/djjproject/dawon_css_server_docker/blob/master/install.sh
4. 컨테이너 작성 (config.sh)
컨테이너를 생성하고 설정을 하는 스크립트 입니다.
원본은 아래와 같습니다.
https://github.com/djjproject/dawon_css_server_docker/blob/master/config.sh
설명은 아래와 같습니다.
#!/bin/bash ROOT=/app DATA_DIR=$ROOT/data CERTI_DIR=$ROOT/certificate SERVER_DIR=$ROOT/server function output() { echo -e "\e[0;33m[config] $1\e[0m" } # 서버 아이피를 입력받습니다. output "server ip" read -p "enter server ip: " SERVER_IP output "SERVER_IP: $SERVER_IP" # 인증서를 새로 생성할지 묻는 부부분입니다. output "certificate" read -p "certificate create? [y/n] " INPUT # 인증서를 새로 생성하기로 했다면 아래 if 문에 걸립니다. if [ "x$INPUT" = "xy" ]; then # 인증서 패스워드를 입력 받습니다. output "certificate password" read -p "certificate password: " CERTI_PASSWORD # Server.cfg 에 CA 가 사용될 IP 주소를 설정합니다. sed -i -e "s,IP.1 = 10.0.0.4,IP.1 = $SERVER_IP,g" $CERTI_DIR/Server.cfg # 루트 인증서를 생성합니다. output "generate root certificate ..." openssl genrsa -out $CERTI_DIR/private/ca.key echo -e "\n\n\n\nPowerManager\n\n\n\n" | openssl req -new -key $CERTI_DIR/private/ca.key -out $CERTI_DIR/certs/ca.csr -config $CERTI_DIR/Server.cfg openssl x509 -req -days 3650 -extensions v3_ca -in $CERTI_DIR/certs/ca.csr -signkey $CERTI_DIR/private/ca.key -out $CERTI_DIR/newcerts/ca.crt -extfile $CERTI_DIR/Server.cfg openssl pkcs12 -inkey $CERTI_DIR/private/ca.key -in $CERTI_DIR/newcerts/ca.crt -export -out $CERTI_DIR/newcerts/ca.p12 -passout pass:$CERTI_PASSWORD # 서버 인증서를 생성합니다. output "generate server certificate ..." openssl genrsa -out $CERTI_DIR/private/S.key echo -e "\n\n\n\n$SERVER_IP\n\n\n\n" | openssl req -new -key $CERTI_DIR/private/S.key -out $CERTI_DIR/certs/S.csr -config $CERTI_DIR/Server.cfg openssl x509 -req -days 3650 -extensions v3_req -in $CERTI_DIR/certs/S.csr -CA $CERTI_DIR/newcerts/ca.crt -CAcreateserial -CAkey $CERTI_DIR/private/ca.key -out $CERTI_DIR/newcerts/S.crt -extfile $CERTI_DIR/Server.cfg openssl pkcs12 -inkey $CERTI_DIR/private/S.key -in $CERTI_DIR/newcerts/S.crt -export -out $CERTI_DIR/newcerts/S.p12 -passout pass:$CERTI_PASSWORD # 클라이언트 인증서를 생성합니다. output "generate client certificate ..." openssl genrsa -out $CERTI_DIR/private/C.key echo -e "\n\n\n\n\nPowerManager\n\n\n\n" | openssl req -new -key $CERTI_DIR/private/C.key -out $CERTI_DIR/certs/C.csr -config $CERTI_DIR/Client.cfg openssl x509 -req -days 365 -extensions v3_user_req -in $CERTI_DIR/certs/C.csr -CA $CERTI_DIR/newcerts/ca.crt -CAcreateserial -CAkey $CERTI_DIR/private/ca.key -out $CERTI_DIR/newcerts/C.crt -extfile $CERTI_DIR/Client.cfg openssl pkcs12 -inkey $CERTI_DIR/private/C.key -in $CERTI_DIR/newcerts/C.crt -export -out $CERTI_DIR/newcerts/C.p12 -passout pass:$CERTI_PASSWORD # 생성된 인증서를 /app/data/newcerts 로 복사합니다. output "copy generated certificate files ..." cp -ar -v $CERTI_DIR/newcerts $DATA_DIR/ fi # 생성 되었거나 이미 있는 루트 인증서를 서버에 등록합니다. output "register root certificate ..." rm /usr/local/share/ca-certificates/ca.crt update-ca-certificates cp $DATA_DIR/newcerts/ca.crt /usr/local/share/ca-certificates/ca.crt update-ca-certificates # DNS 설정을 변경합니다. output "dns server settings ..." # 입력이 192.168.0.200 이였다면, # 아래 변수는 0.168.192 가 됩니다. DNS_IP_3ADDR=$(echo $SERVER_IP | awk -F'.' '{OFS="."; print $3,$2,$1}') # 아래 변수는 200이 됩니다. DNS_IP_4TH_ADDR=$(echo $SERVER_IP | awk -F'.' '{print $4}') # /etc/bind/db.0.168.192 cat << 'EOF' > /etc/bind/db.$DNS_IP_3ADDR $TTL 86400 @ IN SOA dawonai.com. root ( 1 ; Serial 604800 ; Refresh 86400 ; Retry 2419200 ; Expire 86400 ) ; Negative Cache TTL ; @ IN NS dawonai.com # 192.168.0.200 @ IN A DJJPROJECT_CONF_SERVER_IP # 200 DJJPROJECT_CONF_4TH_ADDR IN PTR dawonai.com. DJJPROJECT_CONF_4TH_ADDR IN PTR dwmqtt.dawonai.com DJJPROJECT_CONF_4TH_ADDR IN PTR dwapi.dawonai.com EOF # install.sh 에 설정되었던 부분들과 config.sh 에 설정되었던 부분을 수정합니다. sed -i -e "s,DJJPROJECT_CONF_SERVER_IP,$SERVER_IP,g" /etc/bind/db.$DNS_IP_3ADDR sed -i -e "s,DJJPROJECT_CONF_4TH_ADDR,$DNS_IP_4TH_ADDR,g" /etc/bind/db.$DNS_IP_3ADDR sed -i -e "s,DJJPROJECT_CONF_3_ADDR,$DNS_IP_3ADDR,g" /etc/bind/named.conf.local sed -i -e "s,DJJPROJECT_CONF_SERVER_IP,$SERVER_IP,g" /etc/bind/db.dawonai.com # dns 가 정상 설정 되었는지 확인합니다. output "checks dns server lookup ..." /etc/init.d/bind9 stop /etc/init.d/bind9 start nslookup dwmqtt.dawonai.com $SERVER_IP nslookup dwapi.dawonai.com $SERVER_IP nslookup dawonai.com $SERVER_IP # 서버 설정을 변경합니다. output "server configuration ..." # /app/data/config.yml 이 있으면 스킵합니다. if [ ! -f $DATA_DIR/config.yml ]; then output "no configuration file, install example file" # install.sh 에 있던 설정파일을 복사해 옵니다. cp -v $SERVER_DIR/config/config.yml.example $DATA_DIR/config.yml dos2unix $DATA_DIR/config.yml # 인증서 경로와 DB Path 를 설정합니다. sed -i -e "s,ServerCertificate:.*,ServerCertificate: $DATA_DIR/newcerts/S.p12,g" $DATA_DIR/config.yml sed -i -e "s,DbPath:.*,DbPath: $DATA_DIR/PowerManager.sqlite,g" $DATA_DIR/config.yml # 인증서 생성과정을 거치지 않으면 패스워드를 모르기 때문에 사용자에게 입력받습니다. if [ "x$CERTI_PASSWORD" = "x" ]; then output "certificate password" read -p "enter server certificate password: " CERTI_PASSWORD fi # 인증서 비번을 설정합니다. sed -i -e "s,ServerCertificatePassword:.*,ServerCertificatePassword: $CERTI_PASSWORD,g" $DATA_DIR/config.yml output "server configuration finished." cat $DATA_DIR/config.yml echo "" else # 이미 config.yml 이 있으면 아래 출력하고 끝납니다. output "already config.yml file in $DATA_DIR" fi output "finished. please restart containter." |
5. 컨테이너 dockerhub 에 푸쉬
아래와 같이 push 했으며 test2 가 latest 인 상태입니다.
root@ubuntu:~/dawon_css_server_docker# docker push djjproject/dawon_css_server:latest The push refers to repository [docker.io/djjproject/dawon_css_server] 1b6bf6a71230: Layer already exists 712ffa9776b8: Layer already exists 88abc7c1dbed: Layer already exists e722d396f503: Layer already exists latest: digest: sha256:631550a1267b570cc8fd159270151954b5b6d377f01a8bfa8fc26fe750139ccf size: 1157 |
https://hub.docker.com/r/djjproject/dawon_css_server
6. 컨테이너 구동하기 - macvlan 생성하기
https://blog.djjproject.com/785 의 5번 섹션을 참고하시어 생성하시면 됩니다.
https://blog.djjproject.com/797 로 호스트에서 컨테이너의 macvlan 에 접속되지 않는 문제를 해결 하실 수 있습니다.
7. 컨테이너 구동하기 - pull 및 run
컨테이너가 사용할 폴더를 하나 생성합니다.
root@debian:~# mkdir -p /opt/powermanager |
컨테이너를 아래와 같이 생성합니다.
root@debian:~# docker run -dit \ # 백그라운드로 실행 --name powermanager \ # 컨테이너 이름 지정 --restart unless-stopped \ # 사용자가 중지하지 않으면 재시작 --network macvlan \ # 네트워크 macvlan 설정 --ip=192.168.0.200 \ # IP 지정 -v /opt/powermanager:/app/data \ # 볼륨 설정 djjproject/dawon_css_server:latest # 컨테이너 이미지 설정 Unable to find image 'djjproject/dawon_css_server:latest' locally latest: Pulling from djjproject/dawon_css_server 22c5ef60a68e: Pull complete e8d557cb3d1e: Pull complete b6e62fd607fb: Pull complete d5091fc3bd05: Pull complete Digest: sha256:631550a1267b570cc8fd159270151954b5b6d377f01a8bfa8fc26fe750139ccf Status: Downloaded newer image for djjproject/dawon_css_server:latest b7a12cd467ce9eb084e7c6c0aa1c51aa04faf1ac0522521897dd43ada24e68f8 root@debian:~# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES b7a12cd467ce djjproject/dawon_css_server:latest "/bin/bash /app/init…" About a minute ago Up About a minute powermanager |
8. 컨테이너 구동하기 - 설정하기
아래 명령을 통해 설정을 진행합니다.
root@debian:~# docker exec -it powermanager /app/config.sh # 현 컨테이너가 돌고 있는 IP를 입력합니다. [config] server ip enter server ip: 192.168.0.200 [config] SERVER_IP: 192.168.0.200 # 인증서를 새로 생성합니다. [config] certificate certificate create? [y/n] y # 인증서 비번을 설정합니다. [config] certificate password certificate password: 123456 [config] generate root certificate ... Generating RSA private key, 2048 bit long modulus (2 primes) ........................................................................................................+++++ .......+++++ e is 65537 (0x010001) You are about to be asked to enter information that will be incorporated into your certificate request. What you are about to enter is what is called a Distinguished Name or a DN. There are quite a few fields but you can leave some blank For some fields there will be a default value, If you enter '.', the field will be left blank. ----- Country Name (2 letter code) [KR]:State or Province Name (full name) []:Locality Name (eg, city) []:Organization Name (eg, company) []:Organizational Unit Name (eg, section) []:Common Name (e.g. server FQDN or YOUR name) []:Email Address []: Please enter the following 'extra' attributes to be sent with your certificate request A challenge password []:An optional company name []:Signature ok subject=C = KR, OU = PowerManager Getting Private key [config] generate server certificate ... Generating RSA private key, 2048 bit long modulus (2 primes) .....................................+++++ ...................................................................+++++ e is 65537 (0x010001) You are about to be asked to enter information that will be incorporated into your certificate request. What you are about to enter is what is called a Distinguished Name or a DN. There are quite a few fields but you can leave some blank For some fields there will be a default value, If you enter '.', the field will be left blank. ----- Country Name (2 letter code) [KR]:State or Province Name (full name) []:Locality Name (eg, city) []:Organization Name (eg, company) []:Organizational Unit Name (eg, section) []:Common Name (e.g. server FQDN or YOUR name) []:Email Address []: Please enter the following 'extra' attributes to be sent with your certificate request A challenge password []:An optional company name []:Signature ok subject=C = KR, OU = 192.168.0.200 Getting CA Private Key [config] generate client certificate ... Generating RSA private key, 2048 bit long modulus (2 primes) .................+++++ .........................................................................................+++++ e is 65537 (0x010001) You are about to be asked to enter information that will be incorporated into your certificate request. What you are about to enter is what is called a Distinguished Name or a DN. There are quite a few fields but you can leave some blank For some fields there will be a default value, If you enter '.', the field will be left blank. ----- Country Name (2 letter code) [KR]:State or Province Name (full name) []:Locality Name (eg, city) []:Organization Name (eg, company) []:Organizational Unit Name (eg, section) []:Common Name (e.g. server FQDN or YOUR name) []:Email Address []: Please enter the following 'extra' attributes to be sent with your certificate request A challenge password []:An optional company name []:Signature ok subject=C = KR, CN = PowerManager Getting CA Private Key [config] copy generated certificate files ... '/app/certificate/newcerts' -> '/app/data/newcerts' '/app/certificate/newcerts/ca.crt' -> '/app/data/newcerts/ca.crt' '/app/certificate/newcerts/ca.p12' -> '/app/data/newcerts/ca.p12' '/app/certificate/newcerts/S.crt' -> '/app/data/newcerts/S.crt' '/app/certificate/newcerts/ca.srl' -> '/app/data/newcerts/ca.srl' '/app/certificate/newcerts/S.p12' -> '/app/data/newcerts/S.p12' '/app/certificate/newcerts/C.crt' -> '/app/data/newcerts/C.crt' '/app/certificate/newcerts/C.p12' -> '/app/data/newcerts/C.p12' [config] register root certificate ... # 이 부분은 에러가 아니고 확인 사살을 위해 지우고 새로 cp 하는 것입니다. rm: cannot remove '/usr/local/share/ca-certificates/ca.crt': No such file or directory Updating certificates in /etc/ssl/certs... 0 added, 0 removed; done. Running hooks in /etc/ca-certificates/update.d... done. Updating certificates in /etc/ssl/certs... rehash: warning: skipping ca-certificates.crt,it does not contain exactly one certificate or CRL 1 added, 0 removed; done. Running hooks in /etc/ca-certificates/update.d... done. [config] dns server settings ... [config] checks dns server lookup ... * Stopping domain name service... bind9 waiting for pid 24 to die [ OK ] * Starting domain name service... bind9 [ OK ] Server: 192.168.0.200 Address: 192.168.0.200#53 Name: dwmqtt.dawonai.com Address: 192.168.0.200 Server: 192.168.0.200 Address: 192.168.0.200#53 Name: dwapi.dawonai.com Address: 192.168.0.200 Server: 192.168.0.200 Address: 192.168.0.200#53 Name: dawonai.com Address: 192.168.0.200 # 설정파일이 없어 새로 생성하는 부분입니다. [config] server configuration ... [config] no configuration file, install example file '/app/server/config/config.yml.example' -> '/app/data/config.yml' dos2unix: converting file /app/data/config.yml to Unix format... [config] server configuration finished. # 설정된 config.yml 을 출력해줍니다. WebHttpPort: 80 WebHttpsPort: 443 ServerCertificate: /app/data/newcerts/S.p12 ServerCertificatePassword: 123456 #HTTP2: true #IncludeCipherSuites: # - "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384" # - "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256" DbPath: /app/data/PowerManager.sqlite #TelegramToken: "" [config] finished. please restart containter. |
아 위에 오타가 있네요. container 인데 급하게 하느라 containter 로 오타를.. 다음에 고치겠습니다.
설정이 끝났으니 컨테이너를 재시작합니다.
root@debian:~# docker restart powermanager powermanager |
9. 설정이 제대로 들어갔는지 확인하기
1) DNS 설정
root@debian:~# docker exec -it powermanager /bin/bash root@b7a12cd467ce:/app# root@b7a12cd467ce:/etc/bind# cat named.conf.local zone "dawonai.com" IN { type master; file "/etc/bind/db.dawonai.com"; allow-update { none; }; allow-transfer { none; }; }; zone "0.168.192.in-addr.arpa" IN { type master; file "/etc/bind/db.0.168.192"; allow-update { none; }; allow-transfer { none; }; }; root@b7a12cd467ce:/etc/bind# cat db.dawonai.com $TTL 86400 @ IN SOA dawonai.com. root ( 1 ; Serial 604800 ; Refresh 86400 ; Retry 2419200 ; Expire 86400 ) ; Negative Cache TTL ; @ IN NS dawonai.com. @ IN A 192.168.0.200 dwmqtt IN A 192.168.0.200 dwapi IN A 192.168.0.200 root@b7a12cd467ce:/etc/bind# cat db.0.168.192 $TTL 86400 @ IN SOA dawonai.com. root ( 1 ; Serial 604800 ; Refresh 86400 ; Retry 2419200 ; Expire 86400 ) ; Negative Cache TTL ; @ IN NS dawonai.com @ IN A 192.168.0.200 200 IN PTR dawonai.com. 200 IN PTR dwmqtt.dawonai.com 200 IN PTR dwapi.dawonai.com |
2) config.yml
root@b7a12cd467ce:/etc/bind# cat /app/data/config.yml WebHttpPort: 80 WebHttpsPort: 443 ServerCertificate: /app/data/newcerts/S.p12 ServerCertificatePassword: 123456 #HTTP2: true #IncludeCipherSuites: # - "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384" # - "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256" DbPath: /app/data/PowerManager.sqlite |
호스트에서 아래와 같이 확인할 수 있습니다.
root@debian:~# cd /opt/powermanager/ root@debian:/opt/powermanager# ls config.yml newcerts PowerManager.sqlite-shm tempature_statistics.json log PowerManager.sqlite PowerManager.sqlite-wal watt_statistics.json |
10. 접속할 대상 PC에 인증서 등록하기
/opt/powermanager/newcerts 폴더를 밖으로 가져옵니다.
root@debian:/opt/powermanager# cp -ar newcerts/ /media/data/ |
아래와 같이 등록합니다.
https://blog.djjproject.com/798 - 7번 섹션과 내용이 같습니다.
인증서를 윈도우에서 아래와 같이 등록합니다.
먼저 루트 인증서를 더블클릭해서 등록합니다.
로컬 컴퓨터를 선택하고 다음을 누릅니다.
모든 인증서를 다음 저장소에 저장을 체크하고 찾아보기를 누릅니다.
신뢰할 수 있는 루트 인증기관을 선택합니다.
다음을 누릅니다.
다음으로 클라이언트 인증서를 더블클릭하여 열어서 등록합니다.
현재 사용자를 선택하고 다음을 누릅니다.
다음을 누릅니다.
4번 섹션에서 클라이언트 인증서를 생성할 때 입력했던 비밀번호를 넣고 다음을 누릅니다.
모든 인증서를 다음 저장소에 저장을 체크하고 찾아보기를 누릅니다.
개인용을 선택합니다.
다음을 누릅니다.
11. 웹 UI 접근하기
서버 아이피 주소를 입력하여 접근합니다.
접속할 때 사용할 인증서를 물어봅니다.
선택하여 접근하면 WebUI가 나타납니다.
12. 플러그를 위한 공유기 설정하기
남는 공유기를 통해 무선 WAN 으로 설정하고 DNS만 서버 IP로 수정합니다.
13. 플러그 등록하기
등록 프로그램은 아래에서 받습니다.
https://github.com/SeongSikChae/PowerManagerConfig/releases
newcerts 폴더에서 C.p12 파일을 복사하여 아래와 같이 배치합니다.
주소창에 cmd 라고 입력하면 현재위치에서 cmd 가 열립니다.
먼저 플러그 와이파이에 연결합니다.
다음으로 아래 명령으로 등록합니다.
아래 등록과정은 244.1 제품에 해당하는 것으로 기타 등록 방법은 아래를 참고하시길 바랍니다.
https://github.com/SeongSikChae/PowerManagerDocument/releases
C:\Users\USER\Downloads\Win64-v1.0.1>PowerManagerConfig.exe --host 192.168.244.1 --port 5000 --web_server_addr https://192.168.0.200/ --clientCertificate C.p12 --clientCertificatePassword 123456 Common.Logging Revision: 362ee1b0 Common.Core Revision: 362ee1b0 PowerManagerConfig Revision: b4e6864b [::ffff:192.168.244.1]:5000 Connected Mode V1 (B540 <= v1.01.26) or V2 (B540 == v1.01.28) or V3 (B540 == v1.01.30) or V4 (B550) (default V1): V3 [DUT->PC] START_OK:2ef432510027# SSID: PowerManager Wifi Password: 12345678 UserId: test@naver.com/naver Model: B540_W Mqtt Topic: dwd Push: {"mac":"2ef432510027","api_server_addr":"dwapi.dawonai.com","api_server_port":"18443","server_addr":"dwmqtt.dawonai.com","server_port":"8883","ssl_support":"yes","ssid":"PowerManager","pass":"12345678","user_id":"test@naver.com/naver","company":"DAWONDNS","model":"B540_W","lati":"37.6523018","long":"127.0622559","topic":"dwd"} Send: 332 Byte. {"mac":"2ef432510027","respone":"OK"} 37 {"mac":"2ef432510027","respone":"OK"} 네트워크를 정상화 시킨 후 Enter를 입력하세요. verify: zgL=Xgqyl;sfdhlsdkfjsdlfjkklzjxlkcxjvcrOq6FJ mqtt_key: sdfsddsfsdlfdslfsd |
14. 이 이후 진행
플러그 등록이 정상적으로 되지 않고, server[date].log 는 아래의 로그가 남아 있습니다.
2022-08-15 02:45:16.269 +09:00 [Warning] [Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager.Microsoft.AspNetCore.DataProtection.KeyManagement.Internal.IInternalXmlKeyManager.CreateNewKey:0] No XML encryptor configured. Key {6f6cedc7-d91a-462b-bf66-09d3896974f2} may be persisted to storage in unencrypted form. 2022-08-15 02:45:19.296 +09:00 [Information] [System.Threading.Tasks.CustomTaskScheduler.ITaskWorker.unknown_method:0] task 'StatisticsPersistentTask' starting. 2022-08-15 02:45:19.309 +09:00 [Information] [System.Threading.Tasks.CustomTaskScheduler.ITaskWorker.unknown_method:0] task 'StatisticsPersistentTask' started. 2022-08-15 02:45:19.368 +09:00 [Information] [PowerManagerServer.Mqtt.MqttNetLogger.Publish:27] MqttServerKeepAliveMonitor: Starting keep alive monitor. 2022-08-15 02:45:19.370 +09:00 [Information] [PowerManagerServer.Mqtt.MqttNetLogger.Publish:27] MqttTcpServerListener: Starting TCP listener for 0.0.0.0:1803 TLS=False. 2022-08-15 02:45:19.386 +09:00 [Information] [PowerManagerServer.Mqtt.MqttNetLogger.Publish:27] MqttTcpServerListener: Starting TCP listener for [::]:1803 TLS=False. 2022-08-15 02:45:19.393 +09:00 [Information] [PowerManagerServer.Mqtt.MqttNetLogger.Publish:27] MqttTcpServerListener: Starting TCP listener for 0.0.0.0:8883 TLS=True. 2022-08-15 02:45:19.394 +09:00 [Information] [PowerManagerServer.Mqtt.MqttNetLogger.Publish:27] MqttTcpServerListener: Starting TCP listener for [::]:8883 TLS=True. 2022-08-15 02:45:19.394 +09:00 [Information] [PowerManagerServer.Mqtt.MqttNetLogger.Publish:27] MqttServer: Started. 2022-08-15 02:45:19.713 +09:00 [Warning] [Microsoft.AspNetCore.Server.Kestrel.unknown_method:0] Overriding address(es) 'http://localhost:80, https://localhost:443, https://localhost:18443'. Binding to endpoints defined via IConfiguration and/or UseKestrel() instead. 2022-08-15 02:45:19.861 +09:00 [Information] [Microsoft.Hosting.Lifetime.unknown_method:0] Now listening on: http://0.0.0.0:80 2022-08-15 02:45:19.862 +09:00 [Information] [Microsoft.Hosting.Lifetime.unknown_method:0] Now listening on: https://0.0.0.0:443 2022-08-15 02:45:19.862 +09:00 [Information] [Microsoft.Hosting.Lifetime.unknown_method:0] Now listening on: https://0.0.0.0:18443 2022-08-15 02:45:19.868 +09:00 [Information] [PowerManagerServer.Startup.OnStarted:181] Common.Logging Revision: 32774953 2022-08-15 02:45:19.869 +09:00 [Information] [PowerManagerServer.Startup.OnStarted:182] Common.Core Revision: 31a17c79 2022-08-15 02:45:19.870 +09:00 [Information] [PowerManagerServer.Startup.OnStarted:183] PowerManagerServer Revision: 449885d5 2022-08-15 02:45:19.870 +09:00 [Information] [PowerManagerServer.Startup.OnStarted:184] PowerManagerServer Started. 2022-08-15 02:45:19.871 +09:00 [Information] [Microsoft.Hosting.Lifetime.unknown_method:0] Application started. Press Ctrl+C to shut down. 2022-08-15 02:45:19.871 +09:00 [Information] [Microsoft.Hosting.Lifetime.unknown_method:0] Hosting environment: Production 2022-08-15 02:45:19.871 +09:00 [Information] [Microsoft.Hosting.Lifetime.unknown_method:0] Content root path: /app/server 2022-08-15 02:55:07.939 +09:00 [Error] [Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware.lambda_method46:0] An unhandled exception has occurred while executing the request. System.Exception: Device Auth Not Found at PowerManagerServer.Controllers.ApiController.Create(CreateRequest request) in E:\Git\PowerManagerV2\PowerManagerServer\Controllers\ApiController.cs:line 58 at lambda_method46(Closure , Object , Object[] ) at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.SyncObjectResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments) at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeActionMethodAsync() at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeNextActionFilterAsync() --- End of stack trace from previous location --- at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context) at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeInnerFilterAsync() --- End of stack trace from previous location --- at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextResourceFilter>g__Awaited|25_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResourceExecutedContextSealed context) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.InvokeFilterPipelineAsync() --- End of stack trace from previous location --- at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope) at Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger) at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context) at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context) at PowerManagerServer.RequestLoggingMiddleware.Invoke(HttpContext context) in E:\Git\PowerManagerV2\PowerManagerServer\RequestLoggingMiddleware.cs:line 64 at Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware.<Invoke>g__Awaited|6_0(ExceptionHandlerMiddleware middleware, HttpContext context, Task task) 2022-08-15 02:55:07.955 +09:00 [Error] [Microsoft.AspNetCore.Server.Kestrel.unknown_method:0] Connection id "0HMJU3LVDPOAP", Request id "0HMJU3LVDPOAP:00000002": An unhandled exception was thrown by the application. System.InvalidOperationException: The exception handler configured on ExceptionHandlerOptions produced a 404 status response. This InvalidOperationException containing the original exception was thrown since this is often due to a misconfigured ExceptionHandlingPath. If the exception handler is expected to return 404 status responses then set AllowStatusCode404Response to true. ---> System.Exception: Device Auth Not Found at PowerManagerServer.Controllers.ApiController.Create(CreateRequest request) in E:\Git\PowerManagerV2\PowerManagerServer\Controllers\ApiController.cs:line 58 at lambda_method46(Closure , Object , Object[] ) at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.SyncObjectResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments) at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeActionMethodAsync() at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeNextActionFilterAsync() --- End of stack trace from previous location --- at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context) at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeInnerFilterAsync() --- End of stack trace from previous location --- at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextResourceFilter>g__Awaited|25_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResourceExecutedContextSealed context) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.InvokeFilterPipelineAsync() --- End of stack trace from previous location --- at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope) at Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger) at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context) at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context) at PowerManagerServer.RequestLoggingMiddleware.Invoke(HttpContext context) in E:\Git\PowerManagerV2\PowerManagerServer\RequestLoggingMiddleware.cs:line 64 at Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware.<Invoke>g__Awaited|6_0(ExceptionHandlerMiddleware middleware, HttpContext context, Task task) --- End of inner exception stack trace --- at Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware.HandleException(HttpContext context, ExceptionDispatchInfo edi) at Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware.<Invoke>g__Awaited|6_0(ExceptionHandlerMiddleware middleware, HttpContext context, Task task) at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.ProcessRequests[TContext](IHttpApplication`1 application) 2022-08-15 02:55:09.580 +09:00 [Error] [Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware.unknown_method:0] An unhandled exception has occurred while executing the request. System.InvalidOperationException: The SPA default page middleware could not return the default page '/index.html' because it was not found, and no other middleware handled the request. Your application is running in Production mode, so make sure it has been published, or that you have built your SPA manually. Alternatively you may wish to switch to the Development environment. at Microsoft.AspNetCore.SpaServices.SpaDefaultPageMiddleware.<>c__DisplayClass0_0.<Attach>b__1(HttpContext context, RequestDelegate next) at Microsoft.AspNetCore.Builder.UseExtensions.<>c__DisplayClass1_1.<Use>b__1(HttpContext context) at Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware.Invoke(HttpContext context) at Microsoft.AspNetCore.SpaServices.SpaDefaultPageMiddleware.<>c__DisplayClass0_0.<Attach>b__0(HttpContext context, RequestDelegate next) at Microsoft.AspNetCore.Builder.UseExtensions.<>c__DisplayClass1_1.<Use>b__1(HttpContext context) at Microsoft.AspNetCore.Routing.EndpointMiddleware.Invoke(HttpContext httpContext) at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context) at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context) at PowerManagerServer.RequestLoggingMiddleware.Invoke(HttpContext context) in E:\Git\PowerManagerV2\PowerManagerServer\RequestLoggingMiddleware.cs:line 64 at Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware.<Invoke>g__Awaited|6_0(ExceptionHandlerMiddleware middleware, HttpContext context, Task task) 2022-08-15 02:55:09.582 +09:00 [Error] [Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware.unknown_method:0] An exception was thrown attempting to execute the error handler. System.InvalidOperationException: The SPA default page middleware could not return the default page '/index.html' because it was not found, and no other middleware handled the request. Your application is running in Production mode, so make sure it has been published, or that you have built your SPA manually. Alternatively you may wish to switch to the Development environment. at Microsoft.AspNetCore.SpaServices.SpaDefaultPageMiddleware.<>c__DisplayClass0_0.<Attach>b__1(HttpContext context, RequestDelegate next) at Microsoft.AspNetCore.Builder.UseExtensions.<>c__DisplayClass1_1.<Use>b__1(HttpContext context) at Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware.Invoke(HttpContext context) at Microsoft.AspNetCore.SpaServices.SpaDefaultPageMiddleware.<>c__DisplayClass0_0.<Attach>b__0(HttpContext context, RequestDelegate next) at Microsoft.AspNetCore.Builder.UseExtensions.<>c__DisplayClass1_1.<Use>b__1(HttpContext context) at Microsoft.AspNetCore.Routing.EndpointMiddleware.Invoke(HttpContext httpContext) at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context) at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context) at PowerManagerServer.RequestLoggingMiddleware.Invoke(HttpContext context) in E:\Git\PowerManagerV2\PowerManagerServer\RequestLoggingMiddleware.cs:line 64 at Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware.HandleException(HttpContext context, ExceptionDispatchInfo edi) 2022-08-15 02:55:09.584 +09:00 [Error] [Microsoft.AspNetCore.Server.Kestrel.unknown_method:0] Connection id "0HMJU3LVDPOAQ", Request id "0HMJU3LVDPOAQ:00000002": An unhandled exception was thrown by the application. System.InvalidOperationException: The SPA default page middleware could not return the default page '/index.html' because it was not found, and no other middleware handled the request. Your application is running in Production mode, so make sure it has been published, or that you have built your SPA manually. Alternatively you may wish to switch to the Development environment. at Microsoft.AspNetCore.SpaServices.SpaDefaultPageMiddleware.<>c__DisplayClass0_0.<Attach>b__1(HttpContext context, RequestDelegate next) at Microsoft.AspNetCore.Builder.UseExtensions.<>c__DisplayClass1_1.<Use>b__1(HttpContext context) at Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware.Invoke(HttpContext context) at Microsoft.AspNetCore.SpaServices.SpaDefaultPageMiddleware.<>c__DisplayClass0_0.<Attach>b__0(HttpContext context, RequestDelegate next) at Microsoft.AspNetCore.Builder.UseExtensions.<>c__DisplayClass1_1.<Use>b__1(HttpContext context) at Microsoft.AspNetCore.Routing.EndpointMiddleware.Invoke(HttpContext httpContext) at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context) at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context) at PowerManagerServer.RequestLoggingMiddleware.Invoke(HttpContext context) in E:\Git\PowerManagerV2\PowerManagerServer\RequestLoggingMiddleware.cs:line 64 at Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware.<Invoke>g__Awaited|6_0(ExceptionHandlerMiddleware middleware, HttpContext context, Task task) at Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware.HandleException(HttpContext context, ExceptionDispatchInfo edi) at Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware.<Invoke>g__Awaited|6_0(ExceptionHandlerMiddleware middleware, HttpContext context, Task task) at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.ProcessRequests[TContext](IHttpApplication`1 application) |
추후 해결이 되면 글을 업데이트 하겠습니다.
감사합니다.
일단은 위의 에러에서
---> System.Exception: Device Auth Not Found |
이는 플러그가 접속했지만 인증 키값이 api 서버에 등록되지 않아서 발생하는 문제입니다.
즉, config 프로그램을 구버전을 사용하여 정상적으로 등록과정이 진행되지 않았던 것입니다.
15. 문제 해결
아... 제가 전에 시도하면서 config 프로그램을 이전 버전을 사용하여 작동이 안되는 것이였습니다.
등록 프로그램을 아래 버전을 받고 시도하면 정상 작동합니다.
https://github.com/SeongSikChae/PowerManagerConfig/releases
다시 시도해 보겠습니다.
C:\Users\USER\Downloads\Win64-e5d5f965>PowerManagerConfig.exe --host 192.168.244.1 --port 5000 --web_server_addr https://192.168.0.200 --clientCertificate C.p12 --clientCertificatePassword 123456 Common.Logging Revision: 32774953 Common.Core Revision: 31a17c79 PowerManagerConfig Revision: e5d5f965 [::ffff:192.168.244.1]:5000 Connected Mode V1 (B540 <= v1.01.26) or V2 (B540 == v1.01.28) or V3 (B540 == v1.01.30) or V4 (B550) (default V1): V3 [DUT->PC] START_OK:2ef432510027# SSID: PowerManager Wifi Password: 12345678 # AIPM 에서 사용하는 계정 정보를 입력합니다. # test@google.com/google 이렇게도 가능합니다. UserId: test@naver.com/naver Model: B540_W Mqtt Topic: dwd Push: {"mac":"2ef432510027","api_server_addr":"dwapi.dawonai.com","api_server_port":"18443","server_addr":"dwmqtt.dawonai.com","server_port":"8883","ssl_support":"yes","ssid":"PowerManager","pass":"12345678","user_id":"test@naver.com/naver","company":"DAWONDNS","model":"B540_W","lati":"37.6523018","long":"127.0622559","topic":"dwd"} Send: 332 Byte. {"mac":"2ef432510027","respone":"OK"} 37 {"mac":"2ef432510027","respone":"OK"} 네트워크를 정상화 시킨 후 Enter를 입력하세요. verify: zgsdffsdfsdfsddddddddd mqtt_key: sdfsdfsdfsdfsdfsdf {"time":1660564616786,"statusCode":"Success","code":null,"message":null} |
서버 로그에는 플러그가 정상 연결되면 아래와 같이 로그가 남습니다.
2022-08-15 22:36:23.583 +09:00 [Error] [PowerManagerServer.Mqtt.MqttNetLogger.unknown_method:0] MqttClientSessionsManager: Unknown Device: '2ef432510027' 'DAWONDNS-B540_W-2ef432510027' 'sdfsdfsdfsdfsdfsdf' System.Exception: Unknown Device: '2ef432510027' 'DAWONDNS-B540_W-2ef432510027' 'sdfsdfsdfsdfsdfsdf' at MQTTnet.Server.Internal.MqttClientSessionsManager.ValidateConnection(MqttConnectPacket connectPacket, IMqttChannelAdapter channelAdapter) at MQTTnet.Server.Internal.MqttClientSessionsManager.HandleClientConnectionAsync(IMqttChannelAdapter channelAdapter, CancellationToken cancellationToken) |
플러그 등록과정을 거치지 않아 mqtt 서버에 접근을 못하는 상태입니다.
16. 플러그 등록
webui 에서 아래와 같이 등록을 수행합니다.
등록할 때 나온 로그 기준으로 등록을 하시면 됩니다.
Mqtt Topic: dwd Push: {"mac":"2ef432510027","api_server_addr":"dwapi.dawonai.com","api_server_port":"18443","server_addr":"dwmqtt.dawonai.com","server_port":"8883","ssl_support":"yes","ssid":"PowerManager","pass":"12345678","user_id":"test@naver.com/naver","company":"DAWONDNS","model":"B540_W","lati":"37.6523018","long":"127.0622559","topic":"dwd"} Send: 332 Byte. {"mac":"2ef432510027","respone":"OK"} 37 {"mac":"2ef432510027","respone":"OK"} 네트워크를 정상화 시킨 후 Enter를 입력하세요. verify: zgsdffsdfsdfsddddddddd mqtt_key: sdfsdfsdfsdfsdfsdf {"time":1660564616786,"statusCode":"Success","code":null,"message":null} |
등록을 하게 되면 서버 로그에 아래의 로그가 남고 정상 동작하게 됩니다.
er.unknown_method:0] task 'STATUS_SYNC_TASK-2ef432510027' starting. 2022-08-15 22:39:23.875 +09:00 [Information] [PowerManagerServer.Mqtt.MqttNetLogger.unknown_method:0] MqttClientConnection: Client 'DAWONDNS-2ef432510027': Session started. 2022-08-15 22:39:23.876 +09:00 [Information] [System.Threading.Tasks.CustomTaskScheduler.ITaskWorker.unknown_method:0] task 'STATUS_SYNC_TASK-2ef432510027' started. |
17. 플러그 용 공유기가 없을 때
오늘 새벽 아래의 글을 작성했습니다.
https://blog.djjproject.com/808
일단 wifiap 가 정상 동작한다는 가정하에, 아래의 추가 수정을 합니다.
macvlan 네트워크의 경우 호스트에서 접근하지 못하는 문제가 있습니다.
아래의 글을 참고하여 네트워크를 수정합니다.
https://blog.djjproject.com/797
# 저는 이더넷 이름이 vmbr0 입니다. (eth0 enpXsX 일 수도 있습니다.) root@debian:~# ip link add macvlan-shim link vmbr0 type macvlan mode bridge # 네트워크 대역에서 빈 곳을 하나 지정해서 ip 추가해줍니다. root@debian:~# ip addr add 192.168.0.234/24 dev macvlan-shim # 인터페이스를 up 시켜줍니다. root@debian:~# ip link set macvlan-shim up # 파워매니저 서버가 돌고있는 ip를 route 추가 해줍니다. root@debian:~# ip route add 192.168.0.200 dev macvlan-shim |
일단 192.168.0.200 이 호스트에서 연결이 가능한지 확인합니다.
인증서가 등록이 되어 있지 않아 에러가 나지만 정상 연결 됩니다.
root@debian:~# curl https://192.168.0.200 curl: (60) SSL certificate problem: unable to get local issuer certificate More details here: https://curl.haxx.se/docs/sslcerts.html curl failed to verify the legitimacy of the server and therefore could not establish a secure connection to it. To learn more about this situation and how to fix it, please visit the web page mentioned above. |
그리고 위의 스크립트를 init 스크립트나 rc.local 에 등록합니다.
nmcli 의 post-up-d 를 통해 등록할 수 있지만 귀찮아서 init 스크립트에 등록합니다.
root@debian:~# cat /opt/scripts/init.sh # macvlan powermanager ip link add macvlan-shim link vmbr0 type macvlan mode bridge ip addr add 192.168.0.234/24 dev macvlan-shim ip link set macvlan-shim up ip route add 192.168.0.200 dev macvlan-shim |
wifiap 컨테이너 설정을 변경합니다.
해당 와이파이를 PowerManager 전용으로 사용하기 위해 아래의 명령으로 다시 생성합니다.
root@debian:/opt/wifiap# docker run --restart unless-stopped -dit --name wifiap -e INTERFACE=wlo2 -e OUTGOINGS=macvlan-shim --net host --privileged offlinehacker/docker-ap |
내부적으로 /bin/wlanstart.sh 에 dhcpd 설정이 들어 있습니다.
root@debian:/opt/wifiap# docker cp wifiap:/bin/wlanstart.sh . root@debian:/opt/wifiap# vi wlanstart.sh 110 echo "Configuring DHCP server .." 111 112 cat > "/etc/dhcp/dhcpd.conf" <<EOF 113 option domain-name-servers 192.168.0.200, 192.168.0.200; 114 option subnet-mask 255.255.255.0; 115 option routers ${AP_ADDR}; 116 subnet ${SUBNET} netmask 255.255.255.0 { 117 range ${SUBNET::-1}100 ${SUBNET::-1}200; 118 } 119 EOF |
설정값을 다시 넣어주고 재시작 합니다.
root@debian:/opt/wifiap# docker cp wlanstart.sh wifiap:/bin/wlanstart.sh root@debian:/opt/wifiap# docker restart wifiap root@debian:/opt/wifiap# docker logs -f wifiap --tail 10 PID file: /run/dhcp/dhcpd.pid Wrote 1 leases to leases file. Listening on LPF/wlo2/50:76:af:ac:0e:6d/192.168.254.0/24 Sending on LPF/wlo2/50:76:af:ac:0e:6d/192.168.254.0/24 Sending on Socket/fallback/fallback-net Starting HostAP daemon ... Configuration file: /etc/hostapd.conf Using interface wlo2 with hwaddr 50:76:af:ac:0e:6d and ssid "j5005" wlo2: interface state UNINITIALIZED->ENABLED wlo2: AP-ENABLED |
플러그를 hostapd 가 만든 와이파이로 연결할 수 있게 재 연결합니다.
C:\Users\USER\Downloads\Win64-e5d5f965>PowerManagerConfig.exe --host 192.168.244.1 --port 5000 --web_server_addr https://192.168.0.200 --clientCertificate C.p12 --clientCertificatePassword 123456 Common.Logging Revision: 32774953 Common.Core Revision: 31a17c79 PowerManagerConfig Revision: e5d5f965 [::ffff:192.168.244.1]:5000 Connected Mode V1 (B540 <= v1.01.26) or V2 (B540 == v1.01.28) or V3 (B540 == v1.01.30) or V4 (B550) (default V1): V3 [DUT->PC] START_OK:2ef432510027# SSID: j5005 Wifi Password: 12345678 UserId: test@naver.com/naver Model: B540_W Mqtt Topic: dwd Push: {"mac":"2ef432510027","api_server_addr":"dwapi.dawonai.com","api_server_port":"18443","server_addr":"dwmqtt.dawonai.com","server_port":"8883","ssl_support":"yes","ssid":"j5005","pass":"12345678","user_id":"test@naver.com/naver","company":"DAWONDNS","model":"B540_W","lati":"37.6523018","long":"127.0622559","topic":"dwd"} Send: 325 Byte. {"mac":"2ef432510027","respone":"OK"} 37 {"mac":"2ef432510027","respone":"OK"} 네트워크를 정상화 시킨 후 Enter를 입력하세요. verify: mqtt_key: {"time":1660571564758,"statusCode":"Success","code":null,"message":null} |
그러면 wifiap 로그에 플러그가 연결했다는 로그가 나옵니다.
Using interface wlo2 with hwaddr 50:76:af:ac:0e:6d and ssid "j5005" wlo2: interface state UNINITIALIZED->ENABLED wlo2: AP-ENABLED wlo2: STA 2c:f4:32:51:00:27 IEEE 802.11: authenticated wlo2: STA 2c:f4:32:51:00:27 IEEE 802.11: associated (aid 1) wlo2: AP-STA-CONNECTED 2c:f4:32:51:00:27 wlo2: STA 2c:f4:32:51:00:27 RADIUS: starting accounting session 9CD439C048801956 wlo2: STA 2c:f4:32:51:00:27 WPA: pairwise key handshake completed (RSN) |
아래와 같이 잘 작동하며, 아이피도 wifiap 설정 당시 ip 로 잘 잡혀있는 것을 확인할 수 있습니다.
감사합니다. 일단 여기서 이 글은 마치겠습니다.
감사합니다.