[Support] Linuxserver.io - SWAG - Secure Web Application Gateway (Nginx/PHP/Certbot/Fail2ban)


Recommended Posts

2 hours ago, blaine07 said:


Comment out the “proxy_redirect” line in the OnlyOffice CONF. Restart Swag. Profit.

 

yes , Comment out the “proxy_redirect” line can fix the swag problem , but the onlyoffice will not functionable in nextcloud any more .

i checked and found the reason is swag will redirect onlyoffice to a new web address without port , so the “proxy_redirect” is necessary. i am trying to fix this .... @SpaceInvaderOne ,can you pls help for this ? i am follow you tutorial of onlyoffice and nextcloud . thank you so much .

Link to comment

I'm seeing this too.  I commented out the "proxy_redirect" in the youtube conf file, so I don't get that duplication error, but now my SWAG log is showing:

 

Certbot failed to authenticate some domains (authenticator: standalone). The Certificate Authority reported these problems:

Domain: my.domain.abc
Type: connection
Detail: Fetching http://my.domain.abc/.well-known/acme-challenge/hhLVPzceBWEFUE3a-AaWLF8QnVj5KpUw3ysbsOUC8l8: Timeout during connect (likely firewall problem)

Hint: The Certificate Authority failed to download the challenge files from the temporary standalone webserver started by Certbot on port 80. Ensure that the listed domains point to this machine and that it can accept inbound connections from the internet.


Some challenges have failed.

 

I'm not sure if this is related to the update to SWAG.  It has worked perfectly for months without any change on my side (that I'm aware of).

 

Link to comment

Newbie here (actually, I've been running UnRaid for several years, but I haven't posted much to the forum)...

 

I had started to follow spaceinvaderone's video for setting up a reverse proxy with letsencrypt.  Obviously, due to the change from letsencrypt to swag, I then jumped over to his video on updating from letsencrypt to swag, except I just simply installed swag from the get go and followed the common instructions from both videos.  It appears that Ed was running UnRaid 6.9.0-beta back in October of 2020, but my current version 6.9.2 only has uptime rather than a Log button to the right of the Autostart button, so no log to view here. Clicking the log from the icon menu brings up a blank log.  However, the bigger issue is that clicking the Start option generates an Execution Error with an associated message of "No such container".  I've searched the forum for this sort of error with no luck and I've also uninstalled and reinstalled swag but still got the error.  Any suggestions?

Edited by BobCV
Link to comment
3 hours ago, BobCV said:

Newbie here (actually, I've been running UnRaid for several years, but I haven't posted much to the forum)...

 

I had started to follow spaceinvaderone's video for setting up a reverse proxy with letsencrypt.  Obviously, due to the change from letsencrypt to swag, I then jumped over to his video on updating from letsencrypt to swag, except I just simply installed swag from the get go and followed the common instructions from both videos.  It appears that Ed was running UnRaid 6.9.0-beta back in October of 2020, but my current version 6.9.2 only has uptime rather than a Log button to the right of the Autostart button, so no log to view here. Clicking the log from the icon menu brings up a blank log.  However, the bigger issue is that clicking the Start option generates an Execution Error with an associated message of "No such container".  I've searched the forum for this sort of error with no luck and I've also uninstalled and reinstalled swag but still got the error.  Any suggestions?

