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¶
2. Run the installer¶
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:
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¶
2. Build the backend image¶
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:
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¶
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¶
- Both containers show running —
docker compose ps(shell methods) or the Containers list in Portainer — and the database container shows healthy. - Open
https://vpn.example.com/(your proxy hostname) in a browser — the Valenius sign-in page appears. - Sign in with the
ADMIN_EMAILandADMIN_PASSWORDyou set — the admin panel opens. - 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¶
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.