├── .gitignore ├── LICENSE ├── README.md ├── check_process ├── conf ├── config-cli.ovpn.j2 ├── config.ovpn.j2 ├── fail2ban-filter.conf ├── fail2ban-jail.conf.j2 ├── handler.sh ├── ldap.conf ├── login.cube ├── logrotate.conf ├── nginx.conf.j2 ├── php-fpm.conf.j2 ├── php-fpm.ini ├── sudoers ├── sysctl └── yunohost.conf.j2 ├── hooks ├── post_app_addaccess ├── post_app_clearaccess ├── post_app_removeaccess └── post_iptable_rules ├── manifest.json ├── scripts ├── _common.sh ├── backup ├── install ├── remove ├── restore └── upgrade └── sources ├── assets ├── css │ └── main.css └── img │ └── Ovpntech_logo-s_REVISED.png └── index.php /.gitignore: -------------------------------------------------------------------------------- 1 | *.swp 2 | *.swo 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YunoHost-Apps/vpnserver_ynh/a3e06083763d73f1dde15da7e97f0424d16ad359/LICENSE -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | OpenVPN server for YunoHost 2 | -------------------- 3 | 4 | OpenVPN allow to create secured tunnel between computers. This is the server part, to which OpenVPN clients may connect to. See [vpnclient_ynh](https://github.com/labriqueinternet/vpnclient_ynh) for the client part. 5 | 6 | http://openvpn.net/ 7 | 8 | **Package by:** 9 | 10 | **Categories:** diy-isp 11 | 12 | **Upgrade this package:** 13 | `sudo yunohost app upgrade --verbose OpenVPN -u https://github.com/YunoHost-Apps/openvpn_ynh` 14 | 15 | **Multi-user:** Yes. 16 | 17 | **SSO/LDAP:** SSO and LDAP are configured. Each YunoHost user can have one VPN account. 18 | 19 | 20 | Configuration: 21 | 22 | * Download CA from `https:///yunohost/admin/ca.crt` 23 | * Configure your VPN with TUN interface, LZO compression and password authentication (with your YunoHost account/passwd), on standard UDP port 1194 24 | -------------------------------------------------------------------------------- /check_process: -------------------------------------------------------------------------------- 1 | ;; Test complet sans multisite 2 | auto_remove=1 3 | ; Manifest 4 | domain="domain.tld" (DOMAIN) 5 | path="/path" (PATH) 6 | ip4ranges="10.0.0.8/24" 7 | dynamic_ip=0 8 | ; Checks 9 | pkg_linter=1 10 | setup_sub_dir=1 11 | setup_root=1 12 | setup_nourl=0 13 | setup_private=1 14 | setup_public=0 15 | upgrade=1 16 | backup_restore=1 17 | multi_instance=0 18 | wrong_user=0 19 | wrong_path=1 20 | incorrect_path=1 21 | corrupt_source=0 22 | fail_download_source=0 23 | port_already_use=0 24 | final_path_already_use=0 25 | ;;; Levels 26 | Level 1=auto 27 | Level 2=auto 28 | Level 3=auto 29 | Level 4=0 30 | Level 5=auto 31 | Level 6=auto 32 | Level 7=auto 33 | Level 8=0 34 | Level 9=0 35 | Level 10=0 36 | -------------------------------------------------------------------------------- /conf/config-cli.ovpn.j2: -------------------------------------------------------------------------------- 1 | client 2 | dev tun 3 | proto udp 4 | resolv-retry infinite 5 | nobind 6 | persist-key 7 | persist-tun 8 | comp-lzo 9 | verb 3 10 | remote {{ domain }} {{ port }} 11 | route-delay 12 | reneg-sec 0 13 | tls-version-min 1.2 14 | cipher AES-256-CBC 15 | auth SHA512 16 | tls-cipher TLS-DHE-RSA-WITH-AES-256-GCM-SHA384:TLS-DHE-RSA-WITH-AES-128-GCM-SHA256:TLS-DHE-RSA-WITH-AES-256-CBC-SHA:TLS-DHE-RSA-WITH-CAMELLIA-256-CBC-SHA:TLS-DHE-RSA-WITH-AES-128-CBC-SHA:TLS-DHE-RSA-WITH-CAMELLIA-128-CBC-SHA 17 | redirect-gateway 18 | script-security 2 19 | --auth-user-pass 20 | 21 | {{ ca_yunohost }} 22 | 23 | #user openvpn 24 | #group openvpn 25 | key-direction 1 26 | 27 | {{ ta_key }} 28 | 29 | -------------------------------------------------------------------------------- /conf/config.ovpn.j2: -------------------------------------------------------------------------------- 1 | client 2 | dev tun 3 | proto udp 4 | resolv-retry infinite 5 | nobind 6 | persist-key 7 | persist-tun 8 | comp-lzo 9 | tls-version-min 1.2 10 | cipher AES-256-CBC 11 | auth SHA512 12 | tls-cipher TLS-DHE-RSA-WITH-AES-256-GCM-SHA384:TLS-DHE-RSA-WITH-AES-128-GCM-SHA256:TLS-DHE-RSA-WITH-AES-256-CBC-SHA:TLS-DHE-RSA-WITH-CAMELLIA-256-CBC-SHA:TLS-DHE-RSA-WITH-AES-128-CBC-SHA:TLS-DHE-RSA-WITH-CAMELLIA-128-CBC-SHA 13 | remote {{ domain }} {{ port }} 14 | route-delay 15 | reneg-sec 0 16 | redirect-gateway 17 | script-security 2 18 | auth-user-pass 19 | auth-nocache 20 | verb 3 21 | #auth-user-pass auth.txt 22 | #user openvpn 23 | #group openvpn 24 | 25 | {{ ca_yunohost }} 26 | 27 | key-direction 1 28 | 29 | {{ ta_key }} 30 | 31 | -------------------------------------------------------------------------------- /conf/fail2ban-filter.conf: -------------------------------------------------------------------------------- 1 | [Definition] 2 | ignoreregex = 3 | failregex = :\d{1,5} TLS Auth Error 4 | :\d{1,5} VERIFY ERROR: 5 | :\d{1,5} TLS Error: TLS handshake failed 6 | -------------------------------------------------------------------------------- /conf/fail2ban-jail.conf.j2: -------------------------------------------------------------------------------- 1 | [{{ app }}] 2 | enabled = true 3 | protocol = udp 4 | port = {{ port }} 5 | filter = {{ app }} 6 | logpath = /var/log/{{ app }}/server.log 7 | -------------------------------------------------------------------------------- /conf/handler.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | if [ "$(id -ru)" = "0" ]; then 3 | SUDO= 4 | else 5 | SUDO=sudo 6 | fi 7 | us_file="/etc/openvpn/users_settings.csv" 8 | # ##### Utility 9 | 10 | log() { 11 | local level 12 | level="$1" 13 | shift 14 | # Disabled: 15 | logger -t"ovpn-script[$$]" -pdaemon."$level" -- "$@" 16 | } 17 | 18 | # ##### Functions 19 | 20 | check_user() { 21 | if ! echo "$common_name" | grep ^[a-zA-Z][a-zA-Z0-9_-]*$; then 22 | log notice "Bad common name $common_name" 23 | return 1 24 | fi 25 | } 26 | 27 | # Write user specific OpenvPN configuration to stdout 28 | create_conf() { 29 | ip4ranges=$(cat /etc/openvpn/ip4ranges | tr " " "\n") 30 | reserve_ip "10.8.0.2-10.8.0.255" "${ip4ranges}" 31 | private_ip4=$(get_ip 2 ) 32 | echo "ifconfig-push $private_ip4 $ifconfig_netmask" 33 | 34 | # Link to ipv4 if needed 35 | public_ip4=$(get_ip 3) 36 | if [ -n "$public_ip4" ]; then 37 | $SUDO iptables -t nat -A PREROUTING -d $public_ip4 -j DNAT --to-destination $private_ip4 38 | $SUDO iptables -t nat -A POSTROUTING -s ${private_ip4}/32 ! -d ${private_ip4}/32 -j SNAT --to-source $public_ip4 39 | else 40 | iface=$(ip r|awk '/default/ { print $5 }') 41 | $SUDO iptables -t nat -A POSTROUTING -s $private_ip4 -o "${iface}" -j MASQUERADE 42 | fi 43 | } 44 | 45 | 46 | get_first_ip () { 47 | echo $( netmask -x $(echo $1 | cut -f1 -d"-") | cut -f1 -d"/") 48 | } 49 | get_last_ip () { 50 | echo $( netmask -x $(echo $1 | cut -f1 -d"-") | cut -f1 -d"/") 51 | } 52 | 53 | # Put ip in www.xxx.yyy.zzz format 54 | format_ip() { 55 | netmask $1 | cut -f1 -d"/" | sed -e 's/^[[:space:]]*//' 56 | } 57 | 58 | # Return the ip 59 | # $1 public|private 60 | get_ip() { 61 | echo $(grep $common_name $us_file | awk -F"," "{print \$$1}") 62 | 63 | } 64 | 65 | get_next_ip() { 66 | 67 | for ip4range in $1 68 | do 69 | ip=$(($(get_first_ip $ip4range) + 0 )) 70 | last_ip=$(($(get_last_ip $ip4range) + 0)) 71 | while [ "$ip" \< "$last_ip" ] 72 | do 73 | formated_ip=$(format_ip $ip) 74 | awk -F"," "{print \$$2}" $us_file | grep $formated_ip \ 75 | || break 2 76 | ip=$(( $ip + 1 )) 77 | done 78 | formated_ip=$(format_ip $ip) 79 | awk -F"," "{print \$$2}" $us_file | grep $formated_ip \ 80 | || break 81 | done 82 | if [ "$ip" \> "$last_ip" ]; then 83 | log notice "No more ip available" 84 | exit 1 85 | fi 86 | echo $formated_ip 87 | 88 | } 89 | 90 | # Return the static ip of the user, if needed define it 91 | # $1 IPv4 ranges list ex: 10.8.0.0-10.8.0.255 10.8.1.0-10.8.1.255 92 | # $2 Column number in user settings CSV 93 | reserve_ip () { 94 | local registered_ip 95 | local private_ip 96 | local public_ip 97 | registered_ip=$(get_ip 2) 98 | if [ -z "$registered_ip" ]; then 99 | private_ip=$(get_next_ip $1 2) 100 | public_ip=$(get_next_ip $2 3 || true) 101 | 102 | echo "${common_name},${private_ip},${public_ip}" >> $us_file 103 | fi 104 | } 105 | # ##### OpenVPN handlers 106 | 107 | client_connect() { 108 | conf="$1" 109 | check_user || exit 1 110 | create_conf > "$conf" 111 | } 112 | 113 | client_disconnect() { 114 | check_user || exit 1 115 | } 116 | 117 | # ##### Dispatch 118 | 119 | case "$script_type" in 120 | client-connect) client_connect "$@" ;; 121 | client-disconnect) client_disconnect "$@" ;; 122 | esac 123 | -------------------------------------------------------------------------------- /conf/ldap.conf: -------------------------------------------------------------------------------- 1 | 2 | # LDAP server URL 3 | URL ldap://localhost:389 4 | 5 | # Network timeout (in seconds) 6 | Timeout 15 7 | 8 | # Enable Start TLS 9 | TLSEnable no 10 | 11 | # Follow LDAP Referrals (anonymously) 12 | FollowReferrals yes 13 | 14 | 15 | 16 | 17 | # Base DN 18 | BaseDN "ou=users,dc=yunohost,dc=org" 19 | 20 | # User Search Filter 21 | SearchFilter "(&(uid=%u)(objectClass=mailAccount))" 22 | 23 | # Require Group Membership 24 | RequireGroup false 25 | 26 | 27 | -------------------------------------------------------------------------------- /conf/login.cube: -------------------------------------------------------------------------------- 1 | { 2 | "server_name": "{{ domain }}", 3 | "server_port": "{{ port }}", 4 | "server_proto": "udp", 5 | "ip6_net": "", 6 | "ip4_addr": "{{ public_ip4 }}", 7 | "crt_server_ca": "{{ ca_yunohost }}", 8 | "crt_client": "", 9 | "crt_client_key": "", 10 | "crt_client_ta": "{{ ta_key }}", 11 | "login_user": "{{ user }}", 12 | "login_passphrase": "{{ password }}", 13 | "dns0": "89.234.141.66", 14 | "dns1": "80.67.188.188", 15 | "openvpn_rm": [ 16 | "pull", 17 | "comp-lzo adaptive", 18 | "explicit-exit-notify", 19 | "tls-client", 20 | "remote-cert-tls server", 21 | "ns-cert-type server", 22 | "mute 5", 23 | "route-ipv6 2000::/3", 24 | "redirect-gateway def1 bypass-dhcp" 25 | ], 26 | "openvpn_add": [ 27 | "client", 28 | "persist-key", 29 | "persist-tun", 30 | "comp-lzo", 31 | "tls-version-min 1.2", 32 | "cipher AES-256-CBC", 33 | "auth SHA512", 34 | "tls-cipher TLS-DHE-RSA-WITH-AES-256-GCM-SHA384:TLS-DHE-RSA-WITH-AES-128-GCM-SHA256:TLS-DHE-RSA-WITH-AES-256-CBC-SHA:TLS-DHE-RSA-WITH-CAMELLIA-256-CBC-SHA:TLS-DHE-RSA-WITH-AES-128-CBC-SHA:TLS-DHE-RSA-WITH-CAMELLIA-128-CBC-SHA", 35 | "route-delay", 36 | "reneg-sec 0", 37 | "redirect-gateway", 38 | "auth-nocache", 39 | "key-direction 1" 40 | ] 41 | } 42 | -------------------------------------------------------------------------------- /conf/logrotate.conf: -------------------------------------------------------------------------------- 1 | /var/log/openvpn/*.log 2 | { 3 | weekly 4 | rotate 52 5 | missingok 6 | notifempty 7 | delaycompress 8 | compress 9 | copytruncate 10 | } 11 | -------------------------------------------------------------------------------- /conf/nginx.conf.j2: -------------------------------------------------------------------------------- 1 | location {{ path }} { 2 | alias {{ local_path }}/; 3 | if ($scheme = http) { 4 | rewrite ^ https://$server_name$request_uri? permanent; 5 | } 6 | index index.php; 7 | try_files $uri $uri/ index.php; 8 | location ~ [^/]\.php(/|$) { 9 | fastcgi_split_path_info ^(.+?\.php)(/.*)$; 10 | fastcgi_pass unix:/var/run/php5-fpm-{{ app }}.sock; 11 | fastcgi_index index.php; 12 | include fastcgi_params; 13 | fastcgi_param HTTPS on; 14 | fastcgi_param REMOTE_USER $remote_user; 15 | fastcgi_param PATH_INFO $fastcgi_path_info; 16 | fastcgi_param SCRIPT_FILENAME $request_filename; 17 | } 18 | include conf.d/yunohost_panel.conf.inc; 19 | } 20 | -------------------------------------------------------------------------------- /conf/php-fpm.conf.j2: -------------------------------------------------------------------------------- 1 | ; Start a new pool named 'www'. 2 | ; the variable $pool can we used in any directive and will be replaced by the 3 | ; pool name ('www' here) 4 | [{{ app }}] 5 | 6 | ; Per pool prefix 7 | ; It only applies on the following directives: 8 | ; - 'slowlog' 9 | ; - 'listen' (unixsocket) 10 | ; - 'chroot' 11 | ; - 'chdir' 12 | ; - 'php_values' 13 | ; - 'php_admin_values' 14 | ; When not set, the global prefix (or /usr) applies instead. 15 | ; Note: This directive can also be relative to the global prefix. 16 | ; Default Value: none 17 | ;prefix = /path/to/pools/$pool 18 | 19 | ; Unix user/group of processes 20 | ; Note: The user is mandatory. If the group is not set, the default user's group 21 | ; will be used. 22 | user = {{ webuser }} 23 | group = {{ webuser }} 24 | 25 | ; The address on which to accept FastCGI requests. 26 | ; Valid syntaxes are: 27 | ; 'ip.add.re.ss:port' - to listen on a TCP socket to a specific address on 28 | ; a specific port; 29 | ; 'port' - to listen on a TCP socket to all addresses on a 30 | ; specific port; 31 | ; '/path/to/unix/socket' - to listen on a unix socket. 32 | ; Note: This value is mandatory. 33 | listen = /var/run/php5-fpm-{{ app }}.sock 34 | 35 | ; Set listen(2) backlog. 36 | ; Default Value: 128 (-1 on FreeBSD and OpenBSD) 37 | ;listen.backlog = 128 38 | 39 | ; Set permissions for unix socket, if one is used. In Linux, read/write 40 | ; permissions must be set in order to allow connections from a web server. Many 41 | ; BSD-derived systems allow connections regardless of permissions. 42 | ; Default Values: user and group are set as the running user 43 | ; mode is set to 0660 44 | listen.owner = www-data 45 | listen.group = www-data 46 | ;listen.mode = 0660 47 | 48 | ; List of ipv4 addresses of FastCGI clients which are allowed to connect. 49 | ; Equivalent to the FCGI_WEB_SERVER_ADDRS environment variable in the original 50 | ; PHP FCGI (5.2.2+). Makes sense only with a tcp listening socket. Each address 51 | ; must be separated by a comma. If this value is left blank, connections will be 52 | ; accepted from any ip address. 53 | ; Default Value: any 54 | ;listen.allowed_clients = 127.0.0.1 55 | 56 | ; Specify the nice(2) priority to apply to the pool processes (only if set) 57 | ; The value can vary from -19 (highest priority) to 20 (lower priority) 58 | ; Note: - It will only work if the FPM master process is launched as root 59 | ; - The pool processes will inherit the master process priority 60 | ; unless it specified otherwise 61 | ; Default Value: no set 62 | ; priority = -19 63 | 64 | ; Choose how the process manager will control the number of child processes. 65 | ; Possible Values: 66 | ; static - a fixed number (pm.max_children) of child processes; 67 | ; dynamic - the number of child processes are set dynamically based on the 68 | ; following directives. With this process management, there will be 69 | ; always at least 1 children. 70 | ; pm.max_children - the maximum number of children that can 71 | ; be alive at the same time. 72 | ; pm.start_servers - the number of children created on startup. 73 | ; pm.min_spare_servers - the minimum number of children in 'idle' 74 | ; state (waiting to process). If the number 75 | ; of 'idle' processes is less than this 76 | ; number then some children will be created. 77 | ; pm.max_spare_servers - the maximum number of children in 'idle' 78 | ; state (waiting to process). If the number 79 | ; of 'idle' processes is greater than this 80 | ; number then some children will be killed. 81 | ; ondemand - no children are created at startup. Children will be forked when 82 | ; new requests will connect. The following parameter are used: 83 | ; pm.max_children - the maximum number of children that 84 | ; can be alive at the same time. 85 | ; pm.process_idle_timeout - The number of seconds after which 86 | ; an idle process will be killed. 87 | ; Note: This value is mandatory. 88 | pm = dynamic 89 | 90 | ; The number of child processes to be created when pm is set to 'static' and the 91 | ; maximum number of child processes when pm is set to 'dynamic' or 'ondemand'. 92 | ; This value sets the limit on the number of simultaneous requests that will be 93 | ; served. Equivalent to the ApacheMaxClients directive with mpm_prefork. 94 | ; Equivalent to the PHP_FCGI_CHILDREN environment variable in the original PHP 95 | ; CGI. The below defaults are based on a server without much resources. Don't 96 | ; forget to tweak pm.* to fit your needs. 97 | ; Note: Used when pm is set to 'static', 'dynamic' or 'ondemand' 98 | ; Note: This value is mandatory. 99 | pm.max_children = 10 100 | 101 | ; The number of child processes created on startup. 102 | ; Note: Used only when pm is set to 'dynamic' 103 | ; Default Value: min_spare_servers + (max_spare_servers - min_spare_servers) / 2 104 | pm.start_servers = 2 105 | 106 | ; The desired minimum number of idle server processes. 107 | ; Note: Used only when pm is set to 'dynamic' 108 | ; Note: Mandatory when pm is set to 'dynamic' 109 | pm.min_spare_servers = 1 110 | 111 | ; The desired maximum number of idle server processes. 112 | ; Note: Used only when pm is set to 'dynamic' 113 | ; Note: Mandatory when pm is set to 'dynamic' 114 | pm.max_spare_servers = 3 115 | 116 | ; The number of seconds after which an idle process will be killed. 117 | ; Note: Used only when pm is set to 'ondemand' 118 | ; Default Value: 10s 119 | ;pm.process_idle_timeout = 10s; 120 | 121 | ; The number of requests each child process should execute before respawning. 122 | ; This can be useful to work around memory leaks in 3rd party libraries. For 123 | ; endless request processing specify '0'. Equivalent to PHP_FCGI_MAX_REQUESTS. 124 | ; Default Value: 0 125 | pm.max_requests = 500 126 | 127 | ; The URI to view the FPM status page. If this value is not set, no URI will be 128 | ; recognized as a status page. It shows the following informations: 129 | ; pool - the name of the pool; 130 | ; process manager - static, dynamic or ondemand; 131 | ; start time - the date and time FPM has started; 132 | ; start since - number of seconds since FPM has started; 133 | ; accepted conn - the number of request accepted by the pool; 134 | ; listen queue - the number of request in the queue of pending 135 | ; connections (see backlog in listen(2)); 136 | ; max listen queue - the maximum number of requests in the queue 137 | ; of pending connections since FPM has started; 138 | ; listen queue len - the size of the socket queue of pending connections; 139 | ; idle processes - the number of idle processes; 140 | ; active processes - the number of active processes; 141 | ; total processes - the number of idle + active processes; 142 | ; max active processes - the maximum number of active processes since FPM 143 | ; has started; 144 | ; max children reached - number of times, the process limit has been reached, 145 | ; when pm tries to start more children (works only for 146 | ; pm 'dynamic' and 'ondemand'); 147 | ; Value are updated in real time. 148 | ; Example output: 149 | ; pool: www 150 | ; process manager: static 151 | ; start time: 01/Jul/2011:17:53:49 +0200 152 | ; start since: 62636 153 | ; accepted conn: 190460 154 | ; listen queue: 0 155 | ; max listen queue: 1 156 | ; listen queue len: 42 157 | ; idle processes: 4 158 | ; active processes: 11 159 | ; total processes: 15 160 | ; max active processes: 12 161 | ; max children reached: 0 162 | ; 163 | ; By default the status page output is formatted as text/plain. Passing either 164 | ; 'html', 'xml' or 'json' in the query string will return the corresponding 165 | ; output syntax. Example: 166 | ; http://www.foo.bar/status 167 | ; http://www.foo.bar/status?json 168 | ; http://www.foo.bar/status?html 169 | ; http://www.foo.bar/status?xml 170 | ; 171 | ; By default the status page only outputs short status. Passing 'full' in the 172 | ; query string will also return status for each pool process. 173 | ; Example: 174 | ; http://www.foo.bar/status?full 175 | ; http://www.foo.bar/status?json&full 176 | ; http://www.foo.bar/status?html&full 177 | ; http://www.foo.bar/status?xml&full 178 | ; The Full status returns for each process: 179 | ; pid - the PID of the process; 180 | ; state - the state of the process (Idle, Running, ...); 181 | ; start time - the date and time the process has started; 182 | ; start since - the number of seconds since the process has started; 183 | ; requests - the number of requests the process has served; 184 | ; request duration - the duration in µs of the requests; 185 | ; request method - the request method (GET, POST, ...); 186 | ; request URI - the request URI with the query string; 187 | ; content length - the content length of the request (only with POST); 188 | ; user - the user (PHP_AUTH_USER) (or '-' if not set); 189 | ; script - the main script called (or '-' if not set); 190 | ; last request cpu - the %cpu the last request consumed 191 | ; it's always 0 if the process is not in Idle state 192 | ; because CPU calculation is done when the request 193 | ; processing has terminated; 194 | ; last request memory - the max amount of memory the last request consumed 195 | ; it's always 0 if the process is not in Idle state 196 | ; because memory calculation is done when the request 197 | ; processing has terminated; 198 | ; If the process is in Idle state, then informations are related to the 199 | ; last request the process has served. Otherwise informations are related to 200 | ; the current request being served. 201 | ; Example output: 202 | ; ************************ 203 | ; pid: 31330 204 | ; state: Running 205 | ; start time: 01/Jul/2011:17:53:49 +0200 206 | ; start since: 63087 207 | ; requests: 12808 208 | ; request duration: 1250261 209 | ; request method: GET 210 | ; request URI: /test_mem.php?N=10000 211 | ; content length: 0 212 | ; user: - 213 | ; script: /home/fat/web/docs/php/test_mem.php 214 | ; last request cpu: 0.00 215 | ; last request memory: 0 216 | ; 217 | ; Note: There is a real-time FPM status monitoring sample web page available 218 | ; It's available in: ${prefix}/share/fpm/status.html 219 | ; 220 | ; Note: The value must start with a leading slash (/). The value can be 221 | ; anything, but it may not be a good idea to use the .php extension or it 222 | ; may conflict with a real PHP file. 223 | ; Default Value: not set 224 | ;pm.status_path = /status 225 | 226 | ; The ping URI to call the monitoring page of FPM. If this value is not set, no 227 | ; URI will be recognized as a ping page. This could be used to test from outside 228 | ; that FPM is alive and responding, or to 229 | ; - create a graph of FPM availability (rrd or such); 230 | ; - remove a server from a group if it is not responding (load balancing); 231 | ; - trigger alerts for the operating team (24/7). 232 | ; Note: The value must start with a leading slash (/). The value can be 233 | ; anything, but it may not be a good idea to use the .php extension or it 234 | ; may conflict with a real PHP file. 235 | ; Default Value: not set 236 | ;ping.path = /ping 237 | 238 | ; This directive may be used to customize the response of a ping request. The 239 | ; response is formatted as text/plain with a 200 response code. 240 | ; Default Value: pong 241 | ;ping.response = pong 242 | 243 | ; The access log file 244 | ; Default: not set 245 | ;access.log = log/$pool.access.log 246 | 247 | ; The access log format. 248 | ; The following syntax is allowed 249 | ; %%: the '%' character 250 | ; %C: %CPU used by the request 251 | ; it can accept the following format: 252 | ; - %{user}C for user CPU only 253 | ; - %{system}C for system CPU only 254 | ; - %{total}C for user + system CPU (default) 255 | ; %d: time taken to serve the request 256 | ; it can accept the following format: 257 | ; - %{seconds}d (default) 258 | ; - %{miliseconds}d 259 | ; - %{mili}d 260 | ; - %{microseconds}d 261 | ; - %{micro}d 262 | ; %e: an environment variable (same as $_ENV or $_SERVER) 263 | ; it must be associated with embraces to specify the name of the env 264 | ; variable. Some exemples: 265 | ; - server specifics like: %{REQUEST_METHOD}e or %{SERVER_PROTOCOL}e 266 | ; - HTTP headers like: %{HTTP_HOST}e or %{HTTP_USER_AGENT}e 267 | ; %f: script filename 268 | ; %l: content-length of the request (for POST request only) 269 | ; %m: request method 270 | ; %M: peak of memory allocated by PHP 271 | ; it can accept the following format: 272 | ; - %{bytes}M (default) 273 | ; - %{kilobytes}M 274 | ; - %{kilo}M 275 | ; - %{megabytes}M 276 | ; - %{mega}M 277 | ; %n: pool name 278 | ; %o: ouput header 279 | ; it must be associated with embraces to specify the name of the header: 280 | ; - %{Content-Type}o 281 | ; - %{X-Powered-By}o 282 | ; - %{Transfert-Encoding}o 283 | ; - .... 284 | ; %p: PID of the child that serviced the request 285 | ; %P: PID of the parent of the child that serviced the request 286 | ; %q: the query string 287 | ; %Q: the '?' character if query string exists 288 | ; %r: the request URI (without the query string, see %q and %Q) 289 | ; %R: remote IP address 290 | ; %s: status (response code) 291 | ; %t: server time the request was received 292 | ; it can accept a strftime(3) format: 293 | ; %d/%b/%Y:%H:%M:%S %z (default) 294 | ; %T: time the log has been written (the request has finished) 295 | ; it can accept a strftime(3) format: 296 | ; %d/%b/%Y:%H:%M:%S %z (default) 297 | ; %u: remote user 298 | ; 299 | ; Default: "%R - %u %t \"%m %r\" %s" 300 | ;access.format = "%R - %u %t \"%m %r%Q%q\" %s %f %{mili}d %{kilo}M %C%%" 301 | 302 | ; The log file for slow requests 303 | ; Default Value: not set 304 | ; Note: slowlog is mandatory if request_slowlog_timeout is set 305 | slowlog = /var/log/nginx/{{ app }}.slow.log 306 | 307 | ; The timeout for serving a single request after which a PHP backtrace will be 308 | ; dumped to the 'slowlog' file. A value of '0s' means 'off'. 309 | ; Available units: s(econds)(default), m(inutes), h(ours), or d(ays) 310 | ; Default Value: 0 311 | request_slowlog_timeout = 5s 312 | 313 | ; The timeout for serving a single request after which the worker process will 314 | ; be killed. This option should be used when the 'max_execution_time' ini option 315 | ; does not stop script execution for some reason. A value of '0' means 'off'. 316 | ; Available units: s(econds)(default), m(inutes), h(ours), or d(ays) 317 | ; Default Value: 0 318 | request_terminate_timeout = 1d 319 | 320 | ; Set open file descriptor rlimit. 321 | ; Default Value: system defined value 322 | ;rlimit_files = 1024 323 | 324 | ; Set max core size rlimit. 325 | ; Possible Values: 'unlimited' or an integer greater or equal to 0 326 | ; Default Value: system defined value 327 | ;rlimit_core = 0 328 | 329 | ; Chroot to this directory at the start. This value must be defined as an 330 | ; absolute path. When this value is not set, chroot is not used. 331 | ; Note: you can prefix with '$prefix' to chroot to the pool prefix or one 332 | ; of its subdirectories. If the pool prefix is not set, the global prefix 333 | ; will be used instead. 334 | ; Note: chrooting is a great security feature and should be used whenever 335 | ; possible. However, all PHP paths will be relative to the chroot 336 | ; (error_log, sessions.save_path, ...). 337 | ; Default Value: not set 338 | ;chroot = 339 | 340 | ; Chdir to this directory at the start. 341 | ; Note: relative path can be used. 342 | ; Default Value: current directory or / when chroot 343 | chdir = {{ local_path }} 344 | 345 | ; Redirect worker stdout and stderr into main error log. If not set, stdout and 346 | ; stderr will be redirected to /dev/null according to FastCGI specs. 347 | ; Note: on highloaded environement, this can cause some delay in the page 348 | ; process time (several ms). 349 | ; Default Value: no 350 | catch_workers_output = yes 351 | 352 | ; Limits the extensions of the main script FPM will allow to parse. This can 353 | ; prevent configuration mistakes on the web server side. You should only limit 354 | ; FPM to .php extensions to prevent malicious users to use other extensions to 355 | ; exectute php code. 356 | ; Note: set an empty value to allow all extensions. 357 | ; Default Value: .php 358 | ;security.limit_extensions = .php .php3 .php4 .php5 359 | 360 | ; Pass environment variables like LD_LIBRARY_PATH. All $VARIABLEs are taken from 361 | ; the current environment. 362 | ; Default Value: clean env 363 | ;env[HOSTNAME] = $HOSTNAME 364 | ;env[PATH] = /usr/local/bin:/usr/bin:/bin 365 | ;env[TMP] = /tmp 366 | ;env[TMPDIR] = /tmp 367 | ;env[TEMP] = /tmp 368 | 369 | ; Additional php.ini defines, specific to this pool of workers. These settings 370 | ; overwrite the values previously defined in the php.ini. The directives are the 371 | ; same as the PHP SAPI: 372 | ; php_value/php_flag - you can set classic ini defines which can 373 | ; be overwritten from PHP call 'ini_set'. 374 | ; php_admin_value/php_admin_flag - these directives won't be overwritten by 375 | ; PHP call 'ini_set' 376 | ; For php_*flag, valid values are on, off, 1, 0, true, false, yes or no. 377 | 378 | ; Defining 'extension' will load the corresponding shared extension from 379 | ; extension_dir. Defining 'disable_functions' or 'disable_classes' will not 380 | ; overwrite previously defined php.ini values, but will append the new value 381 | ; instead. 382 | 383 | ; Note: path INI options can be relative and will be expanded with the prefix 384 | ; (pool, global or /usr) 385 | 386 | ; Default Value: nothing is defined by default except the values in php.ini and 387 | ; specified at startup with the -d argument 388 | ;php_admin_value[sendmail_path] = /usr/sbin/sendmail -t -i -f www@my.domain.com 389 | ;php_flag[display_errors] = off 390 | ;php_admin_value[error_log] = /var/log/fpm-php.www.log 391 | ;php_admin_flag[log_errors] = on 392 | ;php_admin_value[memory_limit] = 32M 393 | 394 | -------------------------------------------------------------------------------- /conf/php-fpm.ini: -------------------------------------------------------------------------------- 1 | upload_max_filesize=30M 2 | post_max_size=30M 3 | ; max_execution_time=60 4 | -------------------------------------------------------------------------------- /conf/sudoers: -------------------------------------------------------------------------------- 1 | %openvpn ALL=(root:root) NOPASSWD: /sbin/iptables -t nat -A PREROUTING -d * -j DNAT --to-destination * 2 | %openvpn ALL=(root:root) NOPASSWD: /sbin/iptables -t nat -A POSTROUTING -s * ! -d */32 -j SNAT --to-source * 3 | %openvpn ALL=(root:root) NOPASSWD: /sbin/iptables -t nat -A POSTROUTING -s * -o * -j MASQUERADE 4 | -------------------------------------------------------------------------------- /conf/sysctl: -------------------------------------------------------------------------------- 1 | # Enable packet forwarding for IPv4 2 | net.ipv4.ip_forward=1 3 | -------------------------------------------------------------------------------- /conf/yunohost.conf.j2: -------------------------------------------------------------------------------- 1 | # GENERAL 2 | ; Drop privileges 3 | user openvpn 4 | group openvpn 5 | 6 | ; Don't re-read keys at ping-restart (because of dropped privileges) 7 | persist-key 8 | ; Don't remove tun interface and call up/down scripts at ping-restart 9 | persist-tun 10 | 11 | 12 | # SERVER 13 | mode server 14 | {% if dedicated_ip!="" %}local {{ dedicated_ip }}{% endif %} 15 | port {{ port }} 16 | dev tun 17 | 18 | max-clients 30 19 | 20 | # TLS 21 | tls-server 22 | 23 | ca /etc/yunohost/certs/{{ domain }}/ca.pem 24 | cert /etc/yunohost/certs/{{ domain }}/crt.pem 25 | key /etc/yunohost/certs/{{ domain }}/key.pem 26 | dh /etc/yunohost/certs/{{ domain }}/dh.pem 27 | ; When a client connects, check its certificate hasn't been revoked. 28 | ; Must be accessible without root privileges 29 | crl-verify /etc/openvpn/crl.pem 30 | 31 | ; Certificates from the clients must have a field guaranteeing they really are client certificates 32 | remote-cert-tls client 33 | 34 | tls-version-min 1.2 35 | tls-auth /etc/openvpn/ta.key 0 36 | cipher AES-256-CBC 37 | auth SHA512 38 | tls-cipher TLS-DHE-RSA-WITH-AES-256-GCM-SHA384:TLS-DHE-RSA-WITH-AES-128-GCM-SHA256:TLS-DHE-RSA-WITH-AES-256-CBC-SHA:TLS-DHE-RSA-WITH-CAMELLIA-256-CBC-SHA:TLS-DHE-RSA-WITH-AES-128-CBC-SHA:TLS-DHE-RSA-WITH-CAMELLIA-128-CBC-SHA 39 | 40 | ; Clients don't need a certificate to connect (just ldap password) 41 | client-cert-not-required 42 | plugin /usr/lib/openvpn/openvpn-auth-ldap.so /etc/openvpn/auth/ldap.conf 43 | 44 | # NETWORK 45 | topology subnet 46 | ; Notifies the client about the network topology we use 47 | push "topology subnet" 48 | 49 | ; IPv4 50 | ifconfig 10.8.0.1 255.255.255.0 51 | push "route-gateway 10.8.0.1" 52 | 53 | ; IPv6 54 | ; Allow IPv6 usage inside the tunnel 55 | #tun-ipv6 56 | 57 | #ifconfig-ipv6 2a00:5881:8100:0100::1/64 2a00:5881:8100:0100::1 58 | 59 | ; The user-specific IPv4 and IPv6 configuration is in /etc/openvpn/user/$username 60 | username-as-common-name 61 | client-config-dir /etc/openvpn/users/ 62 | 63 | ; DHCP emulation 64 | ;push "dhcp-option DNS 10.8.0.1" 65 | 66 | # SCRIPTS 67 | ; Add routes, notably the delegated prefix 68 | script-security 2 69 | client-connect /etc/openvpn/handler.sh 70 | client-disconnect /etc/openvpn/handler.sh 71 | 72 | 73 | # DIVERS 74 | ; Logs 75 | verb 3 76 | ; Don't log more than 10 consecutive messages (in the same category) 77 | mute 10 ; On ne log pas plus de 10 messages consecutif de la meme categorie 78 | 79 | ; Adaptative tunnel compression 80 | comp-lzo 81 | push "comp-lzo" 82 | 83 | 84 | ; The client must signal itself every 10 seconds. 85 | keepalive 10 60 86 | inactive 600 87 | 88 | ; Management socket. Useful for example to kill an active client connection. 89 | management /var/run/openvpn.udp.socket unix 90 | management-client-user root 91 | 92 | ; Logs 93 | status /var/log/openvpn/status.log 94 | log-append /var/log/openvpn/server.log 95 | 96 | proto udp 97 | ; LES DEUX OPTIONS SUIVANTES FONCTIONNENT SEULEMENT AVEC UDP 98 | ; Pour contrer les encapsulations (ADSL, ...) et l'absence de découverte de MTU 99 | ;fragment 1300 100 | ;mssfix 101 | -------------------------------------------------------------------------------- /hooks/post_app_addaccess: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | app=$1 4 | new_users=$2 5 | 6 | if [[ "openvpn" = "$app" ]]; 7 | then 8 | if (echo "$new_users"|grep -q ",");then 9 | search_filter="(\&(\&(uid=%u)(objectClass=mailAccount))(|" 10 | for user in ${new_users//,/ };do 11 | search_filter="$search_filter(uid=$user)" 12 | done 13 | search_filter="$search_filter))" 14 | else 15 | search_filter="(\&(\&(uid=%u)(objectClass=mailAccount))(uid=$new_users))" 16 | fi 17 | sudo sed -i "s/SearchFilter .*/SearchFilter \"$search_filter\"/g" /etc/openvpn/auth/ldap.conf 18 | sudo systemctl restart openvpn.service 19 | fi 20 | -------------------------------------------------------------------------------- /hooks/post_app_clearaccess: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | app=$1 4 | 5 | if [[ "openvpn" = "$app" ]]; 6 | then 7 | sudo sed -i "s/SearchFilter .*/SearchFilter \"(\&(uid=%u)(objectClass=mailAccount))\"/g" /etc/openvpn/auth/ldap.conf 8 | sudo systemctl restart openvpn.service 9 | fi 10 | -------------------------------------------------------------------------------- /hooks/post_app_removeaccess: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | app=$1 4 | new_users=$2 5 | 6 | if [[ "openvpn" = "$app" ]]; 7 | then 8 | if [ -z "$new_users" ];then 9 | search_filter="(objectClass=NOPE)" 10 | else 11 | if (echo "$new_users"|grep -q ",");then 12 | search_filter="(\&(\&(uid=%u)(objectClass=mailAccount))(|" 13 | for user in ${new_users//,/ };do 14 | search_filter="$search_filter(uid=$user)" 15 | done 16 | search_filter="$search_filter))" 17 | else 18 | search_filter="(\&(\&(uid=%u)(objectClass=mailAccount))(uid=$new_users))" 19 | fi 20 | fi 21 | sudo sed -i "s/SearchFilter .*/SearchFilter \"$search_filter\"/g" /etc/openvpn/auth/ldap.conf 22 | sudo systemctl restart openvpn.service 23 | fi 24 | -------------------------------------------------------------------------------- /hooks/post_iptable_rules: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | source /usr/share/yunohost/helpers 3 | app=openvpn 4 | #source /etc/yunohost/apps/$app/scripts/_common.sh 5 | 6 | #is_upnp=$1 7 | #is_ipv6=$2 8 | 9 | configure_firewall () { 10 | ip4ranges=$(ynh_app_setting_get $app ip4ranges | tr " " "\n") 11 | iface=$(ynh_app_setting_get $app iface) 12 | sudo iptables -t filter -$1 FORWARD -i "${iface}" -o tun0 -m state --state ESTABLISHED,RELATED -j ACCEPT 13 | 14 | sudo iptables -t filter -$1 FORWARD -i tun0 -o "${iface}" -m state --state ESTABLISHED,RELATED -j ACCEPT 15 | sudo iptables -$1 FORWARD -i tun0 -j ACCEPT 16 | 17 | 18 | } 19 | 20 | add_firewall_rules () { 21 | configure_firewall A 22 | } 23 | add_firewall_rules 24 | -------------------------------------------------------------------------------- /manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "VPN server", 3 | "id": "vpnserver", 4 | "packaging_format": 1, 5 | "version": "2.3.4-3", 6 | "description": { 7 | "en": "A server providing Secure and Private Tunnel to the Internet", 8 | "fr": "Un service permettant de fournir des tunnel privé et sécurisé vers Internet" 9 | }, 10 | "requirements": { 11 | "yunohost": ">= 2.4" 12 | }, 13 | "license": "GPL-2.0", 14 | "url": "http://openvpn.net", 15 | "maintainer": { 16 | "name": "sebian", 17 | "email": "seb@fooboozoo.fr", 18 | "url": "https://github.com/YunoHost-Apps/vpnserver_ynh" 19 | }, 20 | "multi_instance": false, 21 | "services": [ 22 | "nginx", 23 | "php5-fpm", 24 | "slapd", 25 | "openvpn" 26 | ], 27 | "arguments": { 28 | "install" : [ 29 | { 30 | "name": "domain", 31 | "type": "domain", 32 | "ask": { 33 | "en": "Choose a domain for OpenVPN", 34 | "fr": "Choisissez un domaine pour OpenVPN" 35 | }, 36 | "example": "domain.org" 37 | }, 38 | { 39 | "name": "path", 40 | "type": "path", 41 | "ask": { 42 | "en": "Choose a path for OpenVPN", 43 | "fr": "Choisissez un chemin pour OpenVPN" 44 | }, 45 | "example": "/openvpn", 46 | "default": "/openvpn" 47 | }, 48 | { 49 | "name": "dedicated_ip", 50 | "type": "string", 51 | "ask": { 52 | "en": "If your server has an other public ip than the main one, you can use it to make openvpn listen on all ports. It could be useful with some crazy/blocked internet access. Leave empty if it's not needed", 53 | "fr": "Si votre server a une autre ip publique que la principale, vous pouvez l'utiliser pour qu'openvpn écoute sur tous les ports. Ce peut être utile avec certains accès internet sale/bloqué. Laissez vide si ce n'est pas nécessaire" 54 | }, 55 | "example": "169.254.10.1", 56 | "default": "", 57 | "optional": true 58 | }, 59 | { 60 | "name": "ip4ranges", 61 | "type": "string", 62 | "ask": { 63 | "en": "If you have several public IPv4 and you want to provide VPN compatibles for self-hosting (VPN associated to a public IP address), list here public IPv4 range to attribute to VPN clients (seperated by space)", 64 | "fr": "Si vous avez plusieurs IPv4 publiques et que vous voulez fournir des VPN compatibles pour l'auto-hébergement (VPN associé à une adresse IP publique), listez ici plages d'adresses IPv4 à attribuer aux clients VPN (séparé par des espaces)" 65 | }, 66 | "example": "169.254.10.25 169.254.10.32 169.254.11.0/29", 67 | "default": "", 68 | "optional": true 69 | } 70 | ] 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /scripts/_common.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # App package root directory should be the parent folder 4 | PKG_DIR=$(cd ../; pwd) 5 | 6 | 7 | 8 | 9 | #============================================================ 10 | # Specific to openvpn 11 | #============================================================ 12 | 13 | check_iptables () { 14 | # Check if iptables is working 15 | if ! sudo iptables -L > /dev/null 2>&1; then 16 | err "iptables is not available in your environment, aborting..." 17 | exit 1 18 | fi 19 | } 20 | 21 | check_tun_available () { 22 | # Ensure tun device is available 23 | #if [[ ! -c /dev/net/tun ]]; then 24 | # err "OpenVPN requires tun support, aborting..." 25 | # exit 1 26 | #fi 27 | return 0 28 | } 29 | 30 | check_ip4 () { 31 | _255='(25[0-5]|2[0-4][0-9]|1?[0-9][0-9]?)' 32 | regex=(${_255}\.){3}${_255} 33 | if [[ $1 =~ ^${regex}$ ]]; then 34 | return 0 35 | else 36 | err "Bad Ipv4 format, aborting..." 37 | exit 1 38 | fi 39 | exit 1 40 | } 41 | 42 | check_ip4ranges () { 43 | _255='(25[0-5]|2[0-4][0-9]|1?[0-9][0-9]?)' 44 | ip4regex=(${_255}\.){3}${_255} 45 | rangeip4regex="${ip4regex}(/(3[0-2]|[1-2][0-9]|[1-9]))?" 46 | regex="${rangeip4regex}([[:space:]]+${rangeip4regex})*" 47 | if [[ $1 =~ ^${regex}$ ]]; then 48 | return 0 49 | else 50 | err "Bad Ipv4 ranges format, aborting..." 51 | exit 1 52 | fi 53 | exit 1 54 | } 55 | 56 | 57 | configure_firewall () { 58 | ip4ranges=$(ynh_app_setting_get $app ip4ranges | tr " " "\n") 59 | iface=$(ynh_app_setting_get $app iface) 60 | sudo iptables -t filter -$1 FORWARD -i "${iface}" -o tun0 -m state --state ESTABLISHED,RELATED -j ACCEPT 61 | for ip4range in $ip4ranges 62 | do 63 | if [[ "$1" = "A" ]];then 64 | if ! (sudo /sbin/iptables -L -t nat | grep $ip4range | grep MASQUERADE > /dev/null 2>&1); then 65 | sudo iptables -t nat -$1 POSTROUTING -s $ip4range -o "${iface}" -j MASQUERADE 66 | sudo iptables -t filter -$1 FORWARD -s $ip4range -o "${iface}" -j ACCEPT 67 | fi 68 | elif [[ "$1" = "D" ]]; then 69 | if (sudo /sbin/iptables -L -t nat | grep $ip4range | grep MASQUERADE > /dev/null 2>&1); then 70 | sudo iptables -t nat -$1 POSTROUTING -s $ip4range -o "${iface}" -j MASQUERADE 71 | sudo iptables -t filter -$1 FORWARD -s $ip4range -o "${iface}" -j ACCEPT 72 | fi 73 | fi 74 | done 75 | } 76 | 77 | add_firewall_rules () { 78 | configure_firewall A 79 | } 80 | 81 | rm_firewall_rules () { 82 | configure_firewall D 83 | } 84 | 85 | deduce_gateway () { 86 | 87 | first_ip4_range=$(echo $ip4ranges | cut -f1 -d" ") 88 | first_ip=$(netmask -r $first_ip4_range | cut -f1 -d"-" ) 89 | first_ip=$( netmask -x $first_ip ) 90 | first_ip=$(( $first_ip + 1 )) 91 | export first_ip4=$( netmask $first_ip ) 92 | export last_ip4=$(netmask -r $first_ip4_range | cut -f2 -d"-" ) 93 | first_ip4_range=$(netmask -s $first_ip4_range) 94 | export gateway_ip4=$(echo $first_ip4_range | cut -f1 -d"/") 95 | export gateway_mask=$(echo $first_ip4_range | cut -f2 -d"/") 96 | } 97 | 98 | install_files () { 99 | # Make directories and set rights 100 | sudo mkdir -p /etc/openvpn/auth \ 101 | /etc/openvpn/users \ 102 | "${local_path}" \ 103 | /var/log/openvpn 104 | sudo touch /var/log/openvpn/status.log 105 | sudo touch /var/log/openvpn/server.log 106 | sudo touch /etc/openvpn/users_settings.csv 107 | 108 | # Copy web files 109 | sudo cp -a ../sources/. $local_path 110 | 111 | # Configurations 112 | set +x 113 | export ca_yunohost=$(sudo cat /etc/ssl/certs/ca-yunohost_crt.pem) 114 | export ta_key=$(sudo cat /etc/openvpn/ta.key) 115 | set -x 116 | ynh_configure yunohost.conf "/etc/openvpn/yunohost.conf" 117 | ynh_configure config.ovpn "${local_path}/${domain}.conf" 118 | ynh_configure config-cli.ovpn "${local_path}/${domain}.ovpn" 119 | ynh_configure fail2ban-jail.conf "/etc/fail2ban/jail.d/${app}.conf" 120 | sudo cp ../conf/ldap.conf /etc/openvpn/auth/ 121 | sudo ln -s /etc/ssl/certs/ca-yunohost_crt.pem "${local_path}/ca.crt" 122 | sudo cp ../conf/fail2ban-filter.conf /etc/fail2ban/filter.d/$app.conf 123 | sudo cp ../conf/logrotate.conf /etc/logrotate.d/$app.conf 124 | sudo cp ../conf/handler.sh /etc/openvpn/handler.sh 125 | sudo cp ../conf/sudoers /etc/sudoers.d/openvpn 126 | sudo touch /etc/openvpn/crl.pem 127 | echo "$ip4ranges" | sudo tee /etc/openvpn/ip4ranges 128 | 129 | # IP forwarding 130 | sudo cp ../conf/sysctl /etc/sysctl.d/openvpn.conf 131 | 132 | } 133 | 134 | setup_and_restart () { 135 | # Find gateway ip and mask and save it 136 | deduce_gateway 137 | ynh_save_args gateway_ip4 gateway_mask 138 | 139 | # Open port in firewall 140 | if [ -z $dedicated_ip ]; then 141 | sudo yunohost firewall allow Both $port > /dev/null 2>&1 142 | fi 143 | 144 | # Create user 145 | ynh_system_user_create "$user" "/etc/openvpn/" 146 | ynh_system_user_create "$webuser" "$local_path" 147 | 148 | # Copy files 149 | install_files 150 | sudo sysctl -p /etc/sysctl.d/openvpn.conf 151 | 152 | # Permissions 153 | ynh_set_default_perm "${local_path}" $webuser 154 | sudo chown -R $webuser:www-data "${local_path}" 155 | sudo chmod 640 "${local_path}/${domain}.conf" 156 | sudo chmod 640 "${local_path}/${domain}.ovpn" 157 | sudo chown -R $user: /var/log/openvpn 158 | sudo chown -R $user: /etc/openvpn 159 | sudo chmod 640 /etc/openvpn/users_settings.csv 160 | sudo chmod u+x /etc/openvpn/handler.sh 161 | # Add OpenVPN to YunoHost's monitored services 162 | sudo yunohost service add openvpn --log /var/log/openvpn/status.log 163 | 164 | # Ensure that tun device is still available, otherwise try to create it manually 165 | if [[ ! -c /dev/net/tun ]]; then 166 | sudo mkdir -p /dev/net 167 | sudo mknod /dev/net/tun c 10 200 168 | sudo chmod 666 /dev/net/tun 169 | fi 170 | 171 | # Add masquerade rules 172 | add_firewall_rules 173 | 174 | # Let's go ! 175 | sudo yunohost service enable openvpn 176 | sudo yunohost service start openvpn 177 | 178 | ynh_configure_php_fpm 179 | ynh_configure_nginx 180 | } 181 | 182 | 183 | 184 | #============================================================ 185 | # Common helpers 186 | #============================================================ 187 | 188 | ynh_check_var () { 189 | test -n "$1" || ynh_die "$2" 190 | } 191 | 192 | ynh_exit_properly () { 193 | exit_code=$? 194 | if [ "$exit_code" -eq 0 ]; then 195 | exit 0 196 | fi 197 | trap '' EXIT 198 | set +eu 199 | echo -e "\e[91m \e[1m" 200 | err "$app script has encountered an error." 201 | 202 | if type -t CLEAN_SETUP > /dev/null; then 203 | CLEAN_SETUP 204 | fi 205 | 206 | ynh_die 207 | } 208 | 209 | # Activate signal capture 210 | # Exit if a command fail, and if a variable is used unset. 211 | # Capturing exit signals on shell script 212 | # 213 | # example: CLEAN_SETUP () { 214 | # # Clean residual file un remove by remove script 215 | # } 216 | # ynh_trap_on 217 | ynh_trap_on () { 218 | set -eu 219 | trap ynh_exit_properly EXIT # Capturing exit signals on shell script 220 | } 221 | 222 | ynh_export () { 223 | local ynh_arg="" 224 | for var in $@; 225 | do 226 | ynh_arg=$(echo $var | awk '{print toupper($0)}') 227 | ynh_arg="YNH_APP_ARG_$ynh_arg" 228 | export $var=${!ynh_arg} 229 | done 230 | } 231 | 232 | # Check availability of a web path 233 | # 234 | # example: ynh_path_validity $domain$path 235 | # 236 | # usage: ynh_path_validity $domain_and_path 237 | # | arg: domain_and_path - complete path to check 238 | ynh_path_validity () { 239 | sudo yunohost app checkurl $1 -a $app 240 | } 241 | 242 | # Normalize the url path syntax 243 | # Handle the slash at the beginning of path and its absence at ending 244 | # Return a normalized url path 245 | # 246 | # example: url_path=$(ynh_normalize_url_path $url_path) 247 | # ynh_normalize_url_path example -> /example 248 | # ynh_normalize_url_path /example -> /example 249 | # ynh_normalize_url_path /example/ -> /example 250 | # 251 | # usage: ynh_normalize_url_path path_to_normalize 252 | # | arg: url_path_to_normalize - URL path to normalize before using it 253 | ynh_normalize_url_path () { 254 | path=$1 255 | test -n "$path" || ynh_die "ynh_normalize_url_path expect a URL path as first argument and received nothing." 256 | if [ "${path:0:1}" != "/" ]; then # If the first character is not a / 257 | path="/$path" # Add / at begin of path variable 258 | fi 259 | if [ "${path:${#path}-1}" == "/" ] && [ ${#path} -gt 1 ]; then # If the last character is a / and that not the only character. 260 | path="${path:0:${#path}-1}" # Delete the last character 261 | fi 262 | echo $path 263 | } 264 | 265 | # Check the path doesn't exist 266 | # usage: ynh_local_path_available PATH 267 | ynh_local_path_available () { 268 | if [ -e "$1" ] 269 | then 270 | ynh_die "This path '$1' already contains a folder" 271 | fi 272 | } 273 | 274 | # Save listed var in YunoHost app settings 275 | # usage: ynh_save_args VARNAME1 [VARNAME2 [...]] 276 | ynh_save_args () { 277 | for var in $@; 278 | do 279 | ynh_app_setting_set $app $var "${!var}" 280 | done 281 | } 282 | 283 | # Create a database, an user and its password. Then store the password in the app's config 284 | # 285 | # User of database will be store in db_user's variable. 286 | # Name of database will be store in db_name's variable. 287 | # And password in db_pwd's variable. 288 | # 289 | # usage: ynh_mysql_generate_db user name 290 | # | arg: user - Proprietary of the database 291 | # | arg: name - Name of the database 292 | ynh_mysql_generate_db () { 293 | export db_user=${1//[-.]/_} # Mariadb doesn't support - and . in the name of databases. It will be replace by _ 294 | export db_name=${2//[-.]/_} 295 | 296 | export db_pwd=$(ynh_string_random) # Generate a random password 297 | ynh_check_var "$db_pwd" "db_pwd empty" 298 | 299 | ynh_mysql_create_db "$db_name" "$db_user" "$db_pwd" # Create the database 300 | 301 | ynh_app_setting_set $app mysqlpwd $db_pwd # Store the password in the app's config 302 | } 303 | 304 | # Execute a command as another user 305 | # usage: ynh_exec_as USER COMMAND [ARG ...] 306 | ynh_exec_as() { 307 | local USER=$1 308 | shift 1 309 | 310 | if [[ $USER = $(whoami) ]]; then 311 | eval "$@" 312 | else 313 | # use sudo twice to be root and be allowed to use another user 314 | sudo sudo -u "$USER" "$@" 315 | fi 316 | } 317 | 318 | # Get sources, setup it into dest directory and deploy patches 319 | # Try to find locally the sources and download it if missing. 320 | # Check the integrity with an hash program (default: sha256sum) 321 | # Source hash and location are get from a "SOURCE_ID.src" file, 322 | # by default the SOURCE_ID is "app". 323 | # Patches should be located in a "patches" dir, they should be 324 | # named like "SOURCE_ID-*.patch". 325 | # 326 | # example: ynh_setup_source "/var/www/limesurvey/" "limesurvey" 327 | # 328 | # usage: ynh_setup_source DEST_DIR [USER [SOURCE_ID]] 329 | 330 | ynh_setup_source () { 331 | local DEST=$1 332 | local AS_USER=${2:-admin} 333 | local SOURCE_ID=${3:-app} 334 | local SOURCE_FILE="$YNH_APP_ID.tar.gz" 335 | local SUM_PRG="sha256sum" 336 | source ../$SOURCE_ID.src 337 | local LOCAL_SOURCE="/opt/yunohost-apps-src/$YNH_APP_ID/$SOURCE_FILE" 338 | 339 | if test -e $LOCAL_SOURCE; then 340 | cp $LOCAL_SOURCE $SOURCE_FILE 341 | else 342 | wget -nv $SOURCE_URL -O $SOURCE_FILE 343 | fi 344 | echo "$SOURCE_SUM $SOURCE_FILE" |$SUM_PRG -c --status \ 345 | || ynh_die "Corrupt source" 346 | 347 | sudo mkdir -p "$DEST" 348 | sudo chown $AS_USER: "$DEST" 349 | if [ "$(echo ${SOURCE_FILE##*.})" == "gz" ]; then 350 | ynh_exec_as "$AS_USER" tar xf $SOURCE_FILE -C "$DEST" --strip-components 1 351 | elif [ "$(echo ${SOURCE_FILE##*.})" == "bz2" ]; then 352 | ynh_exec_as "$AS_USER" tar xjf $SOURCE_FILE -C "$DEST" --strip-components 1 353 | elif [ "$(echo ${SOURCE_FILE##*.})" == "zip" ]; then 354 | mkdir -p "/tmp/$SOURCE_FILE" 355 | ynh_exec_as "$AS_USER" unzip -q $SOURCE_FILE -d "/tmp/$SOURCE_FILE" 356 | ynh_exec_as "$AS_USER" mv "/tmp/$SOURCE_FILE"/./. "$DEST" 357 | rmdir "$/tmp/$SOURCE_FILE" 358 | else 359 | false 360 | fi 361 | 362 | # Apply patches 363 | if [ -f ${PKG_DIR}/patches/$SOURCE_ID-*.patch ]; then 364 | (cd "$DEST" \ 365 | && for p in ${PKG_DIR}/patches/$SOURCE_ID-*.patch; do \ 366 | ynh_exec_as "$AS_USER" patch -p1 < $p; done) \ 367 | || ynh_die "Unable to apply patches" 368 | 369 | fi 370 | 371 | # Apply persistent modules (upgrade only) 372 | ynh_restore_persistent modules 373 | 374 | # Apply persistent data (upgrade only) 375 | ynh_restore_persistent data 376 | 377 | } 378 | 379 | # TODO support SOURCE_ID 380 | ynh_save_persistent () { 381 | local TYPE=$1 382 | local DIR=/tmp/ynh-persistent/$TYPE/$app/app 383 | sudo mkdir -p $DIR 384 | sudo touch $DIR/dir_names 385 | shift 386 | i=1 387 | for PERSISTENT_DIR in $@; 388 | do 389 | if [ -e $local_path/$PERSISTENT_DIR ]; then 390 | sudo mv $local_path/$PERSISTENT_DIR $DIR/$i 391 | sudo su -c "echo -n '$PERSISTENT_DIR ' >> $DIR/dir_names" 392 | ((i++)) 393 | fi 394 | done 395 | } 396 | 397 | # TODO support SOURCE_ID 398 | ynh_restore_persistent () { 399 | local TYPE=$1 400 | local DIR=/tmp/ynh-persistent/$TYPE/$app/app 401 | shift 402 | if [ -d $DIR ]; then 403 | i=1 404 | for PERSISTENT_DIR in $(cat $DIR/dir_names); 405 | do 406 | if [ "$TYPE" = "modules" ]; then 407 | for updated_subdir in $(ls $local_path/$PERSISTENT_DIR); 408 | do 409 | sudo rm -Rf $DIR/$i/$updated_subdir 410 | done 411 | fi 412 | if [ -d $DIR/$i ]; then 413 | sudo mv $DIR/$i/* $local_path/$PERSISTENT_DIR/ 2> /dev/null || true 414 | else 415 | sudo mv $DIR/$i $local_path/$PERSISTENT_DIR 2> /dev/null || true 416 | fi 417 | ((i++)) 418 | done 419 | sudo rm -Rf $DIR 420 | fi 421 | 422 | } 423 | ynh_mv_to_home () { 424 | local APP_PATH="/home/yunohost.app/$app/" 425 | local DATA_PATH="$1" 426 | sudo mkdir -p "$APP_PATH" 427 | sudo chown $app: "$APP_PATH" 428 | ynh_exec_as "$app" mv "$DATA_PATH" "$APP_PATH" 429 | ynh_exec_as "$app" ln -s "$APP_PATH$DATA_PATH" "$DATA_PATH" 430 | 431 | } 432 | 433 | ynh_set_default_perm () { 434 | local DIRECTORY=$1 435 | local USER=$2 436 | # Set permissions 437 | sudo chown -R $USER:$USER $DIRECTORY 438 | sudo chmod -R 664 $DIRECTORY 439 | sudo find $DIRECTORY -type d -print0 | xargs -0 sudo chmod 775 \ 440 | || echo "No file to modify" 441 | 442 | } 443 | ynh_sso_access () { 444 | ynh_app_setting_set $app unprotected_uris "/" 445 | 446 | if [[ $is_public -eq 0 ]]; then 447 | ynh_app_setting_set $app protected_uris "$1" 448 | fi 449 | sudo yunohost app ssowatconf 450 | } 451 | 452 | ynh_exit_if_up_to_date () { 453 | if [ "${version}" = "${last_version}" ]; then 454 | info "Up-to-date, nothing to do" 455 | exit 0 456 | fi 457 | } 458 | 459 | log() { 460 | echo "${1}" 461 | } 462 | 463 | info() { 464 | log "[INFO] ${1}" 465 | } 466 | 467 | warn() { 468 | log "[WARN] ${1}" 469 | } 470 | 471 | err() { 472 | log "[ERR] ${1}" 473 | } 474 | 475 | to_logs() { 476 | 477 | # When yunohost --verbose or bash -x 478 | if $_ISVERBOSE; then 479 | cat 480 | else 481 | cat > /dev/null 482 | fi 483 | } 484 | 485 | ynh_read_json () { 486 | sudo python3 -c "import sys, json;print(json.load(open('$1'))['$2'])" 487 | } 488 | 489 | ynh_read_manifest () { 490 | if [ -f '../manifest.json' ] ; then 491 | ynh_read_json '../manifest.json' "$1" 492 | else 493 | ynh_read_json '../settings/manifest.json' "$1" 494 | fi 495 | } 496 | 497 | ynh_app_dependencies (){ 498 | export dependencies=$1 499 | export project_url=$(ynh_read_manifest 'url') 500 | export version=$(ynh_read_manifest 'version') 501 | export dep_app=${app/__/-} 502 | mkdir -p ../conf 503 | cat > ../conf/app-ynh-deps.control.j2 << EOF 504 | Section: misc 505 | Priority: optional 506 | Homepage: {{ project_url }} 507 | Standards-Version: 3.9.2 508 | 509 | Package: {{ dep_app }}-ynh-deps 510 | Version: {{ version }} 511 | Depends: {{ dependencies }} 512 | Architecture: all 513 | Description: meta package for {{ app }} (YunoHost app) dependencies 514 | This meta-package is only responsible of installing its dependencies. 515 | EOF 516 | 517 | ynh_configure app-ynh-deps.control ./$dep_app-ynh-deps.control 518 | ynh_package_install_from_equivs ./$dep_app-ynh-deps.control \ 519 | || ynh_die "Unable to install dependencies" 520 | } 521 | 522 | 523 | 524 | 525 | # Create a system user 526 | # 527 | # usage: ynh_system_user_create user_name [home_dir] 528 | # | arg: user_name - Name of the system user that will be create 529 | # | arg: home_dir - Path of the home dir for the user. Usually the final path of the app. If this argument is omitted, the user will be created without home 530 | ynh_system_user_create () { 531 | if ! ynh_system_user_exists "$1" # Check if the user exists on the system 532 | then # If the user doesn't exist 533 | if [ $# -ge 2 ]; then # If a home dir is mentioned 534 | user_home_dir="-d $2" 535 | else 536 | user_home_dir="--no-create-home" 537 | fi 538 | sudo useradd $user_home_dir --system --user-group $1 --shell /usr/sbin/nologin || ynh_die "Unable to create $1 system account" 539 | fi 540 | } 541 | 542 | # Delete a system user 543 | # 544 | # usage: ynh_system_user_delete user_name 545 | # | arg: user_name - Name of the system user that will be create 546 | ynh_system_user_delete () { 547 | if ynh_system_user_exists "$1" # Check if the user exists on the system 548 | then 549 | sudo userdel $1 550 | else 551 | echo "The user $1 was not found" >&2 552 | fi 553 | } 554 | 555 | 556 | ynh_configure () { 557 | local TEMPLATE=$1 558 | local DEST=$2 559 | type j2 2>/dev/null || sudo pip install j2cli jinja2 560 | j2 "${PKG_DIR}/conf/$TEMPLATE.j2" > "${PKG_DIR}/conf/$TEMPLATE" 561 | sudo cp "${PKG_DIR}/conf/$TEMPLATE" "$DEST" 562 | } 563 | 564 | ynh_configure_nginx () { 565 | ynh_configure nginx.conf /etc/nginx/conf.d/$domain.d/$app.conf 566 | sudo service nginx reload 567 | } 568 | 569 | ynh_configure_php_fpm () { 570 | finalphpconf=/etc/php5/fpm/pool.d/$app.conf 571 | ynh_configure php-fpm.conf /etc/php5/fpm/pool.d/$app.conf 572 | sudo chown root: $finalphpconf 573 | 574 | finalphpini=/etc/php5/fpm/conf.d/20-$app.ini 575 | sudo cp ../conf/php-fpm.ini $finalphpini 576 | sudo chown root: $finalphpini 577 | 578 | sudo service php5-fpm reload 579 | } 580 | 581 | # Find a free port and return it 582 | # 583 | # example: port=$(ynh_find_port 8080) 584 | # 585 | # usage: ynh_find_port begin_port 586 | # | arg: begin_port - port to start to search 587 | ynh_find_port () { 588 | port=$1 589 | test -n "$port" || ynh_die "The argument of ynh_find_port must be a valid port." 590 | while netcat -z 127.0.0.1 $port # Check if the port is free 591 | do 592 | port=$((port+1)) # Else, pass to next port 593 | done 594 | echo $port 595 | } 596 | 597 | 598 | ### REMOVE SCRIPT 599 | 600 | # Remove a database if it exist and the associated user 601 | # 602 | # usage: ynh_mysql_remove_db user name 603 | # | arg: user - Proprietary of the database 604 | # | arg: name - Name of the database 605 | ynh_mysql_remove_db () { 606 | if mysqlshow -u root -p$(sudo cat $MYSQL_ROOT_PWD_FILE) | grep -q "^| $2"; then # Check if the database exist 607 | ynh_mysql_drop_db $2 # Remove the database 608 | ynh_mysql_drop_user $1 # Remove the associated user to database 609 | else 610 | echo "Database $2 not found" >&2 611 | fi 612 | } 613 | 614 | ynh_rm_nginx_conf () { 615 | if [ -e "/etc/nginx/conf.d/$domain.d/$app.conf" ]; then 616 | sudo rm "/etc/nginx/conf.d/$domain.d/$app.conf" 617 | sudo service nginx reload 618 | fi 619 | } 620 | 621 | ynh_rm_php_fpm_conf () { 622 | if [ -e "/etc/php5/fpm/pool.d/$app.conf" ]; then 623 | sudo rm "/etc/php5/fpm/pool.d/$app.conf" 624 | fi 625 | if [ -e "/etc/php5/fpm/conf.d/20-$app.ini" ]; then 626 | sudo rm "/etc/php5/fpm/conf.d/20-$app.ini" 627 | fi 628 | sudo service php5-fpm reload 629 | } 630 | 631 | REMOVE_LOGROTATE_CONF () { 632 | if [ -e "/etc/logrotate.d/$app" ]; then 633 | sudo rm "/etc/logrotate.d/$app" 634 | fi 635 | } 636 | 637 | ynh_secure_rm () { 638 | [[ "/var/www /opt /home/yunohost.app" =~ $1 ]] \ 639 | || (test -n "$1" && sudo rm -Rf $1 ) 640 | } 641 | 642 | 643 | -------------------------------------------------------------------------------- /scripts/backup: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # causes the shell to exit if any subcommand or pipeline returns a non-zero status 4 | set -e 5 | 6 | # Source YNH helpers 7 | . /usr/share/yunohost/helpers 8 | 9 | backup_dir=$1 10 | 11 | # Get app instance name 12 | app=$YNH_APP_INSTANCE_NAME 13 | 14 | # Retrieve arguments 15 | domain=$(ynh_app_setting_get $app domain) 16 | path=$(ynh_app_setting_get $app path) 17 | local_path=$(ynh_app_setting_get $app local_path) 18 | 19 | my_ynh_backup () { 20 | ynh_backup $@ 21 | echo $2 $1 >> $backup_dir/list 22 | } 23 | 24 | # Copy the app files 25 | my_ynh_backup "$local_path" "sources" 26 | my_ynh_backup "/etc/openvpn" "etc" 27 | my_ynh_backup "/etc/yunohost/certs/${domain}/dh.pem" "certs/dh.pem" 28 | 29 | # Copy the conf files 30 | my_ynh_backup "/etc/sysctl.d/openvpn.conf" "conf/sysctl" 31 | my_ynh_backup "/etc/nginx/conf.d/$domain.d/$app.conf" "conf/nginx.conf" 32 | my_ynh_backup "/etc/php5/fpm/pool.d/$app.conf" "conf/php-fpm.conf" 33 | my_ynh_backup "/etc/php5/fpm/conf.d/20-$app.ini" "conf/php-fpm.ini" 34 | my_ynh_backup "/etc/fail2ban/jail.d/${app}.conf" "conf/fail2ban-jail.conf" 35 | my_ynh_backup "/etc/fail2ban/filter.d/$app.conf" "conf/fail2ban-filter.conf" 36 | my_ynh_backup "/etc/logrotate.d/$app.conf" "conf/logrotate.conf" 37 | 38 | # Copy log 39 | my_ynh_backup "/var/log/openvpn" "log" 40 | -------------------------------------------------------------------------------- /scripts/install: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | source /usr/share/yunohost/helpers 3 | source _common.sh 4 | 5 | ynh_trap_on 6 | 7 | export app=$YNH_APP_INSTANCE_NAME 8 | export user=$app 9 | export webuser="${user}web" 10 | 11 | # Retrieve arguments 12 | ynh_export domain path ip4ranges dedicated_ip 13 | ynh_find_port 1194 14 | export port=$port 15 | export local_path=/var/www/$app 16 | export iface=$(ip r|awk '/default/ { print $5 }') 17 | 18 | #================================================= 19 | # CHECK IF THE APP CAN BE INSTALLED WITH THIS ARGS 20 | #================================================= 21 | ynh_check_var "$app" "app name not set" 22 | #ynh_user_exists "$admin" || ynh_die "User does not exist: $admin" 23 | ynh_normalize_url_path "$path" 24 | ynh_path_validity "$domain$path" 25 | ynh_local_path_available "$local_path" 26 | check_iptables 27 | check_tun_available 28 | check_ip4ranges $ip4ranges 29 | 30 | 31 | #================================================= 32 | # SETUP THE APP BY MODIFYING THE SYSTEM 33 | #================================================= 34 | ynh_save_args ip4ranges port local_path iface dedicated_ip 35 | 36 | # Install official debian package 37 | ynh_app_dependencies openvpn,openvpn-auth-ldap,netmask 38 | 39 | # Create DH for main domain 40 | dh_size=1024 41 | info "Generate dhparam(${dh_size}) file, this step may be long..." 42 | sudo openssl dhparam -out "/etc/yunohost/certs/${domain}/dh.pem" $dh_size > /dev/null 43 | sudo openvpn --genkey --secret /etc/openvpn/ta.key 44 | 45 | # Install configured files and restart services 46 | setup_and_restart 47 | -------------------------------------------------------------------------------- /scripts/remove: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | source /usr/share/yunohost/helpers 3 | source _common.sh 4 | 5 | app=$YNH_APP_INSTANCE_NAME 6 | user=$app 7 | webuser="${user}web" 8 | 9 | local_path=$(ynh_app_setting_get $app local_path) 10 | domain=$(sudo yunohost app setting $app domain) 11 | 12 | sudo service openvpn stop 13 | 14 | sudo rm -f /etc/yunohost/hooks.d/post_iptable_rules/*openvpn 15 | sudo yunohost firewall disallow UDP 1194 > /dev/null 2>&1 16 | rm_firewall_rules 17 | 18 | sudo sysctl net.ipv4.ip_forward=0 19 | sudo yunohost service remove openvpn 20 | 21 | # We don't delete all /etc/openvpn because it could be used by vpnclient_ynh 22 | sudo rm -rf /etc/openvpn/yunohost.conf \ 23 | /etc/openvpn/auth \ 24 | /etc/openvpn/ta.key \ 25 | /etc/openvpn/users \ 26 | /etc/openvpn/handler.sh \ 27 | /etc/openvpn/ip4_attribution.csv \ 28 | /etc/sysctl.d/openvpn.conf 29 | 30 | # TODO: May be we shouldn't remove it 31 | sudo rm -rf /var/log/openvpn 32 | 33 | 34 | ynh_secure_rm "$local_path" 35 | ynh_secure_rm "/etc/yunohost/certs/${domain}/dh.pem" 36 | ynh_secure_rm "/etc/nginx/conf.d/${domain}.d/openvpn.conf" 37 | ynh_secure_rm "/etc/logrotate.d/$app.conf" 38 | ynh_secure_rm "/etc/fail2ban/filter.d/$app.conf" 39 | ynh_secure_rm "/etc/fail2ban/jail.d/${app}.conf" 40 | 41 | ynh_rm_nginx_conf 42 | ynh_rm_php_fpm_conf 43 | 44 | ynh_system_user_delete "$user" 45 | ynh_system_user_delete "$webuser" 46 | 47 | dep_app=${app/__/-} 48 | ynh_package_remove $dep_app-ynh-deps 49 | 50 | sudo yunohost app ssowatconf 51 | -------------------------------------------------------------------------------- /scripts/restore: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | source /usr/share/yunohost/helpers 3 | source ../settings/scripts/_common.sh 4 | 5 | ynh_trap_on 6 | 7 | export app=$YNH_APP_INSTANCE_NAME 8 | export user=$app 9 | export webuser="${user}web" 10 | 11 | export domain=$(ynh_app_setting_get $app domain) 12 | export path=$(ynh_app_setting_get $app path) 13 | export local_path=$(ynh_app_setting_get $app local_path) 14 | export iface=$(ynh_app_setting_get $app iface) 15 | export port=$(ynh_app_setting_get $app port) 16 | export ip4ranges=$(ynh_app_setting_get $app ip4ranges) 17 | export dynamic_ip=$(ynh_app_setting_get $app dynamic_ip) 18 | 19 | #================================================= 20 | # CHECK IF THE APP CAN BE RESTORED 21 | #================================================= 22 | ynh_check_restore 23 | check_iptables 24 | check_tun_available 25 | 26 | #================================================= 27 | # RESTORE THE APP BY MODIFYING THE SYSTEM 28 | #================================================= 29 | # Install official debian package 30 | ynh_app_dependencies openvpn,openvpn-auth-ldap,netmask 31 | 32 | install_files () { 33 | ynh_restore 34 | } 35 | 36 | setup_and_restart 37 | -------------------------------------------------------------------------------- /scripts/upgrade: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | source /usr/share/yunohost/helpers 3 | source _common.sh 4 | 5 | ynh_trap_on 6 | 7 | export app=$YNH_APP_INSTANCE_NAME 8 | export user=$app 9 | export webuser="${user}web" 10 | 11 | export domain=$(ynh_app_setting_get $app domain) 12 | domain=${prefix:-$(cat /etc/yunohost/current_host)} 13 | export path=$(ynh_app_setting_get $app path) 14 | path=${path:-/openvpn/} 15 | export local_path=$(ynh_app_setting_get $app local_path) 16 | local_path=${local_path:-/var/www/$app} 17 | export iface=$(ynh_app_setting_get $app iface) 18 | iface=${iface:-$(ip r|awk '/default/ { print $5 }')} 19 | export port=$(ynh_app_setting_get $app port) 20 | port=${port:-1194} 21 | export ip4ranges=$(ynh_app_setting_get $app ip4ranges) 22 | ip4ranges=${ip4ranges:-10.0.0.8/24} 23 | export dynamic_ip=$(ynh_app_setting_get $app dynamic_ip) 24 | dynamic_ip=${dynamic_ip:-false} 25 | 26 | 27 | version=$(ynh_read_json "/etc/yunohost/apps/$app/manifest.json" 'version' 2> /dev/null || echo '2.3.4-1') 28 | last_version=$(ynh_read_manifest 'version') 29 | 30 | ynh_exit_if_up_to_date 31 | ynh_check_var "$app" "app name not set" 32 | ynh_normalize_url_path "$path" 33 | 34 | if [ "${version}" = "2.3.4-1" ]; then 35 | ynh_save_args domain path ip4ranges port local_path iface dynamic_ip 36 | 37 | # Install official debian package 38 | ynh_app_dependencies openvpn,openvpn-auth-ldap,netmask 39 | 40 | # Delete old cron (replace by a iptables hooks) 41 | sudo rm -f /etc/openvpn/yunohost.cron 42 | 43 | # Install configured files and restart services 44 | setup_and_restart 45 | 46 | sudo mv /var/log/openvpn.log /var/log/openvpn/status.log 47 | fi 48 | 49 | if [ "${version}" = "2.3.4-2" ]; then 50 | sudo touch /etc/openvpn/crl.pem 51 | sudo mkdir -p /etc/openvpn/users 52 | sudo touch /etc/openvpn/ip4_attribution.csv 53 | sudo cp ../conf/handler.sh /etc/openvpn/handler.sh 54 | sudo chown -R $user: /etc/openvpn 55 | sudo chmod 640 /etc/openvpn/ip4_attribution.csv 56 | sudo chmod u+x /etc/openvpn/handler.sh 57 | fi 58 | -------------------------------------------------------------------------------- /sources/assets/css/main.css: -------------------------------------------------------------------------------- 1 | /* 2 | * Skeleton V1.2 3 | * Copyright 2011, Dave Gamache 4 | * www.getskeleton.com 5 | * Free to use under the MIT license. 6 | * http://www.opensource.org/licenses/mit-license.php 7 | * 6/20/2012 8 | */ 9 | 10 | 11 | /* Table of Content 12 | ================================================== 13 | #Reset & Basics 14 | #Basic Styles 15 | #Site Styles 16 | #Typography 17 | #Links 18 | #Lists 19 | #Images 20 | #Buttons 21 | #Forms 22 | #Misc */ 23 | 24 | 25 | /* #Reset & Basics (Inspired by E. Meyers) 26 | ================================================== */ 27 | html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, em, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, b, u, i, center, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td, article, aside, canvas, details, embed, figure, figcaption, footer, header, hgroup, menu, nav, output, ruby, section, summary, time, mark, audio, video { 28 | margin: 0; 29 | padding: 0; 30 | border: 0; 31 | font-size: 100%; 32 | font: inherit; 33 | vertical-align: baseline; } 34 | article, aside, details, figcaption, figure, footer, header, hgroup, menu, nav, section { 35 | display: block; } 36 | body { 37 | line-height: 1; } 38 | ol, ul { 39 | list-style: none; } 40 | blockquote, q { 41 | quotes: none; } 42 | blockquote:before, blockquote:after, 43 | q:before, q:after { 44 | content: ''; 45 | content: none; } 46 | table { 47 | border-collapse: collapse; 48 | border-spacing: 0; } 49 | 50 | 51 | /* #Basic Styles 52 | ================================================== */ 53 | body { 54 | background: #fff; 55 | font: 14px/21px "HelveticaNeue", "Helvetica Neue", Helvetica, Arial, sans-serif; 56 | color: #444; 57 | -webkit-font-smoothing: antialiased; /* Fix for webkit rendering */ 58 | -webkit-text-size-adjust: 100%; 59 | } 60 | 61 | 62 | /* #Typography 63 | ================================================== */ 64 | h1, h2, h3, h4, h5, h6 { 65 | color: #181818; 66 | font-family: "Georgia", "Times New Roman", serif; 67 | font-weight: normal; } 68 | h1 a, h2 a, h3 a, h4 a, h5 a, h6 a { font-weight: inherit; } 69 | h1 { font-size: 46px; line-height: 50px; margin-bottom: 14px;} 70 | h2 { font-size: 35px; line-height: 40px; margin-bottom: 10px; } 71 | h3 { font-size: 28px; line-height: 34px; margin-bottom: 8px; } 72 | h4 { font-size: 21px; line-height: 30px; margin-bottom: 4px; } 73 | h5 { font-size: 17px; line-height: 24px; } 74 | h6 { font-size: 14px; line-height: 21px; } 75 | .subheader { color: #777; } 76 | 77 | p { margin: 0 0 20px 0; } 78 | p img { margin: 0; } 79 | p.lead { font-size: 21px; line-height: 27px; color: #777; } 80 | 81 | em { font-style: italic; } 82 | strong { font-weight: bold; color: #333; } 83 | small { font-size: 80%; } 84 | 85 | /* Blockquotes */ 86 | blockquote, blockquote p { font-size: 17px; line-height: 24px; color: #777; font-style: italic; } 87 | blockquote { margin: 0 0 20px; padding: 9px 20px 0 19px; border-left: 1px solid #ddd; } 88 | blockquote cite { display: block; font-size: 12px; color: #555; } 89 | blockquote cite:before { content: "\2014 \0020"; } 90 | blockquote cite a, blockquote cite a:visited, blockquote cite a:visited { color: #555; } 91 | 92 | hr { border: solid #ddd; border-width: 1px 0 0; clear: both; margin: 10px 0 30px; height: 0; } 93 | 94 | 95 | /* #Links 96 | ================================================== */ 97 | a, a:visited { color: #333; text-decoration: underline; outline: 0; } 98 | a:hover, a:focus { color: #000; } 99 | p a, p a:visited { line-height: inherit; } 100 | 101 | 102 | /* #Lists 103 | ================================================== */ 104 | ul, ol { margin-bottom: 20px; } 105 | ul { list-style: none outside; } 106 | ol { list-style: decimal; } 107 | ol, ul.square, ul.circle, ul.disc { margin-left: 30px; } 108 | ul.square { list-style: square outside; } 109 | ul.circle { list-style: circle outside; } 110 | ul.disc { list-style: disc outside; } 111 | ul ul, ul ol, 112 | ol ol, ol ul { margin: 4px 0 5px 30px; font-size: 90%; } 113 | ul ul li, ul ol li, 114 | ol ol li, ol ul li { margin-bottom: 6px; } 115 | li { line-height: 18px; margin-bottom: 12px; } 116 | ul.large li { line-height: 21px; } 117 | li p { line-height: 21px; } 118 | 119 | 120 | /* 121 | * Specific style for openvpn_ynh application 122 | * https://github.com/Kloadut/openvpn_ynh 123 | * 124 | */ 125 | 126 | body { 127 | padding: 2em; 128 | max-width: 50em; 129 | margin: auto; 130 | } 131 | 132 | a, a:visited { color: #0a3565;} 133 | a:hover, a:focus { color: #f68220; } 134 | 135 | 136 | header { 137 | text-align: center; 138 | padding: 1em; 139 | } 140 | 141 | section { 142 | margin: 1em 0 0 0; 143 | } 144 | section + section { 145 | padding: 1em 0 0 0; 146 | border-top:1px solid #ddd; 147 | } 148 | 149 | 150 | p.message{ 151 | border-radius: 0.3em; 152 | border-width: 1px solid #888; 153 | border-color: rgba(0, 0, 0, 0.3); 154 | box-shadow: inset 1px 1px 3px rgba(0, 0, 0, 0.2); 155 | color: #444; 156 | color: rgba(0, 0, 0, 0.8); 157 | padding: 1.5em; 158 | } 159 | p.success {background: #88cc88;} 160 | p.error {background: #cc8888;} 161 | p.warning {background: #cccc88;} 162 | 163 | 164 | @media screen and (max-width: 22em) { 165 | h1 { 166 | /* Use h2 value from skeleton */ 167 | font-size: 35px; line-height: 40px; margin-bottom: 10px; 168 | } 169 | } -------------------------------------------------------------------------------- /sources/assets/img/Ovpntech_logo-s_REVISED.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YunoHost-Apps/vpnserver_ynh/a3e06083763d73f1dde15da7e97f0424d16ad359/sources/assets/img/Ovpntech_logo-s_REVISED.png -------------------------------------------------------------------------------- /sources/index.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | OpenVPN configuration 6 | 7 | 8 | 9 | 10 |
11 | 12 |
13 | 14 |
15 | 16 |

You are successfully connected to the VPN server

17 | 18 |

You are not connected to the VPN server

19 | 20 |

Your IP address is :

21 |
22 | 23 |
24 |

Configuration

25 | 29 |
30 | 31 |
32 |

Documentation

33 | 38 |
39 | 40 | 41 | 42 | --------------------------------------------------------------------------------