Solved my own problem...  Turns out that when I installed the docker, I failed to notice that there was an error (I don't think that it was until about the 3rd time of reinstalling it that I noticed the error).  At any rate, like Ed, I had created a unique network just the same as he had (except I named mine ProxyNet -- note the capitalization!).  However, the docker installation error message stated that the network proxynet (all lower case) did not exist.   I went in and removed that network and created another, but in all lower case, and the error went away... problem solved.

 

Not sure if this should be considered a reportable "bug", but users beware!

 

Thanks anyway!

Edited by BobCV
Link to comment

solved, as suggested here: 

removed docker img, wiped appdata/swag and reinstalled docker!

...................................................................................................................................

 

Hi! Yesterday i replaced my cache drive and had to reinstall all my docker containers.

everything went smooth except for SWAG... After reinstalling i get this error when starting the container:

Quote

Using Let's Encrypt as the cert provider
SUBDOMAINS entered, processing
SUBDOMAINS entered, processing
Only subdomains, no URL in cert
Sub-domains processed are: -d subdomain.mydomain.org
E-mail address entered: [email protected]
http validation is selected
Generating new certificate
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Requesting a certificate for subdomain.mydomain.org

Successfully received certificate.
Certificate is saved at: /etc/letsencrypt/live/subdomain.mydomain.org-0001/fullchain.pem
Key is saved at: /etc/letsencrypt/live/subdomain.mydomain.org-0001/privkey.pem
This certificate expires on 2021-10-15.
These files will be updated when the certificate renews.

NEXT STEPS:
- The certificate will need to be renewed before it expires. Certbot can automatically renew the certificate in the background, but you may need to take steps to enable that functionality. See https://certbot.org/renewal-setup for instructions.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
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
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Can't open privkey.pem for reading, No such file or directory
23196505500488:error:02001002:system library:fopen:No such file or directory:crypto/bio/bss_file.c:69:fopen('privkey.pem','r')

23196505500488:error:2006D080:BIO routines:BIO_new_file:no such file:crypto/bio/bss_file.c:76:

unable to load private key

Successfully received certificate.
Certificate is saved at: /etc/letsencrypt/live/subdomain.mydomain.org-0001/fullchain.pem
Key is saved at: /etc/letsencrypt/live/subdomain.mydomain.org-0001/privkey.pem
This certificate expires on 2021-10-15.
These files will be updated when the certificate renews.

NEXT STEPS:
- The certificate will need to be renewed before it expires. Certbot can automatically renew the certificate in the background, but you may need to take steps to enable that functionality. See https://certbot.org/renewal-setup for instructions.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
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
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Can't open privkey.pem for reading, No such file or directory
23196505500488:error:02001002:system library:fopen:No such file or directory:crypto/bio/bss_file.c:69:fopen('privkey.pem','r')

23196505500488:error:2006D080:BIO routines:BIO_new_file:no such file:crypto/bio/bss_file.c:76:

unable to load private key
cat: privkey.pem: No such file or directory
cat: fullchain.pem: No such file or directory
New certificate generated; starting nginx
Starting 2019/12/30, GeoIP2 databases require personal license key to download. Please retrieve a free license key from MaxMind,
and add a new env variable "MAXMINDDB_LICENSE_KEY", set to your license key.
[cont-init.d] 50-config: exited 0.
[cont-init.d] 60-renew: executing...
Can't open /config/keys/letsencrypt/fullchain.pem for reading, No such file or directory
23092982090568:error:02001002:system library:fopen:No such file or directory:crypto/bio/bss_file.c:69:fopen('/config/keys/letsencrypt/fullchain.pem','r')

23092982090568:error:2006D080:BIO routines:BIO_new_file:no such file:crypto/bio/bss_file.c:76:

unable to load certificate
The cert is either expired or it expires within the next day. Attempting to renew. This could take up to 10 minutes.
<------------------------------------------------->

<------------------------------------------------->
cronjob running on Sat Jul 17 10:20:53 CEST 2021
Running certbot renew
Saving debug log to /var/log/letsencrypt/letsencrypt.log

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Processing /etc/letsencrypt/renewal/subdomain.mydomain.org-0001.conf
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Certificate not yet due for renewal

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Processing /etc/letsencrypt/renewal/subdomain.mydomain.org.conf
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Renewal configuration file /etc/letsencrypt/renewal/subdomain.mydomain.org.conf is broken.
The error was: expected /etc/letsencrypt/live/subdomain.mydomain.org/cert.pem to be a symlink


.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
The following certificates are not due for renewal yet:
/etc/letsencrypt/live/subdomain.mydomain.org-0001/fullchain.pem expires on 2021-10-15 (skipped)
No renewals were attempted.
No hooks were run.

Additionally, the following renewal configurations were invalid:
/etc/letsencrypt/renewal/subdomain.mydomain.org.conf (parsefail)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
0 renew failure(s), 1 parse failure(s)
Ask for help or search for solutions at https://community.letsencrypt.org. See the logfile /var/log/letsencrypt/letsencrypt.log or re-run Certbot with -v for more details.
[cont-init.d] 60-renew: exited 0.
[cont-init.d] 70-templates: executing...
**** The following nginx confs have different version dates than the defaults that are shipped. ****
...

 

and then over and over again:

Quote

 

nginx: [emerg] cannot load certificate "/config/keys/letsencrypt/fullchain.pem": BIO_new_file() failed (SSL: error:02001002:system library:fopen:No such file or directory:fopen('/config/keys/letsencrypt/fullchain.pem','r') error:2006D080:BIO routines:BIO_new_file:no such file)

what sould i do?

Edited by pika
solved
Link to comment
On 7/14/2021 at 7:42 PM, blaine07 said:


Comment out the “proxy_redirect” line in the OnlyOffice CONF. Restart Swag. Profit.

This work properly with this modification to the conf. file. Thank alot. Unraid still remain to have the best community in my opinion!

Link to comment

I've been attempting to install wordpress, and the install.php file just downloads when I attempt to open. I can open the readme.html file, but any .php or "non-existing file" results in a download. "Non-existing file" is just referring to any address or file that doesn't exist in the www folder. Everything I've troubleshot makes me think it's php not running correctly but that I have no clue about. I've found various "fixes" across the web, but nothing has worked. Thanks in advance.

 

1) I own the domain, call it jm.us (this is not my default domain in the container, which is mfam.com)

