Install Nexus Repository Manager on Ubuntu 20.04

Run System Update

Update system package cache;

apt update

Install Java on Ubuntu 20.04

Nexus repository manager requires Java 8 Runtime Environment (JRE). You can install full JDK or just the JRE.

You can simply run the command below to install Java 8 on Ubuntu 20.04;

apt update

Then install Java 8;

apt install openjdk-8-jdk

Confirm the installed version of Java;

java -version
openjdk version "1.8.0_282"
OpenJDK Runtime Environment (build 1.8.0_282-8u282-b08-0ubuntu1~20.04-b08)
OpenJDK 64-Bit Server VM (build 25.282-b08, mixed mode)

Create Dedicated Nexus System Account

As a security precaution, Nexus Repository Manager should NOT be run as the root user. Instead, create a system account for Nexus;

useradd -M -d /opt/nexus -s /bin/bash -r nexus

Allow the nexus user to run all commands with sudo without password.

echo "nexus   ALL=(ALL)       NOPASSWD: ALL" > /etc/sudoers.d/nexus

Download Nexus Repository OSS Tarball

Next, navigate to Nexus repository OSS downloads page, register for an account and download Nexus repository OSS for Unix tarball.

You can simply obtain the link and pull the tarball using wget command as shown below. Note that this downloads the current stable release version of Nexus, 3.81.1-01, as of this writing. Be sure to get the link to the latest version from downloads page.

wget https://download.sonatype.com/nexus/3/nexus-3.38.1-01-unix.tar.gz

Install Nexus Repository Manager on Ubuntu 20.04

Extract Nexus Repository OSS tarball

Navigate to the directory where you downloaded the Nexus tarball and extract it to the nexus user home directory, which in this guide is /opt/nexus.

mkdir /opt/nexus
tar xzf nexus-3.38.1-01-unix.tar.gz -C /opt/nexus --strip-components=1

Checking the contents of the /opt/nexus directory;

ls /opt/nexus
bin  deploy  etc  lib  nexus3  NOTICE.txt  OSS-LICENSE.txt  PRO-LICENSE.txt  public  system

Set the proper ownership of the nexus directory;

chown -R nexus: /opt/nexus

Adjust the Nexus Memory Heap Size

The default minimum JVM heap for Nexus is 2037MB with maximum recommended being 4G. If you have less memory, you can reduce it by editing the file /opt/nexus/bin/nexus.vmoptions and setting a lower value, for demo purposes.

vim /opt/nexus/bin/nexus.vmoptions

Replace the default values for the lines;

-Xms2703m
-Xmx2703m
-XX:MaxDirectMemorySize=2703m
...

To for example, to set it to 1024MB;

-Xms1024m
-Xmx1024m
-XX:MaxDirectMemorySize=1024m

Save and exit the file once you have made the changes.

Running Nexus Repository on Ubuntu 20.04

Nexus provides a startup script at /opt/nexus/bin/nexus.

To run Nexus in standalone mode, you can run this command. However, you need to ensure that Nexus is run as nexus user.

Therefore, edit the file /opt/nexus/bin/nexus.rc and uncomment the line, #run_as_user=”” and add nexus as the value.

sed -i 's/#run_as_user=""/run_as_user="nexus"/' /opt/nexus/bin/nexus.rc

Change the location of the Sonatype Work directory (Nexus data directory) to a location where nexus user has permissions to write.

For example, in our setup, we set the home directory for Nexus as /opt/nexus and we gave nexus user ownership of this directory.

By default, sonatype-work data directory is moved one directory up, hence, it is expected to be created under /opt, which the nexus user has no permissions to write.

Therefore, edit the /opt/nexus/bin/nexus.vmoptions and adjust the path of the Nexus directory (in the below settings, the directory is changed from ../sonatype-work to ./sonatype-work).

vim /opt/nexus/bin/nexus.vmoptions
-XX:LogFile=./sonatype-work/nexus3/log/jvm.log
-XX:-OmitStackTraceInFastThrow
-Djava.net.preferIPv4Stack=true
-Dkaraf.home=.
-Dkaraf.base=.
-Dkaraf.etc=etc/karaf
-Djava.util.logging.config.file=etc/karaf/java.util.logging.properties
-Dkaraf.data=./sonatype-work/nexus3
-Dkaraf.log=./sonatype-work/nexus3/log
-Djava.io.tmpdir=./sonatype-work/nexus3/tmp
...

