diff --git a/README.md b/README.md index 959a094..0217cfc 100644 --- a/README.md +++ b/README.md @@ -25,12 +25,24 @@ Make sure to support the developers by buying the choosen subscription for your ## How to setup (api) (optional) ## This is _optional_. You can simply use the default instance of this API (host is noted inside the `setup.py` script) and profit from "automatic" updates. +## API Only: Using Apache Just transfer the `www` files inside a public accessible root-folder on your _dedicated_ Apache webserver (really everthing with PHP support works). Also make sure your instance has a valid SSL-certificate (Let's encrypt is enough), otherwise it may won't work. An example Apache install process can be found [here](docs/apache/install.md). If you want to test your instance, just open the public accessible URI in your browser and append `/healthz` to it - if you see some JSON with the text, then everything worked! +### API Only: Using Nginx +Just transfer the `www` files inside a public accessible root-folder on your _dedicated_ Nginx webserver (really everthing with PHP support works). Also make sure your instance has a valid SSL-certificate (Let's encrypt is enough), otherwise it may won't work. +See the documentation in [Nginx Install](docs/nginx/install.md). + +### API Only: Using Docker +See the documentation in [Docker Install](docs/docker/api-only-install.md). + +### Fully Patched Pritunl: Using Docker +This api has also its own docker image. Take a look into the `docker` folder and enjoy! + +See the documentation in [Patched Pritunl Docker Install](docs/docker/pritunl-patched-install.md). + ### Nett2Know ### * This modification will also block any communication to the Pritunl servers - so no calling home :) * SSO will not work with this api version! As Pritunls own authentication servers handle the whole SSO stuff, track instance ids and verify users, I won't implement this part for privacy concerns (and also this would need to be securly implemented and a database). -* This api has also its own docker image. Take a look into the `docker` folder and enjoy! Have fun with your new premium/enterprise/ultimate Pritunl instance! diff --git a/docker/Dockerfile b/docker/Dockerfile index 03a50e7..9a85f97 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -1,6 +1,9 @@ FROM goofball222/pritunl:latest +ARG API_SERVER_DOMAIN +ENV API_SERVER_DOMAIN $API_SERVER_DOMAIN + # Yes, you will need to copy it over into the build context... COPY setup.py . -RUN chmod +x setup.py; python3 -u setup.py --install; rm setup.py \ No newline at end of file +RUN chmod +x setup.py; python3 -u setup.py --install --api-server ${API_SERVER_DOMAIN:-}; rm setup.py \ No newline at end of file diff --git a/docker/api-only/conf.d/pritunl-fake-api.conf b/docker/api-only/conf.d/pritunl-fake-api.conf new file mode 100644 index 0000000..9423ed8 --- /dev/null +++ b/docker/api-only/conf.d/pritunl-fake-api.conf @@ -0,0 +1,40 @@ + # Pritunl Fake API Server definition + server { + listen [::]:80 default_server; + listen 80 default_server; + server_name _; + + sendfile off; + tcp_nodelay on; + absolute_redirect off; + + root /var/www/html; + index index.php index.html; + + location / { + # First attempt to serve request as file, then + # as directory, then fall back to index.php + try_files $uri $uri/ /index.php?path=$uri&$args; + } + + # Pass the PHP scripts to PHP-FPM listening on php-fpm.sock + location ~ \.php$ { + try_files $uri =404; + fastcgi_split_path_info ^(.+\.php)(/.+)$; + fastcgi_pass unix:/run/php-fpm.sock; + fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; + fastcgi_param SCRIPT_NAME $fastcgi_script_name; + fastcgi_index index.php; + include fastcgi_params; + } + + location ~* \.(jpg|jpeg|gif|png|css|js|ico|xml)$ { + expires 5d; + } + + # Deny access to . files, for security + location ~ /\. { + log_not_found off; + deny all; + } + } \ No newline at end of file diff --git a/docker/api-only/docker-compose.yml b/docker/api-only/docker-compose.yml new file mode 100644 index 0000000..5cfcc3b --- /dev/null +++ b/docker/api-only/docker-compose.yml @@ -0,0 +1,98 @@ +# Runs this API, either on port 80 or behind Traefik, either on docker swarm or single daemon. +# Choose the right configuration for you and comment out the other. +# Read the comments carefully. +# +# +# In case you run behind Traefik, you need to setup the traefik router HOST +# You need correctly setup traefik and docker network (here called proxy_external) +# +# /!\ /!\ Make sure the mount volumes match correctly. /!\ /!\ +# +# The first volume is the path to the www folder from the root of this repo. +# The path shall be a full path, or be next to this docker-compose.yml file. +# No parent folder navigation like `../../../` is allowed by docker. +# +# -> Easy solution: +# Once you have cloned this repo, you shall move this docker-compose.yml file to the root of the repo. +# +# The second volume is the path to the nginx server config file. +# This needs the commited nginx server config (or your own adapted version) to work properly. +# See the file `/docker/api-only/conf.d/pritunl-fake-api.conf` for more details. + +version: '3.7' +services: + web: + image: trafex/php-nginx + volumes: + - "./www:/var/www/html:ro" + - "./docker/api-only/conf.d/pritunl-fake-api.conf:/etc/nginx/conf.d/pritunl-fake-api.conf" + ################################################################# + ### If you run behind Traefik COMMENT OUT the following lines ### + ### BEGIN TRAEFIK_BLOCK ### + ports: + - "80:8080" + ################################################################# + + ################################################################# + + ### BEGIN SINGLE_DAEMON_BLOCK ### + + ### If you run behind on Docker Single Daemon (NOT Swarm) uncomment the following lines ### + # networks: + # - default + # - proxy_external + # labels: + # - "traefik.enable=true" + # - "traefik.docker.network=proxy_external" + # - "traefik.tags=proxy_external" + # ### Services + # ## API + # - "traefik.http.services.pritunl-api.loadbalancer.server.port=8080" + # ### Routers + # - "traefik.http.routers.pritunl-api.entrypoints=https" + # - "traefik.http.routers.pritunl-api.rule=Host(`mypritunlfakeapi.example.com`)" + # - "traefik.http.routers.pritunl-api.service=pritunl-api" + # - "traefik.http.routers.pritunl-api.tls=true" + # - "traefik.http.routers.pritunl-api.tls.certresolver=http" +# networks: +# proxy_external: +# external: true +# name: proxy_external + + ### END SINGLE_DAEMON_BLOCK ### + + + ### BEGIN SWARM_BLOCK ### + + ### If you run on Docker Swarm uncomment the following lines ### + # networks: + # - default + # - proxy_external + # labels: + # - "traefik.enable=true" + # deploy: + # labels: + # - "traefik.enable=true" + # - "traefik.docker.network=proxy_external" + # - "traefik.tags=proxy_external" + # ### Services + # ## API + # - "traefik.http.services.pritunl-api.loadbalancer.server.port=8080" + # ### Routers + # - "traefik.http.routers.pritunl-api.entrypoints=https" + # - "traefik.http.routers.pritunl-api.rule=Host(`mypritunlfakeapi.example.com`)" + # - "traefik.http.routers.pritunl-api.service=pritunl-api" + # - "traefik.http.routers.pritunl-api.tls=true" + # - "traefik.http.routers.pritunl-api.tls.certresolver=http" +# networks: +# proxy_external: +# external: true +# name: proxy_external + + ### END SWARM_BLOCK ### + + + + ### END TRAEFIK BLOCK ### + ################################################################# + \ No newline at end of file diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index 93da4dd..a761b74 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -11,6 +11,8 @@ services: build: context: ../server dockerfile: ../docker/Dockerfile + args: + - API_SERVER_DOMAIN=${API_SERVER_DOMAIN:-} restart: always depends_on: - mongodb diff --git a/docs/docker/api-only-install.md b/docs/docker/api-only-install.md new file mode 100644 index 0000000..88fc927 --- /dev/null +++ b/docs/docker/api-only-install.md @@ -0,0 +1,36 @@ +# API Only: Docker + +## Only installs the API (webserver) and not the Pritunl VPN itself. +This approach runs this API, either on port 80 or behind Traefik, either on docker swarm or single daemon. + +You need to have docker up and running on your server. + +- In your server, clone this repo, then `cd` to the cloned folder. +- Copy the docker-compose file provided in `/docker/api-only/docker-compose.yml` to + the root of the cloned folder. + + You shall now have: `/docker-compose.yml` +- Modify the `/docker-compose.yml` to fit your needs and config + + _Watch for volumes, docker swarm or single daemon, behind Traefik or not and the HOST value if behind traefik:_ + + In case you run behind Traefik, you need to setup the traefik router HOST + + You need correctly setup traefik and docker network (here called proxy_external) + + **(!) Make sure the mount volumes match correctly.** + + * The first volume is the path to the www folder from the root of this repo. + + The path shall be a full path, or be next to this docker-compose.yml file. + + No parent folder navigation like `../../../` is allowed by docker. + + * The second volume is the path to the nginx server config file. + + This needs the commited nginx server config (or your own adapted version) to work properly. + + See the file `/docker/api-only/conf.d/pritunl-fake-api.conf` for more details. +- Run the updated `docker-compose.yml` file in daemon mode with: + + `docker-compose up -d` \ No newline at end of file diff --git a/docs/docker/pritunl-patched-install.md b/docs/docker/pritunl-patched-install.md new file mode 100644 index 0000000..2556f1a --- /dev/null +++ b/docs/docker/pritunl-patched-install.md @@ -0,0 +1,28 @@ +# Fully Patched Pritunl: Using Docker + +## Only installs the API (webserver) and not the Pritunl VPN itself. +You need to have docker up and running on your server. + +This uses the docker image for Pritunl by `goofball222/pritunl` and installs the fake api hooks directly into it. + + +Step: + +- In your server, clone this repo, then `cd` to the cloned folder. +- Go to the `docker` folder of the repo. +- Read the `/docker/docker-compose.yml` file carefully and edit to fit your needs (ports, volumes, network, server domain...) +- Run the `docker-compose.yml` file in daemon mode with: + + `docker-compose up -d` + + - This will `docker build` the patched pritunl container and run it on the following ports: + - Under this port the Pritunl web interface will be exposed (for reverse proxies) + + *9700:9700* + + - The following are the two default ports for the tcp+udp servers (you may edit these as needed!) + + *1194:1194* + + *1194:1194/udp* + diff --git a/www/nginx.conf b/docs/nginx/hard_nginx.conf similarity index 53% rename from www/nginx.conf rename to docs/nginx/hard_nginx.conf index 0465f3b..24a49d0 100644 --- a/www/nginx.conf +++ b/docs/nginx/hard_nginx.conf @@ -27,47 +27,6 @@ http { fastcgi_temp_path /tmp/fastcgi_temp; uwsgi_temp_path /tmp/uwsgi_temp; scgi_temp_path /tmp/scgi_temp; - - # Default server definition - server { - listen [::]:80 default_server; - listen 80 default_server; - server_name _; - - sendfile off; - tcp_nodelay on; - absolute_redirect off; - - root /var/www/html; - index index.php index.html; - - location / { - # First attempt to serve request as file, then - # as directory, then fall back to index.php - try_files $uri $uri/ /index.php?path=$uri&$args; - } - - # Pass the PHP scripts to PHP-FPM listening on php-fpm.sock - location ~ \.php$ { - try_files $uri =404; - fastcgi_split_path_info ^(.+\.php)(/.+)$; - fastcgi_pass unix:/run/php-fpm.sock; - fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; - fastcgi_param SCRIPT_NAME $fastcgi_script_name; - fastcgi_index index.php; - include fastcgi_params; - } - - location ~* \.(jpg|jpeg|gif|png|css|js|ico|xml)$ { - expires 5d; - } - - # Deny access to . files, for security - location ~ /\. { - log_not_found off; - deny all; - } - } # Hardening proxy_hide_header X-Powered-By; diff --git a/docs/nginx/install.md b/docs/nginx/install.md new file mode 100644 index 0000000..f481a52 --- /dev/null +++ b/docs/nginx/install.md @@ -0,0 +1,105 @@ +# HowTo install the selfhost api variant on Nginx + +## Easy way: +Use docker and docker-compose files provided in `docker/api-only` folder. + +See documentation [Docker Install](docs/docker/api-only-install.md). + +The docker compose file has a detailed help in its top too. Read and Roll :) + + +## Hard way: +First, you need to install Nginx. +```bash +sudo apt-get install nginx +``` + +After that, install all of the relevant PHP modules: + +```bash +sudo apt-get -y install php7.4-fpm php7.4-mysql php7.4-curl php7.4-gd php7.4-intl php-pear php-imagick php7.4-imap php-memcache +``` + +Then install certbot for free SSL certs: +```bash +sudo apt-get install -y certbot python3-certbot-nginx +``` + +After this, create a basic site config for the fake api server. Do this by creating a file under /etc/nginx/sites-available/ and create a symbolic link to /etc/nginx/sites-enabled. +You can refer to the provided Nginx server block available in: +`/docker/api-only/conf.d/pritunl-fake-api.conf` + +Then generate an SSL certificate for the website with certbot. +```bash +sudo certbot --nginx -d [PUBLIC_ACCESSIBLE_API_DOMAIN] +``` + +Once this is done, you should check if you have all the required loaded PHP modules for this server. You can check this by running php -m, and the output should list your PHP modules. + +the output should look be something like: +```bash +#... + core_module (static) + so_module (static) + watchdog_module (static) + http_module (static) + log_config_module (static) + logio_module (static) + version_module (static) + unixd_module (static) + access_compat_module (shared) + alias_module (shared) + auth_basic_module (shared) + authn_core_module (shared) + authn_file_module (shared) + authz_core_module (shared) + authz_host_module (shared) + authz_user_module (shared) + autoindex_module (shared) + deflate_module (shared) + dir_module (shared) + env_module (shared) + filter_module (shared) + http2_module (shared) + mime_module (shared) + mpm_prefork_module (shared) + negotiation_module (shared) + php7_module (shared) + proxy_module (shared) + proxy_fcgi_module (shared) + reqtimeout_module (shared) + rewrite_module (shared) + setenvif_module (shared) + socache_shmcb_module (shared) + ssl_module (shared) + status_module (shared) + #... +``` + +Then clone this repository if you haven't done this already and cd into the root of the project: +```bash +git clone https://gitlab.simonmicro.de/simonmicro/pritunl-fake-api.git +cd ./pritunl-fake-api +``` + +After this is done, copy over the API server files to the server and set permissions. +```bash +sudo cp -R ./www/* /var/www/html/ +sudo chown www-data:www-data -R /var/www/html +sudo chmod -R 774 /var/www/html/ +``` + +For your convenience, a hardened Nginx configuration is provided to help you secure and improve your server, +Read it carefully before use and make sure you understand what it does. + +See: `/docs/nginx/hard_nginx.conf` + + +Then restart Nginx to make sure all of the configuration is loaded. +```bash +sudo systemctl restart nginx +``` + +Once this is done, you should get a response when you visit + + `https://[PUBLIC_ACCESSIBLE_API_DOMAIN]/notification`! diff --git a/server/setup.py b/server/setup.py index 9a66ac7..ed5c648 100644 --- a/server/setup.py +++ b/server/setup.py @@ -7,7 +7,7 @@ import argparse originalApiServer = 'app.pritunl.com' originalAuthServer = 'auth.pritunl.com' -newApiServer = 'pritunl-api.simonmicro.de' +defaultApiServer = 'pritunl-api.simonmicro.de' searchIn = [*glob.glob('/usr/lib/python3*'), '/usr/lib/pritunl/', '/usr/share/pritunl/www/', '/usr/lib/pritunl/', '/usr/share/pritunl/www/'] print(" ____ _ _ _ _____ _ _ ____ ___ ") @@ -22,8 +22,10 @@ interactive = True parser = argparse.ArgumentParser() parser.add_argument('--install', type=str, default='DEFAULT', nargs='?', help='Do not ask and install new API endpoint.') parser.add_argument('--reset', type=str, default='DEFAULT', nargs='?', help='Do not ask and remove new API endpoint.') +parser.add_argument('--api-server', type=str, default=defaultApiServer, help='Set new API server.') args = parser.parse_args() +newApiServer = args.api_server if args.api_server.strip() != '' else defaultApiServer if args.install != 'DEFAULT': interactive = False newApiServer = args.install if args.install is not None else newApiServer diff --git a/www/docker-compose_simple-single.yml b/www/docker-compose_simple-single.yml deleted file mode 100644 index 20f830a..0000000 --- a/www/docker-compose_simple-single.yml +++ /dev/null @@ -1,14 +0,0 @@ -# Runs this API on port 80 -# Runs on docker single daemon (no swarm) -# Make sure the mount volumes match correctly -# This needs the commited nginx.conf (or your own adapted version) - -version: '3.7' -services: - web: - image: trafex/php-nginx - ports: - - "80:8080" - volumes: - - ".:/var/www/html:ro" - - "./nginx.conf:/etc/nginx/nginx.conf" diff --git a/www/docker-compose_traefik_swarm.yml b/www/docker-compose_traefik_swarm.yml deleted file mode 100644 index 89c9d7e..0000000 --- a/www/docker-compose_traefik_swarm.yml +++ /dev/null @@ -1,40 +0,0 @@ -# ### Advanced use for expert users ### # -# -# -# Runs this API behind Traefik, on docker swarm -# Make sure the mount volumes match correctly -# Update the traefik router HOST -# You need correctly setup traefik and docker network (here called proxy_external) - -version: '3.7' -services: - web: - image: trafex/php-nginx - volumes: - - ".:/var/www/html:ro" - - "./nginx.conf:/etc/nginx/nginx.conf" - labels: - - "traefik.enable=true" - deploy: - labels: - - "traefik.enable=true" - - "traefik.docker.network=proxy_external" - - "traefik.tags=proxy_external" - # Services - # API - - "traefik.http.services.pritunl-api.loadbalancer.server.port=8080" - # Router - - "traefik.http.routers.pritunl-api.entrypoints=https" - - "traefik.http.routers.pritunl-api.rule=Host(`mypritunlfakeapi.example.com`)" - - "traefik.http.routers.pritunl-api.service=pritunl-api" - - "traefik.http.routers.pritunl-api.tls=true" - - "traefik.http.routers.pritunl-api.tls.certresolver=http" - networks: - - default - - proxy_external - - -networks: - proxy_external: - external: true - name: proxy_external