2) I've listed *.jm.us as EXTRA DOMAIN in container

3) I have a jmus.conf file with server info pointing to subfolder in www

4) I can reach a standard html file by reverse proxy no problem (mfam.com to index.html works as well)

5) I've untar wordpress archive on computer and ssh upload to www sub dir

6) Attempting to reach install.php results in download of file

7) Also, I have tried to update the wp-config.php manually with db info, but still nothing

 

Note: some log and conf modified for my illusion of privacy

SWAG log

[cont-init.d] 10-adduser: exited 0.
[cont-init.d] 20-config: executing...
[cont-init.d] 20-config: exited 0.
[cont-init.d] 30-keygen: executing...
using keys found in /config/keys
[cont-init.d] 30-keygen: exited 0.
[cont-init.d] 50-config: executing...
Variables set:
PUID=99
PGID=100
TZ=America/New_York
URL=mfam.com
SUBDOMAINS=wildcard
EXTRA_DOMAINS=*.jm.us
ONLY_SUBDOMAINS=true
VALIDATION=dns
CERTPROVIDER=
DNSPLUGIN=cloudflare
[email protected]
STAGING=false

Using Let's Encrypt as the cert provider
SUBDOMAINS entered, processing
Wildcard cert for only the subdomains of mfam.com will be requested
EXTRA_DOMAINS entered, processing
Extra domains processed are: -d *.jm.us
E-mail address entered: [email protected]
dns validation via cloudflare plugin is selected
Certificate exists; parameters unchanged; starting nginx
Starting 2019/12/30, GeoIP2 databases require personal license key to download. Please retrieve a free license key from MaxMind,
and add a new env variable "MAXMINDDB_LICENSE_KEY", set to your license key.
[cont-init.d] 50-config: exited 0.
[cont-init.d] 60-renew: executing...
The cert does not expire within the next day. Letting the cron script handle the renewal attempts overnight (2:08am).
[cont-init.d] 60-renew: exited 0.
[cont-init.d] 70-templates: executing...
**** The following nginx confs have different version dates than the defaults that are shipped. ****

**** This may be due to user customization or an update to the defaults. ****
**** To update them to the latest defaults shipped within the image, delete these files and restart the container. ****
**** If they are user customized, check the date version at the top and compare to the upstream changelog via the link. ****

