Skip to content

How to install a self-hosted instance of iFramely for use with NodeBB

Configure
  • I’ve been asked for a walkthrough of how to install iFramely for use with NodeBB several times, and figured it was about time I posted a guide 🙂 I’ve assisted @cagatay and @DownPW with their installations, but this should be useful for anyone else looking to do something similar.

    By way of background, the “hosted” version of iFramely works extremely well, but is not free (what is?) and you’ll exceed their API limit for the free plan very quickly - at which point, they’ll email and inform you that you need to upgrade to one of their paid plans.

    Sadly, these aren’t cheap, however, iFramely do very kindly provide a self-hosted version of their application, and you can find out how to install that here. This guide assumes you have a fully functional copy of NodeBB running, and have already installed and activated the relevant plugin. If you haven’t installed the plugin, do this now (from CLI as it’s not listed in the GUI)

    npm install nodebb-plugin-iframely
    

    Now activate the plugin, but don’t configure it for the moment. You’ll need to rebuild and restart NodeBB also - don’t forget this step.

    Whilst it’s perfectly “feasible” to install iFramely in the same domain as where you host your NodeBB instance, this isn’t generally recommended for security reasons. It ideally needs to be installed in a sub domain (or dedicated domain if you have one), so if your NodeBB URL is something like https://mynodebb.com then the subdomain would be something like https://media.mynodebb.com

    I’m detecting some head scratching already 🙂 - how to I create a subdomain, yes? Well, it differs quite heavily depending on the platform you are using, but for sake of keeping this guide short, I won’t list every single method - that would take forever! Instead, let’s take the most common and effective route - Cloudflare.

    Configure DNS for subdomain

    1. Login to the Cloudflare dashboard for your domain, and select DNS
    2. Add a new A record called “media” and have this point to the same IP address as your existing site
    3. Ensure that the proxy is enabled (orange cloud - grey cloud is DNS only) so that we pass the same wildcard cert to your server as the existing NodeBB site does
    4. DNS convergence on Cloudflare is typically within 60 seconds, so it’ll populate very quickly
    5. If you really want to see how far the propagation has advanced, use this site (very easy to use and self explanatory)

    https://www.whatsmydns.net/

    Configure NGINX to accept traffic for new subdomain

    You now need to configure your NGINX installation so that it will accept the subdomain when traffic is sent towards it - leaving this step out means your server will likely discard the traffic and you’ll land up with a 404 error

    Depending on your *nix build, the nginx.conf file may be in different places. If you know where your specific conf file is for your NodeBB install, open that now.

    1. You’re going to add the below config (note that some parts such as certificate paths need to be changed so they match the same ones you’re using for NodeBB)
    server {
        listen 443 ssl http2;
        listen [::]:443 ssl http2;
    
    
            ssl_certificate /etc/ssl/cert.pem;
        ssl_certificate_key /etc/ssl/key.pem;
            ssl_client_certificate /etc/ssl/cloudflare.crt;
    
            ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    
        server_name media.mynodebb.com;
            location / {
                    proxy_set_header X-Real-IP $remote_addr;
                    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                    proxy_set_header Host $http_host;
                    proxy_set_header X-NginX-Proxy true;
    
                    proxy_pass http://127.0.0.1:8061/;
                    proxy_redirect off;
    
                    # Socket.IO Support
                    proxy_http_version 1.1;
                    proxy_set_header Upgrade $http_upgrade;
                    proxy_set_header Connection "upgrade";
            }
    
    }
    
    

    Again, this is just an example, and will likely need to be modified. Essentially, what we are doing here is sending all traffic into a reverse proxy, where the iFramely installation is listening on port 8061, but will only answer requests from localhost. This makes the installation much more secure as the reverse proxy is responsible for directing the traffic, and also means you can use https://media.mynodebb.com instead of having to use https://media.mynodebb.com:8061 which incidentally, if you are using Cloudflare, this particular port isn’t routable with the free plan, so something to be aware of 😕

    Obviously, don’t forget to change https://media.mynodebb.com with your actual URL 🙂

    1. Save and close the nginx.conf file
    2. Test the config by running nginx -t in the CLI (this validates the config before restarting the service to prevent issues)
    3. If all ok in step 3, restart the NGINX service - note that command will vary depending on the Linux distribution you are using, but generally sudo service nginx restart should work in most cases (if you are using a Debian backed build)

    Install iFramely

    1. At the root of your home (again, this depends on where you’ve installed NodeBB - easy to determine as it will contain the NodeBB installation directory when navigated to) issue the following CLI
    mkdir iframely
    git clone https://github.com/itteco/iframely.git
    cd iframely
    npm install
    

    Note that the user you are installing iFramely under needs admin rights - in most cases, you can use sudo npm install if the first attempt fails. If the user is not in the sudoers file, then you should use su root and then provide the password. Then complete the install

    1. Once the installation is complete, there are some more steps
    cp config.local.js.SAMPLE config.local.js
    nano config.local.js
    

    The above copies the “sample” config file and creates a new file called config.local.js. I’m also using nano as the text editor, as I can’t stand vi 🙂 I’ll leave that preference up to you…

    1. With the editor open, locate the baseAppUrl variable and place the actual URL of the subdomain you are going to use
    baseAppUrl: "https://media.mynodebb.com", // use "https://yourdomain.com/path" where you have Iframely in your reverse proxy
    
    1. Save and exit the file

    Start an iFramely instance

    1. Type node server into the CLI and press enter
    2. This will start a single instance of iFramely
    3. Now navigate to admin/plugins/iframely in your NodeBB installation
    4. Enter the URL you are going to be using as below

    a6428059-dcca-4570-bd8e-0f9708b728e7-image.png

    Make sure that the URL is appended with /iframely as this is the API endpoint where requests are sent

    1. Save the settings
    2. Reload NodeBB

    Initial testing

    1. Create a new post and place a URL inside it such as https://www.whatsmydns.net/ inside it
    2. Add tags if needed
    3. Post it

    Hopefully, it’ll look something like this

    6acbcc9f-4e0a-405b-80ab-efcdc48aa18b-image.png

    In addition, if you switch back to the server CLI, you should see items being logged. At this point, it works 🙂 but you’re not quite finished

    Using PM2 to create a spawned process daemon

    1. Go to the CLI on your server and stop the running node server by using CTRL + Z
    2. Ensure that you are in the same folder as the iFramely installation
    npm install pm2 -g
    pm2 start pm2.json
    pm2 logs
    

    Again, make sure that the account you are using has root permissions when try to use npm install as previously mentioned

    You should hopefully see a log being generated like the below which is updated in real time when accessing posts with links

    27350f64-75c8-40d2-a3f4-f648c0d16568-image.png

    You can safely exit the log with CTRL + C which won’t affect the daemon.

    If you want to see if the process is running or not, you can use pm2 status

    d091acf6-7b43-4307-9e5e-6e70c928db14-image.png

    Similarly, if you need to restart the instance, you can do so using

    pm2 reload iframely
    

    That’s pretty much it - hope this was useful.

  • phenomlabundefined phenomlab marked this topic as a regular topic on
  • phenomlabundefined phenomlab referenced this topic on
  • thanks a lot @phenomlab , if it is OK for you, I would like to share our custom CSS codes with self-hosted iframely…

    The free version looks quite bigger than the paid version, so we improved the look with these CSS changes… It is still not as pretty as the original iframely embeds, but I believe it is still better than the default one.

    Of course, feel free to change/edit it as you like:

    
    .iframely-link .iframely-container {
        
        .img-responsive {
        height:120px !important;
        width: auto !important;
        overflow: hidden !important;
        }
    
    
        .iframely-meta {
        display: none !important;
        }
    
    
        .media {
        float: left !important;
        padding: 0 5px 0 0 !important;
        }
        
        .media-heading {
        margin-top: 5px;
        margin-bottom: 2px;
        }
    
        .description {
        position: relative !important;
        top: 10px !important;
        }
    
        .panel-iframely .iframely-embed .one-line {
        white-space: normal;
        }
        
        .panel-body {
        padding: 5px;
        }
    }
    
    
    
    
  • @crazycells thanks for this. I too changed the default layout, but will certainly have a look at your CSS mods because they might be better than mine! 😄

  • @crazycells I tried this CSS, and it looks a little “cramped” to me - why not post some screenshots ?

  • here is an example… Since previews are just previews and do not give the whole info, we prefer to see them in the text as a small banner with some info in it… free iframely takes a much larger unnecessary space from the post…

    Screen Shot 2022-08-26 at 14.02.01.png

  • @crazycells looks like you’re using a 100% width there which would explain the cramped look on here as I set a static max-width 👍

  • @phenomlab yes, you have very customized themes here; so I guess CSS codes will need some adjustments for a similar look…

  • Thanks @crazycells for your code, I will test it, for sure 😉

    @phenomlab Resources level, do you know to what extent the CPU will be impacted by Iframely?

    Generally speaking, our forum uses between 20 and 50% of the CPU. With peaks at 80-90 which return an excess load and unavailability to the forum (a few seconds).

  • @DownPW iFramely is multi threaded and runs as a cluster, so will spread itself across the amount of cores you have. If you run pm2 status you’ll see how many cores it’s using, plus the memory usage.

    I’ve never had an issue with it and I know that thousands of sites have it installed with no performance degradation. It scales very well and only seems to occupy a small selection of CPU and memory.

  • Ok @phenomlab

    Thanks for your answer but with pm2 status command, I see a % of CPU used but not the number of CPU core used…

  • @DownPW how many cores do you have ?

  • @phenomlab

    What a loser I am lol 😵

    I configured only one core on my VM !!!

  • ha ha, i’m tired voila 🙂

    you say this:

    if you are using Cloudflare, this particular port (8061) isn’t routable with the free plan, so something to be aware of

    @phenomlab
    I’m using a free plan from CloudFlare, will this bother me for use Iframely on my server?

  • @DownPW only if you choose to not proxy the traffic (grey cloud only, which is just DNS rather than the default orange cloud)

  • @DownPW you will win this war 🙂

  • @phenomlab

    A CNAME on Cloudflare is not sufficient ?

    like this :

    16e51b39-776a-43d8-81a8-0b072cb52b6a-image.png

  • @DownPW no. It needs to be an A record. CNAME is canonical meaning that traffic sent to it will land up at your main nginx site. The A record will sent headers which nginx can use to route the traffic correctly.

    CNAME records do not have this and will resolve to the underlying host which will cause you problems. Useful for WWW and non-WWW, but that’s about it.

    Essentially, it’s an alias and not a record in it’s own right.

  • @phenomlab i think my ifamely started to not work i dont know why 😞 youtube embed not working 😞

    7b229e08-8c8f-4d9e-be5d-78a4f0bb1b37-image.png

    [PM2][ERROR] Process or Namespace iframely not found
    [PM2][WARN] Current process list is not synchronized with saved list. App iframely iframely differs. Type ‘pm2 save’ to synchronize.

  • @cagatay is the iframely service started ? That error message would indicate it’s not running


  • NodeBB v3 Android Problem

    Solved Configure
    4
    4 Votes
    4 Posts
    187 Views

    thank you fixed.

  • 0 Votes
    6 Posts
    214 Views

    @mventures You’d need to connect to the server and execute it directly - not on your local terminal. Review the guide below, which will show you how to gain access via SSH to your server

    https://docs.ovh.com/gb/en/dedicated/ssh-introduction/

    Once you have access, you’ll need to navigate to the actual folder where NodeBB is installed

    You’ll then need to change to the directory as shown below

    /home/unbuntu/nodebb

    fdffe673-bf63-4b6d-a728-5506fddc1aff-image.png

    In most cases, initial access takes you to the root of the file system. You can always issue pwd in a Linux terminal which will show you the Present Working Directory. From there, you can issue the command

    cd /home/ubuntu/nodebb

    Once in the NodeBB directory, you’d use the below commands

    ./nodebb stop git fetch && git checkout develop && git reset --hard origin/develop ./nodebb upgrade ./nodebb start

    Line 1 stops the NodeBB instance
    Line 2 gets the latest files from GIT (repository) and then checks out the development branch. It then resets the version you are using to the development branch ready for v3
    Line 3 Runs the upgrade once the new branch is set, and code pulled
    Line 4 Restarts the NodeBB instance after the upgrade has completed

    Note that when you restart NodeBB and log back in, things will look very different to what you had in v2.

  • 1 Votes
    6 Posts
    186 Views

    Up to you really 🙂

  • 5 Votes
    13 Posts
    476 Views
    'use strict'; const winston = require('winston'); const user = require('../user'); const notifications = require('../notifications'); const sockets = require('../socket.io'); const plugins = require('../plugins'); const meta = require('../meta'); module.exports = function (Messaging) { Messaging.notifyQueue = {}; // Only used to notify a user of a new chat message, see Messaging.notifyUser Messaging.notifyUsersInRoom = async (fromUid, roomId, messageObj) => { let uids = await Messaging.getUidsInRoom(roomId, 0, -1); uids = await user.blocks.filterUids(fromUid, uids); let data = { roomId: roomId, fromUid: fromUid, message: messageObj, uids: uids, }; data = await plugins.hooks.fire('filter:messaging.notify', data); if (!data || !data.uids || !data.uids.length) { return; } uids = data.uids; uids.forEach((uid) => { data.self = parseInt(uid, 10) === parseInt(fromUid, 10) ? 1 : 0; Messaging.pushUnreadCount(uid); sockets.in(`uid_${uid}`).emit('event:chats.receive', data); }); if (messageObj.system) { return; } // Delayed notifications let queueObj = Messaging.notifyQueue[`${fromUid}:${roomId}`]; if (queueObj) { queueObj.message.content += `\n${messageObj.content}`; clearTimeout(queueObj.timeout); } else { queueObj = { message: messageObj, }; Messaging.notifyQueue[`${fromUid}:${roomId}`] = queueObj; } queueObj.timeout = setTimeout(async () => { try { await sendNotifications(fromUid, uids, roomId, queueObj.message); } catch (err) { winston.error(`[messaging/notifications] Unabled to send notification\n${err.stack}`); } }, meta.config.notificationSendDelay * 1000); }; async function sendNotifications(fromuid, uids, roomId, messageObj) { const isOnline = await user.isOnline(uids); uids = uids.filter((uid, index) => !isOnline[index] && parseInt(fromuid, 10) !== parseInt(uid, 10)); if (!uids.length) { return; } if (roomId != 11) { // 5 Is the ID of the ID of the global chat room. Messaging.getUidsInRoom(roomId, 0, -1); // Proceed as normal. } else { user.getUidsFromSet('users:online', 0, -1); // Only notify online users. } const { displayname } = messageObj.fromUser; const isGroupChat = await Messaging.isGroupChat(roomId); const notification = await notifications.create({ type: isGroupChat ? 'new-group-chat' : 'new-chat', subject: `[[email:notif.chat.subject, ${displayname}]]`, bodyShort: `[[notifications:new_message_from, ${displayname}]]`, bodyLong: messageObj.content, nid: `chat_${fromuid}_${roomId}`, from: fromuid, path: `/chats/${messageObj.roomId}`, }); delete Messaging.notifyQueue[`${fromuid}:${roomId}`]; notifications.push(notification, uids); } };
  • iFramely self host help

    Solved Configure
    10
    9 Votes
    10 Posts
    1k Views

    @DownPW https://sudonix.com/topic/331/how-to-install-a-self-hosted-instance-of-iframely-for-use-with-nodebb

  • 14 Votes
    65 Posts
    5k Views

    @crazycells huh. Thanks. Will need to check that as well.

  • nodebb dropdown menu

    Solved Configure
    5
    0 Votes
    5 Posts
    418 Views

    @phenomlab said in nodebb dropdown menu:

    @kurulumu-net You set it like the below example taken from this site

    aae36790-3257-4bb2-ad5a-0d744309876a-image.png

    Which presents this

    77f47260-2941-4afe-9614-8e17dcfc8c19-image.png

    Very interesting…

    I actually thought this wasn’t possible, as I remember it being asked in the NodeBB forum.

    Is this something new that’s been implemented? I’ll 100% be doing that when I’m on the laptop over the weekend.

  • Iframely (Nodebb)

    Solved Configure
    40
    4 Votes
    40 Posts
    2k Views

    @DownPW This is now resolved. The issue was an incorrect URL specified in the Nodebb plugin. I’ve corrected this, and now it works as intended.