"시놀로지 도커 설정"의 두 판 사이의 차이
둘러보기로 이동
검색으로 이동
Kim135797531 (토론 | 기여) (새 문서: ===== Nginx 프록시 서버 ===== * 이건 도커가 아닌 시놀로지 VMM에 위치 * Alpine * Cloudflare 연동 expose 서버 * 일본 특성상 IPv4 포트가 매우 제한적...) |
Kim135797531 (토론 | 기여) 잔글 |
||
1번째 줄: | 1번째 줄: | ||
=== | === 외부 노출 서버 (IPv6 보고 및 웹 프록시) === | ||
* 이건 도커가 아닌 시놀로지 VMM에 위치 | * 이건 도커가 아닌 시놀로지 VMM에 위치 | ||
* | * alpine | ||
* Cloudflare 연동 | |||
==== 마운트 설정 ==== | |||
* alpine에 nfsmount 설치 | |||
** apk add nfsmount | |||
* /etc/fstab에 다음 내용 추가 | |||
** 맨 뒤의 _netdev와 0 0을 꼭 추가해야 한다<syntaxhighlight lang="sh"> | |||
내부서버IP:/volume1/시놀로지폴더 /마운트경로 nfs nfsvers=3,rsize=524288,wsize=524288,ro,auto,nolock,_netdev 0 0 | |||
</syntaxhighlight> | |||
==== Cloudflare 연동 IP 등록 ==== | |||
* 일본 특성상 IPv4 포트가 매우 제한적으로 열려 있고, 10000번대 밑으로는 아예 열리지도 않음 | * 일본 특성상 IPv4 포트가 매우 제한적으로 열려 있고, 10000번대 밑으로는 아예 열리지도 않음 | ||
* IPv6는 이런 제한이 없음. 공유기가 각각의 머신에 뿌려주는 IP는 DHCP라기보다는 일본 인터넷에 직접 연결된 공인 IP. | * IPv6는 이런 제한이 없음. 공유기가 각각의 머신에 뿌려주는 IP는 DHCP라기보다는 일본 인터넷에 직접 연결된 공인 IP. | ||
** IPv6는 설계시부터 모든 기기가 고유의 공인 IP를 갖는 형태로 설계됨. 다만 그 특성상 보안에 취약하므로, 영구 IPv6 주소와 별개로 임시 IPv6가 부여되어, 수시로 주소가 바뀜. | ** IPv6는 설계시부터 모든 기기가 고유의 공인 IP를 갖는 형태로 설계됨. 다만 그 특성상 보안에 취약하므로, 영구 IPv6 주소와 별개로 임시 IPv6가 부여되어, 수시로 주소가 바뀜. | ||
** 주소 바뀜을 체크하여, Cloudflare DNS에 등록해 주는 역할 | ** 주소 바뀜을 체크하여, Cloudflare DNS에 등록해 주는 역할 (v6 레코드인 AAAA를 업데이트 함) | ||
** 다음 파일을 alpine 서버의 /etc/init.d에 | ** 다음 파일을 alpine 서버의 /etc/init.d에 저장. (파일 이름 cloudflare-alpine.service)<syntaxhighlight lang="shell" line="1"> | ||
#!/sbin/openrc-run | #!/sbin/openrc-run | ||
22번째 줄: | 32번째 줄: | ||
description="Update Cloudflare DNS" | description="Update Cloudflare DNS" | ||
command="/usr/bin/python3 /root/cloudflare-alpine.py" | |||
pidfile="/var/run/cloudflare/cloudflare.pid" | pidfile="/var/run/cloudflare/cloudflare.pid" | ||
command_background="yes" | command_background="yes" | ||
38번째 줄: | 47번째 줄: | ||
mkdir -p /var/run/cloudflare || return 1 | mkdir -p /var/run/cloudflare || return 1 | ||
} | } | ||
</syntaxhighlight>실제 업데이트를 수행하는 Python 파일을 위의 서비스 스크립트에 지정된 위치로 잘 저장<syntaxhighlight lang="python3" line="1"> | |||
#!/usr/bin/env python | |||
# -*- coding: utf-8 -*- | |||
import os | |||
import requests | |||
import json | |||
from time import sleep | |||
CLOUDFLARE_KEY = 'XXX' | |||
CLOUDFLARE_ZONE_ID = 'XXX' | |||
CLOUDFLARE_DNS_TOKEN = 'XXX' | |||
CLOUDFLARE_HEADER = { | |||
'Authorization': 'Bearer {}'.format(CLOUDFLARE_DNS_TOKEN), | |||
'Content-Type': 'application/json' | |||
} | |||
DNS_GET_URL = 'https://api.cloudflare.com/client/v4/zones/{}/dns_records'.format(CLOUDFLARE_ZONE_ID) | |||
device = 'eth0' | |||
addr_file = '/tmp/cloudflare.addr6' | |||
def check(): | |||
addr = '' | |||
try: | |||
with open(addr_file, 'r') as f: | |||
addr = f.read() | |||
except: | |||
pass | |||
get_addr_cmd = "ip -6 addr list scope global $device | " \ | |||
"grep -v ' fd' | " \ | |||
"grep -v 'deprecated' | " \ | |||
"grep -v 'mngtmpaddr' | " \ | |||
"head -n 2 | " \ | |||
"tail -n 1" | |||
new_addr = os.popen(get_addr_cmd).read() | |||
new_addr = new_addr.split()[1] | |||
new_addr = new_addr.split('/')[0] | |||
if addr == new_addr: | |||
print('same ip {}'.format(new_addr)) | |||
else: | |||
r = requests.get(DNS_GET_URL, headers=CLOUDFLARE_HEADER) | |||
j = json.loads(r.text) | |||
for item in j['result']: | |||
dns_put_url = DNS_GET_URL + '/' + item['id'] | |||
new_data = dict( | |||
type=item['type'], | |||
name=item['name'], | |||
content=new_addr, | |||
) | |||
if item['type'] == 'AAAA': | |||
new_data['proxied'] = True | |||
requests.put(dns_put_url, data=json.dumps(new_data), headers=CLOUDFLARE_HEADER) | |||
elif item['type'] == 'TXT': | |||
new_data['content'] = 'v=spf1 {} ~all'.format(new_addr) | |||
requests.put(dns_put_url, data=json.dumps(new_data), headers=CLOUDFLARE_HEADER) | |||
with open(addr_file, 'w') as f: | |||
f.write(new_addr) | |||
f.close() | |||
print('updated ip {}'.format(new_addr)) | |||
while True: | |||
check() | |||
sleep(60) | |||
</syntaxhighlight> | |||
** 그 후 서비스 등록<syntaxhighlight lang="sh"> | |||
rc-update add cloudflare-alpine.service | |||
rc-service cloudflare-alpine.service restart | |||
rc-update -u | |||
</syntaxhighlight> | </syntaxhighlight> | ||
==== Nginx 웹 프록시 ==== | |||
* Cloudflare로부터 오는 HTTPS 요청을 처리하여, 내부 서버에 전달 | |||
* 처음 도입 목적은 Cloudflare의 IPv6 over IPv4 기능을 이용하기 위함 | |||
* 생각해보니 외부/내부를 분리하여 보안성도 높아지고, 도커를 이용한 로드밸런서 구현 및 포트 번호 추상화가 가능해져 채택 | |||
* /etc/nginx/conf.d는 시놀로지에 config를 등록해 놓고 폴더째로 마운트 | |||
* wiki-proxy.conf 예시 | |||
** proxy_set_header를 설정해야 내부 서버에서 보이는 접속 요청 IP가 실제 사용자의 IP로 제대로 뜬다 | |||
** 내부 서버사이의 통신은 http로 하여 속도 향상 (방화벽 설정은 따로)<syntaxhighlight lang="nginx"> | |||
server { | |||
listen 80; | |||
listen [::]:80; | |||
server_name wiki.dong-min.kim; | |||
location / { | |||
return 301 https://$server_name$request_uri; | |||
} | |||
} | |||
server { | |||
listen 443 ssl; | |||
listen [::]:443 ssl; | |||
ssl_certificate pem파일; | |||
ssl_certificate_key key파일; | |||
server_name wiki.dong-min.kim; | |||
server_tokens off; | |||
location / { | |||
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-Host $server_name; | |||
proxy_set_header Client-IP $remote_addr; | |||
proxy_pass http://내부 서버 주소:포트; | |||
} | |||
} | |||
</syntaxhighlight> | |||
* | |||
* | |||
* | |||
* | |||
* nginx 1.17.8 alpine | * nginx 1.17.8 alpine | ||
* php 7.2.9 fpm alpine | * php 7.2.9 fpm alpine | ||
* 위키 | * 위키 | ||
** 위키 | ** 위키 | ||
47번째 줄: | 175번째 줄: | ||
** parsoid | ** parsoid | ||
** mathoid | ** mathoid | ||
** | ** | ||
* 토렌트 | * 토렌트 | ||
** archlinux deluge openvpn | ** archlinux deluge openvpn |
2020년 2월 27일 (목) 07:32 판
외부 노출 서버 (IPv6 보고 및 웹 프록시)
- 이건 도커가 아닌 시놀로지 VMM에 위치
- alpine
마운트 설정
- alpine에 nfsmount 설치
- apk add nfsmount
- /etc/fstab에 다음 내용 추가
- 맨 뒤의 _netdev와 0 0을 꼭 추가해야 한다
내부서버IP:/volume1/시놀로지폴더 /마운트경로 nfs nfsvers=3,rsize=524288,wsize=524288,ro,auto,nolock,_netdev 0 0
- 맨 뒤의 _netdev와 0 0을 꼭 추가해야 한다
Cloudflare 연동 IP 등록
- 일본 특성상 IPv4 포트가 매우 제한적으로 열려 있고, 10000번대 밑으로는 아예 열리지도 않음
- IPv6는 이런 제한이 없음. 공유기가 각각의 머신에 뿌려주는 IP는 DHCP라기보다는 일본 인터넷에 직접 연결된 공인 IP.
- IPv6는 설계시부터 모든 기기가 고유의 공인 IP를 갖는 형태로 설계됨. 다만 그 특성상 보안에 취약하므로, 영구 IPv6 주소와 별개로 임시 IPv6가 부여되어, 수시로 주소가 바뀜.
- 주소 바뀜을 체크하여, Cloudflare DNS에 등록해 주는 역할 (v6 레코드인 AAAA를 업데이트 함)
- 다음 파일을 alpine 서버의 /etc/init.d에 저장. (파일 이름 cloudflare-alpine.service)실제 업데이트를 수행하는 Python 파일을 위의 서비스 스크립트에 지정된 위치로 잘 저장
#!/sbin/openrc-run # $apk add python3 # $apk add py3-requests # Copy this file into /etc/init.d/ # Test by $rc-service cloudflare-alpine.service start # $rc-update add cloudflare-alpine.service # $rc-service cloudflare-alpine.service restart # $rc-update -u description="Update Cloudflare DNS" command="/usr/bin/python3 /root/cloudflare-alpine.py" pidfile="/var/run/cloudflare/cloudflare.pid" command_background="yes" depend() { need net need nfsmount need sshd after iptables } start_pre() { ebegin "Starting cloudflare" mkdir -p /var/run/cloudflare || return 1 }
#!/usr/bin/env python # -*- coding: utf-8 -*- import os import requests import json from time import sleep CLOUDFLARE_KEY = 'XXX' CLOUDFLARE_ZONE_ID = 'XXX' CLOUDFLARE_DNS_TOKEN = 'XXX' CLOUDFLARE_HEADER = { 'Authorization': 'Bearer {}'.format(CLOUDFLARE_DNS_TOKEN), 'Content-Type': 'application/json' } DNS_GET_URL = 'https://api.cloudflare.com/client/v4/zones/{}/dns_records'.format(CLOUDFLARE_ZONE_ID) device = 'eth0' addr_file = '/tmp/cloudflare.addr6' def check(): addr = '' try: with open(addr_file, 'r') as f: addr = f.read() except: pass get_addr_cmd = "ip -6 addr list scope global $device | " \ "grep -v ' fd' | " \ "grep -v 'deprecated' | " \ "grep -v 'mngtmpaddr' | " \ "head -n 2 | " \ "tail -n 1" new_addr = os.popen(get_addr_cmd).read() new_addr = new_addr.split()[1] new_addr = new_addr.split('/')[0] if addr == new_addr: print('same ip {}'.format(new_addr)) else: r = requests.get(DNS_GET_URL, headers=CLOUDFLARE_HEADER) j = json.loads(r.text) for item in j['result']: dns_put_url = DNS_GET_URL + '/' + item['id'] new_data = dict( type=item['type'], name=item['name'], content=new_addr, ) if item['type'] == 'AAAA': new_data['proxied'] = True requests.put(dns_put_url, data=json.dumps(new_data), headers=CLOUDFLARE_HEADER) elif item['type'] == 'TXT': new_data['content'] = 'v=spf1 {} ~all'.format(new_addr) requests.put(dns_put_url, data=json.dumps(new_data), headers=CLOUDFLARE_HEADER) with open(addr_file, 'w') as f: f.write(new_addr) f.close() print('updated ip {}'.format(new_addr)) while True: check() sleep(60)
- 그 후 서비스 등록
rc-update add cloudflare-alpine.service rc-service cloudflare-alpine.service restart rc-update -u
Nginx 웹 프록시
- Cloudflare로부터 오는 HTTPS 요청을 처리하여, 내부 서버에 전달
- 처음 도입 목적은 Cloudflare의 IPv6 over IPv4 기능을 이용하기 위함
- 생각해보니 외부/내부를 분리하여 보안성도 높아지고, 도커를 이용한 로드밸런서 구현 및 포트 번호 추상화가 가능해져 채택
- /etc/nginx/conf.d는 시놀로지에 config를 등록해 놓고 폴더째로 마운트
- wiki-proxy.conf 예시
- proxy_set_header를 설정해야 내부 서버에서 보이는 접속 요청 IP가 실제 사용자의 IP로 제대로 뜬다
- 내부 서버사이의 통신은 http로 하여 속도 향상 (방화벽 설정은 따로)
server { listen 80; listen [::]:80; server_name wiki.dong-min.kim; location / { return 301 https://$server_name$request_uri; } } server { listen 443 ssl; listen [::]:443 ssl; ssl_certificate pem파일; ssl_certificate_key key파일; server_name wiki.dong-min.kim; server_tokens off; location / { 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-Host $server_name; proxy_set_header Client-IP $remote_addr; proxy_pass http://내부 서버 주소:포트; } }
- nginx 1.17.8 alpine
- php 7.2.9 fpm alpine
- 위키
- 위키
- restbase
- parsoid
- mathoid
- 토렌트
- archlinux deluge openvpn
- busybox
- gitlab
- gitlab postgresql
- redis
- DB
- cassandra 3.5
- mysql5.7.29
- wordpress
- kb_apart
권한 관련