Giter Club home page Giter Club logo

ovpn-admin's Introduction

ovpn-admin

Simple web UI to manage OpenVPN users, their certificates & routes in Linux. While backend is written in Go, frontend is based on Vue.js.

Originally created in Flant for internal needs & used for years, then updated to be more modern and publicly released in March'21. Your contributions are welcome!

DISCLAIMER! This project was created for experienced users (system administrators) and private (e.g., protected by network policies) environments only. Thus, it is not implemented with security in mind (e.g., it doesn't strictly check all parameters passed by users, etc.). It also relies heavily on files and fails if required files aren't available.

Features

  • Adding, deleting OpenVPN users (generating certificates for them);
  • Revoking/restoring/rotating users certificates;
  • Generating ready-to-user config files;
  • Providing metrics for Prometheus, including certificates expiration date, number of (connected/total) users, information about connected users;
  • (optionally) Specifying CCD (client-config-dir) for each user;
  • (optionally) Operating in a master/slave mode (syncing certs & CCD with other server);
  • (optionally) Specifying/changing password for additional authorization in OpenVPN;
  • (optionally) Specifying the Kubernetes LoadBalancer if it's used in front of the OpenVPN server (to get an automatically defined remote in the client.conf.tpl template).
  • (optionally) Storing certificates and other files in Kubernetes Secrets (Attention, this feature is experimental!).

Screenshots

Managing users in ovpn-admin: ovpn-admin UI

An example of dashboard made using ovpn-admin metrics: ovpn-admin metrics

Installation

1. Docker

There is a ready-to-use docker-compose.yaml, so you can just change/add values you need and start it with start.sh.

Requirements: You need Docker and docker-compose installed.

Commands to execute:

git clone https://github.com/flant/ovpn-admin.git
cd ovpn-admin
./start.sh

1.1

Ready docker images available on Docker Hub . Tags are simple: $VERSION or latest for ovpn-admin and openvpn-$VERSION or openvpn-latest for openvpn-server

2. Building from source

Requirements. You need Linux with the following components installed:

Commands to execute:

git clone https://github.com/flant/ovpn-admin.git
cd ovpn-admin
./bootstrap.sh
./build.sh
./ovpn-admin 

(Please don't forget to configure all needed params in advance.)

3. Prebuilt binary

You can also download and use prebuilt binaries from the releases page — just choose a relevant tar.gz file.

Notes

  • this tool uses external calls for bash, coreutils and easy-rsa, thus Linux systems only are supported at the moment.
  • to enable additional password authentication provide --auth and --auth.db="/etc/easyrsa/pki/users.db" flags and install openvpn-user. This tool should be available in your $PATH and its binary should be executable (+x).
  • master-replica synchronization does not work with --storage.backend=kubernetes.secrets - WIP
  • additional password authentication does not work with --storage.backend=kubernetes.secrets - WIP
  • if you use --ccd and --ccd.path="/etc/openvpn/ccd" abd plan to use static address setup for users do not forget to provide --ovpn.network="172.16.100.0/24" with valid openvpn-server network
  • tested only with Openvpn-server versions 2.4 and 2.5 with only tls-auth mode
  • not tested with EasyRsa version > 3.0.8
  • status of users connections update every 28 second(no need to ask why =))

Usage

usage: ovpn-admin [<flags>]

Flags:
  --help                       show context-sensitive help (try also --help-long and --help-man)

  --listen.host="0.0.0.0"      host for ovpn-admin
  (or OVPN_LISTEN_HOST)

  --listen.port="8080"         port for ovpn-admin
  (or OVPN_LISTEN_PORT)

  --listen.base-url="/"        base URL for ovpn-admin web files
  (or $OVPN_LISTEN_BASE_URL)

  --role="master"              server role, master or slave
  (or OVPN_ROLE)

  --master.host="http://127.0.0.1"  
  (or OVPN_MASTER_HOST)       URL for the master server

  --master.basic-auth.user=""  user for master server's Basic Auth
  (or OVPN_MASTER_USER)
 
  --master.basic-auth.password=""  
  (or OVPN_MASTER_PASSWORD)   password for master server's Basic Auth

  --master.sync-frequency=600  master host data sync frequency in seconds
  (or OVPN_MASTER_SYNC_FREQUENCY)

  --master.sync-token=TOKEN    master host data sync security token
  (or OVPN_MASTER_TOKEN)

  --ovpn.network="172.16.100.0/24"  
  (or OVPN_NETWORK)           NETWORK/MASK_PREFIX for OpenVPN server

  --ovpn.server=HOST:PORT:PROTOCOL ...  
  (or OVPN_SERVER)            HOST:PORT:PROTOCOL for OpenVPN server
                               can have multiple values

  --ovpn.server.behindLB       enable if your OpenVPN server is behind Kubernetes
  (or OVPN_LB)                Service having the LoadBalancer type

  --ovpn.service="openvpn-external"  
  (or OVPN_LB_SERVICE)        the name of Kubernetes Service having the LoadBalancer
                               type if your OpenVPN server is behind it

  --mgmt=main=127.0.0.1:8989 ...  
  (or OVPN_MGMT)              ALIAS=HOST:PORT for OpenVPN server mgmt interface;
                               can have multiple values

  --metrics.path="/metrics"    URL path for exposing collected metrics
  (or OVPN_METRICS_PATH)

  --easyrsa.path="./easyrsa/"  path to easyrsa dir
  (or EASYRSA_PATH)

  --easyrsa.index-path="./easyrsa/pki/index.txt"  
  (or OVPN_INDEX_PATH)        path to easyrsa index file

  --ccd                        enable client-config-dir
  (or OVPN_CCD)

  --ccd.path="./ccd"           path to client-config-dir
  (or OVPN_CCD_PATH)

  --templates.clientconfig-path=""  
  (or OVPN_TEMPLATES_CC_PATH) path to custom client.conf.tpl

  --templates.ccd-path=""      path to custom ccd.tpl
  (or OVPN_TEMPLATES_CCD_PATH)

  --auth.password              enable additional password authorization
  (or OVPN_AUTH)

  --auth.db="./easyrsa/pki/users.db"
  (or OVPN_AUTH_DB_PATH)      database path for password authorization
  
  --log.level                  set log level: trace, debug, info, warn, error (default info)
  (or LOG_LEVEL)
  
  --log.format                 set log format: text, json (default text)
  (or LOG_FORMAT)
  
  --storage.backend            storage backend: filesystem, kubernetes.secrets (default filesystem)
  (or STORAGE_BACKEND)
 
  --version                    show application version

Further information

Please feel free to use issues and discussions to get help from maintainers & community.

ovpn-admin's People

Contributors

cheyenneforbes avatar miklezzzz avatar minimajack avatar noamkush avatar pashcovich avatar sabuhish avatar shurup avatar sprait avatar strnk avatar uzhinskiy avatar vabrn avatar vitaliy-sn avatar vmrm avatar wzooff avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

ovpn-admin's Issues

reach client peers from host network . docker version

I'm trying to reach openvpn client peers (10.8.20.0/24) from my lan network (10.8.0.0/24) but cannot even ping.... Maybe it's a network related or docker configure but for some scenarios its useful.

Also as improvement I have to masquerade traffic form openvpn clients (10.8.20.0/24) to lan segment (10.8.0.0/24) to reach lan from openvpn clients.

host:
iptables -t nat -A POSTROUTING -o HOST_INTERFACE -j MASQUERADE

feature request: batch add users

It will be great if we can make batch migration of other openvpn scenarios. Maybe an API or command line tool?

I tried openvp-user but seems its only related to users auth database not making certs or easyrsa stuff. I have a bunch of users with pam_auth login credentials and adding one by one it's a pain in the a**

Thanks a lot....

Release 1.7.4 returns 404 on amd64

On amd64, using 1.7.4 (env based configuration) the service starts, but returns 404 in any case.

Using the same configuration (param based) on 1.7.3 does work without issues

build fails for malformed module path

Clean ubuntu installation, installed openvpn and easy-rsa (not documented but required), and documented dependencies.

Upon executing build.sh I get an error:

build ovpn-admin: cannot load home/ubuntu/ovpn-admin/packrd: malformed module path "home/ubuntu/ovpn-admin/packrd": missing dot in first path element

tried both as root and regular user, with same result.

iptables nat in configure.sh

хотелось бы иметь возможность подставить другую подсеть в configure.sh
для простоты через env

вместо:
iptables -t nat -A POSTROUTING -s 172.16.100.0/255.255.255.0 ! -d 172.16.100.0/255.255.255.0 -j MASQUERADE

например так:
iptables -t nat -A POSTROUTING -s ${OVPN_NET:-172.16.100.0}/${OVPN_MASK:-255.255.255.0} ! -d ${OVPN_NET:-172.16.100.0}/${OVPN_MASK:-255.255.255.0} -j MASQUERADE

Docker build fail on Centos 7

When run ./start.sh
image

Should add to Dockerfile those line:

    apk update &&\
    apk add ca-certificates wget &&\
    update-ca-certificates && \

for wget inside docker.

revert ccd config to dynamic didn't work

ccd config file didn't update (remove static config) after you select dynamic en web ui if previously you add a static ip per client.

Steps to replicate:

create user -> edit routes -> mark "static address" and assign an IP. (at this point all works flawlesly) client gets its static IP

then

edit routes -> unmark "static address" (to get dynamic address) . (at this point client still having its old static IP)

in ccd directory client file isn't change (removed or emptyed)

in other hand modifying ip works well. I mean change i.e. 10.8.1.2 with 10.8.1.3 is reflected ok in ccd config file.

proposal: use the sqlite

How about using sqllite to store user information and additional info?

  • In this case, we can refuse to use the openvpn-user tool to create a user password and transfer this functionality to the ovpn-admin source code.

static mask in templates/ccd.tpl

при указании в шаблоне маски 255.255.255.255, нет роутинга до сервера .1 со стороны клиента
конкретно проблема на микротике

для примера ccd клиента
ifconfig-push 172.16.0.10 255.255.255.255

маршруты в конфиге openvpn
push "route 172.16.0.0 255.255.0.0"

Снимок экрана 2021-03-27 в 17 37 46

Helm chart support

Thanks for awesome web dashboard for managing open-vpn profiles
Do you have any plans to add Helm chart, so one can install it directly into kubernetes cluster?

prebuilt binary crashes

I have downloaded prebuilt binary and ran on debian 11. Server gives message 404 page not found when I open browser at http://ip:8080

then a crash in server console outputs this:


2021/10/08 13:24:15 openssl x509 -in /etc/openvpn/easyrsa/pki/ca.crt -noout -enddate | awk -F "=" {'print $2'}
Bind: http://0.0.0.0:8080
fatal error: unexpected signal during runtime execution
[signal SIGSEGV: segmentation violation code=0x1 addr=0x63 pc=0x7f055de9b298]

runtime stack:
runtime.throw({0x145830c, 0x7f0550000d53})
        /usr/local/go/src/runtime/panic.go:1198 +0x71
runtime.sigpanic()
        /usr/local/go/src/runtime/signal_unix.go:719 +0x396

goroutine 30 [syscall]:
runtime.cgocall(0x11487c0, 0xc00005cd90)
        /usr/local/go/src/runtime/cgocall.go:156 +0x5c fp=0xc00005cd68 sp=0xc00005cd30 pc=0x4040bc
net._C2func_getaddrinfo(0xc0003fe210, 0x0, 0xc0003e7110, 0xc0002b59e8)
        _cgo_gotypes.go:91 +0x56 fp=0xc00005cd90 sp=0xc00005cd68 pc=0x5b2056
net.cgoLookupIPCNAME.func1({0xc0003fe210, 0x0, 0x0}, 0x7ffeae6cede7, 0xc00005ce50)
        /usr/local/go/src/net/cgo_unix.go:163 +0x9f fp=0xc00005cde8 sp=0xc00005cd90 pc=0x5b391f
net.cgoLookupIPCNAME({0x142f028, 0x3}, {0x7ffeae6cede7, 0x0})
        /usr/local/go/src/net/cgo_unix.go:163 +0x16d fp=0xc00005cf38 sp=0xc00005cde8 pc=0x5b316d
net.cgoIPLookup(0x2228a30, {0x142f028, 0xc0003fe200}, {0x7ffeae6cede7, 0xc0000c7340})
        /usr/local/go/src/net/cgo_unix.go:220 +0x3b fp=0xc00005cfa8 sp=0xc00005cf38 pc=0x5b39db
net.cgoLookupIP·dwrap·25()
        /usr/local/go/src/net/cgo_unix.go:230 +0x36 fp=0xc00005cfe0 sp=0xc00005cfa8 pc=0x5b3e56
runtime.goexit()
        /usr/local/go/src/runtime/asm_amd64.s:1581 +0x1 fp=0xc00005cfe8 sp=0xc00005cfe0 pc=0x464aa1
created by net.cgoLookupIP
        /usr/local/go/src/net/cgo_unix.go:230 +0x125

goroutine 1 [IO wait]:
internal/poll.runtime_pollWait(0x7f055df18a18, 0x72)
        /usr/local/go/src/runtime/netpoll.go:229 +0x89
internal/poll.(*pollDesc).wait(0xc000354700, 0x417b06, 0x0)
        /usr/local/go/src/internal/poll/fd_poll_runtime.go:84 +0x32
internal/poll.(*pollDesc).waitRead(...)
        /usr/local/go/src/internal/poll/fd_poll_runtime.go:89
internal/poll.(*FD).Accept(0xc000354700)
        /usr/local/go/src/internal/poll/fd_unix.go:402 +0x22c
net.(*netFD).accept(0xc000354700)
        /usr/local/go/src/net/fd_unix.go:173 +0x35
net.(*TCPListener).accept(0xc000368bd0)
        /usr/local/go/src/net/tcpsock_posix.go:140 +0x28
net.(*TCPListener).Accept(0xc000368bd0)
        /usr/local/go/src/net/tcpsock.go:262 +0x3d
net/http.(*Server).Serve(0xc0001042a0, {0x15f3948, 0xc000368bd0})
        /usr/local/go/src/net/http/server.go:3001 +0x394
net/http.(*Server).ListenAndServe(0xc0001042a0)
        /usr/local/go/src/net/http/server.go:2930 +0x7d
net/http.ListenAndServe(...)
        /usr/local/go/src/net/http/server.go:3184
main.main()
        /github/workspace/main.go:463 +0xe45

goroutine 6 [chan receive]:
k8s.io/klog/v2.(*loggingT).flushDaemon(0x0)
        /go/pkg/mod/k8s.io/klog/[email protected]/klog.go:1169 +0x6a
created by k8s.io/klog/v2.init.0
        /go/pkg/mod/k8s.io/klog/[email protected]/klog.go:417 +0xfb

goroutine 24 [sleep]:
time.Sleep(0x684ee1800)
        /usr/local/go/src/runtime/time.go:193 +0x12e
main.(*OvpnAdmin).updateState(0xc0000c7340)
        /github/workspace/main.go:496 +0x38
created by main.main
        /github/workspace/main.go:411 +0x265

goroutine 25 [IO wait]:
internal/poll.runtime_pollWait(0x7f055df18930, 0x72)
        /usr/local/go/src/runtime/netpoll.go:229 +0x89
internal/poll.(*pollDesc).wait(0xc000354780, 0xc0003a5000, 0x0)
        /usr/local/go/src/internal/poll/fd_poll_runtime.go:84 +0x32
internal/poll.(*pollDesc).waitRead(...)
        /usr/local/go/src/internal/poll/fd_poll_runtime.go:89
internal/poll.(*FD).Read(0xc000354780, {0xc0003a5000, 0x1000, 0x1000})
        /usr/local/go/src/internal/poll/fd_unix.go:167 +0x25a
net.(*netFD).Read(0xc000354780, {0xc0003a5000, 0x100000143f38a, 0x16})
        /usr/local/go/src/net/fd_posix.go:56 +0x29
net.(*conn).Read(0xc0002b5980, {0xc0003a5000, 0x7, 0xc0003e67e8})
        /usr/local/go/src/net/net.go:183 +0x45
net/http.(*connReader).Read(0xc0003e67e0, {0xc0003a5000, 0x1000, 0x1000})
        /usr/local/go/src/net/http/server.go:780 +0x16d
bufio.(*Reader).fill(0xc0003e2180)
        /usr/local/go/src/bufio/bufio.go:101 +0x103
bufio.(*Reader).ReadSlice(0xc0003e2180, 0x0)
        /usr/local/go/src/bufio/bufio.go:360 +0x2f
bufio.(*Reader).ReadLine(0xc0003e2180)
        /usr/local/go/src/bufio/bufio.go:389 +0x27
net/textproto.(*Reader).readLineSlice(0xc0003e6840)
        /usr/local/go/src/net/textproto/reader.go:57 +0x99
net/textproto.(*Reader).ReadLine(...)
        /usr/local/go/src/net/textproto/reader.go:38
net/http.readRequest(0xc0002b5980)
        /usr/local/go/src/net/http/request.go:1029 +0x79
net/http.(*conn).readRequest(0xc0003cc6e0, {0x15f7990, 0xc0002c7780})
        /usr/local/go/src/net/http/server.go:966 +0x225
net/http.(*conn).serve(0xc0003cc6e0, {0x15f7a38, 0xc0003e66f0})
        /usr/local/go/src/net/http/server.go:1855 +0x865
created by net/http.(*Server).Serve
        /usr/local/go/src/net/http/server.go:3033 +0x4e8

goroutine 26 [IO wait]:
internal/poll.runtime_pollWait(0x7f055df18848, 0x72)
        /usr/local/go/src/runtime/netpoll.go:229 +0x89
internal/poll.(*pollDesc).wait(0xc000354980, 0xc000401000, 0x0)
        /usr/local/go/src/internal/poll/fd_poll_runtime.go:84 +0x32
internal/poll.(*pollDesc).waitRead(...)
        /usr/local/go/src/internal/poll/fd_poll_runtime.go:89
internal/poll.(*FD).Read(0xc000354980, {0xc000401000, 0x1000, 0x1000})
        /usr/local/go/src/internal/poll/fd_unix.go:167 +0x25a
net.(*netFD).Read(0xc000354980, {0xc000401000, 0x14385b5, 0xc00006d6b0})
        /usr/local/go/src/net/fd_posix.go:56 +0x29
net.(*conn).Read(0xc0002b5988, {0xc000401000, 0x6, 0xc0003e6908})
        /usr/local/go/src/net/net.go:183 +0x45
net/http.(*connReader).Read(0xc0003e6900, {0xc000401000, 0x1000, 0x1000})
        /usr/local/go/src/net/http/server.go:780 +0x16d
bufio.(*Reader).fill(0xc0003e21e0)
        /usr/local/go/src/bufio/bufio.go:101 +0x103
bufio.(*Reader).ReadSlice(0xc0003e21e0, 0xb)
        /usr/local/go/src/bufio/bufio.go:360 +0x2f
bufio.(*Reader).ReadLine(0xc0003e21e0)
        /usr/local/go/src/bufio/bufio.go:389 +0x27
net/textproto.(*Reader).readLineSlice(0xc0003e6930)
        /usr/local/go/src/net/textproto/reader.go:57 +0x99
net/textproto.(*Reader).ReadLine(...)
        /usr/local/go/src/net/textproto/reader.go:38
net/http.readRequest(0xc0002b5988)
        /usr/local/go/src/net/http/request.go:1029 +0x79
net/http.(*conn).readRequest(0xc0003cc780, {0x15f7990, 0xc0002c7840})
        /usr/local/go/src/net/http/server.go:966 +0x225
net/http.(*conn).serve(0xc0003cc780, {0x15f7a38, 0xc0003e66f0})
        /usr/local/go/src/net/http/server.go:1855 +0x865
created by net/http.(*Server).Serve
        /usr/local/go/src/net/http/server.go:3033 +0x4e8

goroutine 28 [select]:
net.(*Resolver).lookupIPAddr(0x2228a20, {0x15f79c8, 0xc000040098}, {0x142f028, 0x0}, {0x7ffeae6cede7, 0x9})
        /usr/local/go/src/net/lookup.go:302 +0x5c7
net.(*Resolver).internetAddrList(0x15f79c8, {0x15f79c8, 0xc000040098}, {0x142f028, 0x3}, {0x7ffeae6cede7, 0xe})
        /usr/local/go/src/net/ipsock.go:288 +0x67a
net.(*Resolver).resolveAddrList(0xc000040098, {0x15f79c8, 0xc000040098}, {0x142f356, 0x4}, {0x142f028, 0x0}, {0x7ffeae6cede7, 0xe}, {0x0, ...})
        /usr/local/go/src/net/dial.go:221 +0x41b
net.(*Dialer).DialContext(0xc00006ede8, {0x15f79c8, 0xc000040098}, {0x142f028, 0x80460}, {0x7ffeae6cede7, 0x2000000005b36b8})
        /usr/local/go/src/net/dial.go:406 +0x448
net.(*Dialer).Dial(...)
        /usr/local/go/src/net/dial.go:351
net.Dial({0x142f028, 0x3}, {0x7ffeae6cede7, 0x40ab35})
        /usr/local/go/src/net/dial.go:319 +0x7a
main.(*OvpnAdmin).mgmtGetActiveClients(0xc0000c7340)
        /github/workspace/main.go:1044 +0x139
main.(*OvpnAdmin).setState(0xc0000c7340)
        /github/workspace/main.go:488 +0x25
created by main.(*OvpnAdmin).updateState
        /github/workspace/main.go:501 +0x29

goroutine 29 [select]:
net.cgoLookupIP({0x15f7990, 0xc0002c7980}, {0x142f028, 0x9}, {0x7ffeae6cede7, 0xe})
        /usr/local/go/src/net/cgo_unix.go:231 +0x1b7
net.(*Resolver).lookupIP(0x2228a20, {0x15f7990, 0xc0002c7980}, {0x142f028, 0x3}, {0x7ffeae6cede7, 0x9})
        /usr/local/go/src/net/lookup_unix.go:97 +0x128
net.glob..func1({0x15f7990, 0xc0002c7980}, 0x7ffeae6cede7, {0x142f028, 0x7ffeae6cede7}, {0x7ffeae6cede7, 0xc00005ced8})
        /usr/local/go/src/net/hook.go:23 +0x3d
net.(*Resolver).lookupIPAddr.func1()
        /usr/local/go/src/net/lookup.go:296 +0x9f
internal/singleflight.(*Group).doCall(0x2228a30, 0xc0003de370, {0xc0003fe200, 0xd}, 0xc0000c7340)
        /usr/local/go/src/internal/singleflight/singleflight.go:95 +0x3b
created by internal/singleflight.(*Group).DoChan
        /usr/local/go/src/internal/singleflight/singleflight.go:88 +0x2f1

launch command:

./ovpn-admin --debug --ovpn.network="192.168.30.0/24" --master.sync-token="TOKEN" \
--easyrsa.path="/etc/openvpn/easyrsa" \
--easyrsa.index-path="/etc/openvpn/easyrsa/pki/index.txt" \
--ovpn.server="localhost:1195:udp" \
--auth.password \
--auth.db="/etc/openvpn/easyrsa/pki/users.db" \
--ccd --ccd.path="./ccd" --mgmt=localhost:5555

output of netstat :

root@SRV:~/ovpn-admin# netstat -tuenlp
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       User       Inode      PID/Program name
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      0          12865      541/sshd: /usr/sbin
tcp        0      0 0.0.0.0:5555            0.0.0.0:*               LISTEN      0          13022      568/openvpn
tcp6       0      0 :::22                   :::*                    LISTEN      0          12876      541/sshd: /usr/sbin
tcp6       0      0 :::8080                 :::*                    LISTEN      0          16129      1036/./ovpn-admin
udp        0      0 0.0.0.0:1195            0.0.0.0:*                           0          13079      568/openvpn
udp        0      0 0.0.0.0:5353            0.0.0.0:*                           110        12533      402/avahi-daemon: r
udp        0      0 0.0.0.0:52114           0.0.0.0:*                           110        12535      402/avahi-daemon: r
udp6       0      0 :::56439                :::*                                110        12536      402/avahi-daemon: r
udp6       0      0 :::5353                 :::*                                110        12534      402/avahi-daemon: r

It's curious that server opens in tcp6 even when I tried to disable globally ipv6 en /etc/systcl.conf but nevermind because other services still starts in ipv6 as you can see en netstat output.

add in docker-compose.yaml OVPN_PASSWD_AUTH="False"

Долго не понимал почему не работает авторизация.
Думаю, что лучше добавить в пример docker-compose.yaml:

services:
openvpn:
...
environment:
OVPN_PASSWD_AUTH: "False"

тогда можно быстрее догадаться, что для включения авторизации нужно сделать
OVPN_PASSWD_AUTH: "True"

how to provide pass phrase of ca.key ?

hello,

i starting to use the ovpn-admin yesterday , and i faced an issue , i can't find an option to provider my passphrase for generated ca.key, so it can enter it when creating new client or revoking it .

i also tried to create ca.key without passfrase , and it seems not possible,

how can i make it work in my situation ?

thanks in advance, i really likes the simple UI and easiness of it :)