Next, you can then run Nexus;

sudo -u nexus /opt/nexus/bin/nexus start

It might take sometime for Nexus to start. While starting, tail the logs;

tail -f /opt/nexus/sonatype-work/nexus3/log/nexus.log
2021-02-15 17:10:56,914+0000 INFO  [jetty-main-1]  *SYSTEM org.sonatype.nexus.siesta.SiestaServlet - Initialized
2021-02-15 17:10:56,920+0000 INFO  [jetty-main-1]  *SYSTEM org.sonatype.nexus.repository.httpbridge.internal.ViewServlet - Initialized
2021-02-15 17:10:56,962+0000 INFO  [jetty-main-1]  *SYSTEM org.eclipse.jetty.server.handler.ContextHandler - Started o.e.j.w.WebAppContext@3b390334{Sonatype Nexus,/,file:///opt/nexus/public/,AVAILABLE}
2021-02-15 17:10:57,082+0000 INFO  [jetty-main-1]  *SYSTEM org.eclipse.jetty.server.AbstractConnector - Started ServerConnector@75763136{HTTP/1.1, (http/1.1)}{0.0.0.0:8081}
2021-02-15 17:10:57,083+0000 INFO  [jetty-main-1]  *SYSTEM org.eclipse.jetty.server.Server - Started @182105ms
2021-02-15 17:10:57,083+0000 INFO  [jetty-main-1]  *SYSTEM org.sonatype.nexus.bootstrap.jetty.JettyServer - 
-------------------------------------------------

Started Sonatype Nexus OSS 3.29.2-02

-------------------------------------------------

Nexus listens on TCP port 8081 by default;

netstat -altnp | grep :8081
tcp        0      0 0.0.0.0:8081            0.0.0.0:*               LISTEN      2113/java

You should now be able to access Nexus web interface from browser.

Create Nexus Repository Systemd Service

In order to easily manage Nexus repository service, create a systemd service unit for it as shown below;

cat > /etc/systemd/system/nexus.service << 'EOL'
[Unit]
Description=nexus service
After=network.target

[Service]
Type=forking
LimitNOFILE=65536
ExecStart=/opt/nexus/bin/nexus start
ExecStop=/opt/nexus/bin/nexus stop
User=nexus
Restart=on-abort

[Install]
WantedBy=multi-user.target
EOL

Next, stop Nexus if you already started it with startup script above.

/opt/nexus/bin/nexus stop

Reload the systemd manager configuration;

systemctl daemon-reload

Start and enable Nexus service to run on system reboot;

systemctl enable --now nexus.service

Check the service status;

systemctl status nexus
● nexus.service - nexus service
     Loaded: loaded (/etc/systemd/system/nexus.service; enabled; vendor preset: enabled)
     Active: active (running) since Mon 2021-02-15 17:14:49 UTC; 5s ago
    Process: 67085 ExecStart=/opt/nexus/bin/nexus start (code=exited, status=0/SUCCESS)
   Main PID: 67277 (java)
      Tasks: 41 (limit: 4620)
     Memory: 442.9M
     CGroup: /system.slice/nexus.service
             └─67277 /usr/lib/jvm/java-8-openjdk-amd64/jre/bin/java -server -Dinstall4j.jvmDir=/usr/lib/jvm/java-8-openjdk-amd64/jre -Dexe4j.moduleName=/opt/nexus/bin/nexu>

Feb 15 17:14:48 ubuntu20 systemd[1]: Starting nexus service...
Feb 15 17:14:49 ubuntu20 nexus[67085]: Starting nexus
Feb 15 17:14:49 ubuntu20 systemd[1]: Started nexus service.

You can as well check the logs for verification;

tail -f /opt/nexus/sonatype-work/nexus3/log/nexus.log

Accessing Nexus Repository Web Interface

You can now access Nexus repository from browser using the address http://server-IP-or-resolvable-hostname:8081.

If UFW is running, you need to open port 8081 to allow external access.

ufw allow 8081/tcp

Setup Nexus Repository Manager

Click the sign in button at the top right corner. Login as admin. The password is located on the file, /opt/nexus/sonatype-work/nexus3/admin.password. To get the password, just print the contents of the file.

cat /opt/nexus/sonatype-work/nexus3/admin.password

Once you logged in, click next to proceed to setup Nexus.

  1. Reset Nexus repository admin password
  2. Configure anonymous access. You can choose to disable the anonymous access to secure Nexus repositories by requiring user to authenticate before they can browse through the repositories.
  3. Finish the setup

Run Nexus Repository Behind Nginx Reverse Proxy

In all the above tutorials, Nexus port 8081 is exposed to the external networks as can be seen on Nexus URL, http://server-IP:8081.

When you run Nexus repository behind a reverse proxy, you can access it without having to specify its port on the URL.

Bind Nexus Repository to Localhost Interface

NOTE: if your Nexus instance is already listening on a loopback address, then skip this step.

When you check, by default, at least in the guides above, Nexus is not bound to specific interface on a server on which it is running and hence listens on all interfaces on port 8081.

ss -altnp | grep 8081
LISTEN 0      50           0.0.0.0:8081       0.0.0.0:*    users:(("java",pid=663,fd=691))

Before you can proceed to run Nexus repository manager behind Nginx reverse proxy, first configure Nexus to bind it to a loopback interface, 127.0.0.1.

As shown by the ss command output above, Nexus listens on all interfaces on port 8081/tcp.

grep application- /opt/nexus/etc/nexus-default.properties
application-port=8081
application-host=0.0.0.0

To bind Nexus to localhost interface, replace the 0.0.0.0 address in the configuration file above with the specific server loopback IP address;

sed -i 's/0.0.0.0/127.0.0.1/' /opt/nexus/etc/nexus-default.properties

Once you have made the changes, restart Nexus;

systemctl restart nexus

Once Nexus starts, you can confirm the address it is bind to again;

ss -altnp | grep 8081

Sample output;

LISTEN 0      50         127.0.0.1:8081       0.0.0.0:*    users:(("java",pid=2711,fd=699))

Install Nginx Web Server

Next, install Nginx Web server;

apt install nginx -y

Run Nexus Repository Manager Behind Nginx Reverse Proxy

Once Nginx Web server is installed, create Nexus site.

Any requests that comes to this site will be forward to the Nexus repository running on the same host and listening on loopback interface.

Create Nginx Nexus Site Configuration

To create the Nexus site configuration, /etc/nginx/sites-available/nexus, you can simply copy and paste the content below on the terminal.

Replace the names of the site accordingly.

cat > /etc/nginx/sites-available/nexus << 'EOL'
  server {
    listen   *:80 default_server;
    server_name  nexus.kifarunix-demo.com;
    access_log /var/log/nginx/nexus.access.log;
    error_log /var/log/nginx/nexus.error.log;

    location / {
      proxy_pass http://127.0.0.1:8081/;
      proxy_set_header Host $host;
      proxy_set_header X-Real-IP $remote_addr;
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_buffering    off;
      proxy_request_buffering off;
      keepalive_timeout  5 5;
      tcp_nodelay        on;
      proxy_connect_timeout 90;
      proxy_send_timeout 120;
      proxy_read_timeout 300;
      client_max_body_size 10m;
    }
  }
EOL

Verify Nginx Syntax;

nginx -t

If the output is, similar to below;

nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

then you are good to proceed. Otherwise fix any errors before you can proceed.

Disable default Nginx site;

unlink /etc/nginx/sites-enabled/default
rm /etc/nginx/sites-available/default

Enable Nginx Nexus site;

ln -s /etc/nginx/sites-available/nexus /etc/nginx/sites-enabled/

Restart Nginx;

systemctl restart nginx

Secure NGINX With LetsEncrypt SSL

Step 1 — Installing Certbot

The first step to using Let’s Encrypt to obtain an SSL certificate is to install the Certbot software on your server.

Install Certbot and it’s Nginx plugin with apt:

sudo apt install certbot python3-certbot-nginx

Certbot is now ready to use, but in order for it to automatically configure SSL for Nginx, we need to verify some of Nginx’s configuration.

Step 2 — Allowing HTTPS Through the Firewall

If you have the ufw firewall enabled, as recommended by the prerequisite guides, you’ll need to adjust the settings to allow for HTTPS traffic. Luckily, Nginx registers a few profiles with ufw upon installation.

You can see the current setting by typing:

sudo ufw status

It will probably look like this, meaning that only HTTP traffic is allowed to the web server:

OutputStatus: active

To                         Action      From
--                         ------      ----
OpenSSH                    ALLOW       Anywhere                  
Nginx HTTP                 ALLOW       Anywhere                  
OpenSSH (v6)               ALLOW       Anywhere (v6)             
Nginx HTTP (v6)            ALLOW       Anywhere (v6)

To additionally let in HTTPS traffic, allow the Nginx Full profile and delete the redundant Nginx HTTP profile allowance:

sudo ufw allow 'Nginx Full'
sudo ufw delete allow 'Nginx HTTP'

Your status should now look like this:

sudo ufw status
OutputStatus: active

To                         Action      From
--                         ------      ----
OpenSSH                    ALLOW       Anywhere
Nginx Full                 ALLOW       Anywhere
OpenSSH (v6)               ALLOW       Anywhere (v6)
Nginx Full (v6)            ALLOW       Anywhere (v6)

Next, let’s run Certbot and fetch our certificates.

Step 4 — Obtaining an SSL Certificate

Certbot provides a variety of ways to obtain SSL certificates through plugins. The Nginx plugin will take care of reconfiguring Nginx and reloading the config whenever necessary. To use this plugin, type the following:

sudo certbot --nginx -d example.com -d www.example.com

This runs certbot with the –nginx plugin, using -d to specify the domain names we’d like the certificate to be valid for.

If this is your first time running certbot, you will be prompted to enter an email address and agree to the terms of service. After doing so, certbot will communicate with the Let’s Encrypt server, then run a challenge to verify that you control the domain you’re requesting a certificate for.

If that’s successful, certbot will ask how you’d like to configure your HTTPS settings.

Please choose whether or not to redirect HTTP traffic to HTTPS, removing HTTP access.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1: No redirect - Make no further changes to the webserver configuration.
2: Redirect - Make all requests redirect to secure HTTPS access. Choose this for
new sites, or if you're confident your site works on HTTPS. You can undo this
change by editing your web server's configuration.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Select the appropriate number [1-2] then [enter] (press 'c' to cancel):

Select your choice then hit ENTER. The configuration will be updated, and Nginx will reload to pick up the new settings. certbot will wrap up with a message telling you the process was successful and where your certificates are stored:

IMPORTANT NOTES:
 - Congratulations! Your certificate and chain have been saved at:
   /etc/letsencrypt/live/example.com/fullchain.pem
   Your key file has been saved at:
   /etc/letsencrypt/live/example.com/privkey.pem
   Your cert will expire on 2020-08-18. To obtain a new or tweaked
   version of this certificate in the future, simply run certbot again
   with the "certonly" option. To non-interactively renew *all* of
   your certificates, run "certbot renew"
 - If you like Certbot, please consider supporting our work by:

   Donating to ISRG / Let's Encrypt:   https://letsencrypt.org/donate
   Donating to EFF:                    https://eff.org/donate-le

Your certificates are downloaded, installed, and loaded. Try reloading your website using https:// and notice your browser’s security indicator. It should indicate that the site is properly secured, usually with a lock icon. If you test your server using the SSL Labs Server Test, it will get an A grade.

Let’s finish by testing the renewal process.

Step 5 — Verifying Certbot Auto-Renewal

Let’s Encrypt’s certificates are only valid for ninety days. This is to encourage users to automate their certificate renewal process. The certbot package we installed takes care of this for us by adding a systemd timer that will run twice a day and automatically renew any certificate that’s within thirty days of expiration.

You can query the status of the timer with systemctl:

sudo systemctl status certbot.timer
Output● certbot.timer - Run certbot twice daily
     Loaded: loaded (/lib/systemd/system/certbot.timer; enabled; vendor preset: enabled)
     Active: active (waiting) since Mon 2020-05-04 20:04:36 UTC; 2 weeks 1 days ago
    Trigger: Thu 2020-05-21 05:22:32 UTC; 9h left
   Triggers: ● certbot.service

To test the renewal process, you can do a dry run with certbot:

sudo certbot renew --dry-run

If you see no errors, you’re all set. When necessary, Certbot will renew your certificates and reload Nginx to pick up the changes. If the automated renewal process ever fails, Let’s Encrypt will send a message to the email you specified, warning you when your certificate is about to expire.