Skip to content

Backend — Community edition

The Community edition is free and open source. It gives you the full admin panel, client management, OIDC/SSO and TOTP login, per-OS client auto-update, and an audit log. You upload WireGuard® .conf files for your clients by hand — automatic peer provisioning is a Pro feature.

Pick an installation method

There are three ways to get the Community backend running — all three build the exact same image from the exact same source, so pick whichever matches how comfortable you are with a terminal. You only need to follow one of them.

Method What it needs Best for
Shell scripts (recommended) SSH access to the server The fastest path — one command to install, one to upgrade
Plain Docker / shell SSH access, comfortable copy-pasting commands Full control — a custom deploy path, an existing Postgres, non-default volumes
Portainer A Portainer instance (or install one as step 0) No shell commands at all after the initial setup — install and upgrade from a web UI

Prerequisites

  • A Linux server with Docker Engine and the Docker Compose plugin — see Prerequisites.
  • An HTTPS reverse proxy (Nginx Proxy Manager, Caddy, Traefik, …) and a domain name pointed at the server. You can skip this for a quick local test, but sign-in cookies and SSO need real HTTPS in front.
  • git — only needed for the shell scripts and plain Docker / shell methods. Portainer clones the repository for you.

Install

install.sh, in the root of the cloned repository, builds the image, generates strong random DB_PASSWORD / ADMIN_PASSWORD values, writes .env and docker-compose.yml into a local valenius/ folder, starts the stack, and prints your login URL and credentials once the backend is up.

1. Clone the repository

git clone https://github.com/valeniusvpn/valenius.git
cd valenius

2. Run the installer

./install.sh

No chmod needed

install.sh (and update.sh, used later for upgrades) are already marked executable in the repository — you can run them straight after cloning.

Where .env actually ends up

install.sh writes its files into a valenius/ folder inside the directory you ran it from — and since step 1 named the cloned repo valenius too, that's a folder named valenius nested inside another one also named valenius. So if you cloned to ~/valenius, your generated .env is at ~/valenius/valenius/.env, not ~/valenius/.env. ls -a is your friend here — dotfiles like .env don't show up in a plain ls.

It prompts for an admin email and the host port (defaults: admin@example.com, 9001). For a non-interactive run:

ADMIN_EMAIL=<your-email> BACKEND_PORT=9001 ./install.sh --yes

Re-running it is safe

install.sh refuses to overwrite an existing install's secrets. Pass --force to wipe valenius/ and start over.

Once it prints your credentials, skip ahead to Put your reverse proxy in front.

If you'd rather see and control each step yourself — a custom deploy path, an existing Postgres, non-default volumes — follow this instead. install.sh is just a shortcut through the same steps.

1. Get the source

git clone https://github.com/valeniusvpn/valenius.git
cd valenius

2. Build the backend image

docker build -f Backend/Dockerfile -t valenius-backend:latest .

Build from the repo root

Run this from the top of the cloned repository, not from inside Backend/ — the build needs files from Shared/ too. If you see an error mentioning Shared/Valenius.Shared, you're in the wrong directory.

3. Create a deployment folder

Your running stack lives in its own folder, outside the cloned source:

mkdir -p ~/valenius-server/data/downloads
cd ~/valenius-server

4. Create the .env file

Create a file named .env with the following content, replacing every change-me value with a strong random one (generate them with openssl rand -hex 24):

# .env
DB_PASSWORD=change-me-a-strong-random-password

# Bootstrap admin — your first login. Also your emergency fallback later.
ADMIN_EMAIL=admin@example.com
ADMIN_PASSWORD=change-me-a-strong-random-password

# Host port the backend listens on (your reverse proxy forwards to this).
BACKEND_PORT=9001

5. Create the docker-compose.yml file

Create a file named docker-compose.yml next to .env, with exactly this content:

# docker-compose.yml
name: valenius

services:
  db:
    container_name: valenius-db
    image: postgres:17-alpine
    restart: unless-stopped
    environment:
      POSTGRES_DB: valenius
      POSTGRES_USER: valenius
      POSTGRES_PASSWORD: ${DB_PASSWORD}
    volumes:
      - valenius-database-data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U valenius -d valenius"]
      interval: 10s
      timeout: 5s
      retries: 5

  backend:
    container_name: valenius-backend
    image: valenius-backend:latest
    restart: unless-stopped
    depends_on:
      db:
        condition: service_healthy
    environment:
      ASPNETCORE_ENVIRONMENT: Production
      ASPNETCORE_HTTP_PORTS: ""
      ConnectionStrings__DefaultConnection: >-
        Host=db;Port=5432;Database=valenius;Username=valenius;Password=${DB_PASSWORD}
      DataProtection__KeysPath: /app/keys
      Valenius__ManifestPath: /app/data/versions.json
      Valenius__DownloadsPath: /app/data/downloads
      Valenius__AdminEmail: ${ADMIN_EMAIL}
      Valenius__AdminPassword: ${ADMIN_PASSWORD}
    volumes:
      - ./data:/app/data
      - valenius-keystore:/app/keys
    ports:
      - "${BACKEND_PORT}:8080"

volumes:
  valenius-database-data:
  valenius-keystore:

6. Start the stack

docker compose up -d
docker compose logs -f backend

The first start creates the database schema, generates the server's API key, and creates your admin account from .env — all automatically. Wait until the log shows a line beginning with Now listening on:, then press Ctrl+C to leave the logs (the stack keeps running).