Request: Make use of environmental variables in docker-compose.yaml

Using environmental variables will allow users to pull this git without having to reconfigure their settings. An .env file can be used to store these settings.
https://docs.docker.com/compose/environment-variables/

Proposed changes:

environment:
  OVPN_SERVER_NET: ${ENV_OVPN_SERVER_NET}
  OVPN_SERVER_MASK: ${ENV_OVPN_SERVER_MASK}
volumes:
  - ${ENV_BASEDIR}/easyrsa_master:/etc/openvpn/easyrsa
  - ${ENV_BASEDIR}/ccd_master:/etc/openvpn/ccd

environment:
  OVPN_DEBUG: ${ENV_OVPN_DEBUG}
  OVPN_VERBOSE: ${ENV_OVPN_VERBOSE}
  OVPN_NETWORK: ${ENV_OVPN_NETWORK}
  EASYRSA_PATH: ${ENV_EASYRSA_PATH}
  OVPN_SERVER: ${ENV_OVPN_SERVER}
  OVPN_INDEX_PATH: ${ENV_OVPN_INDEX_PATH}
volumes:
  - ${ENV_BASEDIR}/easyrsa_master:/mnt/easyrsa
  - ${ENV_BASEDIR}/ccd_master:/mnt/ccd

The environmental variables can be documented and edited in the .env file. It allows users more flexibility to how they organize and deploy the openvpn-server. For instance, I don't like that the volumes are in the same directory that the git clone is in, so I'd prefer to have a structure like:

