Run the server
This page is for the server admin. It takes a server from nothing to production, in order. To try Telesphorepo on your own computer, Start the server and Sign in are enough.
For production, you need a host with Docker, Docker Compose or Podman, a DNS name that points at it, such as repo.example.com, and ports 80 and 443 open on its firewall.
1How do you run the server?
Start the server
Section titled “Start the server”Docker
-
Start the server.
Terminal window docker run -d --name telesphorepo -p 8080:8080 -v telesphorepo-data:/data -v telesphorepo-backups:/backups ghcr.io/telesphorepo/telesphorepo:latest -
Copy the admin password from the log.
Terminal window docker logs telesphorepo
Docker Compose
-
Save this as
compose.yamlin a folder of its own.compose.yaml services:telesphorepo:image: ghcr.io/telesphorepo/telesphorepo:latestrestart: unless-stoppedports:- "8080:8080"volumes:- telesphorepo-data:/data- telesphorepo-backups:/backupsvolumes:telesphorepo-data:name: telesphorepo-datatelesphorepo-backups:name: telesphorepo-backups -
Start the server.
Terminal window docker compose up -d -
Copy the admin password from the log.
Terminal window docker compose logs telesphorepo
For production, Serve over HTTPS has a Compose file with Caddy in it.
Podman
-
Start the server.
Terminal window podman run -d --name telesphorepo -p 8080:8080 -v telesphorepo-data:/data -v telesphorepo-backups:/backups ghcr.io/telesphorepo/telesphorepo:latest -
Copy the admin password from the log.
Terminal window podman logs telesphorepo
Download the program
-
Download the
telesphorepo-serverfile for your system from GitHub Releases. -
Unpack the file.
-
Start the server, and copy the admin password that it shows.
Terminal window ./telesphorepo-server serve
The data is in ./data, next to where you started it. Check a downloaded program against SHA256SUMS on the release page.
The server prints the password of the user admin once, on its first start. To pick the first admin yourself, set TR_BOOTSTRAP_ADMIN_USER and TR_BOOTSTRAP_ADMIN_PASSWORD on the first start. The server reads them only while it has no users.
Always keep the telesphorepo-data volume. It holds the database, the files and the key for your secret settings.
Serve over HTTPS
Section titled “Serve over HTTPS”The server speaks plain HTTP on port 8080. Put a reverse proxy in front of it for HTTPS. Caddy gets a certificate from Let’s Encrypt and renews it for you.
Before you start, point a DNS name (repo.example.com below) at the host, and open ports 80 and 443 on its firewall: Caddy needs both to get the certificate. With Podman, write podman in place of docker in the commands.
-
Install Caddy from its package repository. On Debian and Ubuntu:
Terminal window sudo apt install --yes debian-keyring debian-archive-keyring apt-transport-https curlcurl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpgcurl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | sudo tee /etc/apt/sources.list.d/caddy-stable.listsudo chmod o+r /usr/share/keyrings/caddy-stable-archive-keyring.gpg /etc/apt/sources.list.d/caddy-stable.listsudo apt updatesudo apt install caddyFor other systems, see Install Caddy. The package runs Caddy as the service
caddy. -
Start the server on the host’s loopback address only, so that it is reachable through Caddy and not from outside:
Terminal window docker run -d --name telesphorepo -p 127.0.0.1:8080:8080 -v telesphorepo-data:/data -v telesphorepo-backups:/backups ghcr.io/telesphorepo/telesphorepo:latestWith the program, set the listen address instead:
TR_LISTEN=127.0.0.1:8080 ./telesphorepo-server serve.Copy the admin password from the log:
Terminal window docker logs telesphorepo 2>&1 | grep 'password:' -
Put this in
/etc/caddy/Caddyfile, in place of what is there:/etc/caddy/Caddyfile repo.example.com {reverse_proxy localhost:8080} -
Reload Caddy:
Terminal window sudo systemctl reload caddy
-
Make a network that the server and Caddy share:
Terminal window docker network create telesphorepo -
Start the server on it. It publishes no port: only Caddy reaches it.
Terminal window docker run -d --name telesphorepo --network telesphorepo -v telesphorepo-data:/data -v telesphorepo-backups:/backups ghcr.io/telesphorepo/telesphorepo:latestCopy the admin password from the log:
Terminal window docker logs telesphorepo 2>&1 | grep 'password:' -
Save this as
Caddyfile:Caddyfile repo.example.com {reverse_proxy telesphorepo:8080} -
Start Caddy in the folder of the
Caddyfile:Terminal window docker run -d --name caddy --network telesphorepo -p 80:80 -p 443:443 -p 443:443/udp \-v "$PWD/Caddyfile":/etc/caddy/Caddyfile:ro \-v telesphorepo-caddy-data:/data -v telesphorepo-caddy-config:/config caddy:2
This one file runs the server, Caddy for HTTPS, and a volume for the backups, which the server writes every 24 hours.
-
Save these two files in a folder of their own. Put your address in place of
repo.example.comin both.compose.yaml services:telesphorepo:image: ghcr.io/telesphorepo/telesphorepo:latestrestart: unless-stoppedenvironment:TR_BASE_URL: https://repo.example.comvolumes:- telesphorepo-data:/data- telesphorepo-backups:/backupscaddy:image: caddy:2restart: unless-stoppedports:- "80:80"- "443:443"- "443:443/udp"volumes:- ./Caddyfile:/etc/caddy/Caddyfile:ro- telesphorepo-caddy-data:/data- telesphorepo-caddy-config:/config# Named in full, so the volumes keep these names whatever the folder is called.volumes:telesphorepo-data:name: telesphorepo-datatelesphorepo-backups:name: telesphorepo-backupstelesphorepo-caddy-data:name: telesphorepo-caddy-datatelesphorepo-caddy-config:name: telesphorepo-caddy-configCaddyfile repo.example.com {reverse_proxy telesphorepo:8080} -
Point the DNS name at the host, then start everything:
Terminal window docker compose up -d -
Copy the password of the user
adminfrom the log:Terminal window docker compose logs telesphorepo 2>&1 | grep 'password:'
TR_BASE_URL sets the public address from the file, so the UI shows it read-only. Leave it out to set it in Settings instead. To keep the master key out of the data volume, add TR_MASTER_KEY from a secret (see Keep the master key safe).
Other proxies
- Let the proxy accept request bodies up to the Max upload size of the server (Settings › General). The default is 2 GiB. Some proxies stop at 1 MiB.
- Without a proxy, on plain HTTP and a host that is not
localhost, the browser drops the session cookie. Start the server with-e TR_COOKIE_SECURE=false. Maven also refuses plain HTTP, and pip, Yarn, dotnet and Docker each need a setting for it, so use HTTPS for real use.
HTTP/2, and TLS in the server itself
The server speaks HTTP/1.1 and HTTP/2. Behind a reverse proxy, the server also takes HTTP/2 without TLS, for a proxy that sends it. A proxy that sends HTTP/1.1 works too, so you need no change.
To let the server do TLS itself, set TR_TLS_CERT_FILE and TR_TLS_KEY_FILE to a certificate and a key (PEM files). Both are needed. The server loads a renewed certificate without a restart. Turning TLS on or off needs a restart.
Sign in
Section titled “Sign in”-
Open your address, such as
https://repo.example.com. Without HTTPS, on your own computer, openhttp://localhost:8080. -
Sign in as
admin, with the password from the log. -
Add your authenticator app when the page asks.
Authenticator app › Add. Scan the code, then type the code from your phone.
The server asks for this second step from everyone who manages it. See Two-step verification.
Trust the proxy
Section titled “Trust the proxy”Do this when a reverse proxy, such as Caddy, sits in front of the server.
-
Open Settings › Network and proxy.
-
Under Detected proxies, click Trust on the row of Caddy.
-
Click Save, then Save changes.
The server then sees the real address of each client. Rate limits, the audit log and the network rules need it.
Cloudflare in front
On the Network and proxy page, under Where your proxy is, tick Cloudflare. If Caddy sits between Cloudflare and the server, also tick Other addresses and add the address of Caddy.
Set the public address
Section titled “Set the public address”-
Open Settings › General.
-
Set Public base URL to the address that people use.
https://repo.example.com -
Click Save.
The addresses in the snippets, the setup lines and the CLI downloads then use your public address. CI jobs cannot publish without it, and passkeys need it: set it before anyone adds a passkey.
Store files in Cloudflare R2
Section titled “Store files in Cloudflare R2”The server keeps files on its local disk by default. Cloudflare R2 is the usual choice for a bucket: R2 charges nothing for downloads. Any S3-compatible bucket works too, such as AWS S3 or SeaweedFS.
-
In Cloudflare, create the bucket. Then create an R2 API token with Object Read & Write on it, and copy its Access Key ID and Secret Access Key: Cloudflare shows them once.
-
Open Settings › Storage. Under Storage type, choose A Cloudflare R2 bucket, or another S3-compatible bucket, and enter:
- Address:
https://<account id>.r2.cloudflarestorage.com, with nothing after the host. The bucket’s Settings page shows it under S3 API. - Region: leave it empty.
- Bucket: the bucket’s name.
- Access key ID and Secret access key: from the token.
- Path-style addresses: off.
A custom domain of the bucket does not work here: it serves public downloads only, and the server writes and signs links through the S3 API.
- Address:
-
Click Test connection. The server writes, reads and deletes one test file.
-
Click Save and confirm. If the server has files, it copies them to the bucket in the background, 16 at a time. Downloads and uploads keep working during the copy.
The old files stay where they were. Delete them yourself when the new storage works.
Who sends the bytes
Section titled “Who sends the bytes”| Setup | Who answers a download | Who sends the bytes |
|---|---|---|
| Local disk | your server | your server |
| R2 (default, Download from the bucket on) | your server: it checks the account and the rules of the repository, then sends the build to a signed link that lasts a few minutes | R2, straight to the build |
| R2 and edge delivery | a Cloudflare Worker near the build, with the rules of the repository at the edge | R2, from the bucket nearest the build |
With R2, each download still makes one trip to your server first. Edge delivery takes that trip away, and keeps copies in buckets in several regions. If the builds cannot reach the bucket, turn off Download from the bucket: then your server sends the bytes.
AWS S3 and SeaweedFS
| Setting | AWS S3 | SeaweedFS |
|---|---|---|
| Address | leave it empty | http://seaweedfs:8333 |
| Region | the bucket’s region, for example us-east-1 |
any name, for example us-east-1 |
| Path-style addresses | off | on |
Keep the master key safe
Section titled “Keep the master key safe”The server encrypts secret settings with a master key. By default it writes the key to master.key in the data volume. Without the key, the server cannot read the S3 secret, the single sign-on secret, the signing keys and the authenticator apps.
To keep the key out of the volume, create one before the first start and pass it in:
openssl rand -base64 32docker run -d --name telesphorepo -p 8080:8080 -v telesphorepo-data:/data -v telesphorepo-backups:/backups \ -e TR_MASTER_KEY="$(cat /run/secrets/tr_master_key)" \ ghcr.io/telesphorepo/telesphorepo:latestDo not change TR_MASTER_KEY later.
Back up
Section titled “Back up”The server backs itself up into /backups every 24 hours and keeps the newest 7. Mount a volume there, as the commands on this page do, best on another disk. The folder, the schedule and the number to keep are under Settings › Server › Backups, next to Back up now.
A backup is a folder with a copy of the database, the master key and, with local disk storage, the stored files. Files in an S3 bucket stay in the bucket, so back up the bucket too, with its versioning or replication. A master key in TR_MASTER_KEY is not written into the backup; keep it with the backups.
To back up from the command line, run this. It works while the server runs:
docker run --rm -v telesphorepo-data:/data -v telesphorepo-backups:/backups \ ghcr.io/telesphorepo/telesphorepo:latest backup /backupsRestore
Section titled “Restore”Restore a backup folder into an empty volume, then start the server on that volume:
docker run --rm -v telesphorepo-backups:/backups -v telesphorepo-restored:/data \ ghcr.io/telesphorepo/telesphorepo:latest restore /backups/20261020T201500.123ZThe restore checks the database against its checksum, refuses a volume that is not empty, and says whether the backup is from the same version of Telesphorepo as the image.
Image tags
Section titled “Image tags”The image ghcr.io/telesphorepo/telesphorepo has these tags, for linux/amd64 and linux/arm64:
| Tag | Is |
|---|---|
latest |
The newest release |
0.1.0, 0.1 |
One release, or the newest of a minor version |
main |
The newest build of the main branch that passed its tests, between releases |
sha-<commit> |
One build of the main branch, by its commit |
Use latest or a version in production. Pin a version, such as 0.1, to choose when you upgrade.
Upgrade
Section titled “Upgrade”-
Back up: click Back up now under Settings › Server › Backups.
-
Pull the new image and start a new container on the same volume:
Terminal window docker compose pulldocker compose up -dTerminal window docker pull ghcr.io/telesphorepo/telesphorepo:latestdocker stop telesphorepodocker rm telesphorepodocker run -d --name telesphorepo -p 8080:8080 -v telesphorepo-data:/data -v telesphorepo-backups:/backups ghcr.io/telesphorepo/telesphorepo:latest -
Check that it runs:
Terminal window curl https://repo.example.com/healthzThe answer is
ok.
Pass the same -e variables as before. On its first start, a new version updates the database to its own structure, one step at a time, and the log names each step. The server refuses to start on a database from a newer version. To go back to an older version, restore the backup you made in step 1.
Push large images
Section titled “Push large images”Behind Cloudflare (Free and Pro plans), each image layer must be under 100 MB. Pulls have no limit. Not behind Cloudflare? You have nothing to do.
To push larger layers, let the layers skip Cloudflare. People still push to the main address. The server tells the client to send the layers to a second address: the upload address. Nobody changes a command.
-
In Cloudflare, add a second name for your server, for example
upload.example.com. Make the record DNS only. Serve it over HTTPS, as in Serve over HTTPS. -
Open the port of that name in the firewall of your server, for the computers that push.
-
Open Settings › General. Under Docker, set Docker upload address to
https://upload.example.com. Turn on Expose the origin IP for Docker uploads. Click Save.
Pulls, logins and the credential helper keep the main address.
ORAS and Helm 4 send layers only to the address in the command. Push with them to the upload address:
helm push mychart-0.1.0.tgz oci://upload.example.com/dockeroras push upload.example.com/docker/team/art:1.0 file.txtNext steps
Section titled “Next steps”If something goes wrong
Section titled “If something goes wrong”The log shows no password
Wait a few seconds, then run the log command again.
You lost the admin password, or the log no longer has it
Set a new one, and type it at the prompt:
docker exec -it telesphorepo /telesphorepo-server user passwd adminYour data is gone after you removed the container
The data lives in the telesphorepo-data volume, not in the container. Always keep the volume: it holds the database, the files and the key for your secret settings. To get data back, restore a backup.
You run the program and cannot find the data
It is in ./data, next to where you started it. TR_DATA_DIR sets another folder.
The browser signs you out at once on plain HTTP
On plain HTTP and a host that is not localhost, the browser drops the session cookie. Serve the server over HTTPS, or start it with -e TR_COOKIE_SECURE=false.
Uploads through the proxy stop at 1 MiB
Let the proxy accept request bodies up to the Max upload size of the server (Settings › General), 2 GiB by default.
A Docker push stops with 413 behind Cloudflare
Each layer must be under 100 MB behind Cloudflare Free and Pro. See Push large images.
The server refuses to start after a downgrade
The server refuses to start on a database from a newer version. Restore the backup that you made before the upgrade.