Deploy straight from the public GitHub repository — Portainer clones it, builds the image, and starts the stack for you. Upgrading later is a single button click, with no shell access needed at all.

0. Install Portainer (skip if you already run it)

docker volume create portainer_data
docker run -d -p 8000:8000 -p 9443:9443 --name portainer --restart=always \
  -v /var/run/docker.sock:/var/run/docker.sock \
  -v portainer_data:/data \
  portainer/portainer-ce:latest

Open https://<server-ip>:9443, create the Portainer admin account, and finish its setup wizard (choose "Get Started" / the local environment).

1. Create the stack

In Portainer, go to Stacks → Add stack and fill in:

Field Value
Name valenius
Build method Repository
Repository URL https://github.com/valeniusvpn/valenius.git
Repository reference refs/heads/main
Compose path Backend/docker-compose.yml

Leave Repository authentication off — the repository is public.

2. Set the environment variables

Still on the "Add stack" page, scroll to Environment variables and add these (Portainer also lets you paste them all at once via "Load variables from .env file" if you prefer):

Name Value
DB_PASSWORD a strong random password, e.g. from openssl rand -hex 24
ADMIN_EMAIL your login email, e.g. admin@example.com
ADMIN_PASSWORD a strong random password
BACKEND_PORT the host port to expose, e.g. 9001

DB_PASSWORD and BACKEND_PORT are required

Unlike the other two variables, these have no built-in default — the stack will fail to deploy without them.

Leave VALENIUS_LICENSE_KEY and LICENSING_CLIENT_API_KEY unset — those are Pro-only and have no effect on Community.

3. Deploy the stack

Click Deploy the stack. Portainer clones the repository, builds the backend image (this is the slow part — several minutes on the first deploy), and starts both containers. Watch progress under Stacks → valenius → Logs.

Once both containers show running (and valenius-db shows healthy) under Containers, skip ahead to Put your reverse proxy in front.

Put your reverse proxy in front

In your reverse proxy, create an HTTPS host (for example vpn.example.com) that forwards to http://<server-ip>:9001 (or whatever you set as BACKEND_PORT).

Verify it works

  1. Both containers show runningdocker compose ps (shell methods) or the Containers list in Portainer — and the database container shows healthy.
  2. Open https://vpn.example.com/ (your proxy hostname) in a browser — the Valenius sign-in page appears.
  3. Sign in with the ADMIN_EMAIL and ADMIN_PASSWORD you set — the admin panel opens.
  4. Check Admin → About — it shows the running backend version.

That's a working backend. Continue with First steps after install to create your first customer and connect a client.

Upgrading later

cd valenius   # wherever you cloned it / ran install.sh from
./update.sh

update.sh pulls the latest source, rebuilds the image, and restarts the stack it finds in valenius/ — in the right order, from the right directory, every time. It stops with a clear error at the first thing that looks wrong (uncommitted local changes blocking the pull, Docker not running, a failed build, the backend not coming back up) instead of leaving the stack half-updated.

cd ~/valenius   # your clone from step 1
git pull
docker build -f Backend/Dockerfile -t valenius-backend:latest .
cd ~/valenius-server   # your deployment folder from step 3
docker compose up -d

docker compose up -d recreates the backend container automatically since the rebuilt image gets a new ID under the same tag — you don't need --force-recreate. Run it from ~/valenius-server (wherever your docker-compose.yml actually is), not from ~/valenius (the source clone) — a directory with no compose file fails with no configuration file provided: not found.

Stacks → valenius → Pull and redeploy.

Portainer re-fetches the repository at the configured branch, rebuilds the image, and recreates any changed containers — one click, no shell access needed.

Database upgrades happen automatically at startup in all three cases — there is no separate migration step, and your data is kept.

Common problems

The build fails mentioning Shared/Valenius.Shared. (Plain Docker / shell) You ran docker build from inside Backend/. Change to the top of the cloned repository and run it again exactly as shown above. (Portainer) Double-check the stack's Compose path is exactly Backend/docker-compose.yml with Build method set to Repository — a plain uploaded compose file has no repository checkout behind it, so the build context it needs (Shared/Valenius.Shared) isn't there.

docker compose up (or the Portainer deploy) fails with "port is already allocated". Another service is using the port. Pick a different BACKEND_PORT and redeploy.

The backend log shows database connection errors at first start. Usually just timing — the backend waits for the database health check, so give it a minute. If it keeps failing, check DB_PASSWORD for stray quotes or spaces.

I changed DB_PASSWORD and now the backend can't connect. The database keeps the password it was first created with — changing DB_PASSWORD later only changes what the backend sends. Either change it back, or reset the database volume (docker compose down -v, or delete the valenius-database-data volume in Portainer — this deletes all data) and start fresh.

I can sign in, but only when I access the port directly — through the proxy I land back on the sign-in page. Your proxy isn't forwarding HTTPS properly. Make sure the proxy host uses HTTPS with a valid certificate and forwards to the backend port over plain HTTP. Learn more →

I forgot the admin password. Set a new ADMIN_PASSWORD (in .env, or the stack's environment variables in Portainer) and redeploy — the bootstrap admin's password is updated on every container start.

Portainer's "Pull and redeploy" doesn't seem to pick up a new commit. Check the stack's Repository reference matches the branch you expect (refs/heads/main) — a stack pinned to a specific commit or tag won't move forward on its own.