This article is a continuation of our discussion on building a web application using Umbraco and Next.js.
Based on the application designed in the previous article, our repository has the following structure:
We will build on this in this article and at the end of the day we will deploy our project to digital ocean via github actions.
Prerequisites
- Github Account
- Digital Ocean Account
Setup Git
By default, when setting up a Next.js app, it initializes its own Git repository. However, if you plan to deploy both the CMS and the Next.js app in the same repository, you need to remove the Git configuration from the Next.js app. To do this, navigate to the Next.js app directory by running cd nextjs-app
, then delete its .git
folder using the command rm -rf .git
. This will remove the Git setup from the Next.js app, allowing you to integrate it into the main repository seamlessly.
Next, initialize the entire project folder as a Git repository. Start by navigating to the root folder with cd ..
. Then, run the following commands:
git init
– Initializes a new Git repository.git add -A
– Stages all files for the initial commit.git commit -m "Initial Setup of Repository"
– Creates the first commit with a message.git push
– Pushes the changes to your remote repository.
For more detailed instructions, refer to the additional guide provided here.
Configure DigitalOcean
Next, create a Droplet in DigitalOcean to host the application. Start by creating a new project in DigitalOcean, providing a name and selecting the purpose for the project. For this guide, we will name the project umbraco-nextjs and set the purpose to Web Application. You can skip the step to move resources into the project at this stage.
Next, create a new Ubuntu Droplet within the project. Configure the server as needed, but for this guide, we will use the following setup:
- Location: San Francisco
- Ubuntu Version: 24
- Droplet Type: Basic
- CPU Options: $6 Regular
Using the $4 droplet will cause your server to encounter memory issues. Hence, choose the $6 own.
Additionally, attach a new SSH key to the Droplet. This will enable secure connections to the server from your local machine. Follow the instructions provided in DigitalOcean to add the SSH key.
Next, set up Node.js on the Droplet, as it is required to run both Next.js and Umbraco. Follow these steps:
- Open the droplet console
- Update the package list:
sudo apt update
- Install Node.js:
sudo apt install nodejs
- Verify the installation:
node -v
- Install npm (Node Package Manager):
sudo apt install npm
Next, we need to set up dotnet on the droplet using the following command. As at the time of writing this article, we are using the dotnet v8.
sudo apt-get install -y dotnet-sdk-8.0
And finally, we need to configure the firewall to allow http, https and ssh access using the following commands:
sudo ufw allow http
sudo ufw allow https
sudo ufw allow ssh
sudo ufw enable
Setup Umbraco Service in Digital Ocean
- Open the Droplet console and navigate to the following directory:
cd /etc/systemd/system
- Run the following command to create or edit the service file:
sudo nano umbraco_app.service
- Add the following content to configure the service:
[Unit]
Description=Umbraco Application
[Service]
WorkingDirectory=/var/www/umbraco-nextjs/umbraco/publish
ExecStart=/usr/bin/dotnet /var/www/umbraco-nextjs/umbraco/publish/umbracoApp.dll
Restart=always
RestartSec=10
SyslogIdentifier=umbraco
User=root
Environment=ASPNETCORE_ENVIRONMENT=Production
[Install]
WantedBy=multi-user.target
- Enable the service using the following command
sudo systemctl enable umbraco_app.service
Setup NextJs Service in Digital Ocean
To manage the Next.js application, we need to install the PM2 process manager globally. This can be done by running the following command:
sudo npm install -g pm2
Next, create a folder to house the Next.js application. In this guide, we will name the folder nextjs.app
. Use the following commands to create it:
cd /var
mkdir www
cd www
mkdir nextjs-app
cd nextjs-app
Create a new file called ecosystem.config.js using nano ecosystem.config.js
and add the following content
module.exports = {
apps: [
{
name: "nextjs-app",
script: "npx",
args: "next start",
cwd: "/var/www/nextjs-app",
},
],
};
and then start the config with pm2 start ecosystem.config.js
Setup Github Actions
Next, set up GitHub Actions to enable automatic deployment of the repository to your Droplet. Begin by adding the Droplet’s IP address and SSH private key as GitHub repository secrets.
- Go to the Settings tab of your GitHub repository.
- Under Secrets and variables, navigate to the Actions section.
- Create a new repository secret named DIGITAL_OCEAN_DROPLET_IP, and set its value to the IP address of your DigitalOcean Droplet.
- Add the following content to configure the service:Create another repository secret named DIGITAL_OCEAN_SSH_KEYS, and set its value to the SSH private key.
These secrets will be used by GitHub Actions to securely connect to your server during deployment.
Next, navigate to your repository and create a folder named .github
. Inside the .github
folder, create another folder called workflows
. Then, create a file named deploy.yml
within the workflows
folder and paste the following code into it.
name: Deploy Umbraco App
on:
push:
branches:
- main
jobs:
deploy_umbraco_db:
needs: deploy_cms
runs-on: ubuntu-latest
steps:
# Step 1: Checkout the repository
- name: Checkout repository
uses: actions/checkout@v3
# Step 2: Upload SQLite database to the server
- name: Deploy SQLite Database
uses: burnett01/rsync-deployments@7.0.1
with:
switches: "-avz --progress"
path: umbracoApp/umbraco/Data/Umbraco.sqlite.db
remote_path: /var/www/umbraco-nextjs/umbraco/publish/umbraco/Data/
remote_host: ${{ secrets.DIGITAL_OCEAN_DROPLET_IP }}
remote_user: root
remote_key: ${{ secrets.DIGITAL_OCEAN_SSH_KEYS }}
- name: Restart Umbraco service
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.DIGITAL_OCEAN_DROPLET_IP }}
username: root
key: ${{ secrets.DIGITAL_OCEAN_SSH_KEYS }}
script: |
sudo systemctl restart umbraco_app.service
deploy_cms:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: "8.0.x"
- name: Restore dependencies
run: dotnet restore ./umbracoApp
- name: Build the project
run: dotnet build ./umbracoApp --configuration Release --no-restore
- name: Publish the project
run: dotnet publish ./umbracoApp --configuration Release --output ./publish
- name: Copy files via SSH
uses: appleboy/scp-action@v0.1.5
with:
host: ${{ secrets.DIGITAL_OCEAN_DROPLET_IP }}
username: root
key: ${{ secrets.DIGITAL_OCEAN_SSH_KEYS }}
source: "publish/*"
target: "/var/www/umbraco-nextjs/umbraco"
- name: Restart Umbraco service
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.DIGITAL_OCEAN_DROPLET_IP }}
username: root
key: ${{ secrets.DIGITAL_OCEAN_SSH_KEYS }}
script: |
cd /var/www/umbraco-nextjs/umbraco/publish/wwwroot
mkdir media
sudo systemctl restart umbraco_app.service
deploy_nextjs:
runs-on: ubuntu-latest
steps:
# Step 1: Check out the repository
- name: Checkout repository
uses: actions/checkout@v3
# Step 2: Set up Node.js environment
- name: Set up Node.js
uses: actions/setup-node@v3
with:
node-version: 20 # Use your project's Node.js version
# Step 3: Install dependencies and build the app
- name: Install dependencies and build
working-directory: ./nextjs-app
run: |
npm install
npm run build
npm install # Install only production dependencies
# Step 4: Transfer files to the DigitalOcean Droplet
- name: Copy files to DigitalOcean Droplet
uses: appleboy/scp-action@v0.1.5
with:
host: ${{ secrets.DIGITAL_OCEAN_DROPLET_IP }}
username: root
key: ${{ secrets.DIGITAL_OCEAN_SSH_KEYS }}
port: 22
source: ./nextjs-app/* # Adjust paths as needed
target: /var/www
# Step 5: Restart the application on the Droplet
- name: Restart app on DigitalOcean
uses: appleboy/ssh-action@v0.1.7
with:
host: ${{ secrets.DIGITAL_OCEAN_DROPLET_IP }}
username: root
key: ${{ secrets.DIGITAL_OCEAN_SSH_KEYS }}
port: 22
script: |
cd /var/www/nextjs-app
npm install
pm2 start ecosystem.config.js
Lastly, we need to deploy the repository to github in order to trigger the actions.
Configure Domains and SSL
The next step is to configure domains to direct traffic to the server, making them accessible over the public internet. We’ll start by obtaining a domain name. In this guide, we’ll use Namecheap to purchase the domain and set up two subdomains: umbraco-test
and nextjs-test
. These subdomains will then be configured to point to our server.
Next, we will need to install nginx and certbot on our servers using the following command:
sudo apt-get install nginx
sudo apt-get install certbot
apt-get install python3-certbot-nginx
Next, create the Nginx configuration file for your Next.js app by running the following command:
sudo nano /etc/nginx/sites-available/nextjs-app
and copy the following command into it
Remember to replace your domain with your actual domain name
server {
listen 80;
server_name nextjs-test.yourdomain.com;
location / {
proxy_pass http://localhost:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection keep-alive;
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
then run the following command
sudo ln -s /etc/nginx/sites-available/nextjs-app /etc/nginx/sites-enabled
sudo nginx -t
sudo systemctl restart nginx
Next we need to create the nginx config file for the umbraco app using the following command
sudo nano /etc/nginx/sites-available/umbraco-app
and copy the following command into it
Remember to replace your domain with your actual domain name
server {
listen 80;
server_name umbraco-test.yourdomain.com;
location / {
proxy_pass http://localhost:5000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection keep-alive;
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
then run the following command
sudo ln -s /etc/nginx/sites-available/umbraco-app /etc/nginx/sites-enabled
sudo nginx -t
sudo systemctl restart nginx
Next, we need to setup https connection to our server using the following command
Remember to replace your domain with your actual domain name
sudo apt-get install certbot python3-certbot-nginx
sudo ufw allow 'Nginx Full'
sudo certbot --nginx -d umbraco-test.yourdomain.com -d nextjs-test.yourdomain.com
sudo certbot renew --dry-run
Updating dotnet project locally
Next, we need to configure the redirect url of the umbraco application by following the steps below:
- Open the
appsettings.json
file in your project directory locally. - Locate the
Umbraco
section and itsCMS
subsection. - Add the following configuration under the
CMS
section:
"WebRouting": {
"UmbracoApplicationUrl": "https://umbraco-test.stackcrawl.com/"
}
To allow for continuous development locally, follow the steps below
- Open the
appsettings.Development.json
file in your project directory locally. - Locate the
Umbraco
section and itsCMS
subsection. - Add the following configuration under the
CMS
section:
"WebRouting": {
"UmbracoApplicationUrl": "https://localhost:{port}"
}
Replace the port with the port your dotnet app runs on locally.
Additionally we need to update the cors settings of the project to allow access from the frontend url. Locate this line in the program.
builder.Services.AddCors(options =>
{
options.AddPolicy("AllowLocalhost3000",
builder => builder.WithOrigins("http://localhost:3000")
.AllowAnyMethod()
.AllowAnyHeader());
});
and add the frontend url so it will match the below code:
builder.Services.AddCors(options =>
{
options.AddPolicy("AllowLocalhost3000",
builder => builder.WithOrigins("http://localhost:3000", "https://nextjs-test.domain.com")
.AllowAnyMethod()
.AllowAnyHeader());
});
Remember to replace domain with your actual domain.
Push the code to the github repository.
Update frontend env on the server
To update the frontend’s .env
file on the server with the necessary backend credentials, follow these steps:
- Open the
ecosystem.config.js
file using this command:
nano /var/www/nextjs-app/ecosystem.config.js
- Update the file content to the following script:
module.exports = {
apps: [
{
name: "nextjs-app",
script: "npx",
args: "next start",
cwd: "/var/www/nextjs-app",
env: {
NODE_ENV: "production",
PORT: 3000,
NEXT_PUBLIC_UMBRACO_URL:{UMBRACO_PUBLIC_URL},
NEXT_PUBLIC_UMBRACO_API_KEY:{UMBACO_API_KEY},
NEXT_PUBLIC_UMBRACO_CONTENT_LANGUAGE:"en-US"
},
},
],
};
Replace
{UMBRACO_PUBLIC_URL}
and{UMBRACO_API_KEY}
with the appropriate values.
- Restart the Next.js app to apply the changes by running:
pm2 restart nextjs-app
Conclusion
After completing these steps, your frontend should be accessible at nextjs-test.yourdomain.com
, and the CMS can be accessed at umbraco-test.yourdomain.com/umbraco
.
The repository for this code is available here.