/config/nginx/ssl.conf
/config/nginx/site-confs/default
/config/nginx/proxy.conf
/config/nginx/nginx.conf
/config/nginx/authelia-server.conf
/config/nginx/authelia-location.conf

**** The following reverse proxy confs have different version dates than the samples that are shipped. ****

**** This may be due to user customization or an update to the samples. ****
**** You should compare them to the samples in the same folder to make sure you have the latest updates. ****
/config/nginx/proxy-confs/****.subdomain.conf
/config/nginx/proxy-confs/****.subdomain.conf
/config/nginx/proxy-confs/****.subdomain.conf

[cont-init.d] 70-templates: exited 0.
[cont-init.d] 90-custom-folders: executing...
[cont-init.d] 90-custom-folders: exited 0.
[cont-init.d] 99-custom-files: executing...
[custom-init] no custom files found exiting...
[cont-init.d] 99-custom-files: exited 0.
[cont-init.d] done.
[services.d] starting services
[services.d] done.
Server ready

 

default

# redirect all traffic to https
server {
	listen 80;
	listen [::]:80;
	server_name mfam.com;
	return 301 https://$host$request_uri;
}

# main server block
server {
	listen 443 ssl http2;
	listen [::]:443 ssl http2;

	root /config/www;
	index index.html index.htm index.php;

	server_name mfam.com;

	# enable subfolder method reverse proxy confs
	include /config/nginx/proxy-confs/*.subfolder.conf;

	# all ssl related config moved to ssl.conf
	include /config/nginx/ssl.conf;

	# enable for ldap auth
	#include /config/nginx/ldap.conf;

	# enable for Authelia
	#include /config/nginx/authelia-server.conf;

	# enable for geo blocking
	# See /config/nginx/geoip2.conf for more information.
	#if ($allowed_country = no) {
	#return 444;
	#}

	client_max_body_size 0;

	location / {
		try_files $uri $uri/ /index.html /index.php?$args =404;
	}

	location ~ \.php$ {
		fastcgi_split_path_info ^(.+\.php)(/.+)$;
		fastcgi_pass 127.0.0.1:9000;
		fastcgi_index index.php;
		include /etc/nginx/fastcgi_params;
	}
 fastcgi_buffer_size 4K; #from a fix online
 fastcgi_buffers 64 4k;  #from a fix online

}

# enable subdomain method reverse proxy confs
include /config/nginx/proxy-confs/*.subdomain.conf;
# enable proxy cache for auth
proxy_cache_path cache/ keys_zone=auth_cache:10m;

 

jmus.conf

# redirect all traffic to https
server {
	listen 80;
	listen [::]:80; 
	server_name *.jm.us;
	return 301 https://$host$request_uri;
}

# main server block
server {
	listen 443 ssl http2;
	listen [::]:443 ssl http2;

	root /config/www/wp_jmus/;
	index index.html index.htm index.php;

	server_name *.jm.us;

	# all ssl related config moved to ssl.conf
	include /config/nginx/ssl.conf;
}

 

Link to comment

I'm having a strange issue where SWAG stops working after seemingly random amounts of time. I will try and browse to a site fronted by swag and it seems like it just isnt responding. I then go and restart the docker and instantly the page loads once the reboot finishs. I don't see anything in the docker logs and have tried checking the nginx error.log in the container but it is usually just a single line unrelated to the incident.

Link to comment

Hi all,

 

Having a hard time with SWAG and authentication right now. Long story short, I'm trying to access my Sonarr calendar file externally without authentication.

 

Here's the code I'm using in my config file

location / {
	auth_basic "Restricted"
	auth_basic_user_file /config/nginx/.htpasswd;

	location /feed/calendar/ {
	auth_basic "off";
	}
}

 

And the url of my sonarr ics file is

https://SUB.DOMAIN/feed/calendar/Sonarr.ics?apikey=REDACTED

 

Any suggestions? I cannot get it to work for the life of me.

Link to comment
On 7/15/2021 at 10:10 AM, h3x3d said:

I'm seeing this too.  I commented out the "proxy_redirect" in the youtube conf file, so I don't get that duplication error, but now my SWAG log is showing:

 


Certbot failed to authenticate some domains (authenticator: standalone). The Certificate Authority reported these problems:

Domain: my.domain.abc
Type: connection
Detail: Fetching http://my.domain.abc/.well-known/acme-challenge/hhLVPzceBWEFUE3a-AaWLF8QnVj5KpUw3ysbsOUC8l8: Timeout during connect (likely firewall problem)

Hint: The Certificate Authority failed to download the challenge files from the temporary standalone webserver started by Certbot on port 80. Ensure that the listed domains point to this machine and that it can accept inbound connections from the internet.


Some challenges have failed.

 

I'm not sure if this is related to the update to SWAG.  It has worked perfectly for months without any change on my side (that I'm aware of).

 

Embarrassing as it is to admit, my particular problem was resolved with a router restart. I'm still using the one from my ISP (replacing it is on the list).

 

The port forwarding had stopped working which is why the cert check failed. 

 

I just went down the wrong path as I had recently had to comment out that duplicate redirect line in the YouTube conf file. 

 

Other than a couple of restarts over the last few months, it's been rock solid.

Link to comment

Hello everyone, I am having issues getting a reverse proxy working correctly.  I have a pretty good idea of the concept of what we are trying to do, but by no means am I an expert. I initally followed This tutorial to set up SWAG. I got a domain from GOOGLE but could not generate a certification. I have a Comcast/Xfinity router and they were blocking port 80, So I continued with This tutorial by spaceinvaderone to set up cloudflare.

 

After setting everything up, I checked the log for SWAG and saw no errors and  successfully created a cert.

 

In cloudflare I created a CNAME "plex" and "qbittorrent" and left the default "proxied" option on and pointed them to my duckdns. If i navigate to plex.mydomain.me i get an unreachable error. If I change the option to "DNS Only" I am then directed to log into my ISP router, also cloudlflare states my IP is exposed in this setting.

 

I have edited the conf files listed in the tutorial as instructed but I am not sure if the issue is that I did this wrong or my comcast router is not redirecting traffic correctly.  If I navigate to mysubdomain.duckdns.org:32400 I can reach my plex server.

 

I am not sure where to begin troubleshooting this. Thanks in advance !

Link to comment
10 hours ago, xxbigfootxx said:

I recently swapped out my Cache drive and moved all Appdata files to the array, Dashboard said the disk was empty and i couldn't see any files after checking in MC. 

 

But now I keep getting these errors from Swag. I've reinstalled the docker container but it hasn't done anything.

image.png

Either the cert file doesn't exist or the permissions on it are incorrect.

Link to comment

Update from my issue posted above .

 

I restarted my router and things are working better however I am still having the issue if I go to Subdomain.Mydomain.me I am directed to my ISP router login page rather than going to my docker.

 

Entering the duckdns.com:PORT# takes me to the docker but I'm sure this is not a secure connection. Any ideas?

Link to comment
9 minutes ago, moose1207 said:

Update from my issue posted above .

 

I restarted my router and things are working better however I am still having the issue if I go to Subdomain.Mydomain.me I am directed to my ISP router login page rather than going to my docker.

 

Entering the duckdns.com:PORT# takes me to the docker but I'm sure this is not a secure connection. Any ideas?

Did you forward port 80 and 443 in the router to your container?

Link to comment
14 minutes ago, Lygris said:

Did you forward port 80 and 443 in the router to your container?

 

Unless I am mistaken, Comcast routers do not allow redirects, I created a "port forward" but I think that just essentially opens the port.

 

My only options are to select my server and then type a port number I want opened.  Those port numbers I selected were 180 and 1443. In my docker container I have set up 180 -->80 and 1443-->443

Link to comment

it should be vice vers

 

external 80 to internal 180 (in case you use swag in bridge or proxynet mode), same for external 443 to internal 1443

 

like described in all tutorials ... http:// will lead to port 80 on your router and https will lead to 443 on your router.

Edited by alturismo
Link to comment

assuming your unraid server is running on ip 10.0.0.195

 

you need to forward external 80 to 180 and external 443 to 1443,

 

this looks more like a simple 180 forward rule, so you could reach your swag only by http://whatever.mydomain.com:180 or http://whatever.mydomain.com:1443 which ir prolly not what you want ... and wont work as swag wants to generate cert(s) and needs http and https

 

for usage like https://whatever.yourdomain.com

 

like described ... in the readme and many times here in this thread, so check your router howto use it and forward

 

image.png.16b60145c1c409bbe6fa9b7d03d7b7ad.png

image.png.6d99790db787499aa940895e8914367b.png

Link to comment
14 minutes ago, moose1207 said:

Attached images of what I have set up.

 

Do I need to use cloudflare for dns auth? Is there a better solution maybe?

 

 

docker.png

forward.png

When you try and go to subdomain.duckdns.com that is pointing to your router on port 80 or 443, so you need to forward 80 and 443 from your router to your docker host at port 180 and 1443.

 

From a quick google it doesnt look like your comcast router supports port forwarding to different destination ports, so you need to put the container on a custom network which it looks like you already did but didn't assign an ip. Once you assign an ip to the container you just forward 80 and 443 on the router to that ip address.

Link to comment
2 minutes ago, alturismo said:

assuming your unraid server is running on ip 10.0.0.195

 

you need to forward external 80 to 180 and external 443 to 1443,

 

this looks more like a simple 180 forward rule, so you could reach your swag only by http://whatever.mydomain.com:180 or http://whatever.mydomain.com:1443 which ir prolly not what you want ... and wont work as swag wants to generate cert(s) and needs http and https

 

for usage like https://whatever.yourdomain.com

 

like described ... in the readme and many times here in this thread, so check your router howto use it and forward

 

image.png.16b60145c1c409bbe6fa9b7d03d7b7ad.png

image.png.6d99790db787499aa940895e8914367b.png

Got it! So unfortunately with the freebie router that comcast provides they have removed access to manage it, and now you can only do a simple forward rule Port X to Port X, and NOT Port X to Port  Y.

 

I have forwarded 443 on my router and now it seems to be working right. I think I'll just buy a proper router I can manage, and ditch the comcast supplied one.

 

Thanks!

Link to comment
3 minutes ago, Lygris said:

When you try and go to subdomain.duckdns.com that is pointing to your router on port 80 or 443, so you need to forward 80 and 443 from your router to your docker host at port 180 and 1443.

 

From a quick google it doesnt look like your comcast router supports port forwarding to different destination ports, so you need to put the container on a custom network which it looks like you already did but didn't assign an ip. Once you assign an ip to the container you just forward 80 and 443 on the router to that ip address.

I'm still learning and loving it lol. I didn't realize I can set up a unique IP address for the docker and use that for navigation/forwarding. I'll try that out. Thanks!

Link to comment
5 minutes ago, moose1207 said:

I'm still learning and loving it lol. I didn't realize I can set up a unique IP address for the docker and use that for navigation/forwarding. I'll try that out. Thanks!

You will have to enable bridging on the network settings page for your interface and then set the "Ipv4 custom network on interface brX" in docker settings to your internal network space, then assign the ip to the container in your internal range. It will appear just like any other thing connected to your network at that point and you can use port 80 since it's on a different ip than unraid is using.

 

 

another option would be to change the port unraid is using for the webgui to something else so the container can use 80, but the bridge network way is what i prefer

Edited by Lygris
Link to comment

I noticed this while checking the logs on swag, why does the cert use the most recent subdomain name listed in the container? As you can see the last subdomain I added was read (read.matchettmedia.com), and now that is being used as the certificate name? 

 

image.png.56fdc9d06d12ac023c5ac34318ecee9e.png

 

Can i change this to a wildcard cert or anything? *.matchettmedia.com, or is this how it's designed?

Link to comment

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.