SCM-Manager 3.12.2 on AWS User Guide
Overview
This guide covers launching and using the SCM-Manager 3.12.2 on Ubuntu 24.04 AMI from cloudimg on Amazon EC2. It is one version of the cloudimg Hardened Apache Subversion (SVN) & CI/CD Tools listing on AWS Marketplace; you pick it as the software version when you subscribe and launch.
SCM-Manager is an open source server for Git, Subversion and Mercurial repositories. It gives your team one place to host repositories over HTTPS, with a web UI to browse code, history and branches, users, groups and per-repository permissions, and a REST API for automation.
The cloudimg image adds:
- No default login and no shared secrets. SCM-Manager's well known
scmadmin/scmadminlogin and its one-time startup token never exist on this image. First boot generates a 24 character password forscmadminon your instance and writes it to/etc/cloudimg-credentials.txt(root only); SCM-Manager keeps only a salted hash of it. SCM-Manager's cipher key, the keys that sign its sessions and its instance id are created at its first start on your instance. SCM-Manager refuses to start on this image until first boot has secured it. - A credential for everything. Anonymous access is off and there is no self-registration: the web UI asks for a login, and the REST API and every Git and Subversion URL answer
401without one. Sign-in attempts and API calls are rate-limited per client address. - Repository imports for administrators only. SCM-Manager can create a repository by importing it from a URL or from an uploaded bundle or export. On this image nginx passes an import on only when SCM-Manager confirms the caller is an administrator, because in 3.12.2 an ordinary user allowed to create repositories could misuse an import to reach data outside their own repositories.
- Repository hooks never run. SCM-Manager runs in a systemd sandbox that cannot execute anything under its data, cache or log directories, so a hook file inside a repository is never executed, whoever put it there.
- No plugin downloads unless you ask. SCM-Manager's first-start plugin wizard is closed before it starts, so nothing is fetched from the plugin center at first boot. Only an administrator can install plugins.
- SCM-Manager on loopback behind nginx. SCM-Manager listens on
127.0.0.1:8080only; nginx serves it on port 443 with a certificate generated on your instance, and port 80 only redirects. SCM-Manager's own SSH server plugin is not installed. - The instance metadata service is blocked for SCM-Manager, nginx and the cloudimg helpers, so an import URL cannot fetch the instance's credentials.
- Fully patched Ubuntu 24.04 LTS at build time, with unattended security upgrades switched on.
What is on the image: SCM-Manager 3.12.2 (AGPL-3.0, the scm-server package from SCM-Manager's signed apt repository, with its bundled Git, Subversion, Mercurial and legacy plugins), OpenJDK 17, git and nginx from Ubuntu 24.04, Ubuntu 24.04 LTS, cloud-init and the AWS Systems Manager agent.
Default user: ubuntu · Architecture: x86_64 · Recommended instance type: m5.large
Imports and outbound access. Repository imports from a URL can reach your VPC and the internet: only the instance metadata service is blocked. An administrator who imports from a URL makes this instance connect to that address, so restrict outbound security group rules to the hosts your imports and plugin installs need, keep the instance metadata hop limit at 1, and attach no instance profile (or a least-privilege one). Step 8 explains each point.
Trademark notice. SCM-Manager is a trademark of Cloudogu GmbH. cloudimg is not affiliated with, endorsed by or sponsored by Cloudogu; the name is used only to identify the open source software in this image, which is the unmodified upstream SCM-Manager release.
Prerequisites
- An AWS account subscribed to the listing, an EC2 key pair and a VPC subnet.
- A security group that allows TCP 443 (SCM-Manager over HTTPS, for the web UI, the API and Git and Subversion clients) and TCP 80 (redirects to HTTPS) from the networks your users work from, and TCP 22 (SSH) from your own network only. SCM-Manager needs no other inbound port.
Step 1: Launch the instance
In the AWS Marketplace listing choose Continue to Subscribe, then Continue to Configuration, pick SCM-Manager 3.12.2 on Ubuntu 24.04 as the software version and your Region, then Launch through EC2. Choose m5.large, your key pair, a security group as above, and a subnet. SCM-Manager keeps its repositories and configuration under /var/lib/scm on the root volume; raise its size under Configure storage for the repositories you expect. Under Advanced details, leave IAM instance profile empty (or choose a least-privilege one), set Metadata version to V2 only and Metadata response hop limit to 1.
With the AWS CLI (replace the values in angle brackets; this sets a 50 GiB root volume and no instance profile):
aws ec2 run-instances --region <region> --image-id <ami-id-from-the-listing> \
--instance-type m5.large --key-name <your-key-pair> \
--security-group-ids <your-security-group> --subnet-id <your-subnet> \
--metadata-options HttpTokens=required,HttpEndpoint=enabled,HttpPutResponseHopLimit=1 \
--block-device-mappings 'DeviceName=/dev/sda1,Ebs={VolumeSize=50,VolumeType=gp3}' \
--tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=scm-manager}]'
Step 2: Connect to your instance
| Version | SSH user |
|---|---|
| SCM-Manager 3.12.2 on Ubuntu 24.04 | ubuntu |
ssh -i <your-key.pem> ubuntu@<public-ip>
Step 3: Check the services
First boot works out the instance's name, generates the certificate and the scmadmin password, starts SCM-Manager once to secure it, proves over HTTPS that anonymous requests are refused and the new password is accepted, and only then opens the web server. It takes a minute or two:
systemctl is-active scm-server nginx scmm-set-host
active
active
active
scmm-set-host runs on every boot before SCM-Manager and nginx: it keeps the served name, the certificate, nginx's host rules and SCM-Manager's base URL in step (Step 10).
Only SSH (22) and nginx (80, 443) listen on the network. SCM-Manager (8080) is on the loopback address only (Java shows it as the IPv4-mapped [::ffff:127.0.0.1]). The :53 entries are Ubuntu's local DNS resolver, :323 is the time service on the loopback address and :68 is the DHCP client:
sudo ss -lntup | awk 'NR>1 {print $1, $5}' | sort -u
tcp 0.0.0.0:22
tcp 0.0.0.0:443
tcp 0.0.0.0:80
tcp 127.0.0.53%lo:53
tcp 127.0.0.54:53
tcp [::]:22
tcp [::]:443
tcp [::]:80
tcp [::ffff:127.0.0.1]:8080
udp 127.0.0.1:323
udp 127.0.0.53%lo:53
udp 127.0.0.54:53
udp 172.31.94.31%ens5:68
udp [::1]:323
SCM-Manager runs as the scm account on Ubuntu's OpenJDK 17, started by the package's own scm-server.service with cloudimg's sandbox added:
ps -o user:10=,args= -C java | sed -E 's# -.* sonia# ... sonia#'
java -version 2>&1 | head -1
scm /usr/lib/jvm/java-17-openjdk-amd64/bin/java ... sonia.scm.server.ScmServerDaemon
openjdk version "17.0.20.1" 2026-08-18
If nginx is not running, first boot has not finished, or it failed, in which case the web server is never opened. Check systemctl status scmm-firstboot and sudo tail -40 /var/log/cloudimg/scmm-firstboot.log.
Step 4: Get your address and password
sudo cat /etc/cloudimg-credentials.txt
The file is readable by root only and holds the address, the administrator's user name and password and the certificate fingerprint:
# SCM-Manager - generated on first boot. Unique to this instance; keep it safe.
# Sign in at SCMM_URL as SCMM_ADMIN_USER / SCMM_ADMIN_PASSWORD. Compare SCMM_TLS_SHA256 with the certificate your
# browser shows (or install your own certificate: see the guide). Rotate the password: sudo scmm-set-password
SCMM_URL=https://ec2-203-0-113-10.compute-1.amazonaws.com/scm/
SCMM_ADMIN_USER=scmadmin
SCMM_ADMIN_PASSWORD=<SCMM_ADMIN_PASSWORD>
SCMM_TLS_SHA256=1C:BB:CB:21:57:B6:70:95:17:D1:82:CC:80:CF:10:1C:04:2D:42:B5:41:2B:9C:75:4B:40:37:43:6A:BA:2D:B0
To see everything but the password:
sudo grep -E '^SCMM_(URL|ADMIN_USER|TLS_SHA256)=' /etc/cloudimg-credentials.txt
SCMM_URL=https://ec2-203-0-113-10.compute-1.amazonaws.com/scm/
SCMM_ADMIN_USER=scmadmin
SCMM_TLS_SHA256=1C:BB:CB:21:57:B6:70:95:17:D1:82:CC:80:CF:10:1C:04:2D:42:B5:41:2B:9C:75:4B:40:37:43:6A:BA:2D:B0
You can confirm the whole path from the instance itself. The helper goes through nginx over HTTPS with the certificate pinned. It checks that SCM-Manager's API, its first-start plugin wizard, an import and Git and Subversion all refuse anonymous requests, that wrong and well known default passwords are refused, and that this instance's password signs in, as a token and with HTTP Basic:
sudo /usr/local/sbin/scmm-verify.sh
SCMM_ROUNDTRIP_OK (HTTPS: 9 API routes + the plugin-set wizard + an import + Git + Subversion refused anonymously, default/wrong passwords refused, the minted password accepted as a token and HTTP Basic reading as scmadmin, foreign method 405, Origin guard)
Change the password with scmm-set-password. With no argument it generates a new 24 character password; with - it reads yours from standard input. It never accepts the password as an argument, so it does not appear in the process list or your shell history. The command updates /etc/cloudimg-credentials.txt, and it is also the way back in if the password is lost:
$ sudo scmm-set-password
scmm-set-password: the scmadmin password was replaced (sudo cat /etc/cloudimg-credentials.txt)
To choose your own:
$ read -rs NEWPW && printf '%s' "$NEWPW" | sudo scmm-set-password - ; unset NEWPW
scmm-set-password: the scmadmin password was replaced (sudo cat /etc/cloudimg-credentials.txt)
SCM-Manager's user store (/var/lib/scm/config/users.xml, readable by the scm account only) keeps a salted SHA-512 hash, never the password:
sudo sed -nE 's#.*<password>(\$shiro1\$SHA-512\$[0-9]+\$).*#\1...#p' /var/lib/scm/config/users.xml
$shiro1$SHA-512$8192$...
Step 5: Sign in
Open SCMM_URL in your browser. The certificate is self-signed until you install your own (Step 10), so the browser warns once; compare the fingerprint it shows with SCMM_TLS_SHA256. SCM-Manager shows its login page; use scmadmin and the password from Step 4. There is no registration link and no anonymous view:

