AWS EC2 에 OpenVPN 서버 구축
리눅스에서 OpenVPN 서버 구축해 보도록 한다. 리눅스 서버는 Ubuntu 24.04 LTS 이다.
아키텍쳐
현재 AWS 아키텍쳐는 다음과 같다.

OpenVPN 를 설치할 서버는 AWS 에 Public Subnet 에 있으며 외부에서 접속을 위해서 EIP(Elastic IP) 를 할당 해줬다. VPC 내에 모든 서버들은 172.31.0.0/16 대역폭에 자동으로 IP를 할당받아 Private IP 를 구성하도록 되어 있다.
이제 사내망 PC 에서 server1 에 Private IP 로 접속을 하기 위한 방법으로 OpenVPN 서버를 설치해보도록 한다.
OpenVPN 작동 방식
OpenVPN 의 작동방법은 NAT 기능을 이용하는 것이다. 먼저, OpenVPN 서버를 설치하고 기동하면 OpenVPN 서버는 서버에 tun0 라고 하는 네트워크 인터페이스 생성한다. 물론 이렇게 생성한 NIC에 네트워크 서브넷을 할당한다. tun0 에 IP를 할당하고 서브넷 라우팅도 함께 구성하게 된다.
이제 OpenVPN 클라이언트를 설치하고 설정파일을 읽어 연결을 하게 되면, OpenVPN 클라이언트는 PC 에 tap0 라고 하는 네트워크 인터페이스를 생성한다. 그리고 이 tap0 에는 OpenVPN 서버로부터 네트워크 관련 정보를 전달 받아서 tun0 와 동일네트워크에 IP, Defaut GW 를 구성하게 된다. 이를 다이어그램으로 표현하면 다음과 같다.