basedir
|_ .env
|_ easyrsa_master
|_ ccd_master
|_ ovpn-admin
    |_ docker-compose -p openvpn-master --env-file ../.env up -d --build

Having a flat configuration file that's outside of the git repo directory allows users to more easily pull changes without having to manually edit the docker-compose.yaml. An adjusted start.sh could take the path to the .env file, add any missing variables and alert users of important changes.

I'd be more than happy to do a pull request with these proposed changes, though I'm by no means an expert in either docker, bash or git.

ccd config error when save

I've found a issue when adding custom options per client. I got the error:

Ccd for user ....... apply failed

my docker-compose.yaml file is :

version: '3'

services:
  openvpn:
    build:
      context: .
      dockerfile: Dockerfile.openvpn
    image: openvpn:local
    command: /etc/openvpn/setup/configure.sh
    cap_add:
      - NET_ADMIN
    ports:
      - 7777:1194 # for openvpn
      - 8080:8080 # for ovpn-admin because of network_mode
      - 5555:5555 # for management      
    volumes:
      - ./easyrsa_master:/etc/openvpn/easyrsa
      - ./ccd_master:/etc/openvpn/ccd
  ovpn-admin:
    build:
      context: .
    image: ovpn-admin:local
    command: /app/ovpn-admin --debug --ovpn.network="192.168.30.0/24" --master.sync-token="TOKEN" --easyrsa.path="/mnt/easyrsa" --easyrsa.index-path="/mnt/easyrsa/pki/index.txt" --ovpn.server="192.168.5.99:7777:tcp" --auth.password --auth.db="./easyrsa/pki/users.db" --ccd --ccd.path="./ccd"
    network_mode: service:openvpn
    volumes:
      - ./easyrsa_master:/mnt/easyrsa
      - ./ccd_master:/mnt/ccd