Repositories lists every repository you can see, by namespace. This is the list with the repository from Step 6:

Open a repository to browse its files, commits, branches and tags, and to find its clone URL:

Administration > Settings > General holds the server-wide settings. On this image Anonymous Access is Disabled and the Base URL further down the page is the instance's HTTPS address (scmm-set-hostname keeps it in step, Step 10). Leave anonymous access disabled unless you mean to publish repositories to anyone who can reach the instance:

Step 6: Create a repository and push to it
In the web UI choose Add Repository (on the Repositories page), pick Git or Subversion, enter a name and save. The repository's page shows its clone URL, https://<host>/scm/repo/<namespace>/<name>; Git and Subversion clients sign in with your SCM-Manager user name and password:
git clone https://<host>/scm/repo/scmadmin/<name>
svn checkout https://<host>/scm/repo/scmadmin/<name>
While the certificate is self-signed, tell your client to trust it (for Git, git config --global http.https://<host>/.sslCAInfo <saved-certificate.pem>) or install your own certificate first (Step 10).
The same from a script, with SCM-Manager's REST API and git. This round trip on the instance itself creates a Git repository with the API, pushes a first commit to it with git over HTTPS, reads the branch back from the API and shows that an anonymous clone is refused. The password is read from the credentials file into files only, never printed or put on a command line:
D=$(mktemp -d) && cd "$D" && umask 077
HOST=$(sudo sed -n 's#^SCMM_URL=https://\([^/]*\)/.*$#\1#p' /etc/cloudimg-credentials.txt)
B="https://${HOST}/scm"; CRT=/etc/ssl/scm-manager/scm-manager.crt
# the password goes into a curl config file and a git credential file (printf is a shell builtin), never onto a command line
PW_LINE=$(sudo sed -n 's/^SCMM_ADMIN_PASSWORD=//p' /etc/cloudimg-credentials.txt)
printf 'user = "scmadmin:%s"\n' "$PW_LINE" > auth.cfg
printf 'https://scmadmin:%s@%s\n' "$PW_LINE" "$HOST" > git-credentials; unset PW_LINE
A=(-s --max-time 60 --cacert "$CRT" --resolve "${HOST}:443:127.0.0.1" -K "$D/auth.cfg")
G=(git -c http.sslCAInfo="$CRT" -c http.curloptResolve="${HOST}:443:127.0.0.1" -c user.name=cloudimg -c user.email=guide@example.com)
# 1. a Git repository, from the API
curl "${A[@]}" -o /dev/null -w 'create repository: %{http_code}\n' -H 'Content-Type: application/vnd.scmm-repository+json;v=2' \
--data '{"namespace":"scmadmin","name":"hello-cloudimg","type":"git","description":"cloudimg guide example"}' "$B/api/v2/repositories/"
# 2. a first commit, pushed with git over HTTPS
git init -q -b main work && cd work
echo "Hello from SCM-Manager on cloudimg" > README.md
"${G[@]}" add README.md && "${G[@]}" commit -qm 'First commit'
"${G[@]}" -c credential.helper="store --file=$D/git-credentials" push -q "$B/repo/scmadmin/hello-cloudimg" main 2>/dev/null && echo "push: OK"
# 3. what SCM-Manager now holds, from the API
curl "${A[@]}" "$B/api/v2/repositories/scmadmin/hello-cloudimg/branches/" \
| python3 -c 'import json,sys; [print("branch:", b["name"], b["revision"][:12]) for b in json.load(sys.stdin)["_embedded"]["branches"]]'
# 4. an anonymous clone is refused
GIT_TERMINAL_PROMPT=0 "${G[@]}" ls-remote "$B/repo/scmadmin/hello-cloudimg" 2>&1 | tail -1
cd / && rm -rf "$D"
create repository: 201
push: OK
branch: main 0c42b8a552c5
fatal: could not read Username for 'https://ec2-203-0-113-10.compute-1.amazonaws.com': terminal prompts disabled
To remove the example repository again:
D=$(mktemp -d) && cd "$D" && umask 077
HOST=$(sudo sed -n 's#^SCMM_URL=https://\([^/]*\)/.*$#\1#p' /etc/cloudimg-credentials.txt)
printf 'user = "scmadmin:%s"\n' "$(sudo sed -n 's/^SCMM_ADMIN_PASSWORD=//p' /etc/cloudimg-credentials.txt)" > auth.cfg
curl -s --max-time 60 --cacert /etc/ssl/scm-manager/scm-manager.crt --resolve "${HOST}:443:127.0.0.1" -K auth.cfg \
-o /dev/null -w 'delete repository: %{http_code}\n' -X DELETE "https://${HOST}/scm/api/v2/repositories/scmadmin/hello-cloudimg"
cd / && rm -rf "$D"
delete repository: 204
From your workstation, use the same calls with https://<host>/scm/api/v2/.... The API takes your user name and password (HTTP Basic, rate-limited per client address like the login form) or, better for scripts, an API key you create under your user's Profile > API Keys: keep either in a file (curl -K), not on the command line.
Step 7: Users, groups and permissions
Add users under Users > Create User (or connect a directory with SCM-Manager's LDAP plugin). A new user can sign in and see only the repositories they are given. Grant access per repository under the repository's Settings > Permissions (read, write or owner, for a user or a group), and server-wide under the user's or group's Settings > Permissions, for example Create repositories. Keep the administrator role to the people who run the server: on this image only administrators can import repositories or install plugins.
Anonymous requests get nothing. From the instance, without credentials, the API, a Git clone and a Subversion checkout of any repository all answer 401:
HOST=$(sudo sed -n 's#^SCMM_URL=https://\([^/]*\)/.*$#\1#p' /etc/cloudimg-credentials.txt)
C=(-s -o /dev/null --max-time 30 --cacert /etc/ssl/scm-manager/scm-manager.crt --resolve "${HOST}:443:127.0.0.1" -w '%{http_code}')
echo "API repositories: $(curl "${C[@]}" "https://${HOST}/scm/api/v2/repositories/")"
echo "API current user: $(curl "${C[@]}" "https://${HOST}/scm/api/v2/me/")"
echo "Git clone: $(curl "${C[@]}" "https://${HOST}/scm/repo/scmadmin/any/info/refs?service=git-upload-pack")"
echo "Subversion: $(curl "${C[@]}" -X PROPFIND -H 'Depth: 0' "https://${HOST}/scm/repo/scmadmin/any")"
API repositories: 401
API current user: 401
Git clone: 401
Subversion: 401
Step 8: Imports, hooks, plugins and outbound access
Imports are for administrators. Add Repository > Import repository creates a repository from a URL, a bundle or a full export. On this image nginx asks SCM-Manager whether the caller is an administrator before it passes any import request on, and refuses everyone else with 403, whatever spelling of the import path they use. In 3.12.2 a user who may only create repositories could otherwise use a crafted import to write files outside their new repository or to copy a repository they cannot read; cloudimg found both while building this image and closed them this way. A user with Create repositories can still create and push to new repositories as usual.
Imports can reach your VPC and the internet. An import from a URL (and a plugin install) is a connection from this instance, so it can reach anything the instance's security group and routing allow. Only the instance metadata service is blocked, for SCM-Manager and everything else cloudimg runs (169.254.169.254 and its IPv6 address fd00:ec2::254), so an import URL cannot fetch the instance's credentials. Restrict outbound security group rules to the hosts your imports and plugin installs need, and do not put this instance in a subnet that can reach systems its administrators should not.
Hooks never execute. Git, Subversion and Mercurial run hook files from a repository's hooks directory. SCM-Manager runs with no execution allowed under its data, cache and log directories, so a hook file there is never run, even one an administrator puts in place by hand; SCM-Manager logs that it is not executable. Use SCM-Manager's plugins (for example its CI and webhook plugins) for actions on push.
Keep the hop limit at 1 and attach no instance profile (or a least-privilege one). The metadata block covers SCM-Manager, nginx and the cloudimg helpers. A hop limit of 1 (Step 1) keeps any container you later run on this host from fetching IMDSv2 tokens, and root and other software on the instance can still reach the service, so an instance profile's permissions are only as safe as the instance.
The sandbox and the metadata block, as systemd applies them to SCM-Manager and nginx:
systemctl show scm-server -p User -p NoNewPrivileges -p ProtectSystem -p PrivateTmp -p CapabilityBoundingSet -p NoExecPaths
systemctl show scm-server nginx -p Id -p IPAddressDeny
CapabilityBoundingSet=
User=scm
NoExecPaths=/var/lib/scm /var/cache/scm /var/log/scm
PrivateTmp=yes
ProtectSystem=strict
NoNewPrivileges=yes
IPAddressDeny=169.254.169.254/32 168.63.129.16/32 fd00:ec2::254/128
Id=scm-server.service
IPAddressDeny=169.254.169.254/32 168.63.129.16/32 fd00:ec2::254/128
Id=nginx.service
Plugins. The image has SCM-Manager's four bundled plugins and no others; SCM-Manager's SSH server plugin is not installed, so Git over SSH is not offered (the instance's port 22 is the system's SSH only). Administrators install more under Administration > Plugins > Available: SCM-Manager downloads them from its plugin center (plugin-center-api.scm-manager.org, so the security group must allow outbound HTTPS to it) and asks for a restart. Each plugin runs inside SCM-Manager with its full access: install only plugins you need and keep them updated. Administration > Plugins > Installed shows them:

The same from the API:
D=$(mktemp -d) && cd "$D" && umask 077
HOST=$(sudo sed -n 's#^SCMM_URL=https://\([^/]*\)/.*$#\1#p' /etc/cloudimg-credentials.txt)
printf 'user = "scmadmin:%s"\n' "$(sudo sed -n 's/^SCMM_ADMIN_PASSWORD=//p' /etc/cloudimg-credentials.txt)" > auth.cfg
curl -s --max-time 60 --cacert /etc/ssl/scm-manager/scm-manager.crt --resolve "${HOST}:443:127.0.0.1" -K auth.cfg \
"https://${HOST}/scm/api/v2/plugins/installed" \
| python3 -c 'import json,sys; [print(p["name"], p["version"]) for p in json.load(sys.stdin)["_embedded"]["plugins"]]'
cd / && rm -rf "$D"
scm-hg-plugin 3.12.2
scm-svn-plugin 3.12.2
scm-git-plugin 3.12.2
scm-legacy-plugin 3.12.2
Step 9: Mercurial repositories
SCM-Manager's Mercurial plugin is installed, but Mercurial itself is not, so the image serves Git and Subversion until you add it. Mercurial comes from Ubuntu's community-maintained universe archive. To add it:
sudo apt-get update && sudo apt-get install -y mercurial
sudo systemctl restart scm-server
SCM-Manager then offers Mercurial as a repository type next to Git and Subversion, and Mercurial clients push and clone at the same https://<host>/scm/repo/<namespace>/<name> URLs; in cloudimg's test on this image a push and a clone over HTTPS worked. SCM-Manager 3.12.2's Mercurial helper extension (javahg) logs an error with Ubuntu 24.04's Mercurial 6.7 (failed to set up extension javahg), an upstream compatibility issue, so check the SCM-Manager documentation for the Mercurial versions it supports before you rely on it. Mercurial's own hook files are never executed on this image, like Git's (Step 8).
Step 10: Your own host name and certificate
On every boot scmm-set-host works out the name to serve: the name you set, else the instance's public DNS name from the instance metadata service (IMDSv2). SCM-Manager's base URL follows it:
systemctl is-enabled scmm-set-host.service
sudo scmm-set-hostname --boot
enabled
scmm-set-hostname: unchanged (ec2-203-0-113-10.compute-1.amazonaws.com)
Use your own DNS name. Point a DNS record at the instance (an Elastic IP keeps the address fixed), then run sudo scmm-set-hostname scm.example.com. The name is kept in /etc/cloudimg/scmm-hostname for every later boot, the credentials file and SCM-Manager's base URL are updated (SCM-Manager restarts for a few seconds), nginx serves that name and redirects the instance's other addresses to it, and browser requests from other origins are refused. Because the certificate in place was the one cloudimg generated, it is re-created for the new name.
Which certificates are replaced. Only a certificate cloudimg generated is ever re-created: its SHA-256 fingerprint is recorded, root owned, in /var/lib/cloudimg/scmm-cert.sha256, and a certificate is treated as cloudimg's only while it matches that record:
sudo cat /var/lib/cloudimg/scmm-cert.sha256
openssl x509 -in /etc/ssl/scm-manager/scm-manager.crt -noout -fingerprint -sha256
1C:BB:CB:21:57:B6:70:95:17:D1:82:CC:80:CF:10:1C:04:2D:42:B5:41:2B:9C:75:4B:40:37:43:6A:BA:2D:B0
sha256 Fingerprint=1C:BB:CB:21:57:B6:70:95:17:D1:82:CC:80:CF:10:1C:04:2D:42:B5:41:2B:9C:75:4B:40:37:43:6A:BA:2D:B0
Install your own certificate (from your CA, or Let's Encrypt with a DNS challenge) by putting the full chain and the key at the same paths. Anything there that does not match the record is yours and is never replaced, not on boot and not when the name changes:
sudo install -m 0644 -o root -g root fullchain.pem /etc/ssl/scm-manager/scm-manager.crt
sudo install -m 0600 -o root -g root privkey.pem /etc/ssl/scm-manager/scm-manager.key
sudo nginx -t && sudo systemctl reload nginx
Go back to a generated certificate by removing both files and running the helper with the name to serve:
$ sudo rm /etc/ssl/scm-manager/scm-manager.crt /etc/ssl/scm-manager/scm-manager.key
$ sudo scmm-set-hostname scm.example.com
To return to the instance's own public name on every boot, sudo rm /etc/cloudimg/scmm-hostname && sudo scmm-set-hostname --boot.
Step 11: Backups and updates
SCM-Manager keeps everything, its configuration, users, permissions, cipher key and every repository, in /var/lib/scm. Back it up with an EBS snapshot of the root volume, or by stopping SCM-Manager and copying the folder. A backup holds the cipher key and every repository, so keep it as safe as the instance:
sudo systemctl stop scm-server
sudo tar -C / -czf /root/scm-manager-backup.tar.gz var/lib/scm
sudo systemctl start scm-server
Ubuntu packages, OpenJDK, git and nginx included, are updated by unattended security upgrades:
systemctl is-enabled unattended-upgrades apt-daily-upgrade.timer
enabled
enabled
SCM-Manager itself comes from SCM-Manager's own apt repository, which stays configured (pinned to its signing key) but is not in unattended upgrades, so SCM-Manager is never upgraded behind your back. To move to a newer release, back up first, then:
sudo apt-get update && sudo apt-get install --only-upgrade scm-server
SCM-Manager migrates its data on start. cloudimg also publishes a new version of this listing for new SCM-Manager releases.
Security notes
- Credential first. Anonymous access and self-registration are off: the web UI shows only the login page, and the REST API and every Git and Subversion URL answer
401without credentials (Step 7). The defaultscmadmin/scmadminlogin and SCM-Manager's startup token never exist on this image. - Rate-limited sign-in. The login form is limited per client address (10 a minute), and so are API calls and requests carrying credentials.
- Administrator-only imports and plugins. Only administrators can import repositories (from a URL, a bundle or an export) or install plugins, and nothing is downloaded from the plugin center at first boot (Step 8).
- Imports can reach your VPC and the internet. Only the instance metadata service is blocked; restrict outbound security group rules to what your imports and plugin installs need (Step 8).
- Hooks never execute. Nothing under SCM-Manager's data, cache and log directories can be executed, so repository hook files never run (Step 8).
- Exact listeners. Only 22, 80 and 443 listen on the network (Step 3); SCM-Manager is on loopback. Port 80 only redirects to HTTPS. Open the ports in the security group only to the networks that need them.
- Forwarded headers. nginx sends SCM-Manager the configured host name,
https, port 443 and the real client address (X-Forwarded-Foris set from the connection, never passed through), drops client-suppliedForwardedheaders, refuses HTTP methods SCM-Manager does not use and refuses state-changing requests from other origins. Responses carry HSTS. - Secrets per instance. The
scmadminpassword, SCM-Manager's cipher key, session signing keys and instance id, the HTTPS certificate and the SSH host keys are all created on your instance's first boot; none is in the image.
Build provenance and licence
SCM-Manager 3.12.2 is the scm-server package from SCM-Manager's apt repository at packages.scm-manager.org, with the repository's signing key pinned to fingerprint 23D2625B235E25A4719875A2975922F193B07D6E and the package's SHA-256 checked. It is installed unmodified; the build checks every file against the package's own checksums:
head -3 /usr/share/doc/cloudimg/scm-manager-BUILD-INFO.txt
dpkg-query -W scm-server
sudo dpkg --verify scm-server && echo "scm-server files: unmodified"
SCM-Manager 3.12.2 on Ubuntu 24.04 (cloudimg AWS bundle member dev-cicd)
scm-server_3.12.2_all.deb sha256 575d1dbe7003d4d51f9db9e446dc650f84bc1c42be632b0b31eff9095ac7638d, installed unmodified from https://packages.scm-manager.org/repository/apt-v2-releases/ (Signed-By exactly key 23D2625B235E25A4719875A2975922F193B07D6E; the source stays configured for updates)
licence: AGPL-3.0-only (/usr/share/doc/cloudimg/scm-manager-LICENSE-AGPL-3.0.txt); sources: /usr/share/doc/cloudimg/scm-manager-SOURCES.txt
scm-server 3.12.2
scm-server files: unmodified
Licence and source. SCM-Manager is licensed under the GNU Affero General Public License v3.0 (AGPL-3.0-only). The licence text is on the image at /usr/share/doc/cloudimg/scm-manager-LICENSE-AGPL-3.0.txt. The complete corresponding source of the SCM-Manager version on this image is SCM-Manager's own, unmodified: github.com/scm-manager/scm-manager (tag 3.12.2), which also holds the four bundled plugins. cloudimg has not changed SCM-Manager; if you modify it and let others use it over the network, the AGPL (section 13) requires you to offer them your modified source. The bundled Subversion plugin includes SCM-Manager's build of SVNKit 1.10.10, which is under the TMate Open Source License; its licence text is inside the jar (/var/lib/scm/plugins/scm-svn-plugin/lib/svnkit-1.10.10-scm2-jakarta.jar, META-INF/LICENSE.txt), and its source is published as the release's -sources.jar under https://packages.scm-manager.org/repository/releases/sonia/svnkit/. /usr/share/doc/cloudimg/scm-manager-SOURCES.txt lists these locations. The other libraries inside SCM-Manager carry their own open source licences.
SCM-Manager's security advisories are published on GitHub; cloudimg publishes a new version of this listing when a release fixes one.
Troubleshooting
- The login page refuses the password. Read the password again from
/etc/cloudimg-credentials.txt(the user name isscmadmin). Afterscmm-set-passwordthe old one is refused. 429 Too Many Requests. Too many sign-in attempts or API calls from one address (10 sign-ins a minute). Wait a minute.403on an import. Only administrators can import repositories on this image (Step 8). Sign in as an administrator, or ask one to import it.- An import from a URL fails to connect. The import is a connection from this instance: check that the security group and routing allow it outbound. The instance metadata service is always refused.
403on a form from another site, or the connection dropped with no answer. The request named a host or origin the instance does not serve. Use the name inSCMM_URL, or set yours withscmm-set-hostname(Step 10).- Git says the certificate is not trusted. The certificate is self-signed until you install your own: trust it in your client (Step 6) or install yours (Step 10).
- Logs:
journalctl -u scm-server,/var/log/scm/scm-manager.log,/var/log/nginx/access.logand/var/log/nginx/error.log, and/var/log/cloudimg/scmm-firstboot.log.
Support
cloudimg images come with 24/7 support. Email support@cloudimg.co.uk with your AWS account ID, the instance ID and the output of sudo /usr/local/sbin/scmm-verify.sh. For SCM-Manager itself, see the SCM-Manager documentation.