OpenVPN 을 이용하는 이유는 172.31.0.0/16 대역에 있는 서버에 접속하기 위해서다. AWS 아키텍쳐 그림상 server1 에 사내PC가 직접 접속할 방법이 없다. 하지만 OpenVPN 을 이용하면 가능하다. 다음과 같이 접속이 이루어진다.
사내PC(192.168.96.112.66) -> tap(192.168.200.56) —– 인터넷 —–> OpenVPN 서버 tun0(192.168.96.200.1) — NAT –> server1(172.31.0.43)
이러한 흐름을 보면 OpenVPN 서버의 설정에서 OpenVPN 서버와 Client 연결을 위한 네트워크 대역 할당과 server1 의 접속은 OpenVPN 서버를 거쳐서 와야하기 때문에 AWS VPC 네트워크 대역을 알려줘야 하고 OpenVPN 서버는 NAT 서버로 동작해야 한다는(그래서 iptables 을 이용한 MASQUERADE 설정을 한다.) 걸 알게 된다.
OpenVPN 2.6
현 시점에서 OpenVPN 은 2.5 를 기준으로 구분이 된다. 2.6 은 현재 최신 버전으로 사용되고 있는데, 2.5 를 기준으로해서 설정에 많은 변화가 있음으로 만일 처음 구축한다면 2.6으로 하고 호환성을 고려한다면 2.4 를 기준으로 구축하는 걸 권장 한다.
OpenVPN 설치
설치는 Ubuntu 24.04 LTS 에서 기본으로 제공하는 패키지로 설치가 가능하다. 이때 OpenVPN 이 사용할 인증서 생성을 위해서 easy-rsa 명령어도 함께 설치해야 한다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
~# apt install openvpn easy-rsa Reading package lists... Done Building dependency tree... Done Reading state information... Done The following additional packages will be installed: libpkcs11-helper1t64 Suggested packages: openvpn-dco-dkms openvpn-systemd-resolved easy-rsa The following NEW packages will be installed: libpkcs11-helper1t64 openvpn 0 upgraded, 2 newly installed, 0 to remove and 122 not upgraded. Need to get 731 kB of archives. After this operation, 1957 kB of additional disk space will be used. Do you want to continue? [Y/n] |
인증서 생성
OpenVPN 서버는 Client 와 보안통신을 위해서 인증서를 필요로 한다. 인증서를 만드는 것은 그렇게 쉬운 절차가 아니여서 많은 이들이 어려움을 겪는데, easy-rsa 를 이용하면 비교적 쉽게 만들 수 있다.
인증서는 서버 인증서와 클라이언트 인증서가 필요하고 이 둘의 인증서를 만들기 위한 CA 인증서도 있어야 한다.
easy-rsa 명령어만 이용하는게 아니라 디렉토리도 있어야 하는데 /usr/share/easy-rsa/3 에서 작업해야 한다.(중요)
easyrsa 초기화
먼저 easyrsa 를 초기화 해준다. /usr/share/easy-rsa 디렉토리로 이동한다. 여기서 다음과 같이 vars 파일을 만든다.
1 2 3 4 5 6 |
set_var EASYRSA_REQ_COUNTRY "KR" set_var EASYRSA_REQ_PROVINCE "Gangseo-gu" set_var EASYRSA_REQ_CITY "Seoul" set_var EASYRSA_REQ_ORG "SYSTEMV" set_var EASYRSA_REQ_EMAIL "admin@systemv.pe.kr" set_var EASYRSA_REQ_OU "Linux" |
이 파일은 CSR 내용이기 때문에 상황에 맞게 입력해주면 된다. 그리고 다음과 같이 easy-rsa 를 초기화 한다.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
]# ./easyrsa init-pki Using Easy-RSA 'vars' configuration: * /usr/share/easy-rsa/3/vars Notice ------ 'init-pki' complete; you may now create a CA or requests. Your newly created PKI dir is: * /usr/share/easy-rsa/3/pki Using Easy-RSA configuration: * /usr/share/easy-rsa/3/vars |
CA 인증서 제작
다음과 같이 root CA 인증서를 제작한다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
]# ./easyrsa build-ca nopass Using Easy-RSA 'vars' configuration: * /usr/share/easy-rsa/3/vars .......................+++++ ....................................................................................................................................................................+++++ 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. ----- Common Name (eg: your user, host, or server name) [Easy-RSA CA]:lgcns.fcc.co.kr Notice ------ CA creation complete. Your new CA certificate is at: * /usr/share/easy-rsa/3/pki/ca.crt Create an OpenVPN TLS-AUTH|TLS-CRYPT-V1 key now: See 'help gen-tls' Build-ca completed successfully. |
root CA 인증서가 생성되었다.
서버 인증서
서버 인증서를 만든다. 서버 인증서를 만들기 위해서는 도메인이 필요하다. 이 도메인은 반드시 있어야 하는건 아니고 서버-클라이언트간 보안을 위한 검증을 위한 것으로 가상으로 입력해줘도 된다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
]# ./easyrsa build-server-full openvpn.systemv.pe.kr nopass Using Easy-RSA 'vars' configuration: * /usr/share/easy-rsa/3/vars Generating a RSA private key ...............+++++ .......................................................................................................................+++++ writing new private key to '/usr/share/easy-rsa/3/pki/8f3780fb/temp.2.1' ----- Notice ------ Private-Key and Public-Certificate-Request files created. Your files are: * req: /usr/share/easy-rsa/3/pki/reqs/openvpn.systemv.pe.kr.req * key: /usr/share/easy-rsa/3/pki/private/openvpn.systemv.pe.kr.key You are about to sign the following certificate: Requested CN: 'openvpn.systemv.pe.kr' Requested type: 'server' Valid for: '825' days subject= commonName = openvpn.systemv.pe.kr Type the word 'yes' to continue, or any other input to abort. Confirm requested details: yes Using configuration from /usr/share/easy-rsa/3/pki/02b0a94b/temp.6.1 Check that the request matches the signature Signature ok The Subject's Distinguished Name is as follows commonName :ASN.1 12:'openvpn.systemv.pe.kr' Certificate is to be certified until Jun 22 05:41:51 2027 GMT (825 days) Write out database with 1 new entries Data Base Updated Notice ------ Inline file created: * /usr/share/easy-rsa/3/pki/inline/private/openvpn.systemv.pe.kr.inline Notice ------ Certificate created at: * /usr/share/easy-rsa/3/pki/issued/openvpn.systemv.pe.kr.crt |
openvpn.systemv.pe.kr 도메인은 가상으로 그냥 적은 것이다. 굳이 신경쓸 필요는 없다.
클라이언트 인증서 제작
여기서 특징이 있는데, OpenVPN 을 위한 Client 인증서는 사용자마다 제작을 해줘야 한다. 그래서 Client 이름은 ID나 이메일등을 지정해 주면 된다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
]# ./easyrsa build-client-full sbhyun nopass Using Easy-RSA 'vars' configuration: * /usr/share/easy-rsa/3/vars Generating a RSA private key ...............+++++ ......................................................+++++ writing new private key to '/usr/share/easy-rsa/3/pki/aade4cae/temp.2.1' ----- Notice ------ Private-Key and Public-Certificate-Request files created. Your files are: * req: /usr/share/easy-rsa/3/pki/reqs/linux.req * key: /usr/share/easy-rsa/3/pki/private/linux.key You are about to sign the following certificate: Requested CN: 'linux' Requested type: 'client' Valid for: '825' days subject= commonName = linux Type the word 'yes' to continue, or any other input to abort. Confirm requested details: yes Using configuration from /usr/share/easy-rsa/3/pki/06c316d2/temp.6.1 Check that the request matches the signature Signature ok The Subject's Distinguished Name is as follows commonName :ASN.1 12:'linux' Certificate is to be certified until Jun 22 05:44:31 2027 GMT (825 days) Write out database with 1 new entries Data Base Updated Notice ------ Inline file created: * /usr/share/easy-rsa/3/pki/inline/private/linux.inline Notice ------ Certificate created at: * /usr/share/easy-rsa/3/pki/issued/linux.crt |
Diffie-Hellman key 생성
서버 접속을 위한 Diffie-Hellman key 를 다음과 같이 생성해 준다.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
]# ./easyrsa gen-dh Using Easy-RSA 'vars' configuration: * /usr/share/easy-rsa/3/vars Generating DH parameters, 2048 bit long safe prime, generator 2 This is going to take a long time ......+........................... DH parameters appear to be ok. Notice ------ DH parameters of size 2048 created at: * /usr/share/easy-rsa/3/pki/dh.pem |
TLS-Auth key 인증 키 생성
다음과 같이 TLS-Auth 키를 생성해 준다.
1 |
]# openvpn --genkey --secret ./pki/ta.key |
생성한 키 복사
이렇게 생성한 키들을 OpenVPN 서버에 설정 디렉토리에 복사해 준다. 여기서 주의해야 할것이 배포판마다 설정 디렉토리가 다를 수 있다. Ubuntu24.04 LTS 의 경우에 /etc/openvpn 디렉토리다.
1 |
]# cp -pR /usr/share/easy-rsa/3/pki/{issued,private,ca.crt,dh.pem,ta.key} /etc/openvpn |
OpenVPN 서버 설정
이제 필요한 파일을 모두 갖췄으니, OpenVPN 설정을 해야 한다. 설정을 어떻게 해야할지 모르기 때문에 OpenVPN 에서 제공하는 Sample 파일을 이용해서 해보자.
1 |
]# cp /usr/share/doc/openvpn/sample/sample-config-files/server.conf /etc/openvpn |
이제 server.conf 파일을 다음과 같이 설정해준다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
port 1194 proto udp dev tun # Network Interface Card ca ca.crt cert issued/linux.systemvp.pe.kr.crt dh dh.pem server 192.168.200.0 255.255.255.0 # OpenVPN CIDR ifconfig-pool-persist /var/log/openvpn/ipp.txt push "route 172.31.0.0 255.255.0.0" # AWS VPC CIDR push "dhcp-option DNS 8.8.8.8" # Public Primary DNS Server push "dhcp-option DNS 8.8.4.4" # Public Sencondary DNS Server keepalive 10 120 persist-key persist-tun status /var/log/openvpn/openvpn-status.log log /var/log/openvpn/openvpn.log log-append /var/log/openvpn/openvpn.log verb 3 explicit-exit-notify 0 comp-lzo |
여기서 AWS VPC CIDR 과 OpenVPN CIDR, DNS 서버 설정등을 주의해서 봐야 한다.
iptables 설정
테스트 하는 서버에는 ufw 명령어가 없다. 만일 ufw 명령어가 있다면 이것을 이용하는 방법으로 해야한다.
iptables 설정을 하는 이유는 MASQUERADE 때문이다. OpenVPN 서버가 NAT로 작동하기 위해서 Iptables 을 이용해 패킷의 흐름을 제어해야 하기 때문이다.
여기서 또 한가지, OpenVPN 서버가 실행중일 때에만 MASQUERADE 설정을 유지하고 실행하지 않을때에는 설정을 꺼야 한다. Iptables 초기화를 하면 설정이 초기화 된다. 이를 위해서 Iptables 설정과 해제 두개의 파일을 작성한다.
먼저 add-bridge.sh 라는 이름으로 쉘 스크립트를 다음과 같이 만든다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
#!/bin/bash if [ ! -x /usr/sbin/iptables ]; then exit 0 fi IPTABLES=/usr/sbin/iptables MY_IP=172.31.2.195 IF=enX0 VPNIF=tun0 PORT=1194 # flush a default policy of rules $IPTABLES -F # flush a policy in the custom rules $IPTABLES -X # Defined a default policy of rules $IPTABLES -P INPUT ACCEPT $IPTABLES -P OUTPUT ACCEPT $IPTABLES -P FORWARD ACCEPT # default rule 22,443,53 $IPTABLES -A INPUT -i ${IF} -p tcp ! --syn -j ACCEPT # 22 $IPTABLES -A INPUT -i ${IF} -p TCP --sport 1024: -d ${MY_IP} --dport 22 -j ACCEPT $IPTABLES -A OUTPUT -o ${IF} -p TCP ! --syn -s ${MY_IP} --sport 22 --dport 1024: -j ACCEPT # 53 $IPTABLES -A OUTPUT -p UDP --sport 1024: --dport 53 -m state --state NEW -j ACCEPT $IPTABLES -A INPUT -p UDP --sport 53 --dport 1024: -m state --state ESTABLISHED -j ACCEPT $IPTABLES -A OUTPUT -p TCP --sport 1024: --dport 53 -m state --state NEW -j ACCEPT $IPTABLES -A INPUT -p TCP --sport 53 --dport 1024: -m state --state ESTABLISHED -j ACCEPT # 443 #$IPTABLES -A INPUT -i ${IF} -p TCP --sport 1024: -d ${MY_IP} --dport 443 -j ACCEPT #$IPTABLES -A OUTPUT -o ${IF} -p TCP ! --syn -s ${MY_IP} --sport 443 --dport 1024: -j ACCEPT # 1194 $IPTABLES -A INPUT -i ${IF} -p UDP --sport ${PORT} --dport 1024: -m state --state ESTABLISHED -j ACCEPT $IPTABLES -A OUTPUT -o ${IF} -p UDP --sport 1024: --dport ${PORT} -m state --state NEW -j ACCEPT # NAT to a vpn $IPTABLES -I FORWARD 1 -i ${VPNIF} -s 192.168.200.0/24 -o ${IF} -d 172.31.0.0/16 -j ACCEPT # Masquerade $IPTABLES -t nat -I POSTROUTING 1 -o ${IF} -j MASQUERADE |
내용이 많지만, 맨 아래 두줄이 핵심이다. tun0 네트워크 장치로부터 192.168.200.0/24 대역으로 들어온 IP에 대해서 enX0 장치를 이용해 172.31.0.0/16 대역으로 패킷을 포워딩 하고 MASQUERADE 설정을 해주고 있다.
OpenVPN 서버가 정지하면 초기화 해주는 remove-bridge.sh 파일을 만들어 준다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
#!/bin/bash if [ ! -x /usr/sbin/iptables ]; then exit 0 fi IPTABLES=/usr/sbin/iptables # flush a default policy of rules $IPTABLES -F $IPTABLES -X $IPTABLES -P INPUT ACCEPT $IPTABLES -P OUTPUT ACCEPT $IPTABLES -P FORWARD ACCEPT # general nat $IPTABLES -t nat -D POSTROUTING 1 |
모든 체인을 플러쉬하고 POSTROUTING 룰을 삭제한다.
이렇게 만들어진 파일을 systemd unit 파일인 openvpn@server 에 override 설정으로 추가해준다. override 설정은 파일을 일반 편집으로 해서 추가해주면 자동으로 알아서 추가가 된다.
1 2 3 4 5 6 |
]# export SYSTEMD_EDITOR=vim ]# systemctl edit openvpn@server [Service] ExecStartPost=/etc/openvpn/add-bridge.sh ExecStopPost=/etc/openvpn/remove-bridge.sh |
이렇게 하면 openvpn 시작/중지 때마다 쉘 스크립트가 실행 된다.
시작/중지
이제 시작과 중지를 해보자. 다음과 같이 한다.
1 2 |
]# systemctl start openvpn@server ]# systemctl stop openvpn@server |
OpenVPN 클라이언트 설정
OpenVPN 홈페이지에서 Windows 용 클라이언트를 다운받아 설치한다. 설정 파일은 개인마다 가지고 있어야 해서 전체 시스템에 액세스하는 디렉토리에 넣으면 좋지 않다. 이는 설치가 끝나면 팝업으로 알려주는데, C:\Users\계정ID\OpenVPN\config 이다.
이 디렉토리에 서버에서 작성한 파일을 복사해줘야 한다. 복사해야 할 파일은 다음과 같다.
- linux.crt (클라이언트 인증서)
- linux.key (클라이언트 인증서 암호화 키)
- ca.crt (CA 인증서)
- ta.key (TLS-Auth Key)
이제 linux.ovpn 파일을 다음과 같이 작성한다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
client dev tun proto udp remote <openvpn 공인IP> 1194 resolv-retry infinite nobind persist-key persist-tun ca ca.crt cert linux.crt key linux.key remote-cert-tls server comp-lzo yes tls-auth ta.key 1 verb 3 |
위와같이 작성하고 OpenVPN Client 에서 설정 파일을 지정하고 연결하기 하면 연결이 된다.