Don't know how to debug app output... only I have are logs from docker logs:

openssl x509 -in /mnt/easyrsa/pki/ca.crt -noout -enddate | awk -F "=" {'print $2'}

No way to use OVPN_AUTH via env

You are forbidding any value in OVPN_AUTH since you use --auth.password as a flag on the cli. Cannot see how to expose an env var like that (though can't really test it due to #81 with 1.7.4) - just verified that neither --auth.password=1 nor --auth.password=true will work.

Separate config

For my purposes, i need client config to be separated and downloaded via archive (ca cert, client cert, client key and ovpn file need to be separated), but im not so good with golang, so i dont know how to modify the code. help pls

add button delete in web ui

Было бы неплохо добавить кнопку удаления сертификатов пользователя и данных из users.db

Объясню зачем:
В моем случае при подключении клиентов, в зависимости от логина пользователя, выполняются дополнительные скрипты.
Т. о. хотел получить возможность пересоздавать (удалить и создать новый) сертификаты с теми же логинами.

Сейчас сделал в виде bash скрипта.
При создании столкнулся с проблемой:
бинарный файл отсюда https://github.com/pashcovich/openvpn-user работает довольно неожиданно
delete --user=USER
не удаляет пользователя, а ставит отметку в поле базы, что он удалён.

На мой взгляд, команда delete должна удалять пользователя из users.db, но вы, вероятно, преследовали другие цели.

Пришлось править код в openvpn-user.go под себя и пересобрать бинарь.

love you

How to modify the server configuration? For example: the network segment pushed to the client, etc.
Please update the readme file so that beginners can install and learn more intuitively. Thank you very much for your contribution.

Prebuilt binary - timeformat problem

Hi,
we have problem with time format in prebuild binary.
The GUI don't show all connected clients - in opvn managment inteface they are connected.
We had upgrade binary to current version, but problem stil exist.

Here some logs:
Nov 30 10:54:47 openvpn ovpn-admin[10649]: 2021/11/30 10:54:47 parsing time "Sat Nov 27 20:21:32 2021" as "2006-01-02 15:04:05": cannot parse "Sat Nov 27 20:21:32 2021" as "2006"
Nov 30 10:54:47 openvpn ovpn-admin[10649]: 2021/11/30 10:54:47 parsing time "Fri Nov 26 14:43:22 2021" as "2006-01-02 15:04:05": cannot parse "Fri Nov 26 14:43:22 2021" as "2006"
Nov 30 10:54:47 openvpn ovpn-admin[10649]: 2021/11/30 10:54:47 parsing time "Fri Nov 26 14:43:22 2021" as "2006-01-02 15:04:05": cannot parse "Fri Nov 26 14:43:22 2021" as "2006"
Nov 30 10:54:47 openvpn ovpn-admin[10649]: 2021/11/30 10:54:47 parsing time "Fri Nov 26 23:55:03 2021" as "2006-01-02 15:04:05": cannot parse "Fri Nov 26 23:55:03 2021" as "2006"
Nov 30 10:54:47 openvpn ovpn-admin[10649]: 2021/11/30 10:54:47 parsing time "Mon Nov 29 20:38:10 2021" as "2006-01-02 15:04:05": cannot parse "Mon Nov 29 20:38:10 2021" as "2006"
Nov 30 10:54:47 openvpn ovpn-admin[10649]: 2021/11/30 10:54:47 parsing time "Sun Nov 28 22:55:25 2021" as "2006-01-02 15:04:05": cannot parse "Sun Nov 28 22:55:25 2021" as "2006"

Recommend a compatible openvpn image

Hi,

I'm trying to make ovpn-admin work with my previously deployed openvpn, based on kylemanna/openvpn, but I cannot get it fully working.

I managed to make ovpn-admin connect, and list the created certificates, but I cannot change passwords, or revoke them. Change password button does not even show, and when I try to revoke, nothing happens, and user is not revoked.

Can anyone suggest an alternative openvpn image, that will work with ovpn-admin?
I can't use the provided docker-compose file, since building the images does not work on my setup.

Thank you :)

checkStaticAddreesIsFree func error

I hae large users in server with ccd like this
user 1 -> 10.10.0.14
user n -> push 10.10.0.169 10.10.0.170
user m -> 10.10.0.173
user k -> 10.10.0.177
if I change address for user 1 - 10.10.0.14 to 10.10.0.17 i get an error - ClientAddress "10.10.0.17" already assigned to another user!
func checkStaticAddressIsFree(staticAddress string, username string) bool {
o := runBash(fmt.Sprintf("**grep -rl %s %s | grep -vx %s/%s | wc -l", staticAddress, ccdDir, ccdDir, username))

if strings.TrimSpace(o) == "0" {
    return true
}
return false

}
RETURN = 3 and give error, BUT the real address 10.10.0.17!!! Need help with grep!

Raspberry Pi 4B vs. ovpn-admin

Hi developer,

please could you help me with my problem?
I want to try install ovpn-admin on my RPi. I tried docker variant
and an error message appears after running the start.sh script.
Is there some solution?

Thanks a lot.
Sorry, I'm a linux rookie.

root@raspberrypi:~/ovpn-admin# ./start.sh Building openvpn Step 1/4 : FROM alpine:3.13 ---> c7140641fa49 Step 2/4 : RUN apk add --update bash openvpn easy-rsa && ln -s /usr/share/easy-rsa/easyrsa /usr/local/bin && wget https://github.com/pashcovich/openvpn -user/releases/download/v1.0.3/openvpn-user-linux-amd64.tar.gz -O - | tar xz -C /usr/local/bin && rm -rf /tmp/* /var/tmp/* /var/cache/apk/* /var/cache/distfiles/* ---> Using cache ---> 2951f531f259 Step 3/4 : COPY setup/ /etc/openvpn/setup ---> Using cache ---> d688a58731e4 Step 4/4 : RUN chmod +x /etc/openvpn/setup/configure.sh ---> Using cache ---> 6821bdb55430 Successfully built 6821bdb55430 Successfully tagged openvpn:local Building ovpn-admin Step 1/12 : FROM node:14.2-alpine3.11 AS frontend-builder 14.2-alpine3.11: Pulling from library/node ERROR: Service 'ovpn-admin' failed to build: no matching manifest for linux/arm/v7 in the manifest list entries

Packr2 path has changed

The packr2 has changed from github.com/gobuffalo/packr/v2/packr2 to github.com/gobuffalo/packr/packr2
This is breaking builds as the dockerfile is attempting to get the old path which no longer exists

client configuration content shows in logs

Version: 1.7.0
Run args:

ovpn-admin \
  --templates.clientconfig-path=/mnt/setup/client.conf.tpl \
  --easyrsa.path=/mnt/certs \
  --easyrsa.index-path=/mnt/certs/pki/index.txt \
  --listen.port=8080

With provided configuration when you press Download user config button in web ui, ovpn-admin prints full user config with certificates to log(stdout). Even without --verbose and --debug arguments.

Coz credentials is sensitive data, i suppose that it should not be logged or at least only on debug mode

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.